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