1 /*============================================================================
2 FILE pp_lst.c
3
4 MEMBER OF process cmpp
5
6 Public Domain
7
8 Georgia Tech Research Corporation
9 Atlanta, Georgia 30332
10 PROJECT A-8503
11
12 AUTHORS
13
14 9/12/91 Bill Kuhn
15
16 MODIFICATIONS
17
18 <date> <person name> <nature of modifications>
19
20 SUMMARY
21
22 This file contains functions used in processing the files:
23
24 modpath.lst
25 udnpath.lst
26
27 The files 'modpath.lst' and 'udnpath.lst' are read to get
28 the pathnames to directories containing the models and node types
29 desired in the simulator to be built. Files in each of these
30 directories are then examined to get the names of functions and/or
31 data structures that the simulator must know about. The names
32 are then checked for uniqueness, and finally, a collection of
33 files needed in the 'make' for the simulator are written.
34
35 INTERFACES
36
37 preprocess_lst_files()
38
39 REFERENCED FILES
40
41 None.
42
43 NON-STANDARD FEATURES
44
45 None.
46
47 ============================================================================*/
48
49 #include <ctype.h>
50 #include <errno.h>
51 #include <limits.h>
52 #include <stdbool.h>
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include "cmpp.h"
57 #include "file_buffer.h"
58
59 /* *********************************************************************** */
60
61 /*
62 * Information for processing the pathname files
63 */
64
65 typedef struct {
66 char *path_name; /* Pathname read from model path file */
67 char *spice_name; /* Name of model from ifspec.ifs */
68 char *cfunc_name; /* Name of C fcn from ifspec.ifs */
69 unsigned int version; /* version of the code model */
70 } Model_Info_t;
71
72
73 typedef struct {
74 char *path_name; /* Pathname read from udn path file */
75 char *node_name; /* Name of node type */
76 unsigned int version; /* version of the code model */
77 } Node_Info_t;
78
79
80 /* Structure for uniqueness testing */
81 struct Key_src {
82 const char *key; /* value to compare */
83 const char *src; /* source of value */
84 };
85
86
87
88
89
90 /************************************************************************ */
91
92 static int cmpr_ks(const struct Key_src *ks1, const struct Key_src *ks2);
93 static void free_model_info(int num_models, Model_Info_t *p_model_info);
94 static void free_node_info(int num_nodes, Node_Info_t *p_node_info);
95 static int read_modpath(int *num_models, Model_Info_t **model_info);
96 static int read_udnpath(int *num_nodes, Node_Info_t **node_info);
97 static int read_model_names(int num_models, Model_Info_t *model_info);
98 static int read_node_names(int num_nodes, Node_Info_t *node_info);
99 static int check_uniqueness(int num_models, Model_Info_t *model_info,
100 int num_nodes, Node_Info_t *node_info);
101 static void report_error_spice_name(const struct Key_src *p_ks1,
102 const struct Key_src *p_ks2);
103 static void report_error_function_name (const struct Key_src *p_ks1,
104 const struct Key_src *p_ks2);
105 static void report_error_udn_name(const struct Key_src *p_ks1,
106 const struct Key_src *p_ks2);
107 static bool test_for_duplicates(unsigned int n, struct Key_src *p_ks,
108 void (*p_error_reporter)(const struct Key_src *p_ks1,
109 const struct Key_src *p_ks2));
110 static inline void trim_slash(size_t *p_n, char *p);
111 static int write_CMextrn(int num_models, Model_Info_t *model_info);
112 static int write_CMinfo(int num_models, Model_Info_t *model_info);
113 static int write_CMinfo2(int num_models, Model_Info_t *model_info);
114 static int write_UDNextrn(int num_nodes, Node_Info_t *node_info);
115 static int write_UDNinfo(int num_nodes, Node_Info_t *node_info);
116 static int write_UDNinfo2(int num_nodes, Node_Info_t *node_info);
117 static int write_objects_inc(int num_models, Model_Info_t *model_info,
118 int num_nodes, Node_Info_t *node_info);
119 static int read_udn_type_name(const char *path, char **node_name);
120
121
122 /* *********************************************************************** */
123
124
125 /*
126 preprocess_lst_files
127
128 Function preprocess_lst_files is the top-level driver function for
129 preprocessing a simulator model path list file (modpath.lst).
130 This function calls read_ifs_file() requesting it to read and
131 parse the Interface Specification file (ifspec.ifs) to extract
132 the model name and associated C function name and place this
133 information into an internal data structure. It then calls
134 check_uniqueness() to verify that the model names and function
135 names are unique with respect to each other and to the models and
136 functions internal to SPICE 3C1. Following this check, it calls
137 write_CMextrn(), write_CMinfo(), and write_make_include() to
138 write out the C include files CMextrn.h and CMinfo.h required by
139 SPICE function SPIinit.c to define the models known to the
140 simulator, and to write out a make include file used by the make
141 utility to locate the object modules necessary to link the models
142 into the simulator.
143 */
144
preprocess_lst_files(void)145 void preprocess_lst_files(void)
146 {
147 int status; /* Return status */
148 Model_Info_t *model_info; /* Info about each model */
149 Node_Info_t *node_info; /* Info about each user-defined node type */
150 int num_models; /* The number of models */
151 int num_nodes; /* The number of user-defined nodes */
152
153 /* Get list of models from model pathname file */
154 status = read_modpath(&num_models, &model_info);
155 if (status != 0) {
156 exit(1);
157 }
158
159 /* Get list of node types from udn pathname file */
160 status = read_udnpath(&num_nodes, &node_info);
161 if (status < 0) {
162 exit(1);
163 }
164
165 /* Get the spice and C function names from the ifspec.ifs files */
166 status = read_model_names(num_models, model_info);
167 if(status != 0) {
168 exit(1);
169 }
170
171 /* Get the user-defined node type names */
172 status = read_node_names(num_nodes, node_info);
173 if(status != 0) {
174 exit(1);
175 }
176
177 /* Check to be sure the names are unique */
178 status = check_uniqueness(num_models, model_info, num_nodes, node_info);
179 if(status != 0) {
180 exit(1);
181 }
182
183 /* Write out the CMextrn.h file used to compile SPIinit.c */
184 status = write_CMextrn(num_models, model_info);
185 if(status != 0) {
186 exit(1);
187 }
188
189 /* Write out the CMinfo.h file used to compile SPIinit.c */
190 status = write_CMinfo(num_models, model_info);
191 if(status != 0) {
192 exit(1);
193 }
194 status = write_CMinfo2(num_models, model_info);
195 if(status != 0) {
196 exit(1);
197 }
198
199 /* Write out the UDNextrn.h file used to compile SPIinit.c */
200 status = write_UDNextrn(num_nodes, node_info);
201 if(status != 0) {
202 exit(1);
203 }
204
205 /* Write out the UDNinfo.h file used to compile SPIinit.c */
206 status = write_UDNinfo(num_nodes, node_info);
207 if(status != 0) {
208 exit(1);
209 }
210 status = write_UDNinfo2(num_nodes, node_info);
211 if(status != 0) {
212 exit(1);
213 }
214
215 /* Write the make_include file used to link the models and */
216 /* user-defined node functions with the simulator */
217 status = write_objects_inc(num_models, model_info,
218 num_nodes, node_info);
219 if(status != 0) {
220 exit(1);
221 }
222
223 /* Free allocations */
224 if (model_info != (Model_Info_t *) NULL) {
225 free_model_info(num_models, model_info);
226 }
227 if (node_info != (Node_Info_t *) NULL) {
228 free_node_info(num_nodes, node_info);
229 }
230 } /* end of function preprocess_lst_files */
231
232
233
234 /* This function parses the supplied .lst file and outputs the paths to
235 * stdout */
output_paths_from_lst_file(const char * filename)236 int output_paths_from_lst_file(const char *filename)
237 {
238 int xrc = 0;
239 FILEBUF *fbp = (FILEBUF *) NULL; /* for reading MODPATH_FILENAME */
240 unsigned int n_path = 0;
241
242 /* Open the file */
243 if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) {
244 print_error("ERROR - Unable to open file \"%s\" to obtain "
245 "paths: %s",
246 filename, strerror(errno));
247 xrc = -1;
248 goto EXITPOINT;
249 }
250
251 bool f_have_path = false; /* do not have a path to store */
252 FBTYPE fbtype;
253 FBOBJ fbobj;
254 for ( ; ; ) { /* Read items until end of file */
255 /* Get the next path if not found yet */
256 if (!f_have_path) {
257 const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj);
258 if (rc != 0) {
259 if (rc == -1) { /* Error */
260 print_error("ERROR - Unable to read item to buffer");
261 xrc = -1;
262 goto EXITPOINT;
263 }
264 else { /* +1 -- EOF */
265 break;
266 }
267 } /* end of abnormal case */
268
269 /* Remove trailing slash if appended to path */
270 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
271 }
272
273 /* Output the file that was found */
274 if (fprintf(stdout, "%s\n", fbobj.str_value.sz) < 0) {
275 print_error("ERROR - Unable to output path name to stdout: %s",
276 strerror(errno));
277 xrc = -1;
278 goto EXITPOINT;
279 }
280 ++n_path; /* 1 more path printed OK */
281
282 /* Try getting a version. If found, it will be discarded */
283 FBTYPE type_wanted = BUF_TYPE_ULONG;
284 const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj);
285 if (rc != 0) {
286 if (rc == -1) { /* Error */
287 print_error("ERROR - Unable to read item to buffer");
288 xrc = -1;
289 goto EXITPOINT;
290 }
291 else { /* +1 -- EOF */
292 break;
293 }
294 } /* end of abnormal case */
295
296 if (fbtype == BUF_TYPE_ULONG) { /* found version number */
297 f_have_path = false;
298 }
299 else { /* it was a string, so it is the next path */
300 f_have_path = true;
301
302 /* Remove trailing slash if appended to path */
303 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
304 }
305 } /* end of loop reading items into buffer */
306
307 EXITPOINT:
308 /* Close model pathname file and return data read */
309 if (fbclose(fbp) != 0) {
310 print_error("ERROR - Unable to close file with path names: %s",
311 strerror(errno));
312 xrc = -1;
313 }
314
315 /* Return the path count if no errors */
316 if (xrc == 0) {
317 xrc = (int) n_path;
318 }
319
320 return xrc;
321 } /* end of function output_paths_from_lst_file */
322
323
324
325
326 /* *********************************************************************** */
327
328
329 /*
330 read_modpath
331
332 This function opens the modpath.lst file, reads the pathnames from the
333 file, and puts them into an internal data structure for future
334 processing.
335 */
336
337 /* Structure for retrieving data items from the file. These will be either
338 * names, such as directory names or unsigned integers that are version
339 * numbers */
340 #define N_MODEL_INIT 10
341
read_modpath(int * p_num_model_info,Model_Info_t ** pp_model_info)342 static int read_modpath(
343 int *p_num_model_info, /* Number of model pathnames found */
344 Model_Info_t **pp_model_info) /* Info about each model */
345 {
346 int xrc = 0;
347 FILEBUF *fbp = (FILEBUF *) NULL; /* for reading MODPATH_FILENAME */
348 Model_Info_t *p_model_info = (Model_Info_t *) NULL;
349 unsigned int n_model_info = 0;
350 unsigned int n_model_info_alloc = 0;
351 char *filename = (char *) NULL;
352
353 /* Open the model pathname file */
354 if ((filename = gen_filename(MODPATH_FILENAME, "r")) == (char *) NULL) {
355 print_error("ERROR - Unable to build mod path file name");
356 xrc = -1;
357 goto EXITPOINT;
358 }
359 /* Open the file using the default buffer size. For debugging, a very
360 * small value can be used, for example by giving the size as 1, to
361 * force the function do actions that otherwise would be done rarely
362 * if at all. */
363 if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) {
364 print_error("ERROR - Unable to open mod path file \"%s\": %s",
365 filename, strerror(errno));
366 xrc = -1;
367 goto EXITPOINT;
368 }
369
370 /* Allocate initial model info array */
371 if ((p_model_info = (Model_Info_t *) malloc(N_MODEL_INIT *
372 sizeof(Model_Info_t))) == (Model_Info_t *) NULL) {
373 print_error("ERROR - Unable to allocate initial model array");
374 xrc = -1;
375 goto EXITPOINT;
376 }
377 n_model_info_alloc = N_MODEL_INIT;
378
379 bool f_have_path = false; /* do not have a path to store */
380 FBTYPE fbtype;
381 FBOBJ fbobj;
382 for ( ; ; ) { /* Read items until end of file */
383 /* Get the next path if not found yet */
384 if (!f_have_path) {
385 const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj);
386 if (rc != 0) {
387 if (rc == -1) { /* Error */
388 print_error("ERROR - Unable to read item to buffer");
389 xrc = -1;
390 goto EXITPOINT;
391 }
392 else { /* +1 -- EOF */
393 break;
394 }
395 } /* end of abnormal case */
396
397 /* Remove trailing slash if appended to path */
398 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
399 }
400
401 /* Enlarge model array if full */
402 if (n_model_info_alloc == n_model_info) {
403 n_model_info_alloc *= 2;
404 void * const p = realloc(p_model_info,
405 n_model_info_alloc * sizeof(Model_Info_t));
406 if (p == NULL) {
407 print_error("ERROR - Unable to enlarge model array");
408 xrc = -1;
409 goto EXITPOINT;
410 }
411 p_model_info = (Model_Info_t *) p;
412 }
413
414 /* Put pathname into info structure */
415 Model_Info_t * const p_model_info_cur = p_model_info +
416 n_model_info;
417
418 if ((p_model_info_cur->path_name = (char *) malloc(
419 fbobj.str_value.n_char + 1)) == (char *) NULL) {
420 print_error("ERROR - Unable to allocate path name");
421 xrc = -1;
422 goto EXITPOINT;
423 }
424
425 strcpy(p_model_info_cur->path_name, fbobj.str_value.sz);
426 p_model_info_cur->spice_name = (char *) NULL;
427 p_model_info_cur->cfunc_name = (char *) NULL;
428
429 /* Must set before returning due to EOF. */
430 p_model_info_cur->version = 1;
431 ++n_model_info;
432
433 /* Try getting a version */
434 FBTYPE type_wanted = BUF_TYPE_ULONG;
435 const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj);
436 if (rc != 0) {
437 if (rc == -1) { /* Error */
438 print_error("ERROR - Unable to read item to buffer");
439 xrc = -1;
440 goto EXITPOINT;
441 }
442 else { /* +1 -- EOF */
443 break;
444 }
445 } /* end of abnormal case */
446
447 if (fbtype == BUF_TYPE_ULONG) { /* found version number */
448 f_have_path = false;
449 p_model_info_cur->version = (unsigned int) fbobj.ulong_value;
450 }
451 else { /* it was a string, so it is the next path */
452 f_have_path = true;
453
454 /* Remove trailing slash if appended to path */
455 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
456 }
457 } /* end of loop reading items into buffer */
458
459 EXITPOINT:
460 /* Close model pathname file and return data read */
461 if (fbclose(fbp) != 0) {
462 print_error("ERROR - Unable to close file with model info: %s",
463 strerror(errno));
464 xrc = -1;
465 }
466
467 /* Free name of file being used */
468 if (filename) {
469 free((void *) filename);
470 }
471
472 /* If error, free model info */
473 if (xrc != 0) {
474 free_model_info(n_model_info, p_model_info);
475 n_model_info = 0;
476 p_model_info = (Model_Info_t *) NULL;
477 }
478
479 *p_num_model_info = n_model_info;
480 *pp_model_info = p_model_info;
481
482 return xrc;
483 } /* end of function read_modpath */
484
485
486
487 /* Remove slash at end of path name if present */
trim_slash(size_t * p_n,char * p)488 static inline void trim_slash(size_t *p_n, char *p)
489 {
490 size_t n = *p_n;
491 if (n > 1) {
492 char * const p_last = p + n - 1;
493 if (*p_last == '/') {
494 *p_last = '\0';
495 --*p_n;
496 }
497 }
498 } /* end of function trim_slash */
499
500
501
502 /* *********************************************************************** */
503
504
505 /*
506 read_udnpath
507
508 This function opens the udnpath.lst file, reads the pathnames from the
509 file, and puts them into an internal data structure for future
510 processing.
511 */
512
513
514 #define N_NODE_INIT 5
515
read_udnpath(int * p_num_node_info,Node_Info_t ** pp_node_info)516 static int read_udnpath(
517 int *p_num_node_info, /* Addr to receive # node pathnames */
518 Node_Info_t **pp_node_info /* Addr to receive node info */
519 )
520 {
521 int xrc = 0;
522 FILEBUF *fbp = (FILEBUF *) NULL; /* For reading Udn pathname */
523 Node_Info_t *p_node_info = (Node_Info_t *) NULL;
524 /* array of node info */
525 unsigned int n_node_info = 0;
526 unsigned int n_node_info_alloc = 0;
527 char *filename = (char *) NULL;
528
529
530 /* Open the node pathname file */
531 if ((filename = gen_filename(UDNPATH_FILENAME, "r")) == (char *) NULL) {
532 print_error("ERROR - Unable to build udn path file name");
533 xrc = -1;
534 goto EXITPOINT;
535 }
536
537 /* For backward compatibility, return with WARNING only if file
538 * not found */
539 if ((fbp = fbopen(filename, 0)) == (FILEBUF *) NULL) {
540 print_error("WARNING - File not found: %s", filename);
541 xrc = +1;
542 goto EXITPOINT;
543 }
544
545 /* Allocate initial node info array */
546 if ((p_node_info = (Node_Info_t *) malloc(N_NODE_INIT *
547 sizeof(Node_Info_t))) == (Node_Info_t *) NULL) {
548 print_error("ERROR - Unable to allocate initial node array");
549 xrc = -1;
550 goto EXITPOINT;
551 }
552 n_node_info_alloc = N_NODE_INIT;
553
554 bool f_have_path = false; /* do not have a path to store */
555 FBTYPE fbtype;
556 FBOBJ fbobj;
557
558 for ( ; ; ) { /* Read items until end of file */
559 /* Get the next path if not found yet */
560 if (!f_have_path) {
561 const int rc = fbget(fbp, 0, (FBTYPE *) NULL, &fbtype, &fbobj);
562 if (rc != 0) {
563 if (rc == -1) { /* Error */
564 print_error("ERROR - Unable to read item to buffer");
565 xrc = -1;
566 goto EXITPOINT;
567 }
568 else { /* +1 -- EOF */
569 break;
570 }
571 } /* end of abnormal case */
572
573 /* Remove trailing slash if appended to path */
574 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
575 }
576
577
578 /* Enlarge node array if full */
579 if (n_node_info_alloc == n_node_info) {
580 n_node_info_alloc *= 2;
581 void * const p = realloc(p_node_info,
582 n_node_info_alloc * sizeof(Node_Info_t));
583 if (p == NULL) {
584 print_error("ERROR - Unable to enlarge node array");
585 xrc = -1;
586 goto EXITPOINT;
587 }
588 p_node_info = (Node_Info_t *) p;
589 }
590
591 /* Put pathname into info structure */
592 Node_Info_t * const p_node_info_cur = p_node_info +
593 n_node_info;
594
595 if ((p_node_info_cur->path_name = (char *) malloc(
596 fbobj.str_value.n_char + 1)) == (char *) NULL) {
597 print_error("ERROR - Unable to allocate path name");
598 xrc = -1;
599 goto EXITPOINT;
600 }
601
602 strcpy(p_node_info_cur->path_name, fbobj.str_value.sz);
603 p_node_info_cur->node_name = NULL;
604
605 /* Must set before returning due to EOF. */
606 p_node_info_cur->version = 1;
607 ++n_node_info;
608
609 /* Try getting a version */
610 FBTYPE type_wanted = BUF_TYPE_ULONG;
611 const int rc = fbget(fbp, 1, &type_wanted, &fbtype, &fbobj);
612 if (rc != 0) {
613 if (rc == -1) { /* Error */
614 print_error("ERROR - Unable to read item to buffer");
615 xrc = -1;
616 goto EXITPOINT;
617 }
618 else { /* +1 -- EOF */
619 break;
620 }
621 } /* end of abnormal case */
622
623 if (fbtype == BUF_TYPE_ULONG) { /* found version number */
624 f_have_path = false;
625 p_node_info_cur->version = (unsigned int) fbobj.ulong_value;
626 }
627 else { /* it was a string, so it is the next path */
628 f_have_path = true;
629
630 /* Remove trailing slash if appended to path */
631 trim_slash(&fbobj.str_value.n_char, fbobj.str_value.sz);
632 }
633
634 } /* end of loop reading items into buffer */
635
636 EXITPOINT:
637 /* Close model pathname file and return data read */
638 if (fbclose(fbp) != 0) {
639 print_error("ERROR - Unable to close file with node info: %s",
640 strerror(errno));
641 xrc = -1;
642 }
643
644 /* Free name of file being used */
645 if (filename) {
646 free((void *) filename);
647 }
648
649 /* If error, free node info */
650 if (xrc != 0) {
651 free_node_info(n_node_info, p_node_info);
652 n_node_info = 0;
653 p_node_info = (Node_Info_t *) NULL;
654 }
655
656 *p_num_node_info = n_node_info;
657 *pp_node_info = p_node_info;
658
659 return xrc;
660 } /* end of function read_udnpath */
661
662
663
664 /* *********************************************************************** */
665
666
667 /*
668 read_model_names
669
670 This function opens each of the models and gets the names of the model
671 and the C function into the internal model information structure.
672 */
673
read_model_names(int num_models,Model_Info_t * model_info)674 static int read_model_names(
675 int num_models, /* Number of model pathnames */
676 Model_Info_t *model_info /* Info about each model */
677 )
678 {
679 bool all_found = true; /* True if all ifspec files read */
680 int i; /* A temporary counter */
681 char path_stack[100]; /* full pathname to ifspec file if from stack */
682 char *path = path_stack; /* actual path buffer */
683 int status; /* Return status */
684
685 /* Repository for info read from ifspec file.*/
686 Ifs_Table_t ifs_table;
687
688 /* Find the required buffer size and allocate if the default buffer
689 * on the stack is too small */
690 {
691 int j;
692 size_t n_byte_needed = 0;
693 for (j = 0; j < num_models; j++) { /* max(model path lengths) */
694 const size_t n = strlen(model_info[j].path_name);
695 if (n_byte_needed < n) {
696 n_byte_needed = n;
697 }
698 }
699 n_byte_needed += 1 + strlen(IFSPEC_FILENAME) + 1;
700 if (n_byte_needed > sizeof path_stack) {
701 if ((path = (char *) malloc(n_byte_needed)) == (char *) NULL) {
702 print_error("ERROR - Unable to allocate a buffer "
703 "for model paths");
704 return -1;
705 }
706 }
707 }
708
709
710 /* For each model found in model pathname file, read the interface */
711 /* spec file to get the SPICE and C function names into model_info */
712 for(i = 0; i < num_models; i++) {
713 Model_Info_t *p_model_info_cur = model_info + i;
714
715 /* 0 for error recovery */
716 (void) memset(&ifs_table, 0, sizeof ifs_table);
717
718 /* Form the full pathname to the interface spec file. Size has
719 * been checked to ensure that all strings will fit. */
720 {
721 char *p_dst = path;
722
723 /* Copy path name */
724 const char *p_src = model_info[i].path_name;
725 for ( ; ; ) {
726 const char ch_cur = *p_src;
727 if (ch_cur == '\0') {
728 break;
729 }
730 *p_dst++ = ch_cur;
731 ++p_src;
732 }
733 *p_dst++ = '/'; /* add directory separator */
734 strcpy(p_dst, IFSPEC_FILENAME);
735 }
736
737 /* Read the SPICE and C function names from the interface spec file */
738 status = read_ifs_file(path, GET_IFS_NAME, &ifs_table);
739
740 /* Transfer the names into the model_info structure */
741 if (status == 0) {
742 if ((p_model_info_cur->spice_name = strdup(
743 ifs_table.name.model_name)) == (char *) NULL) {
744 print_error("ERROR - Unable to copy code model name");
745 all_found = false;
746 break;
747 }
748 if ((p_model_info_cur->cfunc_name = strdup(
749 ifs_table.name.c_fcn_name)) == (char *) NULL) {
750 print_error("ERROR - Unable to copy code model function name");
751 all_found = false;
752 break;
753 }
754 }
755 else {
756 print_error(
757 "ERROR - Problems reading \"%s\" in directory \"%s\"",
758 IFSPEC_FILENAME, p_model_info_cur->path_name);
759 all_found = false;
760 break;
761 }
762
763 /* Remove the ifs_table */
764 rem_ifs_table(&ifs_table);
765 } /* end of loop over models */
766
767 /* Free buffer if allocated */
768 if (path != path_stack) {
769 free(path);
770 }
771
772 if (all_found) {
773 return 0;
774 }
775 else {
776 /* Free allocations of model when failure occurred */
777 rem_ifs_table(&ifs_table);
778 return -1;
779 }
780 } /* end of function read_model_names */
781
782
783
784 /* *********************************************************************** */
785
786
787 /*
788 read_node_names
789
790 This function opens each of the user-defined node definition files
791 and gets the names of the node into the internal information structure.
792 */
793
794
read_node_names(int num_nodes,Node_Info_t * node_info)795 static int read_node_names(
796 int num_nodes, /* Number of node pathnames */
797 Node_Info_t *node_info /* Info about each node */
798 )
799 {
800 bool all_found = true; /* True if all ifspec files read */
801 int i; /* A temporary counter */
802 char path_stack[100]; /* full pathname to ifspec file if from stack */
803 char *path = path_stack; /* actual path buffer */
804 int status; /* Return status */
805 char *node_name; /* Name of node type read from file */
806
807 /* Find the required buffer size and allocate if the default buffer
808 * on the stack is too small */
809 {
810 int j;
811 size_t n_byte_needed = 0;
812 for (j = 0; j < num_nodes; j++) { /* max(model path lengths) */
813 const size_t n = strlen(node_info[j].path_name);
814 if (n_byte_needed < n) {
815 n_byte_needed = n;
816 }
817 }
818 n_byte_needed += 1 + strlen(UDNFUNC_FILENAME) + 1;
819 if (n_byte_needed > sizeof path_stack) {
820 if ((path = (char *) malloc(n_byte_needed)) == (char *) NULL) {
821 print_error("ERROR - Unable to allocate a buffer "
822 "for user types");
823 return -1;
824 }
825 }
826 }
827
828
829 /* For each node found in node pathname file, read the udnfunc.c */
830 /* file to get the node type names into node_info */
831
832 for(i = 0, all_found = true; i < num_nodes; i++) {
833 /* Form the full pathname to the user-defined type file. Size has
834 * been checked to ensure that all strings will fit. */
835 {
836 char *p_dst = path;
837
838 /* Copy path name */
839 const char *p_src = node_info[i].path_name;
840 for ( ; ; ) {
841 const char ch_cur = *p_src;
842 if (ch_cur == '\0') {
843 break;
844 }
845 *p_dst++ = ch_cur;
846 ++p_src;
847 }
848 *p_dst++ = '/'; /* add directory separator */
849 strcpy(p_dst, UDNFUNC_FILENAME);
850 }
851
852 /* Read the udn node type name from the file */
853 status = read_udn_type_name(path, &node_name);
854
855 /* Transfer the names into the node_info structure */
856 if(status == 0) {
857 node_info[i].node_name = node_name;
858 }
859 else {
860 all_found = false;
861 print_error("ERROR - Problems reading %s in directory %s",
862 UDNFUNC_FILENAME, node_info[i].path_name);
863 }
864 }
865
866 if(all_found)
867 return 0;
868 else
869 return -1;
870 } /* end of function read_node_names */
871
872
873
874 /* *********************************************************************** */
875
876
877 /*
878 check_uniqueness
879
880 Function check_uniqueness determines if model names and function
881 names are unique with respect to each other and to the models and
882 functions internal to SPICE 3C1.
883 */
884
check_uniqueness(int num_models,Model_Info_t * model_info,int num_nodes,Node_Info_t * node_info)885 static int check_uniqueness(
886 int num_models, /* Number of model pathnames */
887 Model_Info_t *model_info, /* Info about each model */
888 int num_nodes, /* Number of node type pathnames */
889 Node_Info_t *node_info /* Info about each node type */
890 )
891 {
892 /* Define a list of model names used internally by XSPICE */
893 /* These names (except 'poly') are defined in src/sim/INP/INPdomodel.c and */
894 /* are case insensitive */
895 static const char *SPICEmodel[] = {
896 "npn",
897 "pnp",
898 "d",
899 "njf",
900 "pjf",
901 "nmf",
902 "pmf",
903 "urc",
904 "nmos",
905 "pmos",
906 "r",
907 "c",
908 "sw",
909 "csw",
910 "poly" };
911 static const int numSPICEmodels = sizeof(SPICEmodel) / sizeof(char *);
912
913
914 /* Define a list of node type names used internally by the simulator */
915 /* These names are defined in src/sim/include/MIFtypes.h and are case */
916 /* insensitive */
917 static const char *UDNidentifier[] = {
918 "v",
919 "vd",
920 "i",
921 "id",
922 "vnam",
923 "g",
924 "gd",
925 "h",
926 "hd",
927 "d" };
928 static const int numUDNidentifiers = sizeof(UDNidentifier) / sizeof(char *);
929
930 bool f_have_duplicate = false; /* no duplicates found yet */
931
932 /* First, normalize case of all model and node names to lower since */
933 /* SPICE is case insensitive in parsing decks */
934 {
935 int i;
936 for(i = 0; i < num_models; i++) {
937 str_to_lower(model_info[i].spice_name);
938 }
939 }
940 {
941 int i;
942 for(i = 0; i < num_nodes; i++) {
943 str_to_lower(node_info[i].node_name);
944 }
945 }
946
947 /* Sizes of models and nodes */
948 const unsigned int n_model = (unsigned int) numSPICEmodels + num_models;
949 const unsigned int n_node = (unsigned int) numUDNidentifiers + num_nodes;
950 const unsigned int n_ks = n_model > n_node ? n_model : n_node;
951
952 /* Allocate structure to compare */
953 struct Key_src * const p_ks = (struct Key_src *) malloc(
954 n_ks * sizeof *p_ks);
955 if (p_ks == (struct Key_src *) NULL) {
956 print_error("ERROR - Unable to allocate array to check uniqueness.");
957 return -1;
958 }
959
960 /* Set up for test of SPICE name of models and test */
961 if (num_models > 0) { /* Have user-defined models */
962 {
963 int i, j;
964
965 /* Fill up with SPICE models */
966 for (i = 0; i < numSPICEmodels; ++i) {
967 struct Key_src *p_ks_cur = p_ks + i;
968 p_ks_cur->key = SPICEmodel[i];
969 p_ks_cur->src = (char *) NULL; /* denotes internal SPICE */
970 }
971 /* Add SPICE model names for code models */
972 for (j = 0; j < num_models; ++i, ++j) {
973 struct Key_src *p_ks_cur = p_ks + i;
974 Model_Info_t *p_mi_cur = model_info + j;
975 p_ks_cur->key = p_mi_cur->spice_name;
976 p_ks_cur->src = p_mi_cur->path_name;
977 }
978
979 /* Test for duplicates */
980 f_have_duplicate |= test_for_duplicates(n_model, p_ks,
981 &report_error_spice_name);
982 }
983
984 /* Set up for test of function names */
985 {
986 int i;
987
988 /* Fill up with C function names from code models */
989 for (i = 0; i < num_models; ++i) {
990 struct Key_src *p_ks_cur = p_ks + i;
991 Model_Info_t *p_mi_cur = model_info + i;
992 p_ks_cur->key = p_mi_cur->cfunc_name;
993 p_ks_cur->src = p_mi_cur->path_name;
994 }
995
996 /* Test for duplicates */
997 f_have_duplicate |= test_for_duplicates(num_models, p_ks,
998 &report_error_function_name);
999 }
1000 }
1001
1002 /* Set up for test of node types and test */
1003 if (num_nodes > 0) { /* Have user-defined types */
1004 int i, j;
1005
1006 /* Fill up with SPICE node types */
1007 for (i = 0; i < numUDNidentifiers; ++i) {
1008 struct Key_src *p_ks_cur = p_ks + i;
1009 p_ks_cur->key = UDNidentifier[i];
1010 p_ks_cur->src = (char *) NULL; /* denotes internal SPICE */
1011 }
1012 /* Add user-defined nodes */
1013 for (j = 0; j < num_nodes; ++i, ++j) {
1014 struct Key_src *p_ks_cur = p_ks + i;
1015 Node_Info_t *p_ni_cur = node_info + j;
1016 p_ks_cur->key = p_ni_cur->node_name;
1017 p_ks_cur->src = p_ni_cur->path_name;
1018 }
1019
1020 /* Test for duplicates */
1021 f_have_duplicate |= test_for_duplicates(n_node, p_ks,
1022 &report_error_udn_name);
1023 }
1024
1025 /* Free allocation for compares */
1026 free(p_ks);
1027
1028 /* Return error status */
1029 return f_have_duplicate ? -1 : 0;
1030 } /* end of function check_uniqueness */
1031
1032
1033
1034 /* Test for duplicate key values and report using the supplied function
1035 * if found */
test_for_duplicates(unsigned int n,struct Key_src * p_ks,void (* p_error_reporter)(const struct Key_src * p_ks1,const struct Key_src * p_ks2))1036 static bool test_for_duplicates(unsigned int n, struct Key_src *p_ks,
1037 void (*p_error_reporter)(const struct Key_src *p_ks1,
1038 const struct Key_src *p_ks2))
1039 {
1040 bool f_have_duplicate = false;
1041
1042 /* Sort to put duplicates together */
1043 qsort(p_ks, n, sizeof(struct Key_src),
1044 (int (*)(const void *, const void *)) &cmpr_ks);
1045
1046 unsigned int i;
1047 for (i = 0; i != n; ) {
1048 const struct Key_src * const p_ks_i = p_ks + i;
1049 const char * const p_key_i_val = p_ks_i->key;
1050 unsigned int j;
1051 for (j = i + 1; j != n; ++j) {
1052 const struct Key_src * const p_ks_j = p_ks + j;
1053 const char * const p_key_j_val = p_ks_j->key;
1054 if (strcmp(p_key_i_val, p_key_j_val) != 0) {
1055 break;
1056 }
1057
1058 /* Duplicate found. Indicate a duplicate was found and report
1059 * the error */
1060 f_have_duplicate = true;
1061 (*p_error_reporter)(p_ks_i, p_ks_j);
1062 } /* end of loop testing for duplicates */
1063 i = j; /* advance to next unique value or end of list */
1064 } /* end of loop over items to test */
1065 return f_have_duplicate;
1066 } /* end of function test_for_duplicates */
1067
1068
1069
1070 /* Compare function for struct Key_src.
1071 *
1072 * Remarks
1073 * the src field may be NULL to indicate internal values. These should
1074 * be ordered before values that are not NULL for nicer error messages.
1075 * Note that for a given key, only one src field can be NULL. */
cmpr_ks(const struct Key_src * ks1,const struct Key_src * ks2)1076 static int cmpr_ks(const struct Key_src *ks1, const struct Key_src *ks2)
1077 {
1078 /* First order by the value of the key */
1079 const int rc = strcmp(ks1->key, ks2->key);
1080 if (rc != 0) {
1081 return rc;
1082 }
1083
1084 /* Test for NULL src fields. Only one can be NULL for the same key */
1085 if (ks1->src == (char *) NULL) {
1086 return -1;
1087 }
1088 if (ks2->src == (char *) NULL) {
1089 return +1;
1090 }
1091
1092 /* Both keys not NULL, so compare */
1093 return strcmp(ks1->src, ks2->src);
1094 } /* end of function cmpr_ks */
1095
1096
1097
report_error_spice_name(const struct Key_src * p_ks1,const struct Key_src * p_ks2)1098 static void report_error_spice_name(const struct Key_src *p_ks1,
1099 const struct Key_src *p_ks2)
1100 {
1101 const char * const p_ks1_src = p_ks1->src;
1102 if (p_ks1_src == (char *) NULL) { /* internal SPICE name */
1103 print_error("ERROR: Model name \"%s\" from directory \"%s\" "
1104 "is the name of an internal SPICE model",
1105 p_ks1->key, p_ks2->src);
1106 }
1107 else {
1108 print_error("ERROR: Model name \"%s\" in directory \"%s\" "
1109 "is also in directory \"%s\".",
1110 p_ks1->key, p_ks1_src, p_ks2->src);
1111 }
1112 } /* end of function report_error_spice_name */
1113
1114
1115
report_error_function_name(const struct Key_src * p_ks1,const struct Key_src * p_ks2)1116 static void report_error_function_name (const struct Key_src *p_ks1,
1117 const struct Key_src *p_ks2)
1118 {
1119 print_error("ERROR: C function name \"%s\" in directory \"%s\" "
1120 "is also in directory \"%s\".",
1121 p_ks1->key, p_ks1->src, p_ks2->src);
1122 } /* end of function report_error_spice_name */
1123
1124
1125
report_error_udn_name(const struct Key_src * p_ks1,const struct Key_src * p_ks2)1126 static void report_error_udn_name(const struct Key_src *p_ks1,
1127 const struct Key_src *p_ks2)
1128 {
1129 const char * const p_ks1_src = p_ks1->src;
1130 if (p_ks1_src == (char *) NULL) { /* internal SPICE name */
1131 print_error("ERROR: Node type \"%s\" from directory \"%s\" "
1132 "is the name of an internal SPICE node type",
1133 p_ks1->key, p_ks2->src);
1134 }
1135 else {
1136 print_error("ERROR: Node type \"%s\" in directory \"%s\" "
1137 "is also in directory \"%s\".",
1138 p_ks1->key, p_ks1_src, p_ks2->src);
1139 }
1140 } /* end of function report_error_udn_name */
1141
1142
1143
1144 /* *********************************************************************** */
1145
1146
1147 /*
1148 write_CMextrn
1149
1150 Function write_CMextrn writes the CMextrn.h file used in
1151 compiling SPIinit.c immediately prior to linking the simulator
1152 and code models. This SPICE source file uses the structures
1153 mentioned in the include file to define the models known to the
1154 simulator.
1155 */
1156
write_CMextrn(int num_models,Model_Info_t * model_info)1157 static int write_CMextrn(
1158 int num_models, /* Number of model pathnames */
1159 Model_Info_t *model_info /* Info about each model */
1160 )
1161 {
1162 int i; /* A temporary counter */
1163 FILE *fp; /* File pointer for writing CMextrn.h */
1164
1165 char *filename = (char *) NULL;
1166
1167 /* Open the file to be written */
1168 if ((filename = gen_filename("cmextrn.h", "w")) == (char *) NULL) {
1169 print_error("ERROR - Unable to build path to cmextrn.h");
1170 return -1;
1171 }
1172 fp = fopen(filename, "w");
1173 if(fp == NULL) {
1174 print_error("ERROR - Problems opening %s for write", filename);
1175 free(filename);
1176 return -1;
1177 }
1178
1179 /* Write out the data */
1180 for(i = 0; i < num_models; i++) {
1181 fprintf(fp, "extern SPICEdev %s_info;\n", model_info[i].cfunc_name);
1182 }
1183
1184 /* Close the file and return */
1185 if (fclose(fp) != 0) {
1186 print_error("ERROR - Problems closing %s", filename);
1187 free(filename);
1188 return -1;
1189 }
1190 free(filename);
1191 return 0;
1192 } /* end of function write_CMextrn */
1193
1194
1195 /* *********************************************************************** */
1196
1197
1198 /*
1199 write_CMinfo
1200
1201 Function write_CMinfo writes the CMinfo.h file used in compiling
1202 SPIinit.c immediately prior to linking the simulator and code
1203 models. This SPICE source file uses the structures mentioned in
1204 the include file to define the models known to the simulator.
1205 */
1206
1207
write_CMinfo(int num_models,Model_Info_t * model_info)1208 static int write_CMinfo(
1209 int num_models, /* Number of model pathnames */
1210 Model_Info_t *model_info /* Info about each model */
1211 )
1212 {
1213 int i; /* A temporary counter */
1214 FILE *fp; /* File pointer for writing CMinfo.h */
1215
1216 char *filename = (char *) NULL;
1217
1218 /* Open the file to be written */
1219 if ((filename = gen_filename("cminfo.h", "w")) == (char *) NULL) {
1220 print_error("ERROR - Unable to build path to cminfo.h");
1221 return -1;
1222 }
1223 fp = fopen(filename, "w");
1224 if(fp == NULL) {
1225 print_error("ERROR - Problems opening %s for write", filename);
1226 free(filename);
1227 return -1;
1228 }
1229
1230 /* Write out the data */
1231 for(i = 0; i < num_models; i++) {
1232 Model_Info_t *p_mi_cur = model_info + i;
1233 if (p_mi_cur->version == 1) {
1234 fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name);
1235 }
1236 }
1237
1238 /* Close the file and return */
1239 if (fclose(fp) != 0) {
1240 print_error("ERROR - Problems closing %s", filename);
1241 free(filename);
1242 return -1;
1243 }
1244
1245 free(filename);
1246 return 0;
1247 } /* end of function write_CMinfo */
1248
1249
1250
write_CMinfo2(int num_models,Model_Info_t * model_info)1251 static int write_CMinfo2(
1252 int num_models, /* Number of model pathnames */
1253 Model_Info_t *model_info /* Info about each model */
1254 )
1255 {
1256 int i; /* A temporary counter */
1257 FILE *fp; /* File pointer for writing CMinfo.h */
1258
1259 char *filename = (char *) NULL;
1260
1261 /* Open the file to be written */
1262 if ((filename = gen_filename("cminfo2.h", "w")) == (char *) NULL) {
1263 print_error("ERROR - Unable to build path to cminfo2.h");
1264 return -1;
1265 }
1266 fp = fopen(filename, "w");
1267 if(fp == NULL) {
1268 print_error("ERROR - Problems opening %s for write", filename);
1269 free(filename);
1270 return -1;
1271 }
1272
1273 /* Write out the data */
1274 for (i = 0; i < num_models; i++) {
1275 Model_Info_t *p_mi_cur = model_info + i;
1276 if (p_mi_cur->version <= 2) {
1277 fprintf(fp, "&%s_info,\n", model_info[i].cfunc_name);
1278 }
1279 }
1280
1281 /* Close the file and return */
1282 if (fclose(fp) != 0) {
1283 print_error("ERROR - Problems closing %s", filename);
1284 free(filename);
1285 return -1;
1286 }
1287
1288 free(filename);
1289 return 0;
1290 } /* end of function write_CMinfo2 */
1291
1292
1293
1294 /* *********************************************************************** */
1295
1296
1297
1298 /*
1299 write_UDNextrn
1300
1301 Function write_UDNextrn writes the UDNextrn.h file used in
1302 compiling SPIinit.c immediately prior to linking the simulator
1303 and user-defined nodes. This SPICE source file uses the structures
1304 mentioned in the include file to define the node types known to the
1305 simulator.
1306 */
1307
1308
1309
write_UDNextrn(int num_nodes,Node_Info_t * node_info)1310 static int write_UDNextrn(
1311 int num_nodes, /* Number of node pathnames */
1312 Node_Info_t *node_info /* Info about each node */
1313 )
1314 {
1315 int i; /* A temporary counter */
1316 FILE *fp; /* File pointer for writing UDNextrn.h */
1317
1318 char *filename = (char *) NULL;
1319
1320 /* Open the file to be written */
1321 if ((filename = gen_filename("udnextrn.h", "w")) == (char *) NULL) {
1322 print_error("ERROR - Unable to build path to udnextrn.h");
1323 return -1;
1324 }
1325 fp = fopen(filename, "w");
1326 if(fp == NULL) {
1327 print_error("ERROR - Problems opening %s for write", filename);
1328 return -1;
1329 }
1330
1331 /* Write out the data */
1332 for(i = 0; i < num_nodes; i++) {
1333 fprintf(fp, "extern Evt_Udn_Info_t udn_%s_info;\n", node_info[i].node_name);
1334 }
1335
1336 /* Close the file and return */
1337 if (fclose(fp) != 0) {
1338 print_error("ERROR - Problems closing %s", filename);
1339 free(filename);
1340 return -1;
1341 }
1342
1343 free(filename);
1344 return 0;
1345 } /* end of function write_UDNextrn */
1346
1347
1348
1349 /* *********************************************************************** */
1350
1351
1352 /*
1353 write_UDNinfo
1354
1355 Function write_UDNinfo writes the UDNinfo.h file used in
1356 compiling SPIinit.c immediately prior to linking the simulator
1357 and user-defined nodes. This SPICE source file uses the structures
1358 mentioned in the include file to define the node types known to the
1359 simulator.
1360 */
write_UDNinfo(int num_nodes,Node_Info_t * node_info)1361 static int write_UDNinfo(
1362 int num_nodes, /* Number of node pathnames */
1363 Node_Info_t *node_info /* Info about each node */
1364 )
1365 {
1366 int i; /* A temporary counter */
1367 FILE *fp; /* File pointer for writing UDNinfo.h */
1368
1369 char *filename = (char *) NULL;
1370
1371 /* Open the file to be written */
1372 if ((filename = gen_filename("udninfo.h", "w")) == (char *) NULL) {
1373 print_error("ERROR - Unable to build path to udninfo.h");
1374 return -1;
1375 }
1376 fp = fopen(filename, "w");
1377 if(fp == NULL) {
1378 print_error("ERROR - Problems opening %s for write", filename);
1379 return -1;
1380 }
1381
1382 /* Write out the data */
1383 for(i = 0; i < num_nodes; i++) {
1384 Node_Info_t *p_ni_cur = node_info + i;
1385 if (p_ni_cur->version == 1) {
1386 fprintf(fp, "&udn_%s_info,\n", p_ni_cur->node_name);
1387 }
1388 }
1389
1390 /* Close the file and return */
1391 if (fclose(fp) != 0) {
1392 print_error("ERROR - Problems closing %s", filename);
1393 free(filename);
1394 return -1;
1395 }
1396
1397 free(filename);
1398 return 0;
1399 } /* end of function write_UDNinfo */
1400
1401
1402
write_UDNinfo2(int num_nodes,Node_Info_t * node_info)1403 static int write_UDNinfo2(
1404 int num_nodes, /* Number of node pathnames */
1405 Node_Info_t *node_info /* Info about each node */
1406 )
1407 {
1408 int i; /* A temporary counter */
1409 FILE *fp; /* File pointer for writing UDNinfo.h */
1410
1411 char *filename = (char *) NULL;
1412
1413 /* Open the file to be written */
1414 if ((filename = gen_filename("udninfo2.h", "w")) == (char *) NULL) {
1415 print_error("ERROR - Unable to build path to udninfo2.h");
1416 return -1;
1417 }
1418 fp = fopen(filename, "w");
1419 if(fp == NULL) {
1420 print_error("ERROR - Problems opening %s for write", filename);
1421 return -1;
1422 }
1423
1424 /* Write out the data */
1425 for(i = 0; i < num_nodes; i++) {
1426 Node_Info_t *p_ni_cur = node_info + i;
1427 if (p_ni_cur->version <= 2) {
1428 fprintf(fp, "&udn_%s_info,\n", p_ni_cur->node_name);
1429 }
1430 }
1431
1432 /* Close the file and return */
1433 if (fclose(fp) != 0) {
1434 print_error("ERROR - Problems closing %s", filename);
1435 free(filename);
1436 return -1;
1437 }
1438
1439 free(filename);
1440 return 0;
1441 } /* end of function write_UDNinfo */
1442
1443
1444
1445 /* *********************************************************************** */
1446
1447 /*
1448 write_objects_inc
1449
1450 Function write_objects_inc writes a make include file used by
1451 the make utility to locate the object modules needed to link the
1452 simulator with the code models and user-defined node types.
1453 */
1454
write_objects_inc(int num_models,Model_Info_t * model_info,int num_nodes,Node_Info_t * node_info)1455 static int write_objects_inc(
1456 int num_models, /* Number of model pathnames */
1457 Model_Info_t *model_info, /* Info about each model */
1458 int num_nodes, /* Number of udn pathnames */
1459 Node_Info_t *node_info /* Info about each node type */
1460 )
1461 {
1462 int i; /* A temporary counter */
1463 FILE *fp; /* File pointer for writing make_include */
1464
1465 char *filename = (char *) NULL;
1466
1467 /* Open the file to be written */
1468 if ((filename = gen_filename("objects.inc", "w")) == (char *) NULL) {
1469 print_error("ERROR - Unable to build path to objects.inc");
1470 return -1;
1471 }
1472 fp = fopen(filename, "w");
1473 if(fp == NULL) {
1474 print_error("ERROR - Problems opening %s for write", filename);
1475 return -1;
1476 }
1477
1478 /* Write out the data */
1479 for(i = 0; i < num_models; i++) {
1480 fprintf(fp, "%s/*.o", model_info[i].path_name);
1481 if((i < (num_models - 1)) || (num_nodes > 0))
1482 fprintf(fp, " \\\n");
1483 else
1484 fprintf(fp, "\n");
1485 }
1486 for(i = 0; i < num_nodes; i++) {
1487 fprintf(fp, "%s/*.o", node_info[i].path_name);
1488 if(i < (num_nodes - 1))
1489 fprintf(fp, " \\\n");
1490 else
1491 fprintf(fp, "\n");
1492 }
1493
1494 /* Close the file and return */
1495 if (fclose(fp) != 0) {
1496 print_error("ERROR - Problems closing %s", filename);
1497 free(filename);
1498 return -1;
1499 }
1500
1501 free(filename);
1502 return 0;
1503 } /* end of function write_objects_inc */
1504
1505
1506
1507 /*
1508 read_udn_type_name
1509
1510 This function reads a User-Defined Node Definition File until
1511 the definition of the Evt_Udn_Info_t struct
1512 is found, and then gets the name of the node type from the first
1513 member of the structure.
1514 */
1515
read_udn_type_name(const char * path,char ** node_name)1516 static int read_udn_type_name(
1517 const char *path, /* the path to the node definition file */
1518 char **node_name /* the node type name found in the file */
1519 )
1520 {
1521 FILE *fp; /* file pointer for opened file */
1522 bool found; /* true if name found successfully */
1523 bool in_struct; /* true if found struct with name */
1524 char name[MAX_NAME_LEN + 1]; /* temporary storage for name read */
1525 int c; /* a character read from the file */
1526 int i; /* a counter */
1527
1528 static char *struct_type = "Evt_Udn_Info_t";
1529 char *filename = (char *) NULL;
1530
1531 /* Open the file from which the node type name will be read */
1532 if ((filename = gen_filename(path, "r")) == (char *) NULL) {
1533 print_error("ERROR - Unable to build path to Evt_Udn_Info_t");
1534 return -1;
1535 }
1536 fp = fopen(filename, "r");
1537 if(fp == NULL) {
1538 print_error("ERROR - Problems opening %s for reading", filename);
1539 return -1;
1540 }
1541
1542 /* Read the file until the definition of the Evt_Udn_Info_t struct */
1543 /* is found, then get the name of the node type from the first */
1544 /* member of the structure */
1545 found = false;
1546 do {
1547 /* read the next character */
1548 c = fgetc(fp);
1549
1550 /* check for and gobble up comments */
1551 if(c == '/') {
1552 c = fgetc(fp);
1553 if(c == '*') {
1554 do {
1555 c = fgetc(fp);
1556 if(c == '*') {
1557 c = fgetc(fp);
1558 if((c == '/') || (c == EOF))
1559 break;
1560 else
1561 ungetc(c, fp);
1562 }
1563 } while(c != EOF);
1564 }
1565 }
1566 if(c == EOF)
1567 break;
1568
1569 /* read until "Evt_Udn_Info_t" is encountered */
1570 for(i = 0, in_struct = false; ; i++) {
1571 if(c != struct_type[i])
1572 break;
1573 else if(i == (sizeof(struct_type) - 2)) {
1574 in_struct = true;
1575 break;
1576 }
1577 else
1578 c = fgetc(fp);
1579 }
1580 /* if found it, read until open quote found */
1581 /* and then read the name until the closing quote is found */
1582 if(in_struct) {
1583 do {
1584 c = fgetc(fp);
1585 if(c == '"') {
1586 i = 0;
1587 do {
1588 c = fgetc(fp);
1589 if(c == '"') {
1590 found = true;
1591 if (i >= sizeof name) {
1592 print_error("name too long");
1593 exit(1);
1594 }
1595 name[i] = '\0';
1596 }
1597 else if(c != EOF) {
1598 if (i > sizeof name) {
1599 print_error("name too long");
1600 exit(1);
1601 }
1602 name[i++] = (char) c;
1603 }
1604 } while((c != EOF) && (! found));
1605 }
1606 } while((c != EOF) && (! found));
1607 }
1608
1609 } while((c != EOF) && (! found));
1610
1611 /* Close the file and return */
1612 fclose(fp);
1613
1614 if(found) {
1615 if ((*node_name = (char *) malloc(
1616 strlen(name) + 1)) == (char *) NULL) {
1617 print_error("ERROR - Unable to allocate node name");
1618 return -1;
1619 }
1620 strcpy(*node_name, name);
1621 return 0;
1622 }
1623 else {
1624 *node_name = NULL;
1625 return -1;
1626 }
1627 }
1628
1629
1630
1631 /* Free allocations in p_model_info array */
free_model_info(int num_models,Model_Info_t * p_model_info)1632 static void free_model_info(int num_models, Model_Info_t *p_model_info)
1633 {
1634 /* Return if no structure */
1635 if (p_model_info == (Model_Info_t *) NULL) {
1636 return;
1637 }
1638
1639 int i;
1640 for (i = 0; i < num_models; ++i) {
1641 Model_Info_t *p_cur = p_model_info + i;
1642 void *p;
1643 if ((p = p_cur->cfunc_name) != NULL) {
1644 free(p);
1645 }
1646 if ((p = p_cur->path_name) != NULL) {
1647 free(p);
1648 }
1649 if ((p = p_cur->spice_name) != NULL) {
1650 free(p);
1651 }
1652 }
1653
1654 free(p_model_info);
1655 } /* end of function free_model_info */
1656
1657
1658
1659 /* Free allocations in p_nod_info array */
free_node_info(int num_nodes,Node_Info_t * p_node_info)1660 static void free_node_info(int num_nodes, Node_Info_t *p_node_info)
1661 {
1662 /* Return if no structure */
1663 if (p_node_info == (Node_Info_t *) NULL) {
1664 return;
1665 }
1666
1667 int i;
1668 for (i = 0; i < num_nodes; ++i) {
1669 Node_Info_t *p_cur = p_node_info + i;
1670 void *p;
1671 if ((p = p_cur->node_name) != NULL) {
1672 free(p);
1673 }
1674 if ((p = p_cur->path_name) != NULL) {
1675 free(p);
1676 }
1677 }
1678
1679 free(p_node_info);
1680 } /* end of function free_node_info */
1681
1682
1683
1684