1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
4 Modified: 2000 AlansFixes
5 **********/
6 
7 /*
8  * Routines to query and alter devices.
9  */
10 
11 #include "ngspice/ngspice.h"
12 #include "ngspice/gendefs.h"
13 #include "ngspice/cktdefs.h"
14 #include "ngspice/cpdefs.h"
15 #include "ngspice/ftedefs.h"
16 #include "ngspice/dgen.h"
17 #include "ngspice/sim.h"
18 
19 #include "circuits.h"
20 #include "device.h"
21 #include "variable.h"
22 #include "com_commands.h"
23 #include "../misc/util.h" /* ngdirname() */
24 
25 #include "gens.h" /* wl_forall */
26 
27 
28 static wordlist *devexpand(char *name);
29 static void all_show(wordlist *wl, int mode);
30 static void all_show_old(wordlist *wl, int mode);
31 static void com_alter_mod(wordlist *wl);
32 static void if_set_binned_model(CKTcircuit *, char *, char *, struct dvec *);
33 
34 
35 /*
36  * devhelp: lists available devices and information on parameters
37  *   devhelp                 : shows all available devices
38  *   devhelp devname         : shows all parameters of that model/instance
39  *   devhelp devname parname : shows parameter meaning
40  *   Options: -csv (comma separated value for generating docs)
41  */
42 
43 void
com_devhelp(wordlist * wl)44 com_devhelp(wordlist *wl)
45 {
46     /* Just a simple driver now */
47     devhelp(wl);
48 }
49 
50 
51 void
devhelp(wordlist * wl)52 devhelp(wordlist *wl)
53 {
54     int i, k = 0;
55     int devindex = -1, devInstParNo = 0, devModParNo = 0;
56     bool found = FALSE;
57     bool csv = FALSE;
58     wordlist *wlist;
59     IFparm *plist;
60 
61     /*First copy the base pointer */
62     wlist = wl;
63 
64     /* If there are no arguments output the list of available devices */
65     if (!wlist) {
66         out_init();
67         out_printf("\nDevices available in the simulator\n\n");
68         for (k = 0; k < ft_sim->numDevices; k++)
69             if (ft_sim->devices[k])
70                 out_printf("%-*s:\t%s\n",
71                            DEV_WIDTH, ft_sim->devices[k]->name,
72                            ft_sim->devices[k]->description);
73         out_send("\n");
74         return;
75     }
76 
77     /* The first argument must be the csv option or a device name */
78     if (wlist && wlist->wl_word && eq(wlist->wl_word, "-csv")) {
79         csv = TRUE;
80         if (wlist->wl_next)
81             wlist = wlist->wl_next;
82         else
83             return;
84     }
85 
86     /* This argument, if exists, must be the device name */
87     if (wlist && wlist->wl_word) {
88         while (k < ft_sim->numDevices && !found) {
89             if (ft_sim->devices[k])
90                 if (strcasecmp(ft_sim->devices[k]->name, wlist->wl_word) == 0) {
91                     devindex = k;
92                     if (ft_sim->devices[devindex]->numInstanceParms)
93                         devInstParNo = *(ft_sim->devices[devindex]->numInstanceParms);
94                     else
95                         devInstParNo = 0;
96 
97                     if (ft_sim->devices[devindex]->numModelParms)
98                         devModParNo = *(ft_sim->devices[devindex]->numModelParms);
99                     else
100                         devModParNo = 0;
101 
102                     wlist = wlist->wl_next;
103                     found = TRUE;
104                 }
105             k++;
106         }
107 
108         if (!found) {
109             fprintf(cp_out, "Error: Device %s not found\n", wlist->wl_word);
110             return;
111         }
112     }
113 
114     /* At this point, found is TRUE and we have found the device.
115      * Now we have to scan the model and instance parameters to print
116      * the string
117      */
118     found = FALSE;
119     if (wlist && wlist->wl_word) {
120         plist = ft_sim->devices[devindex]->modelParms;
121         for (i = 0; i < devModParNo; i++) { /* Scan model parameters first */
122             if (strcasecmp(plist[i].keyword, wlist->wl_word) == 0) {
123                 found = TRUE;
124                 out_init();
125                 out_printf("Model Parameters\n");
126                 if (csv)
127                     out_printf("id#, Name, Dir, Description\n");
128                 else
129                     out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
130                 printdesc(plist[i], csv);
131                 out_send("\n");
132             }
133         }
134 
135         if (!found) {
136             plist = ft_sim->devices[devindex]->instanceParms;
137             for (i = 0; i < devInstParNo; i++) { /* Scan instance parameters then */
138                 if (strcasecmp(plist[i].keyword, wlist->wl_word) == 0) {
139                     found = TRUE;
140                     out_init();
141                     out_printf("Instance Parameters\n");
142                     if (csv)
143                         out_printf("id#, Name, Dir, Description\n");
144                     else
145                         out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
146                     printdesc(plist[i], csv);
147                     out_send("\n");
148                 }
149             }
150         }
151 
152         if (!found)
153             fprintf(cp_out, "Error: Parameter %s not found\n", wlist->wl_word);
154         return;
155 
156     }
157 
158     /* No arguments - we want all the parameters*/
159     out_init();
160     out_printf("%s - %s\n\n", ft_sim->devices[devindex]->name, ft_sim->devices[devindex]->description);
161     out_printf("Model Parameters\n");
162     if (csv)
163         out_printf("id#, Name, Dir, Description\n");
164     else
165         out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
166 
167     plist = ft_sim->devices[devindex]->modelParms;
168     for (i = 0; i < devModParNo; i++)
169         printdesc(plist[i], csv);
170     out_printf("\n");
171     out_printf("Instance Parameters\n");
172     if (csv)
173         out_printf("id#, Name, Dir, Description\n");
174     else
175         out_printf("%5s\t %-10s\t Dir\t Description\n", "id#", "Name");
176 
177     plist = ft_sim->devices[devindex]->instanceParms;
178     for (i = 0; i < devInstParNo; i++)
179         printdesc(plist[i], csv);
180 
181     out_send("\n");
182 }
183 
184 
185 /*
186  * Pretty print parameter descriptions
187  * This function prints description of device parameters
188  */
189 
190 void
printdesc(IFparm p,bool csv)191 printdesc(IFparm p, bool csv)
192 {
193     char sep;
194     int spacer1, spacer2;
195 
196     /* First we indentify the separator */
197     if (csv) {
198         sep = ',';
199         spacer1 = 0;
200         spacer2 = 0;
201     } else {
202         sep = '\t';
203         spacer1 = 5;
204         spacer2 = 10;
205     }
206 
207     out_printf("%*d%c %-*s%c ", spacer1, p.id, sep, spacer2, p.keyword, sep);
208 
209     if (p.dataType & IF_SET)
210         if (p.dataType & IF_ASK)
211             out_printf("inout%c ", sep);
212         else
213             out_printf("in%c ", sep);
214     else
215         out_printf("out%c ", sep);
216 
217     if (p.description)
218         out_printf("%s\n", p.description);
219     else
220         out_printf("n.a.\n");
221 }
222 
223 
224 /*
225  * show: list device operating point info
226  *   show
227  *   show devs : params
228  *   show devs : params ; devs : params
229  *   show dev dev dev : param param param , dev dev : param param
230  *   show t : param param param, t : param param
231  */
232 
233 static int count;
234 
235 void
com_showmod(wordlist * wl)236 com_showmod(wordlist *wl)
237 {
238     if (cp_getvar("altshow", CP_BOOL, NULL, 0))
239         all_show(wl, 1);
240     else
241         all_show_old(wl, 1);
242 }
243 
244 
245 void
com_show(wordlist * wl)246 com_show(wordlist *wl)
247 {
248     if (cp_getvar("altshow", CP_BOOL, NULL, 0))
249         all_show(wl, 0);
250     else
251         all_show_old(wl, 0);
252 }
253 
254 
255 static void
all_show(wordlist * wl,int mode)256 all_show(wordlist *wl, int mode)
257 {
258     wordlist    *params, *nextgroup, *thisgroup;
259     wordlist    *prev, *next, *w;
260     int         screen_width;
261     dgen        *dg;
262     int         instances;
263     int         i, j, n;
264     int         param_flag, dev_flag;
265 
266     if (!ft_curckt || !ft_curckt->ci_ckt) {
267         fprintf(cp_err, "Error: no circuit loaded\n");
268         return;
269     }
270 
271     if (wl && wl->wl_word && eq(wl->wl_word, "-v")) {
272         old_show(wl->wl_next);
273         return;
274     }
275 
276     if (!cp_getvar("width", CP_NUM, &screen_width, 0))
277         screen_width = DEF_WIDTH;
278     count = (screen_width - LEFT_WIDTH) / (DEV_WIDTH + 1);
279     count = 1;
280 
281     n = 0;
282     do {
283         prev = NULL;
284         params = NULL;
285         nextgroup = NULL;
286         thisgroup = wl;
287         param_flag = 0;
288         dev_flag = 0;
289 
290         /* find the parameter list and the nextgroup */
291         for (w = wl; w && !nextgroup; w = next) {
292             next = w->wl_next;
293 
294             if (eq(w->wl_word, "*")) {
295                 tfree(w->wl_word);
296                 w->wl_word = copy("all");
297             }
298 
299             if (eq(w->wl_word, "++") || eq(w->wl_word, "all")) {
300                 if (params) {
301                     param_flag = DGEN_ALLPARAMS;
302                     if (prev)
303                         prev->wl_next = w->wl_next;
304                     else
305                         params = next;
306                 } else {
307                     dev_flag = DGEN_ALLDEVS;
308                     if (prev)
309                         prev->wl_next = w->wl_next;
310                     else
311                         thisgroup = next;
312                 }
313                 /* w must not be freed here */
314                 w = NULL;
315             } else if (eq(w->wl_word, "+")) {
316                 if (params) {
317                     param_flag = DGEN_DEFPARAMS;
318                     if (prev)
319                         prev->wl_next = w->wl_next;
320                     else
321                         params = next;
322                 } else {
323                     dev_flag = DGEN_DEFDEVS;
324                     if (prev)
325                         prev->wl_next = w->wl_next;
326                     else
327                         thisgroup = next;
328                 }
329                 /* w must not be freed here */
330                 w = NULL;
331             } else if (eq(w->wl_word, ":")) {
332                 /* w must not be freed here */
333                 w = NULL;
334                 if (!params) {
335                     params = next;
336                     if (prev)
337                         prev->wl_next = NULL;
338                     else
339                         thisgroup = NULL;
340                 } else {
341                     if (prev)
342                         prev->wl_next = next;
343                     else
344                         params = next;
345                 }
346             } else if (eq(w->wl_word, ";") || eq(w->wl_word, ",")) {
347                 nextgroup = next;
348                 /* w must not be freed here */
349                 w = NULL;
350                 if (prev)
351                     prev->wl_next = NULL;
352                 break;
353             }
354             prev = w;
355         }
356 
357         instances = 0;
358         for (dg = dgen_init(ft_curckt->ci_ckt, thisgroup, 1, dev_flag, mode);
359              dg; dgen_nth_next(&dg, count))
360         {
361             instances = 1;
362             if (dg->flags & DGEN_INSTANCE) {
363                 instances = 2;
364                 n += 1;
365 
366                 fprintf(cp_out, "%s:\n", dg->instance->GENname);
367                 fprintf(cp_out, "    %-19s= %s\n", "model", dg->model->GENmodName);
368 
369                 if (param_flag)
370                     param_forall(dg, param_flag);
371                 else if (!params)
372                     param_forall(dg, DGEN_DEFPARAMS);
373 
374                 if (params)
375                     wl_forall(params, listparam, dg);
376 
377             } else if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
378                 fprintf(cp_out, " %s models (%s)\n",
379                         ft_sim->devices[dg->dev_type_no]->name,
380                         ft_sim->devices[dg->dev_type_no]->description);
381                 n += 1;
382                 i = 0;
383                 do {
384                     fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
385                     j = dgen_for_n(dg, count, printstr_m, NULL, i);
386                     i += 1;
387                     fprintf(cp_out, "\n");
388                 } while (j);
389                 fprintf(cp_out, "\n");
390 
391                 if (param_flag)
392                     param_forall(dg, param_flag);
393                 else if (!params)
394                     param_forall(dg, DGEN_DEFPARAMS);
395 
396                 if (params)
397                     wl_forall(params, listparam, dg);
398                 fprintf(cp_out, "\n");
399             }
400         }
401 
402         wl = nextgroup;
403 
404     } while (wl);
405 
406     if (!n) {
407         if (instances == 0)
408             printf("No matching instances or models\n");
409         else if (instances == 1)
410             printf("No matching models\n");
411         else
412             printf("No matching elements\n");
413     }
414 }
415 
416 
417 static void
all_show_old(wordlist * wl,int mode)418 all_show_old(wordlist *wl, int mode)
419 {
420     wordlist    *params, *nextgroup, *thisgroup;
421     wordlist    *prev, *next, *w;
422     int         screen_width;
423     dgen        *dg;
424     int         instances;
425     int         i, j, n;
426     int         param_flag, dev_flag;
427 
428     if (!ft_curckt || !ft_curckt->ci_ckt) {
429         fprintf(cp_err, "Error: no circuit loaded\n");
430         return;
431     }
432 
433     if (wl && wl->wl_word && eq(wl->wl_word, "-v")) {
434         old_show(wl->wl_next);
435         return;
436     }
437 
438     if (!cp_getvar("width", CP_NUM, &screen_width, 0))
439         screen_width = DEF_WIDTH;
440     count = (screen_width - LEFT_WIDTH) / (DEV_WIDTH + 1);
441 
442     n = 0;
443     do {
444         prev = NULL;
445         params = NULL;
446         nextgroup = NULL;
447         thisgroup = wl;
448         param_flag = 0;
449         dev_flag = 0;
450 
451         /* find the parameter list and the nextgroup */
452         for (w = wl; w && !nextgroup; w = next) {
453             next = w->wl_next;
454 
455             if (eq(w->wl_word, "*")) {
456                 tfree(w->wl_word);
457                 w->wl_word = copy("all");
458             }
459 
460             if (eq(w->wl_word, "++") || eq(w->wl_word, "all")) {
461                 if (params) {
462                     param_flag = DGEN_ALLPARAMS;
463                     if (prev)
464                         prev->wl_next = w->wl_next;
465                     else
466                         params = next;
467                 } else {
468                     dev_flag = DGEN_ALLDEVS;
469                     if (prev)
470                         prev->wl_next = w->wl_next;
471                     else
472                         thisgroup = next;
473                 }
474                 /* w must not be freed here */
475                 w = NULL;
476             } else if (eq(w->wl_word, "+")) {
477                 if (params) {
478                     param_flag = DGEN_DEFPARAMS;
479                     if (prev)
480                         prev->wl_next = w->wl_next;
481                     else
482                         params = next;
483                 } else {
484                     dev_flag = DGEN_DEFDEVS;
485                     if (prev)
486                         prev->wl_next = w->wl_next;
487                     else
488                         thisgroup = next;
489                 }
490                 /* w must not be freed here */
491                 w = NULL;
492             } else if (eq(w->wl_word, ":")) {
493                 /* w must not be freed here */
494                 w = NULL;
495                 if (!params) {
496                     params = next;
497                     if (prev)
498                         prev->wl_next = NULL;
499                     else
500                         thisgroup = NULL;
501                 } else {
502                     if (prev)
503                         prev->wl_next = next;
504                     else
505                         params = next;
506                 }
507             } else if (eq(w->wl_word, ";") || eq(w->wl_word, ",")) {
508                 nextgroup = next;
509                 /* w must not be freed here */
510                 w = NULL;
511                 if (prev)
512                     prev->wl_next = NULL;
513                 break;
514             }
515             prev = w;
516         }
517 
518         instances = 0;
519         for (dg = dgen_init(ft_curckt->ci_ckt, thisgroup, 1, dev_flag, mode);
520              dg; dgen_nth_next(&dg, count))
521         {
522             instances = 1;
523             if (dg->flags & DGEN_INSTANCE) {
524                 instances = 2;
525                 fprintf(cp_out, " %s: %s\n",
526                         ft_sim->devices[dg->dev_type_no]->name,
527                         ft_sim->devices[dg->dev_type_no]->description);
528                 n += 1;
529 
530                 i = 0;
531                 do {
532                     fprintf(cp_out, "%*s", LEFT_WIDTH, "device");
533                     j = dgen_for_n(dg, count, printstr_n, NULL, i);
534                     i += 1;
535                     fprintf(cp_out, "\n");
536                 } while (j);
537 
538                 if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
539                     i = 0;
540                     do {
541                         fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
542                         j = dgen_for_n(dg, count, printstr_m, NULL, i);
543                         i += 1;
544                         fprintf(cp_out, "\n");
545                     } while (j);
546                 }
547 
548                 if (param_flag)
549                     param_forall_old(dg, param_flag);
550                 else if (!params)
551                     param_forall_old(dg, DGEN_DEFPARAMS);
552 
553                 if (params)
554                     wl_forall(params, listparam, dg);
555                 fprintf(cp_out, "\n");
556 
557             } else if (ft_sim->devices[dg->dev_type_no]->numModelParms) {
558                 fprintf(cp_out, " %s models (%s)\n",
559                         ft_sim->devices[dg->dev_type_no]->name,
560                         ft_sim->devices[dg->dev_type_no]->description);
561                 n += 1;
562                 i = 0;
563                 do {
564                     fprintf(cp_out, "%*s", LEFT_WIDTH, "model");
565                     j = dgen_for_n(dg, count, printstr_m, NULL, i);
566                     i += 1;
567                     fprintf(cp_out, "\n");
568                 } while (j);
569                 fprintf(cp_out, "\n");
570 
571                 if (param_flag)
572                     param_forall_old(dg, param_flag);
573                 else if (!params)
574                     param_forall_old(dg, DGEN_DEFPARAMS);
575 
576                 if (params)
577                     wl_forall(params, listparam, dg);
578                 fprintf(cp_out, "\n");
579             }
580         }
581 
582         wl = nextgroup;
583 
584     } while (wl);
585 
586     if (!n) {
587         if (instances == 0)
588             printf("No matching instances or models\n");
589         else if (instances == 1)
590             printf("No matching models\n");
591         else
592             printf("No matching elements\n");
593     }
594 }
595 
596 
597 int
printstr_n(dgen * dg,IFparm * p,int i)598 printstr_n(dgen *dg, IFparm *p, int i)
599 {
600     NG_IGNORE(p);
601     NG_IGNORE(i);
602 
603     if (dg->instance)
604         fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, dg->instance->GENname);
605     else
606         fprintf(cp_out, " %*s", DEV_WIDTH, "<\?\?\?\?\?\?\?>");
607     return 0;
608 }
609 
610 
611 int
printstr_m(dgen * dg,IFparm * p,int i)612 printstr_m(dgen *dg, IFparm *p, int i)
613 {
614     NG_IGNORE(p);
615     NG_IGNORE(i);
616 
617     if (dg->model)
618         fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, dg->model->GENmodName);
619     else
620         fprintf(cp_out, " %*s", DEV_WIDTH, "<\?\?\?\?\?\?\?>");
621     return 0;
622 }
623 
624 
625 void
param_forall(dgen * dg,int flags)626 param_forall(dgen *dg, int flags)
627 {
628     int i, j, k;
629     int xcount;
630     IFparm *plist;
631 
632     if (dg->flags & DGEN_INSTANCE) {
633         xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
634         plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
635     } else {
636         xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
637         plist = ft_sim->devices[dg->dev_type_no]->modelParms;
638     }
639 
640     for (i = 0; i < xcount; i++)
641         if ((plist[i].dataType & IF_ASK)
642             && !(plist[i].dataType & IF_REDUNDANT)
643             && ((plist[i].dataType & IF_SET) || dg->ckt->CKTrhsOld)
644             && (!(plist[i].dataType & IF_UNINTERESTING) || (flags == DGEN_ALLPARAMS)))
645         {
646             j = 0;
647             do {
648                 fprintf(cp_out, "    %-19s=", plist[i].keyword);
649 
650                 k = dgen_for_n(dg, count, printvals, (plist + i), j);
651                 fprintf(cp_out, "\n");
652                 j += 1;
653 
654             } while (k);
655         }
656 }
657 
658 
659 void
param_forall_old(dgen * dg,int flags)660 param_forall_old(dgen *dg, int flags)
661 {
662     int i, j, k;
663     int xcount;
664     IFparm *plist;
665 
666     if (dg->flags & DGEN_INSTANCE) {
667         xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
668         plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
669     } else {
670         xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
671         plist = ft_sim->devices[dg->dev_type_no]->modelParms;
672     }
673 
674     for (i = 0; i < xcount; i++)
675         if ((plist[i].dataType & IF_ASK)
676             && !(plist[i].dataType & IF_REDUNDANT)
677             && ((plist[i].dataType & IF_SET) || dg->ckt->CKTrhsOld)
678             && (!(plist[i].dataType & IF_UNINTERESTING) || (flags == DGEN_ALLPARAMS)))
679         {
680             j = 0;
681             do {
682                 if (!j)
683                     fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH,
684                             plist[i].keyword);
685                 else
686                     fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, " ");
687                 k = dgen_for_n(dg, count, printvals_old, (plist + i), j);
688                 fprintf(cp_out, "\n");
689                 j += 1;
690             } while (k);
691         }
692 }
693 
694 
695 void
listparam(wordlist * p,dgen * dg)696 listparam(wordlist *p, dgen *dg)
697 {
698     int i, j, k, found;
699     int xcount;
700     IFparm *plist;
701 
702     found = 0;
703 
704     if (dg->flags & DGEN_INSTANCE) {
705         xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms;
706         plist = ft_sim->devices[dg->dev_type_no]->instanceParms;
707     } else {
708         xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms;
709         plist = ft_sim->devices[dg->dev_type_no]->modelParms;
710     }
711 
712     for (i = 0; i < xcount; i++)
713         if (eqc(p->wl_word, plist[i].keyword) && (plist[i].dataType & IF_ASK)) {
714             found = 1;
715             break;
716         }
717 
718     if (found) {
719         if (dg->ckt->CKTrhsOld ||
720             (plist[i].dataType & IF_SET))
721         {
722             j = 0;
723             do {
724                 if (!j)
725                     fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
726                 else
727                     fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, " ");
728                 k = dgen_for_n(dg, count, printvals_old, (plist + i), j);
729                 printf("\n");
730                 j += 1;
731             } while (k > 0);
732         } else {
733             j = 0;
734             do {
735                 if (!j)
736                     fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
737                 else
738                     fprintf(cp_out, "%*s", LEFT_WIDTH, " ");
739                 k = dgen_for_n(dg, count, bogus1, NULL, j);
740                 fprintf(cp_out, "\n");
741                 j += 1;
742             } while (k > 0);
743         }
744     } else {
745         j = 0;
746         do {
747             if (!j)
748                 fprintf(cp_out, "%*.*s", LEFT_WIDTH, LEFT_WIDTH, p->wl_word);
749             else
750                 fprintf(cp_out, "%*s", LEFT_WIDTH, " ");
751             k = dgen_for_n(dg, count, bogus2, NULL, j);
752             fprintf(cp_out, "\n");
753             j += 1;
754         } while (k > 0);
755     }
756 }
757 
758 
759 int
bogus1(dgen * dg,IFparm * p,int i)760 bogus1(dgen *dg, IFparm *p, int i)
761 {
762     NG_IGNORE(dg);
763     NG_IGNORE(p);
764     NG_IGNORE(i);
765 
766     fprintf(cp_out, " %*s", DEV_WIDTH, "---------");
767     return 0;
768 }
769 
770 
771 int
bogus2(dgen * dg,IFparm * p,int i)772 bogus2(dgen *dg, IFparm *p, int i)
773 {
774     NG_IGNORE(dg);
775     NG_IGNORE(p);
776     NG_IGNORE(i);
777 
778     fprintf(cp_out, " %*s", DEV_WIDTH, "?????????");
779     return 0;
780 }
781 
782 
783 int
printvals(dgen * dg,IFparm * p,int i)784 printvals(dgen *dg, IFparm *p, int i)
785 {
786     IFvalue     val;
787     int         n;
788 
789     if (dg->flags & DGEN_INSTANCE)
790         ft_sim->askInstanceQuest
791             (ft_curckt->ci_ckt, dg->instance, p->id, &val, &val);
792     else
793         ft_sim->askModelQuest
794             (ft_curckt->ci_ckt, dg->model, p->id, &val, &val);
795 
796     if (p->dataType & IF_VECTOR)
797         n = val.v.numValue;
798     else
799         n = 1;
800 
801     if (((p->dataType & IF_VARTYPES) & ~IF_VECTOR) == IF_COMPLEX)
802         n *= 2;
803 
804     if (i >= n) {
805         if (i == 0)
806             fprintf(cp_out, "         -");
807         else
808             fprintf(cp_out, "          ");
809         return 0;
810     }
811 
812     if (p->dataType & IF_VECTOR) {
813         /* va: ' ' is no flag for %s */
814         switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
815         case IF_FLAG:
816             fprintf(cp_out, " %d", val.v.vec.iVec[i]);
817             break;
818         case IF_INTEGER:
819             fprintf(cp_out, " %d", val.v.vec.iVec[i]);
820             break;
821         case IF_REAL:
822             fprintf(cp_out, " %.6g", val.v.vec.rVec[i]);
823             break;
824         case IF_COMPLEX:
825             if (!(i % 2))
826                 fprintf(cp_out, " %.6g", val.v.vec.cVec[i / 2].real);
827             else
828                 fprintf(cp_out, " %.6g", val.v.vec.cVec[i / 2].imag);
829             break;
830         case IF_STRING:
831             fprintf(cp_out, " %s", val.v.vec.sVec[i]);
832             break;
833         case IF_INSTANCE:
834             fprintf(cp_out, " %s", val.v.vec.uVec[i]);
835             break;
836         default:
837             fprintf(cp_out, " %s", " ******** ");
838         }
839     } else {
840         switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
841         case IF_FLAG:
842             fprintf(cp_out, " %d", val.iValue);
843             break;
844         case IF_INTEGER:
845             fprintf(cp_out, " %d", val.iValue);
846             break;
847         case IF_REAL:
848             fprintf(cp_out, " %.6g", val.rValue);
849             break;
850         case IF_COMPLEX:
851             if (i % 2)
852                 fprintf(cp_out, " %.6g", val.cValue.real);
853             else
854                 fprintf(cp_out, " %.6g", val.cValue.imag);
855             break;
856         case IF_STRING:
857             fprintf(cp_out, " %s", val.sValue);
858             break;
859         case IF_INSTANCE:
860             fprintf(cp_out, " %s", val.uValue);
861             break;
862         default:
863             fprintf(cp_out, " %s", " ******** ");
864         }
865     }
866 
867     return n - 1;
868 }
869 
870 
871 int
printvals_old(dgen * dg,IFparm * p,int i)872 printvals_old(dgen *dg, IFparm *p, int i)
873 {
874     IFvalue     val;
875     int         n, error;
876 
877     if (dg->flags & DGEN_INSTANCE)
878         error = ft_sim->askInstanceQuest
879             (ft_curckt->ci_ckt, dg->instance, p->id, &val, &val);
880     else
881         error = ft_sim->askModelQuest
882             (ft_curckt->ci_ckt, dg->model, p->id, &val, &val);
883 
884     if (p->dataType & IF_VECTOR)
885         n = val.v.numValue;
886     else
887         n = 1;
888 
889     if (((p->dataType & IF_VARTYPES) & ~IF_VECTOR) == IF_COMPLEX)
890         n *= 2;
891 
892     if (i >= n) {
893         if (i == 0)
894             fprintf(cp_out, "         -");
895         else
896             fprintf(cp_out, "          ");
897         return 0;
898     }
899 
900     if (error) {
901         fprintf(cp_out, " <<NAN, error = %d>>", error);
902     } else if (p->dataType & IF_VECTOR) {
903         /* va: ' ' is no flag for %s */
904         switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
905         case IF_FLAG:
906             fprintf(cp_out, " % *d", DEV_WIDTH, val.v.vec.iVec[i]);
907             break;
908         case IF_INTEGER:
909             fprintf(cp_out, " % *d", DEV_WIDTH, val.v.vec.iVec[i]);
910             break;
911         case IF_REAL:
912             fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.rVec[i]);
913             break;
914         case IF_COMPLEX:
915             if (!(i % 2))
916                 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.cVec[i / 2].real);
917             else
918                 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.v.vec.cVec[i / 2].imag);
919             break;
920         case IF_STRING:
921             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.v.vec.sVec[i]);
922             break;
923         case IF_INSTANCE:
924             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.v.vec.uVec[i]);
925             break;
926         default:
927             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, " ******** ");
928         }
929     } else {
930         switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) {
931         case IF_FLAG:
932             fprintf(cp_out, " % *d", DEV_WIDTH, val.iValue);
933             break;
934         case IF_INTEGER:
935             fprintf(cp_out, " % *d", DEV_WIDTH, val.iValue);
936             break;
937         case IF_REAL:
938             fprintf(cp_out, " % *.6g", DEV_WIDTH, val.rValue);
939             break;
940         case IF_COMPLEX:
941             if (i % 2)
942                 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.cValue.real);
943             else
944                 fprintf(cp_out, " % *.6g", DEV_WIDTH, val.cValue.imag);
945             break;
946         case IF_STRING:
947             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.sValue);
948             break;
949         case IF_INSTANCE:
950             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, val.uValue);
951             break;
952         default:
953             fprintf(cp_out, " %*.*s", DEV_WIDTH, DEV_WIDTH, " ******** ");
954         }
955     }
956 
957     return n - 1;
958 }
959 
960 
961 /*
962  * (old "show" command)
963  * Display various device parameters.  The syntax of this command is
964  *   show devicelist : parmlist
965  * where devicelist can be "all", the name of a device, a string like r*,
966  * which means all devices with names that begin with 'r', repeated one
967  * or more times.   The parms are names of parameters that are (hopefully)
968  * valid for all the named devices, or "all".
969  */
970 
971 void
old_show(wordlist * wl)972 old_show(wordlist *wl)
973 {
974     wordlist *devs, *parms, *tw, *ww;
975     struct variable *v;
976     char *nn;
977 
978     devs = wl;
979     wl = wl_find(":", wl);
980     if (!wl) {
981         parms = NULL;
982     } else {
983         if (wl->wl_prev)
984             wl->wl_prev->wl_next = NULL;
985         parms = wl->wl_next;
986         if (parms)
987             parms->wl_prev = NULL;
988     }
989 
990     /* Now expand the devicelist... */
991     for (tw = NULL; devs; devs = devs->wl_next) {
992         inp_casefix(devs->wl_word);
993         tw = wl_append(tw, devexpand(devs->wl_word));
994     }
995 
996     devs = tw;
997     tw = wl_find("all", parms);
998     if (tw)
999         parms = NULL;
1000 
1001     /* This is a crock... */
1002     if (!devs)
1003         devs = cp_cctowl(ft_curckt->ci_devices);
1004 
1005     out_init();
1006 
1007     while (devs) {
1008         out_printf("%s:\n", devs->wl_word);
1009         if (parms) {
1010             for (tw = parms; tw; tw = tw->wl_next) {
1011                 nn = copy(devs->wl_word);
1012                 v = if_getparam(ft_curckt->ci_ckt, &nn, tw->wl_word, 0, 0);
1013                 if (!v)
1014                     v = if_getparam(ft_curckt->ci_ckt, &nn, tw->wl_word, 0, 1);
1015                 if (v) {
1016                     out_printf("\t%s =", tw->wl_word);
1017                     for (ww = cp_varwl(v); ww; ww = ww->wl_next)
1018                         out_printf(" %s", ww->wl_word);
1019                     out_send("\n");
1020                 }
1021             }
1022         } else {
1023             nn = copy(devs->wl_word);
1024             v = if_getparam(ft_curckt->ci_ckt, &nn, "all", 0, 0);
1025             if (!v)
1026                 v = if_getparam(ft_curckt->ci_ckt, &nn, "all", 0, 1);
1027             while (v) {
1028                 out_printf("\t%s =", v->va_name);
1029                 for (ww = cp_varwl(v); ww; ww = ww->wl_next)
1030                     out_printf(" %s", ww->wl_word);
1031                 out_send("\n");
1032                 v = v->va_next;
1033             }
1034         }
1035         devs = devs->wl_next;
1036     }
1037 }
1038 
1039 
1040 /*
1041  * Alter a device parameter.  The new syntax here is
1042  *   alter @device[parameter] = expr
1043  *   alter device = expr
1044  *   alter device parameter = expr
1045  * expr must be real (complex isn't handled right now, integer is fine though,
1046  * but no strings ... for booleans, use 0/1).
1047  */
1048 
1049 static void com_alter_common(wordlist *wl, int do_model);
1050 
1051 void
com_alter(wordlist * wl)1052 com_alter(wordlist *wl)
1053 {
1054     if (!wl) {
1055         fprintf(cp_err, "usage: alter dev param = expression\n");
1056         fprintf(cp_err, "  or   alter @dev[param] = expression\n");
1057         fprintf(cp_err, "  or   alter dev = expression\n");
1058         return;
1059     }
1060 
1061     com_alter_common(wl, 0);
1062 }
1063 
1064 
1065 void
com_altermod(wordlist * wl)1066 com_altermod(wordlist *wl)
1067 {
1068     wordlist *fileword;
1069     bool newfile = FALSE;
1070 
1071     fileword = wl;
1072     while (fileword) {
1073         if (ciprefix("file", fileword->wl_word))
1074             newfile = TRUE;
1075         fileword = fileword->wl_next;
1076     }
1077 
1078     if (newfile)
1079         com_alter_mod(wl);
1080     else
1081         com_alter_common(wl, 1);
1082 }
1083 
1084 
1085 static void
if_set_binned_model(CKTcircuit * ckt,char * devname,char * param,struct dvec * val)1086 if_set_binned_model(CKTcircuit *ckt, char *devname, char *param, struct dvec *val)
1087 {
1088     char *width_length;
1089     double w = 0.0, l = 0.0;
1090     struct variable *v;
1091 
1092     v = if_getparam(ckt, &devname, "w", 0, 0);
1093     if (!v) {
1094         fprintf(cp_err, "Error: Can't access width instance parameter.\n");
1095         return;
1096     }
1097     w = v->va_V.vV_real;
1098     free_struct_variable(v);
1099 
1100     v = if_getparam(ckt, &devname, "l", 0, 0);
1101     if (!v) {
1102         fprintf(cp_err, "Error: Can't access length instance parameter.\n");
1103         return;
1104     }
1105     l = v->va_V.vV_real;
1106     free_struct_variable(v);
1107 
1108     if (param[0] == 'w')
1109         w = *val->v_realdata; /* overwrite the width with the alter param */
1110     else
1111         l = *val->v_realdata; /* overwrite the length with the alter param */
1112 
1113     width_length = tprintf("w=%15.7e l=%15.7e", w, l);
1114 
1115     if_setparam_model(ft_curckt->ci_ckt, &devname, width_length);
1116     FREE(width_length);
1117 }
1118 
1119 
1120 static void
com_alter_common(wordlist * wl,int do_model)1121 com_alter_common(wordlist *wl, int do_model)
1122 {
1123     wordlist *wl_head = wl;
1124     wordlist *eqword, *words;
1125     char *dev, *param;
1126     struct dvec *dv;
1127     struct pnode *names;
1128 
1129     int i;
1130 
1131     if (!ft_curckt) {
1132         fprintf(cp_err, "Error: no circuit loaded\n");
1133         return;
1134     }
1135 
1136     /*
1137      * when the assignment operator '=' is embedded in a wl_word
1138      *  then split the word into several words
1139      *
1140      * Spaces around the '=' sign have to be removed. This is provided
1141      * by inp_remove_excess_ws(). But take care if command is entered manually!
1142      */
1143     for (; wl; wl = wl->wl_next) {
1144         char *argument = wl->wl_word;
1145         char *eqptr = strchr(argument, '=');
1146         if (eqptr) {
1147             if (strlen(argument) > 1) {
1148                 wordlist *wn = NULL;
1149                 if (eqptr[1])
1150                     wn = wl_cons(copy(eqptr + 1), wn);
1151                 wn = wl_cons(copy("="), wn);
1152                 if (eqptr > argument)
1153                     wn = wl_cons(copy_substring(argument, eqptr), wn);
1154                 wl_splice(wl, wn);
1155                 if (wl_head == wl)
1156                     wl_head = wn;
1157             }
1158             break;
1159         }
1160     }
1161 
1162     if (!wl) {
1163         /* no equal sign found, probably a pre3f4 input format
1164          *   'alter device value'
1165          *   'alter device parameter value'
1166          * are supported,
1167          *   'alter device parameter value parameter value [ parameter value ]'
1168          * with multiple param value pairs are not supported!
1169          */
1170         wordlist *wlin = wl_head;
1171         int wlen = wl_length(wlin);
1172         int maxelem = 3;
1173         /* Return the last element of wlin */
1174         wlin = wl_nthelem(100, wlin); /* no more than 100 vector elements */
1175 
1176         if (eq(wlin->wl_word, "]"))     /* we have a vector */
1177             for (i = 0; i < 100; i++) { /* no more than 100 vector elements */
1178                 wlin = wlin->wl_prev;
1179                 maxelem++;
1180                 if (eq(wlin->wl_word, "["))
1181                     break;
1182                 if (wlin->wl_prev == NULL) {
1183                     fprintf(cp_err, "Error: '[' is missing.\n");
1184                     fprintf(cp_err, "Cannot alter parameters.\n");
1185                     return;
1186                 }
1187             }
1188 
1189         if (wlen > maxelem) {
1190             fprintf(cp_err, "Error: Only a single param - value pair supported.\n");
1191             fprintf(cp_err, "Cannot alter parameters.\n");
1192             return;
1193         }
1194         /* add the '=' */
1195         wlin = wlin->wl_prev;
1196         wlin = wl_append(wlin, wl_cons(copy("="), wl_chop_rest(wlin)));
1197     }
1198 
1199     wl = wl_head;
1200 
1201     /* Everything is ready, parsing of the wordlist starts here. */
1202     eqword = wl_find("=", wl);
1203     if (!eqword || !eqword->wl_next) {
1204         fprintf(cp_err, "Error: no assignment found.\n");
1205         fprintf(cp_err, "Cannot alter parameters.\n");
1206         return;
1207     }
1208 
1209     /*
1210      * device parameter = expr
1211      * device = expr
1212      * @dev[param] = expr
1213      */
1214 
1215     dev = NULL;
1216     param = NULL;
1217     words = wl;
1218     while (words != eqword) {
1219         char *p = words->wl_word;
1220         if (param) {
1221             fprintf(cp_err, "Warning: excess parameter name \"%s\" ignored.\n", p);
1222         } else if (dev) {
1223             param = words->wl_word;
1224         } else if (*p == '@' || *p == '#') {
1225             dev = p + 1;
1226             p = strchr(p, '[');
1227             if (p) {
1228                 *p++ = '\0';
1229                 param = p;
1230                 p = strchr(p, ']');
1231                 if (p)
1232                     *p = '\0';
1233             }
1234         } else {
1235             dev = p;
1236         }
1237         words = words->wl_next;
1238     }
1239 
1240     if (!dev) {
1241         fprintf(cp_err, "Error: no model or device name provided.\n");
1242         fprintf(cp_err, "Cannot alter parameters.\n");
1243         return;
1244     }
1245 
1246     /* in case the altermod command comes from commandline or
1247        over shared library we have to provide lowercase */
1248     strtolower(param);
1249     strtolower(dev);
1250 
1251     words = eqword->wl_next;
1252     /* skip next line if words is a vector */
1253     if (!eq(words->wl_word, "["))
1254         names = ft_getpnames(words, FALSE);
1255     else
1256         names = NULL;
1257 
1258     if (!names) {
1259         /* Put this to try to resolve the case of
1260          *   alter @vin[pulse] = [ 0 5 10n 10n 10n 50n 100n ]
1261          */
1262         char *xsbuf, *rem_xsbuf;
1263 
1264         double *list;
1265         double tmp;
1266         int error;
1267         /* move beyond '[' to allow INPevaluate() */
1268         if (eq(words->wl_word, "["))
1269             words = words->wl_next;
1270         xsbuf = rem_xsbuf = wl_flatten(words);
1271         /* fprintf(cp_err, "Chain    converted  %s \n", xsbuf); */
1272 
1273         for (i = 0, list = NULL;;) {
1274             tmp = INPevaluate(&xsbuf, &error, 1);
1275             if (error)
1276                 break;
1277             /* printf(" returning vector value %g\n", tmp); */
1278             list = TREALLOC(double, list, i + 1);
1279             list[i++] = tmp;
1280         }
1281 
1282         if (i < 1) {
1283             fprintf(cp_err, "Error: cannot evaluate new parameter value.\n");
1284             return;
1285         }
1286 
1287         dv = dvec_alloc(copy("real vector"),
1288                         SV_NOTYPE,
1289                         VF_REAL,
1290                         i, list);
1291         if (!dv)
1292             return;
1293 
1294         /* Here I was, to change the inclusion in the circuit.
1295          * will have to revise that dv is right for its insertion.
1296          */
1297         if_setparam(ft_curckt->ci_ckt, &dev, param, dv, do_model);
1298 
1299         tfree(rem_xsbuf);
1300         vec_free(dv);
1301         return;
1302     }
1303 
1304     dv = ft_evaluate(names);
1305     if (!dv)
1306         goto done;
1307 
1308     if (dv->v_length < 1) {
1309         fprintf(cp_err, "Error: cannot evaluate new parameter value.\n");
1310         goto done;
1311     }
1312 
1313     /* If we want alter the geometry of a MOS device
1314        we have to ensure that we are in the valid model bin. */
1315     if ((dev[0] == 'm') && (eq(param, "w") || eq(param, "l")))
1316         if_set_binned_model(ft_curckt->ci_ckt, dev, param, dv);
1317 
1318     if_setparam(ft_curckt->ci_ckt, &dev, param, dv, do_model);
1319 
1320  done:
1321     /* va: garbage collection for dv, if pnode names is no simple value */
1322     if (names && !names->pn_value && dv)
1323         vec_free(dv);
1324     free_pnode(names); /* free also dv, if pnode names is simple value */
1325 }
1326 
1327 
1328 /* Given a device name, possibly with wildcards, return the matches. */
1329 
1330 static wordlist *
devexpand(char * name)1331 devexpand(char *name)
1332 {
1333     wordlist *wl, *devices;
1334 
1335     if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
1336         devices = cp_cctowl(ft_curckt->ci_devices);
1337         for (wl = NULL; devices; devices = devices->wl_next)
1338             if (!strcmp(name, devices->wl_word))
1339                 wl = wl_cons(devices->wl_word, wl);
1340     } else if (cieq(name, "all")) {
1341         wl = cp_cctowl(ft_curckt->ci_devices);
1342     } else {
1343         wl = wl_cons(name, NULL);
1344     }
1345 
1346     wl_sort(wl);
1347     return wl;
1348 }
1349 
1350 
1351 /* altermod mod_1 [mod_nn] file=modelparam.mod
1352    load model file and overwrite models mod_1 till mod_nn with
1353    all new parameters (limited to 16 models) */
1354 
1355 static void
com_alter_mod(wordlist * wl)1356 com_alter_mod(wordlist *wl)
1357 {
1358 #define MODLIM 16 /* max number of models */
1359     FILE *modfile;
1360     char *modellist[MODLIM] = {NULL}, *modellines[MODLIM] = {NULL}, *newmodelname, *newmodelline;
1361     char *filename = NULL, *eqword, *input, *modelline = NULL, *inptoken;
1362     int modno = 0, molineno = 0, i, j;
1363     wordlist *newcommand;
1364     struct card *modeldeck, *tmpdeck;
1365     char *readmode = "r";
1366     char **arglist;
1367     bool modelfound = FALSE;
1368     int ij[MODLIM];
1369 
1370     /* initialize */
1371     for (i = 0; i < MODLIM; i++)
1372         ij[i] = -1;
1373 
1374     /* read all model names */
1375     while (!ciprefix("file", wl->wl_word)) {
1376         if (modno == MODLIM) {
1377             fprintf(cp_err, "Error: too many model names in altermod command\n");
1378             controlled_exit(1);
1379         }
1380         modellist[modno] = copy(wl->wl_word);
1381         modno++;
1382         wl = wl->wl_next;
1383     }
1384     input = wl_flatten(wl);
1385     /* get the file name */
1386     eqword = strchr(input, '=');
1387     if (eqword) {
1388         eqword++;
1389         while (*eqword == ' ')
1390             eqword++;
1391         if (*eqword == '\0') {
1392             fprintf(cp_err, "Error: no filename given\n");
1393             controlled_exit(1);
1394         }
1395         filename = copy(eqword);
1396     } else {
1397         eqword = strstr(input, "file");
1398         eqword += 4;
1399         while (*eqword == ' ')
1400             eqword++;
1401         if (*eqword == '\0') {
1402             fprintf(cp_err, "Error: no filename given\n");
1403             controlled_exit(1);
1404         }
1405         filename = copy(eqword);
1406     }
1407 
1408     modfile = inp_pathopen(filename, readmode);
1409 
1410     if (modfile == NULL) {
1411         fprintf(cp_err, "Warning: Could not open file %s, altermod ignored\n", filename);
1412         tfree(input);
1413         tfree(filename);
1414         return;
1415     }
1416     {
1417         char *dir_name = ngdirname(filename);
1418         modeldeck = inp_readall(modfile, dir_name, 0, 0, NULL);
1419         tfree(dir_name);
1420     }
1421     tfree(input);
1422     tfree(filename);
1423     /* get all lines starting with *model */
1424     for (tmpdeck = modeldeck; tmpdeck; tmpdeck = tmpdeck->nextcard)
1425         /* We are looking for *model because the input paerser has
1426            invalidated all unused models by replacing '.' by '*'. */
1427         if (ciprefix("*model", tmpdeck->line)) {
1428             if (molineno == MODLIM) {
1429                 fprintf(cp_err, "Error: more than %d models in deck, rest ignored\n", molineno);
1430                 break;
1431             }
1432             modellines[molineno] = tmpdeck->line;
1433             molineno++;
1434         }
1435     /* Check if all models named in altermod command are to be found in input deck.
1436        Exit if not successfull */
1437     for (i = 0; i < modno; i++) {
1438         for (j = 0; j < molineno; j++) {
1439             newmodelline = modellines[j];
1440             /* get model name from model line */
1441             inptoken = gettok(&newmodelline); /* *model */
1442             tfree(inptoken);
1443             newmodelname = gettok(&newmodelline); /* modelname */
1444             if (cieq(newmodelname, modellist[i])) {
1445                 modelfound = TRUE;
1446                 tfree(newmodelname);
1447                 break;
1448             }
1449             tfree(newmodelname);
1450         }
1451         if (modelfound) {
1452             modelfound = FALSE;
1453             ij[i] = j; /* model in altermod, found in model line */
1454             continue;
1455         } else {
1456             fprintf(cp_err, "Error: could not find model %s in input deck\n", modellist[i]);
1457             controlled_exit(1);
1458         }
1459     }
1460     /* read the model line, generate the altermod commands as a wordlist,
1461        and call com_alter_common() */
1462     arglist = TMALLOC(char *, 4);
1463     arglist[0] = copy("altermod");
1464     arglist[3] = NULL;
1465     /* for each model name of altermod command */
1466     for (i = 0; i < modno; i++) {
1467         /* model name */
1468         arglist[1] = copy(modellist[i]);
1469         /* parse model line from deck */
1470         modelline = modellines[ij[i]];
1471         inptoken = gettok(&modelline); /* skip *model */
1472         tfree(inptoken);
1473         inptoken = gettok(&modelline); /* skip modelname */
1474         tfree(inptoken);
1475         inptoken = gettok(&modelline); /* skip model type */
1476         tfree(inptoken);
1477         while ((inptoken = gettok_node(&modelline)) != NULL) {
1478             /* exclude level, version and mfg */
1479             if (ciprefix("version", inptoken) || ciprefix("level", inptoken) ||
1480                 ciprefix("mfg", inptoken)) {
1481                 tfree(inptoken);
1482                 continue;
1483             }
1484             arglist[2] = inptoken;
1485             /* create a new wordlist from array arglist */
1486             newcommand = wl_build((const char * const *) arglist);
1487             com_alter_common(newcommand->wl_next, 1);
1488             wl_free(newcommand);
1489             tfree(inptoken);
1490         }
1491         tfree(arglist[1]);
1492     }
1493     tfree(arglist[0]);
1494     tfree(arglist[3]);
1495 }
1496 
1497 
1498 #ifdef HAVE_TSEARCH
1499 
1500 #include <search.h>
1501 
1502 static int
check_ifparm_compare(const void * a,const void * b)1503 check_ifparm_compare(const void *a, const void *b)
1504 {
1505     IFparm *pa = (IFparm *) a;
1506     IFparm *pb = (IFparm *) b;
1507     return pa->id - pb->id;
1508 }
1509 
1510 
1511 static void
check_ifparm_freenode(void * node)1512 check_ifparm_freenode(void *node)
1513 {
1514     NG_IGNORE(node);
1515 }
1516 
1517 
1518 static void
check_ifparm(IFdevice * device,int instance_flag)1519 check_ifparm(IFdevice *device, int instance_flag)
1520 {
1521     int i, xcount;
1522     IFparm *plist;
1523 
1524     if (instance_flag) {
1525         plist = device->instanceParms;
1526         if (!plist)
1527             return;
1528         fprintf(stderr, " checking %s instanceParams\n", device->name);
1529         xcount = *device->numInstanceParms;
1530     } else {
1531         plist = device->modelParms;
1532         if (!plist)
1533             return;
1534         fprintf(stderr, " checking %s modelParams\n", device->name);
1535         xcount = *device->numModelParms;
1536     }
1537 
1538     void *root = NULL;
1539 
1540     for (i = 0; i < xcount; i++) {
1541 
1542         IFparm *psearch = *(IFparm **) tsearch(plist + i, &root,
1543                                                check_ifparm_compare);
1544 
1545         int type_err = (psearch->dataType ^ plist[i].dataType) & ~IF_REDUNDANT;
1546         if (type_err)
1547             fprintf(stderr,
1548                     " ERROR, dataType mismatch \"%s\" \"%s\" %08x\n",
1549                     psearch->keyword, plist[i].keyword, type_err);
1550 
1551         if ((plist[i].dataType & IF_REDUNDANT) &&
1552             (i == 0 || plist[i-1].id != plist[i].id)) {
1553             fprintf(stderr,
1554                     "ERROR, alias \"%s\" has non matching predecessor \"%s\"\n",
1555                     plist[i].keyword, plist[i-1].keyword);
1556         }
1557 
1558         if (i == 0)
1559             continue;
1560 
1561         if (plist[i-1].id != plist[i].id) {
1562             if (psearch != plist + i)
1563                 fprintf(stderr,
1564                         "ERROR: non neighbored duplicate id: \"%s\" \"%s\"\n",
1565                         psearch->keyword, plist[i].keyword);
1566         } else if (!(plist[i].dataType & IF_REDUNDANT)) {
1567             fprintf(stderr,
1568                     "ERROR: non R duplicate id: \"%s\" \"%s\"\n",
1569                     plist[i-1].keyword, plist[i].keyword);
1570         }
1571     }
1572 
1573 #ifdef HAVE_TDESTROY
1574     tdestroy (root, check_ifparm_freenode);
1575 #endif
1576 }
1577 
1578 
1579 void
com_check_ifparm(wordlist * wl)1580 com_check_ifparm(wordlist *wl)
1581 {
1582     NG_IGNORE(wl);
1583 
1584     int k;
1585 
1586     for (k = 0; k < ft_sim->numDevices; k++)
1587         if (ft_sim->devices[k]) {
1588             check_ifparm(ft_sim->devices[k], 0);
1589             check_ifparm(ft_sim->devices[k], 1);
1590         }
1591 }
1592 
1593 #endif
1594