|
163
|
1 /* ----------------------------------------------------------------------------
|
|
|
2 * File : input.c
|
|
|
3 * Purpose : input routine to create a Tree from an input file
|
|
|
4 * ----------------------------------------------------------------------------
|
|
|
5 */
|
|
|
6
|
|
|
7 #include <ctype.h>
|
|
|
8 #include <string.h>
|
|
167
|
9 #include <stdlib.h>
|
|
163
|
10 #include "defs.h"
|
|
|
11 #include "tree.h"
|
|
|
12 #include "input.h"
|
|
167
|
13 #include "dbl.h"
|
|
|
14 #include "intf.h"
|
|
163
|
15
|
|
|
16 char *EnvNm; /* Stores name of current Envir file */
|
|
|
17 static int tokDepth = 0; /* Depth in tree of current token */
|
|
|
18 static int prevTokDepth; /* Depth in tree of prev token */
|
|
|
19
|
|
167
|
20 static void SaveSubtree(Tree *tree, int level, FILE *fp);
|
|
163
|
21
|
|
|
22 /* ----------------------------------------------------------------------------
|
|
167
|
23 *
|
|
163
|
24 * GetNextToken() reads the next token from the file indicated by 'fp' and
|
|
|
25 * returns a token. If the token is TOKEN_LABEL, the lexeme is returned
|
|
|
26 * in 'lexeme'. If memory could not be allocated for 'lexeme', it is NULL.
|
|
167
|
27 *
|
|
163
|
28 * The following tokens are supported:
|
|
167
|
29 *
|
|
163
|
30 * - TOKEN_LABEL: a string of characters, up to 'TOKEN-MAXSIZ'
|
|
|
31 * characters, delimited by number of leading spaces and newlines.
|
|
|
32 * If a label has more than this number of characters, the rest are
|
|
167
|
33 * ignored.
|
|
163
|
34 * - TOKEN_EOF
|
|
167
|
35 *
|
|
163
|
36 * ----------------------------------------------------------------------------
|
|
|
37 */
|
|
|
38
|
|
167
|
39 static int
|
|
|
40 GetNextToken(FILE *fp, char **lexeme)
|
|
163
|
41 {
|
|
|
42 static char lexbuf[INPUT_BUFSIZ];
|
|
|
43 register char *curbuf = lexbuf;
|
|
|
44 register int charct = 0;
|
|
|
45 register int c;
|
|
167
|
46
|
|
163
|
47 prevTokDepth = tokDepth;
|
|
|
48 tokDepth = 0;
|
|
167
|
49
|
|
163
|
50 c = getc(fp);
|
|
167
|
51
|
|
163
|
52 /* skip over leading whitespace */
|
|
|
53 while (c == ' ')
|
|
|
54 {
|
|
|
55 tokDepth++;
|
|
|
56 c = getc(fp);
|
|
|
57 }
|
|
|
58 tokDepth /= 2;
|
|
167
|
59
|
|
163
|
60 while (1)
|
|
|
61 {
|
|
|
62 switch (c)
|
|
|
63 {
|
|
|
64 case EOF:
|
|
169
|
65 return TOKEN_EOF;
|
|
163
|
66 case '\n':
|
|
|
67 *curbuf = '\0';
|
|
|
68 *lexeme = strdup(lexbuf);
|
|
169
|
69 return TOKEN_LABEL;
|
|
163
|
70 default:
|
|
|
71 *curbuf++ = c;
|
|
|
72 charct++;
|
|
|
73 /* check for buffer overflow */
|
|
|
74 if (charct >= TOKEN_MAXSIZ)
|
|
|
75 {
|
|
|
76 *curbuf = '\0';
|
|
|
77 *lexeme = strdup(lexbuf);
|
|
|
78 /* since buffer is full, skip over remaining chars */
|
|
|
79 c = getc(fp);
|
|
|
80 while (c != '\n' && c != EOF)
|
|
|
81 c = getc(fp);
|
|
|
82 if (c == EOF)
|
|
|
83 ungetc(c, fp);
|
|
169
|
84 return TOKEN_LABEL;
|
|
163
|
85 }
|
|
|
86 else
|
|
|
87 c = getc(fp);
|
|
|
88 }
|
|
|
89 }
|
|
|
90 }
|
|
|
91
|
|
|
92
|
|
|
93 /* ----------------------------------------------------------------------------
|
|
167
|
94 *
|
|
163
|
95 * SetNodeLabelAndValue() sets the label text of the specified node and
|
|
|
96 * stores any string value following the label and preceded by a "^^"
|
|
167
|
97 * delimiter.
|
|
|
98 *
|
|
163
|
99 * ----------------------------------------------------------------------------
|
|
|
100 */
|
|
|
101
|
|
|
102 void
|
|
167
|
103 SetNodeLabelAndValue(Tree *node, char *label_and_value)
|
|
163
|
104 {
|
|
|
105 char* val;
|
|
|
106
|
|
167
|
107 if ((val = strstr(label_and_value, "^^")))
|
|
163
|
108 {
|
|
|
109 /* Set node value to string following ^^ delimiter. */
|
|
|
110 node->value = val+2;
|
|
|
111 /* Erase value from input string, leaving only label. */
|
|
|
112 *val = '\0';
|
|
|
113 }
|
|
|
114 else
|
|
|
115 { node->value = NULL; }
|
|
|
116 SetNodeLabel(node, label_and_value);
|
|
|
117 }
|
|
|
118
|
|
|
119
|
|
|
120 /* ----------------------------------------------------------------------------
|
|
167
|
121 *
|
|
163
|
122 * ReadTreeFromFile() takes a filename argument and constructs
|
|
|
123 * a Tree from the labels in the file. If a tree could be constructed,
|
|
|
124 * even partially, it is returned by the function. NULL is returned if
|
|
|
125 * the file could not be opened or there was insufficient memory for
|
|
|
126 * creating the tree.
|
|
167
|
127 *
|
|
163
|
128 * ----------------------------------------------------------------------------
|
|
|
129 */
|
|
|
130
|
|
|
131 Tree*
|
|
167
|
132 ReadTreeFromFile(char *fname, ErrCode *error)
|
|
163
|
133 {
|
|
|
134 FILE *infile;
|
|
|
135 int inside_list = 0; /* for semantic checking */
|
|
|
136 int first_child = TRUE;
|
|
167
|
137
|
|
163
|
138 int token;
|
|
|
139 char *label;
|
|
167
|
140
|
|
163
|
141 Tree *tree = NULL; /* the return value of this function */
|
|
|
142 Tree *parent = NULL; /* parent of 'node' */
|
|
|
143 Tree *node; /* current node */
|
|
|
144 Tree *new_node; /* new node to add after current node */
|
|
167
|
145
|
|
163
|
146 *error = ERR_NONE;
|
|
167
|
147
|
|
163
|
148 infile = fopen(fname, "r");
|
|
|
149 if (infile == NULL)
|
|
|
150 {
|
|
|
151 *error = ERR_OPENFAIL;
|
|
169
|
152 return NULL;
|
|
163
|
153 }
|
|
167
|
154
|
|
163
|
155 /* first line of file is Envir file name, save */
|
|
|
156 token = GetNextToken(infile, &label);
|
|
|
157 if (token == TOKEN_EOF)
|
|
|
158 {
|
|
|
159 *error = ERR_EMPTYFILE;
|
|
|
160 fclose(infile);
|
|
169
|
161 return NULL;
|
|
163
|
162 }
|
|
|
163 else if (token == TOKEN_LABEL)
|
|
|
164 {
|
|
|
165 if (label == NULL)
|
|
|
166 {
|
|
|
167 *error = ERR_MEMALLOC;
|
|
|
168 fclose(infile);
|
|
169
|
169 return NULL;
|
|
163
|
170 }
|
|
|
171 EnvNm = strdup(label);
|
|
|
172 }
|
|
167
|
173
|
|
163
|
174 /* set up root node */
|
|
|
175 token = GetNextToken(infile, &label);
|
|
|
176 if (token == TOKEN_EOF)
|
|
|
177 {
|
|
|
178 *error = ERR_EMPTYFILE;
|
|
|
179 fclose(infile);
|
|
169
|
180 return NULL;
|
|
163
|
181 }
|
|
|
182 else if (token == TOKEN_LABEL)
|
|
|
183 {
|
|
|
184 if (label == NULL)
|
|
|
185 {
|
|
|
186 *error = ERR_MEMALLOC;
|
|
|
187 fclose(infile);
|
|
169
|
188 return NULL;
|
|
163
|
189 }
|
|
|
190 tree = MakeNode();
|
|
|
191 if (tree == NULL)
|
|
|
192 {
|
|
|
193 *error = ERR_MEMALLOC;
|
|
|
194 fclose(infile);
|
|
|
195 free(label);
|
|
169
|
196 return NULL;
|
|
163
|
197 }
|
|
|
198 SetNodeLabelAndValue(tree, label);
|
|
|
199 tree->parent = NULL;
|
|
|
200 node = tree;
|
|
|
201 }
|
|
|
202 else
|
|
|
203 {
|
|
|
204 *error = ERR_NOROOT;
|
|
|
205 fclose(infile);
|
|
169
|
206 return NULL;
|
|
163
|
207 }
|
|
167
|
208
|
|
163
|
209 /* add children and siblings */
|
|
|
210 while (1)
|
|
|
211 {
|
|
|
212 token = GetNextToken(infile, &label);
|
|
|
213 if (token == TOKEN_EOF)
|
|
|
214 break;
|
|
167
|
215
|
|
163
|
216 if (tokDepth > prevTokDepth) /* then new subtree */
|
|
|
217 {
|
|
|
218 inside_list++;
|
|
|
219 first_child = TRUE;
|
|
|
220 parent = node;
|
|
|
221 }
|
|
|
222 else if (tokDepth < prevTokDepth) /* then end of subtree */
|
|
|
223 if (!inside_list)
|
|
|
224 {
|
|
|
225 *error = ERR_NOBEGIN;
|
|
|
226 fclose(infile);
|
|
169
|
227 return tree;
|
|
163
|
228 }
|
|
|
229 else
|
|
|
230 while (tokDepth < inside_list)
|
|
|
231 {
|
|
|
232 inside_list--;
|
|
|
233 node = node->parent;
|
|
|
234 parent = node->parent;
|
|
|
235 }
|
|
167
|
236
|
|
163
|
237 if (label == NULL)
|
|
|
238 {
|
|
|
239 *error = ERR_MEMALLOC;
|
|
|
240 fclose(infile);
|
|
169
|
241 return tree;
|
|
163
|
242 }
|
|
|
243 if (parent == NULL)
|
|
|
244 {
|
|
|
245 *error = ERR_MANYROOT;
|
|
|
246 fclose(infile);
|
|
|
247 free(label);
|
|
169
|
248 return tree;
|
|
163
|
249 }
|
|
|
250 else
|
|
|
251 {
|
|
|
252 new_node = MakeNode();
|
|
|
253 if (new_node == NULL)
|
|
|
254 {
|
|
|
255 *error = ERR_MEMALLOC;
|
|
|
256 fclose(infile);
|
|
|
257 free(label);
|
|
169
|
258 return tree;
|
|
163
|
259 }
|
|
|
260 SetNodeLabelAndValue(new_node, label);
|
|
|
261 new_node->parent = parent;
|
|
167
|
262
|
|
163
|
263 if (first_child)
|
|
|
264 {
|
|
|
265 new_node->parent->child = new_node;
|
|
|
266 first_child = FALSE;
|
|
|
267 }
|
|
|
268 else
|
|
|
269 node->sibling = new_node;
|
|
167
|
270
|
|
163
|
271 node = new_node;
|
|
|
272 /*
|
|
|
273 * printf("%3d tok: '%s'; tokDepth: %d; prevTokDepth: %d; inside_list: %d\n",
|
|
|
274 * NumNodes, node->label.text, tokDepth, prevTokDepth, inside_list);
|
|
|
275 */
|
|
|
276 }
|
|
|
277 }
|
|
|
278 fclose(infile);
|
|
169
|
279 return tree;
|
|
163
|
280 }
|
|
|
281
|
|
|
282
|
|
|
283 /* ----------------------------------------------------------------------------
|
|
167
|
284 *
|
|
163
|
285 * SaveTreeToFile() takes a tree and saves it to a file specified by 'fname.'
|
|
|
286 * If the file could not be opened for writing, False is returned. Otherwise,
|
|
|
287 * True is returned.
|
|
167
|
288 *
|
|
163
|
289 * ----------------------------------------------------------------------------
|
|
|
290 */
|
|
|
291
|
|
167
|
292 int
|
|
|
293 SaveTreeToFile(Tree *tree, char *fname)
|
|
163
|
294 {
|
|
|
295 FILE *outfile;
|
|
167
|
296
|
|
163
|
297 outfile = fopen(fname, "w");
|
|
|
298 if (outfile == NULL)
|
|
169
|
299 return FALSE;
|
|
167
|
300
|
|
163
|
301 fprintf(outfile, "%s\n", EnvNm); /* Save Env File Name */
|
|
|
302 fprintf(outfile, "%s\n", tree->label.text);
|
|
|
303 if (tree->child)
|
|
|
304 SaveSubtree(tree->child, 0, outfile);
|
|
167
|
305
|
|
163
|
306 fclose(outfile);
|
|
169
|
307 return TRUE;
|
|
163
|
308 }
|
|
|
309
|
|
|
310
|
|
|
311 /* ----------------------------------------------------------------------------
|
|
167
|
312 *
|
|
163
|
313 * SaveSubtree() is the recursive procedure that supports SaveTreeToFile().
|
|
|
314 *
|
|
|
315 * ----------------------------------------------------------------------------
|
|
|
316 */
|
|
|
317
|
|
|
318 static void
|
|
167
|
319 SaveSubtree(Tree *tree, int level, FILE *fp)
|
|
163
|
320 {
|
|
|
321 int i;
|
|
167
|
322
|
|
163
|
323 level++;
|
|
|
324 for ( ; tree ; tree = tree->sibling)
|
|
|
325 {
|
|
|
326 for (i = 0 ; i < level ; i++)
|
|
|
327 {
|
|
|
328 putc(' ', fp);
|
|
|
329 putc(' ', fp);
|
|
|
330 }
|
|
|
331 fprintf(fp, "%s\n", tree->label.text);
|
|
|
332 if (tree->child)
|
|
|
333 SaveSubtree(tree->child, level, fp);
|
|
|
334 }
|
|
|
335 level--;
|
|
|
336 }
|