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