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