1 //
2 // ipv2_read.cc
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 /* This file provides the routines to do the initial parse of the input
29  * file. */
30 
31 #include <util/misc/string.h>
32 #ifdef DEC
33 #include <math.h>
34 #else
35 #include <stdlib.h>
36 #endif
37 #include <util/keyval/ipv2.h>
38 
39 #include <stdio.h>
40 #include <iostream>
41 #include <fstream>
42 
43 using namespace std;
44 using namespace sc;
45 
46 /* Initialize the ip routines.  This involves parsing the entire file and
47  * converting it into an internal representation. */
48 /* in = the input file. */
49 /* out = the output file. */
50 void
ip_initialize(istream & in,ostream & out)51 IPV2::ip_initialize(istream&in,ostream&out)
52 {
53   ip_initialized = 1;
54 
55   ip_in = &in;
56   ip_out = &out;
57 
58   /* Just in case a scanner has already been running. */
59   lexer->switch_streams(ip_in, ip_out);
60 
61   /* If ip_tree is not NULL, then ip_initialize has been called twice,
62    * with a done inbetween. Call done now. */
63   if (ip_tree) {
64       warn("ip_initialize has been called twice without an IPV2::done");
65       done();
66     }
67 
68   sub_tree = ip_tree;
69 
70   yparse();
71 
72   /* The initial cwk list is nothing. */
73   cwk_clear();
74 
75   ip_internal_values();
76 }
77 
78 /* Continue adding to the ip_tree with, presumably, another input file.
79  * This should be called after ip_initialize has been called with different
80  * input file.  Multiple calls to ip_append, with different input files,
81  * are allowed. */
82 /* in = the input file. */
83 /* out = the output file. */
84 void
ip_append(istream & in,ostream & out)85 IPV2::ip_append(istream&in,ostream&out)
86 {
87 
88   ip_in = &in;
89   ip_out = &out;
90 
91   lexer->switch_streams(ip_in, ip_out);
92 
93   if (sub_tree != NULL) {
94       error("ip_append: sub_tree != NULL - impossible");
95     }
96 
97   yparse();
98 
99   ip_internal_values();
100 }
101 
102 /* This routine can be called by the user after the ip routines have been
103  * initialized.  It look for a prefix"dir" in the cwk list and a prefix"files"
104  * array.  If prefix"dir" is found this concatenated with each of the
105  * prefix"files" that does not begin with a '/'.  Each of these files is
106  * ip_append'ed to the set of inputs. */
107 void
append_from_input(const char * prefix,ostream & outfile)108 IPV2::append_from_input(const char*prefix,ostream&outfile)
109 {
110   char keyword[KEYWORD_LENGTH];
111   const char *dir;
112   const char *file;
113   char dirfile[512];
114   int i,nfile;
115 
116   /* Get the prefix. */
117   strcpy(keyword,prefix);
118   strcat(keyword,"dir");
119   if (value(keyword,&dir,0) != OK) dir = NULL;
120 
121   strcpy(keyword,prefix);
122   strcat(keyword,"files");
123   if (count(keyword,&nfile,0)!=OK) return;
124   for (i=0; i<nfile; i++) {
125       if (value_v(keyword,&file,1,&i) == OK) {
126 	  if (dir && (file[0] != '/')) strcpy(dirfile,dir);
127 	  else dirfile[0] = '\0';
128 	  strcat(dirfile,file);
129           ifstream infile(dirfile, ios::in);
130 	  if (infile.bad()) {
131               ExEnv::errn() << "WARNING: IPV2::append_from_input: "
132                    << "couldn't open the file "
133                    << dirfile
134                    << endl;
135 	    }
136 	  else {
137               outfile << "appending " << dirfile << " to input" << endl;
138 	      ip_append(infile,outfile);
139 	    }
140 	}
141     }
142 }
143 
144 
145 /* Set up internal ip variables based on the input that has been read in. */
146 void
ip_internal_values()147 IPV2::ip_internal_values()
148 {
149   int errcod;
150 
151   errcod = boolean(":ip:keyword",&ip_keyword,0);
152   if (errcod) ip_keyword = 0;
153 
154 }
155 
156 /* Free all of the data. */
157 void
done()158 IPV2::done()
159 {
160   ip_free_keyword_tree(ip_tree);
161   ip_tree = NULL;
162   sub_tree = NULL;
163   ip_in = NULL;
164   ip_out = NULL;
165 }
166 
167 void
ip_push_keyword(char * keyword)168 IPV2::ip_push_keyword(char*keyword)
169 {
170   ip_push_keyclass(keyword,0,0);
171 }
172 
173 void
ip_push_keyclass(char * keyword,char * classname,ip_string_list_t * parentlist)174 IPV2::ip_push_keyclass(char*keyword,char*classname,ip_string_list_t*parentlist)
175 {
176   ip_keyword_tree_t *I, *new_keyword;
177 
178   // if there is no keyword, then set the classname of the current
179   // sub_tree
180   if (!keyword) {
181       if (classname && sub_tree && sub_tree->keyword && !sub_tree->classname) {
182           sub_tree->classname = classname;
183           return;
184         }
185       else if (!sub_tree) {
186           keyword = strdup("TOP");
187         }
188       else {
189           if (classname) error("got a classname only in invalid context: %k");
190           else error("no classname, no keyword");
191         }
192     }
193 
194   /* Make the parentlist a part of the keyword. */
195   if (parentlist) {
196       int newkeysize = strlen(keyword) + 4 + 1;
197       ip_string_list_t *pl;
198       char* newkey;
199 
200       for (pl=parentlist; pl != NULL; pl=pl->p) {
201 	  newkeysize += strlen(pl->string);
202 	  if (pl->p) newkeysize++;
203 	}
204 
205       newkey = (char*)malloc(newkeysize);
206       strcpy(newkey,keyword);
207       strcat(newkey,"<<");
208 
209       for (pl=parentlist; pl != NULL; pl=pl->p) {
210 	  strcat(newkey,pl->string);
211 	  if (pl->p) strcat(newkey,",");
212 	}
213       strcat(newkey,">>");
214 
215       free(keyword);
216       keyword = newkey;
217     }
218 
219   /* If this is the first keyword, then create the tree. */
220   if (!ip_tree) {
221       sub_tree = ip_tree = ip_alloc_keyword_tree();
222       sub_tree->across = sub_tree;
223       sub_tree->keyword = keyword;
224       sub_tree->classname = classname;
225       return;
226     }
227 
228   /* This is not the first keyword, so descend the tree. */
229 
230   /* If sub_tree is at the top (NULL), then move to ip_tree. */
231   if (!sub_tree) {
232       sub_tree = ip_tree;
233     }
234   /* If there is not already a sub_tree->down, then create it. */
235   else if (!sub_tree->down) {
236       sub_tree->down = ip_alloc_keyword_tree();
237       sub_tree->down->across = sub_tree->down;
238       sub_tree->down->up = sub_tree;
239 
240       sub_tree = sub_tree->down;
241       sub_tree->keyword = keyword;
242       sub_tree->classname = classname;
243       return;
244     }
245   /* Descend the tree, but keep track of where we were. */
246   else {
247       sub_tree = sub_tree->down;
248     }
249 
250   /* Does the keyword exist in the current sub tree? */
251   I=sub_tree;
252   do {
253 
254       if (!strcmp(I->keyword,keyword)) {
255 	  /* We found it. */
256 	  sub_tree = I;
257 	  if (classname && I->classname) {
258 	      if (strcmp(classname,I->classname)) {
259 		  error("Class specifications differ for keyword %k\n");
260 		}
261               free(classname);
262 	    }
263           else if (classname) I->classname = classname;
264 	  free(keyword);
265 	  return;
266 	}
267 
268     } while ((I = I->across) != sub_tree);
269 
270   /* We could not find it -- create a new entry. */
271 
272   new_keyword = ip_alloc_keyword_tree();
273   new_keyword->across = sub_tree->across;
274   new_keyword->keyword = keyword;
275   new_keyword->classname = classname;
276   sub_tree->across = new_keyword;
277 
278   new_keyword->up = sub_tree->up;
279 
280   /* Move us down to the new keyword. */
281   sub_tree = new_keyword;
282 }
283 
284 void
ip_pop_keyword()285 IPV2::ip_pop_keyword()
286 {
287   /* Make sure we aren\'t already on top. */
288   if (!sub_tree) {
289       error("ip_pop_keyword: tried to pop above top");
290     }
291   sub_tree = sub_tree->up;
292 }
293 
294 void
ip_begin_table(ip_string_list_t * keywords)295 IPV2::ip_begin_table(ip_string_list_t*keywords)
296 {
297   current_table_keyword = table_keywords = keywords;
298   table_sub_tree = sub_tree;
299   table_row_number = 0;
300 }
301 
302 /* Given a string containing keywords separated by ':', push the
303  * keywords. */
304 void
ip_push_table_col(char * keys)305 IPV2::ip_push_table_col(char*keys)
306 {
307   char cindex[10];
308   char * tmp = dup_string(keys);
309   char * keyword = strtok(tmp,":");
310   int n = 0;
311   do {
312       ip_push_keyword(dup_string(keyword));
313       n++;
314     } while((keyword = strtok(NULL,":")) != NULL);
315   free(tmp);
316   sprintf(cindex,"%d",table_row_number);
317   ip_push_keyword(dup_string(cindex));
318 }
319 
320 void
ip_next_table_entry()321 IPV2::ip_next_table_entry()
322 {
323   if (table_array_depth>0) return;
324 
325   sub_tree = table_sub_tree;
326   ip_push_table_col(current_table_keyword->string);
327 
328   /* Advance the current_table_keyword pointer */
329   if (current_table_keyword->p == NULL) {
330       current_table_keyword = table_keywords;
331       table_row_number++;
332     }
333   else {
334       current_table_keyword = current_table_keyword->p;
335     }
336 }
337 
338 void
ip_done_table()339 IPV2::ip_done_table()
340 {
341   ip_string_list_t *I,*J;
342 
343   /* Free the keywords strings and string list */
344   for (I=table_keywords; I!=NULL; ) {
345       free(I->string);
346       J = I->p;
347       free(I);
348       I = J;
349     }
350   table_keywords = NULL;
351   current_table_keyword = NULL;
352   sub_tree = table_sub_tree;
353   table_sub_tree = NULL;
354   }
355 
356 /* This adds the string, s, to the string list linked list, sl. */
357 ip_string_list_t *
ip_add_string_list(ip_string_list_t * sl,char * s)358 IPV2::ip_add_string_list(ip_string_list_t*sl,char*s)
359 {
360   ip_string_list_t *I;
361 
362   if (!sl) return ip_string_to_string_list(s);
363 
364   for (I=sl; I->p!=NULL; I=I->p);
365   I->p = ip_string_to_string_list(s);
366   return sl;
367 }
368 
369 ip_string_list_t *
ip_string_to_string_list(char * s)370 IPV2::ip_string_to_string_list(char*s)
371 {
372   ip_string_list_t *r;
373   r = (ip_string_list_t *) malloc(sizeof(ip_string_list_t));
374   r->string = s;
375   r->p = NULL;
376   return r;
377 }
378 
379 char *
dup_string(const char * s)380 IPV2::dup_string(const char*s)
381 {
382   char *r;
383   r = (char *) malloc(strlen(s)+1);
384   strcpy(r,s);
385   return r;
386 }
387 
388 ip_keyword_tree_t *
ip_get_variable_kt(char * variable)389 IPV2::ip_get_variable_kt(char* variable)
390 {
391   char* passed_variable = variable;
392   ip_keyword_tree_t *kt;
393   ip_keyword_tree_t *top;
394 
395   top = sub_tree;
396 
397   /* One or more occurrences of "..:" at the beginning of the keyword
398    * move us up the keyword tree */
399   while(top && !strncmp(variable,"..:",3)) {
400       variable = &variable[3];
401       top = top->up;
402     }
403 
404   /* If top is still then we have a problem. */
405   if (!top) {
406       error("tried to get a variable above the top level - impossible");
407     }
408 
409   /* Descend the keyword tree, creating nodes if needed. */
410   if (variable[0] == ':') {
411       kt = ip_descend_tree(ip_tree,variable);
412     }
413   else {
414       kt = ip_descend_tree(top,variable);
415     }
416 
417   /* This should never be the case since variable keyword trees are
418    * created as needed. */
419   if (!kt) {
420       ExEnv::errn() << "WARNING: couldn't find the variable "
421            << variable
422            << endl;
423       return NULL;
424     }
425 
426   /* Release storage for the variable. */
427   free(passed_variable);
428 
429   return(kt);
430 }
431 
432 void
ip_assign_variable(char * variable)433 IPV2::ip_assign_variable(char* variable)
434 {
435   if (table_keywords) ip_next_table_entry();
436 
437   /* Note that the subtree is really a reference to another subtree. */
438   sub_tree->variable = variable;
439 }
440 
441 char *
ip_get_variable_value(char * variable)442 IPV2::ip_get_variable_value(char*variable)
443 {
444   ip_keyword_tree_t *kt;
445 
446   /* Get the keyword tree associated with the variable. */
447   kt = ip_get_variable_kt(variable);
448 
449   /* Return the value associated with the keyword. */
450   if (kt) return(kt->value);
451   else return NULL;
452 }
453 
454 double
ip_get_variable_double(char * variable)455 IPV2::ip_get_variable_double(char*variable)
456 {
457   char *value;
458 
459   value = ip_get_variable_value(variable);
460 
461   if (value == NULL) return 0.0;
462   else return atof(value);
463 }
464 
465 char *
ip_double_to_string(double val)466 IPV2::ip_double_to_string(double val)
467 {
468   char *result;
469 
470   result = (char *) malloc(64);
471 
472   sprintf(result,"%22.15e",val);
473 
474   return result;
475 }
476 
477 void
ip_assign_value(char * value)478 IPV2::ip_assign_value(char*value)
479 {
480 
481   if (table_keywords) ip_next_table_entry();
482 
483   /* If sub_tree is still NULL then we have a problem. */
484   if (!sub_tree) {
485     error("tried to put a keyword at the top level - impossible");
486     }
487 
488   /* Check for duplicate definitions. */
489   if (sub_tree->value) {
490 #   ifdef DUP_WARN
491       /* Warn the user about duplicate definitions. */
492       warn("duplicate definition of the following keyword:");
493       ip_print_keyword(ip_out,sub_tree);
494       fprintf(ip_out,"\n");
495       warn("the new value will be ignored");
496 #   endif /* DUP_WARN */
497       free(value);
498     }
499   else sub_tree->value = value;
500   }
501 
502 void
ip_start_karray()503 IPV2::ip_start_karray()
504 {
505   if (table_keywords && table_array_depth == 0) ip_next_table_entry();
506   if (table_keywords) table_array_depth++;
507   if (!karray_indices) {
508     karray_indices = (intlist_t *) malloc(sizeof(intlist_t));
509     karray_indices->p = NULL;
510     }
511   else {
512       intlist_t *tmp;
513       tmp = (intlist_t *) malloc(sizeof(intlist_t));
514       tmp->p = karray_indices;
515       karray_indices = tmp;
516     }
517   }
518 
519 void
ip_init_karray()520 IPV2::ip_init_karray()
521 {
522   init_karray = 1;
523   karray_indices->i = 0;
524 }
525 
526 void
ip_incr_karray()527 IPV2::ip_incr_karray()
528 {
529   char *key;
530 
531   if (init_karray) {
532       init_karray = 0;
533     }
534   else {
535       ip_pop_keyword();
536     }
537 
538   /* Construct a keyword to push. */
539   /* A cheap, yet inaccurate estimate of the string size needed. */
540   key = (char *) malloc(karray_indices->i/1000 + 4);
541   sprintf(key,"%d",karray_indices->i);
542 
543   ip_push_keyword(key);
544 
545   /* Increment the current karray index. */
546   karray_indices->i++;
547 }
548 
549 void
ip_pop_karray()550 IPV2::ip_pop_karray()
551 {
552   intlist_t *tmp;
553   if (table_keywords) table_array_depth--;
554   if (!init_karray) ip_pop_keyword();
555   tmp = karray_indices;
556   karray_indices = karray_indices->p;
557   if (tmp) free(tmp);
558 }
559 
560 char *
ip_append_keystrings(char * s1,char * s2)561 IPV2::ip_append_keystrings(char*s1,char*s2)
562 {
563   char *r;
564 
565   if (s1) r = (char *) malloc(strlen(s1)+strlen(s2)+2);
566   else    r = (char *) malloc(strlen(s2)+2);
567   r[0] = '\0';
568   if (s1) strcat(r,s1);
569   strcat(r,":");
570   strcat(r,s2);
571   if (s1) free(s1);
572   free(s2);
573   return r;
574 }
575 
576 /////////////////////////////////////////////////////////////////////////////
577 
578 // Local Variables:
579 // mode: c++
580 // c-file-style: "CLJ"
581 // End:
582