Initial Commit
[packages] / xemacs-packages / oo-browser / tree-x / input.c
1 /* ----------------------------------------------------------------------------
2  * File    : input.c
3  * Purpose : input routine to create a Tree from an input file
4  * ----------------------------------------------------------------------------
5  */
6
7 /* SunOS 5.4+ way to ask for all functions in header files. */
8 #define __EXTENSIONS__ 1
9
10 #include <ctype.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include "defs.h"
14 #include "tree.h"
15 #include "input.h"
16 #include "dbl.h"
17 #include "intf.h"
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
23 static void SaveSubtree(Tree *tree, int level, FILE *fp);
24
25 /* ----------------------------------------------------------------------------
26  *
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.
30  *
31  *   The following tokens are supported:
32  *
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
36  *       ignored.
37  *     - TOKEN_EOF
38  *
39  * ----------------------------------------------------------------------------
40  */
41
42 static int
43 GetNextToken(FILE *fp, char **lexeme)
44 {
45   static   char  lexbuf[INPUT_BUFSIZ];
46   register char *curbuf = lexbuf;
47   register int   charct = 0;
48   register int   c;
49
50   prevTokDepth = tokDepth;
51   tokDepth = 0;
52
53   c = getc(fp);
54
55   /* skip over leading whitespace */
56   while (c == ' ')
57     {
58       tokDepth++;
59       c = getc(fp);
60     }
61   tokDepth /= 2;
62
63   while (1)
64     {
65       switch (c)
66         {
67         case EOF:
68           return TOKEN_EOF;
69         case '\n':
70           *curbuf = '\0';
71           *lexeme = strdup(lexbuf);
72           return TOKEN_LABEL;
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);
87               return TOKEN_LABEL;
88             }
89           else
90             c = getc(fp);
91         }
92     }
93 }
94
95
96 /* ----------------------------------------------------------------------------
97  *
98  *   SetNodeLabelAndValue() sets the label text of the specified node and
99  *   stores any string value following the label and preceded by a "^^"
100  *   delimiter.
101  *
102  * ----------------------------------------------------------------------------
103  */
104
105 void
106 SetNodeLabelAndValue(Tree *node, char *label_and_value)
107 {
108    char*       val;
109
110    if ((val = strstr(label_and_value, "^^")))
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 /* ----------------------------------------------------------------------------
124  *
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.
130  *
131  * ----------------------------------------------------------------------------
132  */
133
134 Tree*
135 ReadTreeFromFile(char *fname, ErrCode *error)
136 {
137   FILE *infile;
138   int   inside_list = 0;        /* for semantic checking */
139   int   first_child = TRUE;
140
141   int   token;
142   char *label;
143
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 */
148
149   *error = ERR_NONE;
150
151   infile = fopen(fname, "r");
152   if (infile == NULL)
153     {
154       *error = ERR_OPENFAIL;
155       return NULL;
156     }
157
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);
164       return NULL;
165     }
166   else if (token == TOKEN_LABEL)
167     {
168       if (label == NULL)
169         {
170           *error = ERR_MEMALLOC;
171           fclose(infile);
172           return NULL;
173         }
174       EnvNm = strdup(label);
175     }
176
177   /* set up root node */
178   token = GetNextToken(infile, &label);
179   if (token == TOKEN_EOF)
180     {
181       *error = ERR_EMPTYFILE;
182       fclose(infile);
183       return NULL;
184     }
185   else if (token == TOKEN_LABEL)
186     {
187       if (label == NULL)
188         {
189           *error = ERR_MEMALLOC;
190           fclose(infile);
191           return NULL;
192         }
193       tree = MakeNode();
194       if (tree == NULL)
195         {
196           *error = ERR_MEMALLOC;
197           fclose(infile);
198           free(label);
199           return NULL;
200         }
201       SetNodeLabelAndValue(tree, label);
202       tree->parent = NULL;
203       node = tree;
204     }
205   else
206     {
207       *error = ERR_NOROOT;
208       fclose(infile);
209       return NULL;
210     }
211
212   /* add children and siblings */
213   while (1)
214     {
215       token = GetNextToken(infile, &label);
216       if (token == TOKEN_EOF)
217         break;
218
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);
230             return tree;
231           }
232         else
233           while (tokDepth < inside_list)
234             {
235               inside_list--;
236               node = node->parent;
237               parent = node->parent;
238             }
239
240       if (label == NULL)
241         {
242           *error = ERR_MEMALLOC;
243           fclose(infile);
244           return tree;
245         }
246       if (parent == NULL)
247         {
248           *error = ERR_MANYROOT;
249           fclose(infile);
250           free(label);
251           return tree;
252         }
253       else
254         {
255           new_node = MakeNode();
256           if (new_node == NULL)
257             {
258               *error = ERR_MEMALLOC;
259               fclose(infile);
260               free(label);
261               return tree;
262             }
263           SetNodeLabelAndValue(new_node, label);
264           new_node->parent = parent;
265
266           if (first_child)
267             {
268               new_node->parent->child = new_node;
269               first_child = FALSE;
270             }
271           else
272             node->sibling = new_node;
273
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);
282   return tree;
283 }
284
285
286 /* ----------------------------------------------------------------------------
287  *
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.
291  *
292  * ----------------------------------------------------------------------------
293  */
294
295 int
296 SaveTreeToFile(Tree *tree, char *fname)
297 {
298   FILE *outfile;
299
300   outfile = fopen(fname, "w");
301   if (outfile == NULL)
302     return FALSE;
303
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);
308
309   fclose(outfile);
310   return TRUE;
311 }
312
313
314 /* ----------------------------------------------------------------------------
315  *
316  *   SaveSubtree() is the recursive procedure that supports SaveTreeToFile().
317  *
318  * ----------------------------------------------------------------------------
319  */
320
321 static void
322 SaveSubtree(Tree *tree, int level, FILE *fp)
323 {
324   int i;
325
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 }