1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
4 **********/
5 
6 #include "ngspice/ngspice.h"
7 #include "ngspice/bool.h"
8 #include "ngspice/wordlist.h"
9 #include "ngspice/defines.h"
10 #include "ngspice/macros.h"
11 #include "ngspice/cpdefs.h"
12 #include "ngspice/memory.h"
13 #include "ngspice/inpdefs.h"
14 #include "ngspice/fteext.h"
15 
16 #include "circuits.h"
17 #include "com_history.h"
18 #include "ngspice/cpextern.h"
19 #include "variable.h"
20 
21 
22 bool cp_noglob = TRUE;
23 bool cp_nonomatch = FALSE;
24 bool cp_noclobber = FALSE;
25 bool cp_ignoreeof = FALSE;
26 bool cp_echo = FALSE;   /* CDHW */
27 
28 struct variable *variables = NULL;
29 
30 
31 
32 static void update_option_variables(const char *sz_var_name,
33     struct variable *p_v);
34 
35 
36 
cp_varwl(struct variable * var)37 wordlist *cp_varwl(struct variable *var)
38 {
39     wordlist *wl = NULL, *w, *wx = NULL;
40     char *buf;
41     struct variable *vt;
42 
43     switch (var->va_type) {
44     case CP_BOOL:
45         /* Can't ever be FALSE. */
46         buf = copy(var->va_bool ? "TRUE" : "FALSE");
47         break;
48     case CP_NUM:
49         buf = tprintf("%d", var->va_num);
50         break;
51     case CP_REAL:
52         /* This is a case where printnum isn't too good... */
53         buf = tprintf("%G", var->va_real);
54         break;
55     case CP_STRING:
56         buf = copy(var->va_string);
57         break;
58     case CP_LIST:   /* The tricky case. */
59         for (vt = var->va_vlist; vt; vt = vt->va_next) {
60             w = cp_varwl(vt); /* recursive call */
61             if (wl == NULL) {
62                 wl = wx = w;
63             }
64             else {
65                 wx->wl_next = w;
66                 w->wl_prev = wx;
67                 wx = w;
68             }
69         }
70         return wl;
71     default:
72         fprintf(cp_err,
73                 "cp_varwl: Internal Error: bad variable type %d\n",
74                 var->va_type);
75         return NULL;
76     }
77 
78     return wl_cons(buf, NULL);
79 } /* end of function cp_varwl */
80 
81 
82 
83 /* Set a variable. */
cp_vset(const char * varname,enum cp_types type,const void * value)84 void cp_vset(const char *varname, enum cp_types type,
85         const void *value)
86 {
87     struct variable *v, *u, *w;
88     int i;
89     bool alreadythere = FALSE, v_free = FALSE;
90     char *copyvarname;
91 
92     /* varname = cp_unquote(varname);  DG: Memory leak old varname is lost*/
93 
94     copyvarname = cp_unquote(varname);
95 
96     w = NULL;
97     for (v = variables; v; v = v->va_next) {
98         if (eq(copyvarname, v->va_name)) {
99             alreadythere = TRUE;
100             break;
101         }
102         w = v;
103     }
104 
105     if (alreadythere) {
106         if (v->va_type == CP_LIST)
107             free_struct_variable(v->va_vlist);
108         if (v->va_type == CP_STRING)
109             tfree(v->va_string);
110     }
111 
112     if (!v) {
113         v = var_alloc(copy(copyvarname), NULL);
114         v_free = TRUE;
115     }
116 
117     switch (type) {
118     case CP_BOOL:
119         if (* ((bool *) value) == FALSE) {
120             cp_remvar(copyvarname);
121             if (v_free) {
122                 tfree(v->va_name);
123                 tfree(v);
124             }
125             tfree(copyvarname);
126             return;
127         }
128         else {
129             /* The variable only exists in TRUE state */
130             var_set_bool(v, TRUE);
131         }
132         break;
133 
134     case CP_NUM:
135         var_set_num(v, * (int *) value);
136         break;
137 
138     case CP_REAL:
139         var_set_real(v, * (double *) value);
140         break;
141 
142     case CP_STRING:
143         var_set_string(v, copy((char*) value));
144         break;
145 
146     case CP_LIST:
147         var_set_vlist(v, (struct variable *) value);
148         break;
149 
150     default:
151         fprintf(cp_err,
152                 "cp_vset: Internal Error: bad variable type %d.\n",
153                 type);
154         tfree(copyvarname);
155         return;
156     }
157 
158     /* Update variables controlling options */
159     update_option_variables(copyvarname, v);
160 
161     switch (i = cp_usrset(v, TRUE)) {
162 
163     case US_OK:
164         /* Normal case. */
165         if (!alreadythere) {
166             v->va_next = variables;
167             variables = v;
168         }
169         else if (v_free)
170             free_struct_variable(v);
171         break;
172 
173     case US_DONTRECORD:
174         /* 'curplot' 'curplotname' 'curplottitle' 'curplotdate' */
175         /* Do nothing... */
176         if (alreadythere) {
177             fprintf(cp_err, "cp_vset: Internal Error: "
178                     "%s already there, but 'dont record'\n", v->va_name);
179         }
180         if (v_free)
181             free_struct_variable(v);
182         break;
183 
184     case US_READONLY:
185         /* 'plots' and any var in plot_cur->pl_env */
186         fprintf(cp_err, "Error: %s is a read-only variable.\n", v->va_name);
187         if (alreadythere)
188             fprintf(cp_err, "cp_vset: Internal Error: "
189                     "it was already there too!!\n");
190         break;
191 
192     case US_SIMVAR:
193         /* variables processed by if_option(ft_curckt->ci_ckt, ...) */
194         if (alreadythere) {
195             /* somehow it got into the front-end list of variables */
196             if (w) {
197                 w->va_next = v->va_next;
198             } else {
199                 variables = v->va_next;
200             }
201         }
202         alreadythere = FALSE;
203         if (ft_curckt) {
204             for (u = ft_curckt->ci_vars; u; u = u->va_next)
205                 if (eq(copyvarname, u->va_name)) {
206                     alreadythere = TRUE;
207                     break;
208                 }
209             if (!alreadythere) {
210                 v->va_next = ft_curckt->ci_vars;
211                 ft_curckt->ci_vars = v;
212             } else {
213                 if (u->va_type == CP_STRING)
214                     tfree(u->va_string);
215                 else if (u->va_type == CP_LIST)
216                     tfree(u->va_vlist);
217                 u->va_V = v->va_V;
218                 u->va_type = v->va_type;
219                 /* va_name is the same string */
220                 tfree(u->va_name);
221                 u->va_name = v->va_name;
222                 /* va_next left unchanged */
223                 tfree(v);
224             }
225         }
226         break;
227 
228     case US_NOSIMVAR:
229         /* variables processed by if_option(NULL, ...) */
230         /* What do you do? */
231         free_struct_variable(v);
232         break;
233 
234     default:
235         fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i);
236         break;
237     }
238 
239     tfree(copyvarname);
240 } /* end of function cp_vset */
241 
242 
243 
244 /* Process special variables: noglob, nonomatch, history,
245  * noclobber, echo, prompt, ignoreeof, cpdebug, and no_histsubst
246  * by setting the values of associated option variables.
247  *
248  * Parmeters
249  * sz_var_name: Name of variable
250  * p_v: Variable if it is being added or NULL if being removed.
251  */
update_option_variables(const char * sz_var_name,struct variable * p_v)252 static void update_option_variables(const char *sz_var_name,
253     struct variable *p_v)
254 {
255     static const unsigned char p_ch0['p' - 'a' + 1] = {
256         ['n' - 'a'] = 1, /* noglob, nonomatch, noclobber, no_histsubst */
257         ['h' - 'a'] = 2, /* history */
258         ['e' - 'a'] = 3, /* echo */
259         ['p' - 'a'] = 4, /* prompt, program */
260         ['i' - 'a'] = 5, /* ignoreeof */
261         ['c' - 'a'] = 6 /* cpdebug */
262     };
263 
264     unsigned int index0 = (unsigned int) sz_var_name[0] - 'a';
265 
266     /* Check if first char of is in range of interest.
267      * Note that if < 0, as unsigned, it will be very large so this
268      * single compare checks both < 'a' and > 'p' */
269     if (index0 >= sizeof p_ch0) {
270         return;
271     }
272 
273     unsigned int id0 = (unsigned int) p_ch0[index0];
274     if (id0 == 0) { /* not of interest */
275         return;
276     }
277 
278     /* Flag that bool values should be set is based on if the
279      * variable is being added (via a set) or removed */
280     const bool f_set = p_v != (struct variable *) NULL;
281 
282     switch (id0) {
283     case 1:
284         /* noglob, nonomatch, noclobber, no_histsubst */
285         if (sz_var_name[1] != 'o') {
286             return;
287         }
288         {
289             bool *p_var;
290             const char *sz_rest = sz_var_name + 2;
291             if (eq(sz_rest, "glob")) {
292                 p_var = &cp_noglob;
293             }
294             else if (eq(sz_rest, "nomatch")) {
295                 p_var = &cp_nonomatch;
296             }
297             else if (eq(sz_rest, "clobber")) {
298                 p_var = &cp_noclobber;
299             }
300             else if (eq(sz_rest, "_histsubst")) {
301                 p_var = &cp_no_histsubst;
302             }
303             else { /* not a variable of interest */
304                 return;
305             }
306             *p_var = f_set;
307         }
308         return;
309     case 2: /* history */
310         if (eq(sz_var_name + 1, "istory")) {
311             if (f_set) {
312                 int n = -1;
313                 enum cp_types type = p_v->va_type;
314                 if (type == CP_NUM) {
315                     n = p_v->va_num;
316                 }
317                 else if (type == CP_REAL) {
318                     n = (int) round(p_v->va_real);
319                 }
320                 if (n >= 0) {
321                     cp_maxhistlength = n;
322                 }
323             }
324             /* Note that 'unset history' doesn't do anything here... Causes
325              * trouble...  */
326         }
327         return;
328     case 3: /* echo */
329         if (eq(sz_var_name + 1, "cho")) {
330             cp_echo = f_set;
331         }
332         return;
333     case 4: /* prompt, program */
334         if (sz_var_name[1] != 'r') {
335             return;
336         }
337         if (sz_var_name[2] != 'o') {
338             return;
339         }
340         const char *sz_rest = sz_var_name + 3;
341         if (eq(sz_rest, "mpt")) { /* prompt */
342             if (f_set && p_v->va_type == CP_STRING) {
343                 cp_promptstring = p_v->va_string;
344             }
345             else {
346                 /* Use a default string since prompt is not a string or the
347                  * previous prompt string was freed */
348                 cp_promptstring = "-> ";
349             }
350             return;
351         }
352         if (eq(sz_rest, "gram")) { /* program */
353             if (f_set && p_v->va_type == CP_STRING) {
354                 cp_program = p_v->va_string;
355             }
356             else {
357                 /* Use a default string since program is not a string or the
358                  * previous program string was freed */
359                 cp_program = "";
360             }
361             return;
362         }
363         return; /* not of interest */
364     case 5:
365         if (eq(sz_var_name + 1, "gnoreeof")) { /* ignoreeof */
366             cp_ignoreeof = f_set;
367         }
368         return;
369     case 6:
370         if (eq(sz_var_name + 1, "pdebug")) { /* cpdebug */
371             cp_debug = f_set;
372 #ifndef CPDEBUG
373             if (cp_debug) {
374                 fprintf(cp_err, "Warning: program not compiled "
375                         "with cshpar debug messages\n");
376             }
377 #endif
378         }
379     } /* end of switch over index for first char */
380 } /* end of function update_option_variables */
381 
382 
383 
384 /* Read a wordlist, e.g. from the options or set commands
385    e.g. set myvar=myval or set myvar="myval" or myvar=( "myval1" myval2 ) or
386    set myvar1=myval1 myvar2=myval2 myvar3="myval3"
387    Separate into name and value(s)
388    Generate variables (real, string or list)
389    Value in double quotes will always become string variable.
390    Without quotes tokens like 2N5401_C will be evaluated as real number 2n, i.e. 2e-9 */
cp_setparse(wordlist * wl)391 struct variable *cp_setparse(wordlist *wl)
392 {
393     char *name = NULL, *val, *copyval, *s, *ss;
394     struct variable *listv = NULL, *vv, *lv = NULL;
395     struct variable *vars = NULL;
396 
397     /* Step through the list of words. Words may be various combinations of
398      * the information needed to set a variable. For example, to set x to
399      * the value 3, the data could be supplied as one word x=3, two words
400      * x= 3 or x =3 or three words x = 3. Additionally words may be quoted
401      * or unquoted. Each iteration through the loop handles one variable */
402     while (wl) {
403 
404         if (name) {
405             txfree(name);
406         }
407 
408         name = cp_unquote(wl->wl_word);
409 
410         wl = wl->wl_next;
411         if ((!wl || (*wl->wl_word != '=')) && !strchr(name, '=')) {
412             vars = var_alloc_bool(name, TRUE, vars);
413             name = (char *) NULL; /* Given to variable vars */
414             continue;
415         }
416 
417         if (wl && eq(wl->wl_word, "=")) { /* name<space>= */
418             wl = wl->wl_next;
419             if (wl == NULL) {
420                 fprintf(cp_err, "Error: bad set form.\n");
421                 tfree(name);    /*DG: cp_unquote Memory leak*/
422                 if (ft_stricterror)
423                     controlled_exit(EXIT_BAD);
424                 return NULL;
425             }
426             val = wl->wl_word;
427             wl = wl->wl_next;
428         } else if (wl && (*wl->wl_word == '=')) { /* name<space>=val */
429             val = wl->wl_word + 1;
430             wl = wl->wl_next;
431         } else if ((s = strchr(name, '=')) != NULL) {
432             /* name=<space>value or name=value */
433             val = s + 1;
434             *s = '\0';
435             if (*val == '\0') {
436                 if (!wl) {
437                     fprintf(cp_err, "Error:  %s equals what?.\n", name);
438                     tfree(name); /*DG: cp_unquote Memory leak: free name before exiting*/
439                     if (ft_stricterror)
440                         controlled_exit(EXIT_BAD);
441                     return NULL;
442                 } else {
443                     val = wl->wl_word;
444                     wl = wl->wl_next;
445                 }
446             }
447         }
448         else {
449             fprintf(cp_err, "Error: bad set form.\n");
450             tfree(name); /*DG: cp_unquote Memory leak: free name befor exiting */
451             if (ft_stricterror)
452                 controlled_exit(EXIT_BAD);
453             return NULL;
454         }
455 
456         /* if val is in double quotes, treat as string */
457         copyval = cp_unquote(val);
458         if (!eq(val, copyval)) {
459             vars = var_alloc_string(copy(name), copy(copyval), vars);
460             tfree(name);
461             tfree(copyval);
462             continue;
463         }
464         strcpy(val, copyval);
465         tfree(copyval);
466 
467         /* Test for a list variable */
468         if (eq(val, "(")) {
469             /* The beginning of a list... We have to walk down the
470              * list until we find a close paren... If there are nested
471              * ()'s, treat them as tokens...  */
472             int balance = 1;
473             while (wl && wl->wl_word) {
474                 if (eq(wl->wl_word, "(")) {
475                     balance++;
476                 } else if (eq(wl->wl_word, ")")) {
477                     if (!--balance)
478                         break;
479                 }
480                 copyval = ss = cp_unquote(wl->wl_word);
481                 /* if val is in double quotes, treat as string */
482                 if (!eq(wl->wl_word, copyval)) {
483                     vv = var_alloc_string(NULL, copy(ss), NULL);
484                 }
485                 else {
486                     double dbl_val;
487                     switch (ft_numparse(&ss, FALSE, &dbl_val)) {
488                     case 0: /* CP_REAL */
489                         vv = var_alloc_real(NULL, dbl_val, NULL);
490                         break;
491                     case +1: /* CP_NUM */
492                         vv = var_alloc_num(NULL, (int) dbl_val, NULL);
493                         break;
494                     default: /* CP_STRING */
495                         vv = var_alloc_string(NULL, copy(ss), NULL);
496                     }
497                 }
498                 tfree(copyval);
499                 if (listv) {
500                     lv->va_next = vv;
501                     lv = vv;
502                 } else {
503                     listv = lv = vv;
504                 }
505                 wl = wl->wl_next;
506             }
507             if (balance && !wl) {
508                 fprintf(cp_err, "Error: bad set form.\n");
509                 tfree(name); /* va: cp_unquote memory leak: free name before exiting */
510                 if (ft_stricterror)
511                     controlled_exit(EXIT_BAD);
512                 return NULL;
513             }
514 
515             /* Add list variable to linked list of variables. */
516             vars = var_alloc_vlist(copy(name), listv, vars);
517 
518             wl = wl->wl_next;
519             continue;
520         }
521 
522         copyval = ss = cp_unquote(val);
523         /* if val is in double quotes, treat as string */
524         if (!eq(val, copyval)) {
525             vars = var_alloc_string(copy(name), copy(copyval), vars);
526         }
527         else {
528             double dbl_val;
529             switch (ft_numparse(&ss, FALSE, &dbl_val)) {
530             case 0: /* CP_REAL */
531                 vars = var_alloc_real(name, dbl_val, vars);
532                 break;
533             case +1: /* CP_NUM */
534                 vars = var_alloc_num(name, (int) dbl_val, vars);
535                 break;
536             default: /* CP_STRING */
537                 vars = var_alloc_string(name, copy(val), vars);
538             }
539 
540 
541         }
542         name = (char *) NULL; /* name given to variable via var_alloc_* */
543         tfree(copyval); /*DG: must free ss any way to avoid cp_unquote memory leak */
544     }
545 
546     if (name) {
547         tfree(name);
548     }
549     return vars;
550 } /* end of function cp_setparse */
551 
552 
553 
554 /* free the struct variable. The type of the union is given by va_type */
555 void
free_struct_variable(struct variable * v)556 free_struct_variable(struct variable *v)
557 {
558     while (v) {
559         struct variable *next_v = v->va_next;
560         if (v->va_name)
561             txfree(v->va_name);
562         if (v->va_type == CP_LIST)
563             free_struct_variable(v->va_vlist);
564         if (v->va_type == CP_STRING)
565             txfree(v->va_string);
566         txfree(v);
567         v = next_v;
568     }
569 } /* end of function free_struct_variable */
570 
571 
cp_remvar(char * varname)572 void cp_remvar(char *varname)
573 {
574     struct variable *v, **p;
575     struct variable *uv1;
576     int i;
577 
578     uv1 = cp_usrvars();
579 
580     for (p = &variables; *p; p = &(*p)->va_next) {
581         if (eq((*p)->va_name, varname)) {
582             break;
583         }
584     }
585 
586     if (*p == NULL) {
587         for (p = &uv1; *p; p = &(*p)->va_next) {
588             if (eq((*p)->va_name, varname)) {
589                 break;
590             }
591         }
592     }
593 
594     if (*p == NULL && plot_cur) {
595         for (p = &plot_cur->pl_env; *p; p = &(*p)->va_next) {
596             if (eq((*p)->va_name, varname)) {
597                 break;
598             }
599         }
600     }
601 
602     if (*p == NULL && ft_curckt) {
603         for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next) {
604             if (eq((*p)->va_name, varname)) {
605                 break;
606             }
607         }
608     }
609 
610     v = *p;
611 
612     /* make up an auxiliary struct variable for cp_usrset() */
613     if (!v) {
614         v = var_alloc_num(copy(varname), 0, NULL);
615     }
616 
617     /* Update options that depend on variables */
618     update_option_variables(varname, (struct variable *) NULL);
619 
620     switch (i = cp_usrset(v, FALSE)) {
621 
622     case US_OK:
623         /* Normal case. */
624         if (*p) {
625             *p = v->va_next;
626         }
627         break;
628 
629     case US_DONTRECORD:
630         /* 'curplot' 'curplotname' 'curplottitle' 'curplotdate' */
631         /* Do nothing... */
632         if (*p)
633             fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
634         break;
635 
636     case US_READONLY:
637         /* 'plots' and any var in plot_cur->pl_env */
638         /* Badness... */
639         fprintf(cp_err, "Error: %s is read-only.\n", v->va_name);
640         if (*p)
641             fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
642         break;
643 
644     case US_SIMVAR:
645         /* variables processed by if_option(ft_curckt->ci_ckt, ...) */
646         fprintf(stderr, "it's a US_SIMVAR!\n");
647         if (ft_curckt) {
648             for (p = &ft_curckt->ci_vars; *p; p = &(*p)->va_next)
649                 if (eq(varname, (*p)->va_name))
650                     break;
651             if (*p) {
652                 struct variable *u = *p;
653                 *p = u->va_next;
654                 tfree(u);
655             }
656         }
657         break;
658 
659     case US_NOSIMVAR:
660     default:
661         /* variables processed by if_option(NULL, ...) */
662         fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i);
663         break;
664     }
665 
666     v->va_next = NULL;
667     free_struct_variable(v);
668 
669     free_struct_variable(uv1);
670 } /* end of function cp_remvar */
671 
672 
673 
674 /* Determine the value of a variable.  Fail if the variable is unset,
675  * and if the type doesn't match, try and make it work...  */
676 bool
cp_getvar(char * name,enum cp_types type,void * retval,size_t rsize)677 cp_getvar(char *name, enum cp_types type, void *retval, size_t rsize)
678 {
679     struct variable *v;
680     struct variable *uv1;
681 
682     uv1 = cp_usrvars();
683 
684 #ifdef TRACE
685     /* SDB debug statement */
686     fprintf(stderr, "in cp_getvar, trying to get value of variable %s.\n", name);
687 #endif
688 
689     for (v = variables; v; v = v->va_next)
690         if (eq(name, v->va_name))
691             break;
692 
693     if (!v)
694         for (v = uv1; v; v = v->va_next)
695             if (eq(name, v->va_name))
696                 break;
697 
698     if (!v && plot_cur)
699         for (v = plot_cur->pl_env; v; v = v->va_next)
700             if (eq(name, v->va_name))
701                 break;
702 
703     if (!v && ft_curckt)
704         for (v = ft_curckt->ci_vars; v; v = v->va_next)
705             if (eq(name, v->va_name))
706                 break;
707 
708     if (!v) {
709         if (type == CP_BOOL && retval)
710             *(bool *) retval = FALSE;
711         free_struct_variable(uv1);
712         return (FALSE);
713     }
714 
715     if (v->va_type == type) {
716 
717         if (retval)
718             switch (type) {
719             case CP_BOOL:
720                 *(bool *) retval = TRUE;
721                 break;
722             case CP_NUM:
723                 *(int *) retval = v->va_num;
724                 break;
725             case CP_REAL:
726                 *(double *) retval = v->va_real;
727                 break;
728             case CP_STRING: {   /* Gotta be careful to have room. */
729                 char *s = cp_unquote(v->va_string);
730                 if (strlen(s) > rsize) {
731                     fprintf(stderr, "Warning: string length for variable %s is limited to %zu chars\n", v->va_name, rsize);
732                     /* limit the string length */
733                     s[rsize] = '\0';
734                 }
735                 strcpy((char*) retval, s);
736                 tfree(s);
737                 break;
738             }
739             case CP_LIST:       /* Funny case... */
740                 *(struct variable **) retval = v->va_vlist;
741                 break;
742             default:
743                 fprintf(cp_err,
744                         "cp_getvar: Internal Error: bad var type %d.\n", type);
745                 break;
746             }
747 
748         free_struct_variable(uv1);
749         return (TRUE);
750     }
751 
752     /* Try to coerce it.. */
753     if ((type == CP_NUM) && (v->va_type == CP_REAL)) {
754         *(int *) retval = (int) v->va_real;
755     } else if ((type == CP_REAL) && (v->va_type == CP_NUM)) {
756         *(double *) retval = (double) v->va_num;
757     } else if ((type == CP_STRING) && (v->va_type == CP_NUM)) {
758         sprintf((char*) retval, "%d", v->va_num);
759     } else if ((type == CP_STRING) && (v->va_type == CP_REAL)) {
760         sprintf((char*) retval, "%f", v->va_real);
761     } else {
762         free_struct_variable(uv1);
763         return (FALSE);
764     }
765 
766     free_struct_variable(uv1);
767     return (TRUE);
768 }
769 
770 
771 /* A variable substitution is indicated by a $, and the variable name
772  * is the following string of non-special characters. All variable
773  * values are inserted as a single word, except for lists, which are a
774  * list of words.  A routine cp_usrset must be supplied by the host
775  * program to deal with variables that aren't used by cshpar -- it
776  * should be cp_usrset(var, isset), where var is a variable *, and
777  * isset is TRUE if the variable is being set, FALSE if unset.  Also
778  * required is a routine cp_enqvar(name) which returns a struct
779  * variable *, which allows the host program to provide values for
780  * non-cshpar variables.  */
781 
782 char cp_dol = '$';
783 
784 /* Non-alphanumeric characters that may appear in variable names. < is very
785  * special...
786  */
787 #define VALIDCHARS "$-_<#?@.()[]&"
788 
789 /* This function determines the first character after a variable name and
790  * returns its address.
791  *
792  * Parameter
793  * t: Address of the variable name whose end is to be found. This is the
794  *      address of the first character following the leading $
795  *
796  * Return value
797  * Address of the first character after the variable name.
798  */
span_var_expr(char * t)799 char *span_var_expr(char *t)
800 {
801     int parenthesis = 0;
802     int brackets = 0;
803 
804     while (*t && (isalnum_c(*t) || strchr(VALIDCHARS, *t)))
805         switch (*t++)
806         {
807         case '[':
808             brackets++;
809             break;
810         case '(':
811             parenthesis++;
812             break;
813         case ']':
814             if (brackets <= 0)
815                 return t-1;
816             if (--brackets <= 0)
817                 return t;
818             break;
819         case ')':
820             if (parenthesis <= 0)
821                 return t-1;
822             if (--parenthesis <= 0)
823                 return t;
824             break;
825         default:
826             break;
827         }
828 
829     return t;
830 } /* end of function span_var_expr */
831 
832 
833 /* Substitute variable name by its value and restore to wordlist */
cp_variablesubst(wordlist * wlist)834 wordlist *cp_variablesubst(wordlist *wlist)
835 {
836     wordlist *wl;
837 
838     for (wl = wlist; wl; wl = wl->wl_next) {
839 
840         char *s_dollar;
841         int i = 0;
842 
843         while ((s_dollar = strchr(wl->wl_word + i, cp_dol)) != NULL) {
844 
845             int prefix_len = (int) (s_dollar - wl->wl_word);
846 
847             char *tail = span_var_expr(s_dollar + 1);
848             char *var = copy_substring(s_dollar + 1, tail);
849 
850             wordlist *nwl = vareval(var);
851             tfree(var);
852 
853             if (nwl) {
854                 char *x = nwl->wl_word;
855                 char *tail_ = copy(tail);
856                 nwl->wl_word = tprintf("%.*s%s", prefix_len, wl->wl_word, nwl->wl_word);
857                 tfree(x);
858                 if (wlist == wl)
859                     wlist = nwl;
860                 wl = wl_splice(wl, nwl);
861                 i = (int) strlen(wl->wl_word);
862                 x = wl->wl_word;
863                 wl->wl_word = tprintf("%s%s", wl->wl_word, tail_);
864                 tfree(x);
865                 tfree(tail_);
866             } else if (prefix_len || *tail) {
867                 char *x = wl->wl_word;
868                 wl->wl_word = tprintf("%.*s%s", prefix_len, wl->wl_word, tail);
869                 i = prefix_len;
870                 tfree(x);
871             } else {
872                 wordlist *next = wl->wl_next;
873                 if (wlist == wl) {
874                     wlist = next;
875                 }
876                 wl_delete_slice(wl, next);
877                 if (!next) { /* wordlist ends after wl */
878                     return wlist;
879                 }
880                 wl = next;
881                 i = 0;
882             }
883         } /* end of loop over parts of wordlist node */
884     } /* end of loop over words in wordlist */
885 
886     return wlist;
887 } /* end of function cp_variablesubst */
888 
889 
890 
891 /* Evaluate a variable. */
vareval(char * string)892 wordlist *vareval(/* NOT const */ char *string)
893 {
894     struct variable *v, *vfree = NULL;
895     wordlist *wl;
896     char buf[BSIZE_SP], *s;
897     char *oldstring = copy(string);
898     char *range = NULL;
899     int i, up, low, tbfreed;
900 
901     /* usage of vfree: variable v has to be freed only if created by cp_enqvar()! */
902 
903     if ((s = strchr(string, '[')) != NULL) {
904         *s = '\0';
905         range = s + 1;
906     }
907 
908     switch (*string) {
909 
910     case '$':
911         wl = wl_cons(tprintf("%d", getpid()), NULL);
912         txfree(oldstring);
913         return wl;
914 
915     case '<':
916         (void) fflush(cp_out);
917         if (!fgets(buf, BSIZE_SP, cp_in)) {
918             clearerr(cp_in);
919             (void) strcpy(buf, "EOF");
920         }
921         for (s = buf; *s && (*s != '\n'); s++)
922             ;
923         *s = '\0';
924         wl = cp_lexer(buf);
925         /* This is a hack. */
926         if (!wl->wl_word)
927             wl->wl_word = copy("");
928         txfree(oldstring);
929         return wl;
930 
931     case '?':
932         string++;
933         for (v = variables; v; v = v->va_next)
934             if (eq(v->va_name, string))
935                 break;
936         if (!v) {
937             v = cp_enqvar(string, &tbfreed);
938             if (tbfreed) {
939                 vfree = v;
940             }
941         }
942         wl = wl_cons(copy(v ? "1" : "0"), NULL);
943         free_struct_variable(vfree);
944         txfree(oldstring);
945         return wl;
946 
947     case '#':
948         string++;
949         for (v = variables; v; v = v->va_next) {
950             if (eq(v->va_name, string)) {
951                 break;
952             }
953         }
954         if (!v) {
955             v = cp_enqvar(string, &tbfreed);
956             if (tbfreed) {
957                 vfree = v;
958             }
959         }
960         if (!v) {
961             fprintf(cp_err, "Error: %s: no such variable.\n", string);
962             txfree(oldstring);
963             return NULL;
964         }
965         if (v->va_type == CP_LIST) {
966             for (v = v->va_vlist, i = 0; v; v = v->va_next) {
967                 i++;
968             }
969         }
970         else {
971             i = (v->va_type != CP_BOOL);
972         }
973         wl = wl_cons(tprintf("%d", i), NULL);
974         txfree(oldstring);
975         free_struct_variable(vfree);
976         return wl;
977 
978     case '\0':
979         wl = wl_cons(copy("$"), NULL);
980         txfree(oldstring);
981         return wl;
982     }
983 
984     vfree = NULL; //just in case ...
985     /* The notation var[stuff] has two meanings...  If this is a real
986      * variable, then the [] denotes range, but if this is a strange
987      * (e.g, device parameter) variable, it could be anything...
988      */
989     for (v = variables; v; v = v->va_next)
990         if (eq(v->va_name, string))
991             break;
992     if (!v && isdigit_c(*string)) {
993         for (v = variables; v; v = v->va_next) {
994             if (eq(v->va_name, "argv")) {
995                 break;
996             }
997         }
998         range = string;
999     }
1000     if (!v) {
1001         range = NULL;
1002         string = oldstring;
1003         v = cp_enqvar(string, &tbfreed);
1004         if (tbfreed) {
1005             vfree = v;
1006         }
1007     }
1008     if (!v && (s = getenv(string)) != NULL) {
1009         wl = wl_cons(copy(s), NULL);
1010         tfree(oldstring);
1011         return (wl);
1012     }
1013     if (!v) {
1014         fprintf(cp_err, "Error: %s: no such variable.\n", string);
1015         txfree(oldstring);
1016         return NULL;
1017     }
1018     wl = cp_varwl(v);
1019     free_struct_variable(vfree);
1020 
1021     /* Now parse and deal with 'range' ... */
1022     if (range) {
1023         /* rather crude fix when range itself is a $expression */
1024         wordlist *r = NULL;
1025         if (*range == '$') {
1026             char *t = ++range;
1027             if (*t == '&') {
1028                 t++;
1029             }
1030             while (isalnum_c(*t)) {
1031                 t++;
1032             }
1033             *t = '\0';
1034             r = vareval(range);
1035             if (!r || r->wl_next) {
1036                 fprintf(cp_err, "Error: %s: illegal index.\n", string);
1037                 txfree(oldstring);
1038                 wl_free(r);
1039                 return NULL;
1040             }
1041             range = r->wl_word;
1042         }
1043         for (low = 0; isdigit_c(*range); range++) {
1044             low = low * 10 + *range - '0';
1045         }
1046         if ((*range == '-') && isdigit_c(range[1])) {
1047             for (up = 0, range++; isdigit_c(*range); range++) {
1048                 up = up * 10 + *range - '0';
1049             }
1050         }
1051         else if (*range == '-') {
1052             up = wl_length(wl);
1053         }
1054         else {
1055             up = low;
1056         }
1057         up--, low--;
1058         wl = wl_range(wl, low, up);
1059         wl_free(r);
1060     } /* end of case of range given for variable */
1061 
1062     txfree(oldstring);
1063     return (wl);
1064 }
1065 
1066 
1067 struct xxx {
1068     struct variable *x_v;
1069     char x_char;
1070 };
1071 
1072 
vcmp(const void * a,const void * b)1073 static int vcmp(const void *a, const void *b)
1074 {
1075     int i;
1076     struct xxx *v1 = (struct xxx *) a;
1077     struct xxx *v2 = (struct xxx *) b;
1078 
1079     if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)) != 0) {
1080         return i;
1081     }
1082     else {
1083         return v1->x_char - v2->x_char;
1084     }
1085 }
1086 
1087 
1088 /* Print the values of currently defined variables. */
cp_vprint(void)1089 void cp_vprint(void)
1090 {
1091     struct variable *v;
1092     struct variable *uv1;
1093     wordlist *wl;
1094     int i, j;
1095     char *s;
1096     struct xxx *vars;
1097 
1098     uv1 = cp_usrvars();
1099 
1100     for (v = variables, i = 0; v; v = v->va_next) {
1101         i++;
1102     }
1103     for (v = uv1; v; v = v->va_next) {
1104         i++;
1105     }
1106     if (plot_cur) {
1107         for (v = plot_cur->pl_env; v; v = v->va_next) {
1108             i++;
1109         }
1110     }
1111     if (ft_curckt) {
1112         for (v = ft_curckt->ci_vars; v; v = v->va_next) {
1113             i++;
1114         }
1115     }
1116 
1117     vars = TMALLOC(struct xxx, i);
1118 
1119     out_init();
1120     for (v = variables, i = 0; v; v = v->va_next, i++) {
1121         vars[i].x_v = v;
1122         vars[i].x_char = ' ';
1123     }
1124     for (v = uv1; v; v = v->va_next, i++) {
1125         vars[i].x_v = v;
1126         vars[i].x_char = '*';
1127     }
1128     if (plot_cur) {
1129         for (v = plot_cur->pl_env; v; v = v->va_next, i++) {
1130             vars[i].x_v = v;
1131             vars[i].x_char = '*';
1132         }
1133     }
1134     if (ft_curckt) {
1135         for (v = ft_curckt->ci_vars; v; v = v->va_next, i++) {
1136             vars[i].x_v = v;
1137             vars[i].x_char = '+';
1138         }
1139     }
1140 
1141     qsort(vars, (size_t) i, sizeof(*vars), vcmp);
1142 
1143     for (j = 0; j < i; j++) {
1144         if (j && eq(vars[j].x_v->va_name, vars[j-1].x_v->va_name)) {
1145             continue;
1146         }
1147         v = vars[j].x_v;
1148         if (v->va_type == CP_BOOL) {
1149             out_printf("%c %s\n", vars[j].x_char, v->va_name);
1150         }
1151         else {
1152             out_printf("%c %s\t", vars[j].x_char, v->va_name);
1153             wl = vareval(v->va_name);
1154             s = wl_flatten(wl);
1155             if (v->va_type == CP_LIST)
1156                 out_printf("( %s )\n", s);
1157             else
1158                 out_printf("%s\n", s);
1159         }
1160     }
1161 
1162     free_struct_variable(uv1);
1163     tfree(vars);
1164 } /* end of function cp_vprint */
1165 
1166 
1167 
var_alloc(char * name,struct variable * next)1168 struct variable *var_alloc(char *name, struct variable *next)
1169 {
1170     struct variable * const v = TMALLOC(struct variable, 1);
1171     ZERO(v, struct variable);
1172     v -> va_name = name;
1173     v -> va_next = next;
1174     return v;
1175 }
1176 
1177 
1178 
var_alloc_bool(char * name,bool value,struct variable * next)1179 struct variable *var_alloc_bool(char *name, bool value,
1180         struct variable *next)
1181 {
1182     struct variable *v = var_alloc(name, next);
1183     var_set_bool(v, value);
1184     return v;
1185 }
1186 
var_alloc_num(char * name,int value,struct variable * next)1187 struct variable *var_alloc_num(char *name, int value,
1188         struct variable *next)
1189 {
1190     struct variable *v = var_alloc(name, next);
1191     var_set_num(v, value);
1192     return v;
1193 }
1194 
var_alloc_real(char * name,double value,struct variable * next)1195 struct variable *var_alloc_real(char *name, double value,
1196         struct variable *next)
1197 {
1198     struct variable *v = var_alloc(name, next);
1199     var_set_real(v, value);
1200     return v;
1201 }
1202 
var_alloc_string(char * name,char * value,struct variable * next)1203 struct variable *var_alloc_string(char *name, char * value,
1204         struct variable *next)
1205 {
1206     struct variable *v = var_alloc(name, next);
1207     var_set_string(v, value);
1208     return v;
1209 }
1210 
var_alloc_vlist(char * name,struct variable * value,struct variable * next)1211 struct variable * var_alloc_vlist(char *name, struct variable * value,
1212         struct variable *next)
1213 {
1214     struct variable *v = var_alloc(name, next);
1215     var_set_vlist(v, value);
1216     return v;
1217 }
1218 
var_set_bool(struct variable * v,bool value)1219 void var_set_bool(struct variable *v, bool value)
1220 {
1221   v->va_type = CP_BOOL;
1222   v->va_bool = value;
1223 }
1224 
var_set_num(struct variable * v,int value)1225 void var_set_num(struct variable *v, int value)
1226 {
1227   v->va_type = CP_NUM;
1228   v->va_num = value;
1229 }
1230 
var_set_real(struct variable * v,double value)1231 void var_set_real(struct variable *v, double value)
1232 {
1233   v->va_type = CP_REAL;
1234   v->va_real = value;
1235 }
1236 
var_set_string(struct variable * v,char * value)1237 void var_set_string(struct variable *v, char *value)
1238 {
1239   v->va_type = CP_STRING;
1240   v->va_string = value;
1241 }
1242 
var_set_vlist(struct variable * v,struct variable * value)1243 void var_set_vlist(struct variable *v, struct variable *value)
1244 {
1245   v->va_type = CP_LIST;
1246   v->va_vlist = value;
1247 }
1248