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 = ∈
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 = ∈
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