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