1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California.  All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * The user-supplied routine to deal with variables. Most variables we
10  * don't use often, so just call cp_getvar when they are needed. Spice
11  * variables, though, and a few commonly used ones are dealt with here.
12  */
13 
14 #include "spice.h"
15 #include "ftedefs.h"
16 #include "fteinp.h"
17 
18 /* used by Josephson junction model,
19  * default max phase change is 2*PI/10
20  */
21 double JJdphi = 2.07e-16;
22 
23 bool ft_nopage = false;
24 bool ft_parsedb = false;
25 bool ft_vecdb = false;
26 bool ft_simdb = false;
27 bool ft_evdb = false;
28 bool ft_grdb = false;
29 bool ft_gidb = false;
30 bool ft_controldb = false;
31 bool ft_asyncdb = false;
32 
33 #ifdef __STDC__
34 static struct variable *vec2var(struct dvec*,int,int);
35 static struct variable *getlist(struct dvec*,int,char**);
36 #else
37 static struct variable *vec2var();
38 static struct variable *getlist();
39 #endif
40 
41 /* The following routines take care of managing internal variables.
42  * Some of the functionality was previously found in variable.c. Here,
43  * all variables are included in a single table below, many of which
44  * have dispatch functions.  This code should be much faster.
45  */
46 
47 /* These are the dispatch functions... */
48 
49 #define def_fn(name) \
50 static int name(v,flag) \
51 struct variable *v; \
52 bool flag;
53 
54 /* "shell" variables */
55 
def_fn(_iv_cpdebug)56 def_fn(_iv_cpdebug)
57 {
58     cp_debug = flag;
59 #ifndef CPDEBUG
60     if(flag)
61         fprintf(cp_err,
62         "Warning: program not compiled with cshpar debug messages\n");
63 #endif
64     return (US_OK);
65 }
66 
def_fn(_iv_history)67 def_fn(_iv_history)
68 {
69     if (!flag) return (US_OK);
70     if (v->va_type == VT_NUM)
71         cp_maxhistlength = v->va_num;
72     else if (v->va_type == VT_REAL)
73         cp_maxhistlength = v->va_real;
74     return (US_OK);
75 }
76 
def_fn(_iv_ignoreeof)77 def_fn(_iv_ignoreeof) {cp_ignoreeof=flag; return (US_OK);}
def_fn(_iv_noclobber)78 def_fn(_iv_noclobber) {cp_noclobber=flag; return (US_OK);}
def_fn(_iv_noglob)79 def_fn(_iv_noglob)    {cp_noglob=flag;    return (US_OK);}
def_fn(_iv_nonomatch)80 def_fn(_iv_nonomatch) {cp_nonomatch=flag; return (US_OK);}
81 
def_fn(_iv_prompt)82 def_fn(_iv_prompt)
83 {
84     if (!flag)
85         cp_promptstring = "";
86     else if (v->va_type == VT_STRING)
87         cp_promptstring = copy(v->va_string);
88     return (US_OK);
89 }
90 
91 
92 /* spice and nutmeg variables */
93 
94 static char *huhmsg = "Excuse me??\n";
95 static char *pltmsg = "Error: can't set plot";
96 
def_fn(_iv_acct)97 def_fn(_iv_acct)    {ft_acctprint=flag;  return (US_OK);}
98 
def_fn(_iv_curplot)99 def_fn(_iv_curplot)
100 {
101     if (v->va_type == VT_STRING)
102         plot_setcur(v->va_string);
103     else if (flag)
104         fprintf(cp_err, "Error: plot name not a string\n");
105     return (US_DONTRECORD);
106 }
107 
def_fn(_iv_curplotdate)108 def_fn(_iv_curplotdate)
109 {
110     if (plot_cur && (v->va_type == VT_STRING))
111         plot_cur->pl_date = copy(v->va_string);
112     else if (flag)
113         fprintf(cp_err,"%s %s\n",pltmsg,"date");
114     return (US_DONTRECORD);
115 }
116 
def_fn(_iv_curplotname)117 def_fn(_iv_curplotname)
118 {
119     if (plot_cur && (v->va_type == VT_STRING))
120         plot_cur->pl_name = copy(v->va_string);
121     else if (flag)
122         fprintf(cp_err,"%s %s\n",pltmsg,"name");
123     return (US_DONTRECORD);
124 }
125 
def_fn(_iv_curplottitle)126 def_fn(_iv_curplottitle)
127 {
128     if (plot_cur && (v->va_type == VT_STRING))
129         plot_cur->pl_title = copy(v->va_string);
130     else
131         fprintf(cp_err,"%s %s\n",pltmsg,"title");
132     return (US_DONTRECORD);
133 }
134 
135 static void
setdb(word)136 setdb(word)
137 
138 char *word;
139 {
140     if (eq(word,"async"))
141         ft_asyncdb = true;
142     else if (eq(word,"control"))
143         ft_controldb = true;
144     else if (eq(word,"cshpar"))
145         cp_debug = true;
146     else if (eq(word,"eval"))
147         ft_evdb = true;
148     else if (eq(word,"ginterface"))
149         ft_gidb = true;
150     else if (eq(word,"graf"))
151         ft_grdb = true;
152     else if (eq(word,"parser"))
153         ft_parsedb = true;
154     else if (eq(word,"siminterface"))
155         ft_simdb = true;
156     else if (eq(word,"vecdb"))
157         ft_vecdb = true;
158 }
159 
def_fn(_iv_debug)160 def_fn(_iv_debug)
161 {
162     struct variable *tv;
163     char *dbgmsg = "Error: bad type for debug var\n";
164 
165     if (v->va_type == VT_BOOL) {
166         cp_debug = ft_simdb = ft_parsedb = ft_evdb = ft_vecdb =
167             ft_grdb = ft_gidb = ft_controldb = flag;
168     }
169     else if (v->va_type == VT_LIST) {
170         for (tv = v->va_vlist; tv; tv = tv->va_next) {
171             if (v->va_type != VT_STRING)
172                 fprintf(cp_err,dbgmsg);
173             else
174                 setdb(tv->va_string);
175         }
176     }
177     else if (v->va_type == VT_STRING) {
178         setdb(v->va_string);
179     }
180     else if (flag)
181         fprintf(cp_err,dbgmsg);
182 #ifndef FTEDEBUG
183     if (flag)
184         fprintf(cp_err, "Warning: %s compiled without debug messages\n",
185         cp_program);
186 #endif
187     return (US_OK);
188 }
189 
def_fn(_iv_display)190 def_fn(_iv_display)  { return (US_READONLY);}
191 
def_fn(_iv_height)192 def_fn(_iv_height)
193 {
194     if ((v->va_type == VT_BOOL) && (flag == false))
195         out_height = 0;
196     else if (v->va_type == VT_REAL)
197         out_height = v->va_real;
198     else if (v->va_type == VT_NUM)
199         out_height = v->va_num;
200     else
201         fprintf(cp_err, "Bad 'height' \"%s\"\n", v->va_name);
202     return (US_OK);
203 }
204 
def_fn(_iv_jjdphimax)205 def_fn(_iv_jjdphimax)
206 {
207     if (flag == false)
208         JJdphi = 2.07e-16;
209     else if (v->va_type == VT_REAL) {
210         if (v->va_real < M_PI/50 || v->va_real > M_PI/2)
211             goto errm;
212         JJdphi = v->va_real*3.3e-16; /* phi0 /2*pi */
213     }
214     else if (v->va_type == VT_NUM) {
215         if (v->va_num < M_PI/50 || v->va_num > M_PI/2)
216             goto errm;
217         JJdphi = v->va_num*3.3e-16; /* phi0 /2*pi */
218     }
219     else
220         fprintf(cp_err,huhmsg);
221     return (US_OK);
222 errm:
223     fprintf(cp_err, "Error: must be between pi/50 and pi/2\n");
224     return (US_OK);
225 }
226 
def_fn(_iv_list)227 def_fn(_iv_list)       {ft_listprint=flag;  return (US_OK);}
def_fn(_iv_nocc)228 def_fn(_iv_nocc)       {cp_nocc=flag;       return (US_OK);}
def_fn(_iv_node)229 def_fn(_iv_node)       {ft_nodesprint=flag; return (US_OK);}
def_fn(_iv_noiter)230 def_fn(_iv_noiter)     {return (US_OK);}
def_fn(_iv_nomoremode)231 def_fn(_iv_nomoremode) {out_moremode=!flag; return (US_OK);}
def_fn(_iv_nopage)232 def_fn(_iv_nopage)     {ft_nopage=flag;     return (US_OK);}
233 
def_fn(_iv_numdgt)234 def_fn(_iv_numdgt)
235 {
236     if ((v->va_type == VT_BOOL) && (flag == false))
237         cp_numdgt = -1;
238     else if (v->va_type == VT_REAL)
239         cp_numdgt = v->va_real;
240     else if (v->va_type == VT_NUM)
241         cp_numdgt = v->va_num;
242     else
243         fprintf(cp_err,huhmsg);
244     return (US_OK);
245 }
246 
def_fn(_iv_opts)247 def_fn(_iv_opts)    {ft_optsprint=flag;  return (US_OK);}
def_fn(_iv_plots)248 def_fn(_iv_plots)   {return (US_READONLY);}
249 
def_fn(_iv_program)250 def_fn(_iv_program)
251 {
252     if (!flag)
253         cp_program = "";
254     else if (v->va_type == VT_STRING)
255         cp_program = copy(v->va_string);
256     return (US_OK);
257 }
258 
def_fn(_iv_rawfile)259 def_fn(_iv_rawfile)
260 {
261     if (!flag)
262         ft_rawfile = "";
263     else if (v->va_type == VT_STRING)
264         ft_rawfile = copy(v->va_string);
265     return (US_OK);
266 }
267 
def_fn(_iv_rawfileprec)268 def_fn(_iv_rawfileprec)
269 {
270     if ((v->va_type == VT_BOOL) && (flag == false))
271         raw_prec = -1;
272     else if (v->va_type == VT_REAL)
273         raw_prec = v->va_real;
274     else if (v->va_type == VT_NUM)
275         raw_prec = v->va_num;
276     else
277         fprintf(cp_err, "Bad 'rawfileprec' \"%s\"\n", v->va_name);
278     return (US_OK);
279 }
280 
def_fn(_iv_strictnumparse)281 def_fn(_iv_strictnumparse) {ft_strictnumparse=flag; return (US_OK);}
282 
def_fn(_iv_units)283 def_fn(_iv_units)
284 {
285     if (false && ((*v->va_string == 'd') ||
286             (*v->va_string == 'D')))
287         cx_degrees = true;
288     else
289         cx_degrees = false;
290     return (US_OK);
291 }
292 
def_fn(_iv_unixcom)293 def_fn(_iv_unixcom)
294 {
295     char *s;
296 
297     cp_dounixcom = flag;
298     if (flag) {
299         s = getenv("PATH");
300         if (s)
301             cp_rehash(s, !cp_nocc);
302         else
303             fprintf(cp_err,
304                 "Warning: no PATH in environment.\n");
305     }
306     else {
307         struct comm *c;
308         cp_ccrestart(false);
309         for (c = cp_coms; c->co_func; c++)
310             cp_addcomm(c->co_comname, c->co_cctypes[0],
311                 c->co_cctypes[1], c->co_cctypes[2],
312                 c->co_cctypes[3]);
313     }
314     return (US_OK);
315 }
316 
def_fn(_iv_width)317 def_fn(_iv_width)
318 {
319     if ((v->va_type == VT_BOOL) && (flag == false))
320         out_width = 0;
321     else if (v->va_type == VT_REAL)
322         out_width = v->va_real;
323     else if (v->va_type == VT_NUM)
324         out_width = v->va_num;
325     else
326         fprintf(cp_err, "Bad 'width' \"%s\"\n", v->va_name);
327     return (US_OK);
328 }
329 
330 
331 
332 /* The table below includes all variables with significance to the
333  * program.
334  */
335 char *kw_abstol           = "abstol";
336 char *kw_acct             = "acct";
337 char *kw_appendwrite      = "appendwrite";
338 char *kw_checkiterate     = "checkiterate";
339 char *kw_chgtol           = "chgtol";
340 char *kw_color            = "color";
341 char *kw_cpdebug          = "cpdebug";
342 char *kw_curplot          = "curplot";
343 char *kw_curplotname      = "curplotname";
344 char *kw_curplottitle     = "curplottitle";
345 char *kw_curplotdate      = "curplotdate";
346 char *kw_debug            = "debug";
347 char *kw_defad            = "defad";
348 char *kw_defas            = "defas";
349 char *kw_defl             = "defl";
350 char *kw_defw             = "defw";
351 char *kw_device           = "device";
352 char *kw_display          = "display";
353 char *kw_dontplot         = "dontplot";
354 char *kw_editor           = "editor";
355 char *kw_filetype         = "filetype";
356 char *kw_fourgridsize     = "fourgridsize";
357 char *kw_gmin             = "gmin";
358 char *kw_gridsize         = "gridsize";
359 char *kw_gridstyle        = "gridstyle";
360 char *kw_hcopydev         = "hcopydev";
361 char *kw_hcopydevtype     = "hcopydevtype";
362 char *kw_height           = "height";
363 char *kw_history          = "history";
364 char *kw_hitusertp        = "hitusertp";
365 char *kw_ignoreeof        = "ignoreeof";
366 char *kw_itl1             = "itl1";
367 char *kw_itl2             = "itl2";
368 char *kw_itl3             = "itl3";
369 char *kw_itl4             = "itl4";
370 char *kw_itl5             = "itl5";
371 char *kw_jjdphimax        = "jjdphimax";
372 char *kw_level            = "level";
373 char *kw_list             = "list";
374 char *kw_maxwins          = "maxwins";
375 char *kw_modelcard        = "modelcard";
376 char *kw_mplot_cur        = "mplot_cur";
377 char *kw_nfreqs           = "nfreqs";
378 char *kw_noasciiplotvalue = "noasciiplotvalue";
379 char *kw_noaskquit        = "noaskquit";
380 char *kw_nobjthack        = "nobjthack";
381 char *kw_nobreak          = "nobreak";
382 char *kw_nocc             = "nocc";
383 char *kw_noclobber        = "noclobber";
384 char *kw_node             = "node";
385 char *kw_noglob           = "noglob";
386 char *kw_nogrid           = "nogrid";
387 char *kw_noiter           = "noiter";
388 char *kw_nojjtp           = "nojjtp";
389 char *kw_nomoremode       = "nomoremode";
390 char *kw_nonomatch        = "nonomatch";
391 char *kw_nopage           = "nopage";
392 char *kw_noparse          = "noparse";
393 char *kw_noprintscale     = "noprintscale";
394 char *kw_nosort           = "nosort";
395 char *kw_nosubckt         = "nosubckt";
396 char *kw_nousertp         = "nousertp";
397 char *kw_numdgt           = "numdgt";
398 char *kw_opts             = "opts";
399 char *kw_pivrel           = "pivrel";
400 char *kw_pivtol           = "pivtol";
401 char *kw_plots            = "plots";
402 char *kw_plotstyle        = "plotstyle";
403 char *kw_pointchars       = "pointchars";
404 char *kw_polydegree       = "polydegree";
405 char *kw_polysteps        = "polysteps";
406 char *kw_printinfo        = "printinfo";
407 char *kw_program          = "program";
408 char *kw_prompt           = "prompt";
409 char *kw_rawfile          = "rawfile";
410 char *kw_rawfileprec      = "rawfileprec";
411 char *kw_reltol           = "reltol";
412 char *kw_renumber         = "renumber";
413 char *kw_rhost            = "rhost";
414 char *kw_rprogram         = "rprogram";
415 char *kw_scedfont         = "scedfont";
416 char *kw_slowplot         = "slowplot";
417 char *kw_sourcepath       = "sourcepath";
418 char *kw_spicepath        = "spicepath";
419 char *kw_strictnumparse   = "strictnumparse";
420 char *kw_subend           = "subend";
421 char *kw_subinvoke        = "subinvoke";
422 char *kw_substart         = "substart";
423 char *kw_term             = "term";
424 char *kw_ticmarks         = "ticmarks";
425 char *kw_tnom             = "tnom";
426 char *kw_trtol            = "trtol";
427 char *kw_units            = "units";
428 char *kw_unixcom          = "unixcom";
429 char *kw_vntol            = "vntol";
430 char *kw_width            = "width";
431 char *kw_wpboxh           = "wpboxh";
432 char *kw_wpboxw           = "wpboxw";
433 char *kw_xglinewidth      = "xglinewidth";
434 char *kw_xgmarkers        = "xgmarkers";
435 char *kw_xfont            = "xfont";
436 
437 
438 struct intvar {
439     char **name;
440     char *descr;
441 #ifdef __STDC__
442     int (*func)(struct variable*,bool);
443 #else
444     int (*func)();
445 #endif
446 };
447 static struct intvar int_vars[] = {
448 {&kw_abstol, "real   Absolute error tolerance, default 1e-12.", NULL},
449 {&kw_acct, "bool   Print accounting summary.", _iv_acct},
450 {&kw_appendwrite, "bool   Append to file with write command, no overwrite.", NULL},
451 {&kw_checkiterate,"int    Binary search iterations in range analysis.", NULL},
452 {&kw_chgtol,"real   Charge tolerance, default 1e-14.", NULL},
453 {&kw_color, "list   X window colors, see help.", NULL},
454 {&kw_cpdebug, "bool   Enable command processor debugging.", _iv_cpdebug},
455 {&kw_curplot, "str    Current plot.", _iv_curplot},
456 {&kw_curplotname, "str    Current plot name, read only.", _iv_curplotname},
457 {&kw_curplottitle, "str    Current plot title, read only.", _iv_curplottitle},
458 {&kw_curplotdate, "str    Current plot date, read only", _iv_curplotdate},
459 {&kw_debug, "list   Enable debugging, see help for keywords.", _iv_debug},
460 {&kw_defad, "real   MOS drain diffusion area, default 0.", NULL},
461 {&kw_defas, "real   MOS source diffusion area, defalut 0", NULL},
462 {&kw_defl, "real   MOS channel length, default 100 microns.", NULL},
463 {&kw_defw, "real   MOS channel width, default 100 microns.", NULL},
464 {&kw_device, "str    UNIX /dev/tty?? device for output.", NULL},
465 {&kw_display, "str    X uses this display, read only.", _iv_display},
466 {&kw_dontplot, "bool   Don't send graphics code to output device.", NULL},
467 {&kw_editor, "str    Editor invocation string.", NULL},
468 {&kw_filetype, "str    Rawfile type: ascii or binary.", NULL},
469 {&kw_fourgridsize, "int    Number of interpolation points in fourier analysis.", NULL},
470 {&kw_gmin, "real   Minimum conductance allowed, default 1e-12.", NULL},
471 {&kw_gridsize, "real   Number of y-axis grid lines.", NULL},
472 {&kw_gridstyle, "str    Plot default grid type (lingrid, loglog, nogrid, \n\t\t   xlog, ylog, polar, smith).", NULL},
473 {&kw_hcopydev, "str    UNIX: send hardcopy using LPR -P??. DOS: prn,lpt?.", NULL},
474 {&kw_hcopydevtype, "str    Hardcopy device type: postscript, etc.", NULL},
475 {&kw_height, "real   Screen height in characters.", _iv_height},
476 {&kw_history, "int    Number of remembered commands, default 1000.", _iv_history},
477 {&kw_hitusertp, "bool   Force transient analysis at user time points.", NULL},
478 {&kw_ignoreeof,"bool   Ignore end of file (^D) in UNIX.", _iv_ignoreeof},
479 {&kw_itl1, "int    DC iteration limit, default 100.", NULL},
480 {&kw_itl2, "int    DC transfer curve iteration limit, default 50", NULL},
481 {&kw_itl3, "int    Lower transient iteration limit, default 4.", NULL},
482 {&kw_itl4, "int    Upper transient iteration limit, default 10.", NULL},
483 {&kw_itl5, "int    Unused.", NULL},
484 {&kw_jjdphimax, "real   Max Josephson phase delta per step, default pi/10.", _iv_jjdphimax},
485 {&kw_level, "str    Level for newhelp, (b, i, or a).", NULL},
486 {&kw_list, "bool   Causes the input to be listed.", _iv_list},
487 {&kw_maxwins, "int    Maximum number of windows in X.", NULL},
488 {&kw_modelcard, "str    Name of model card, default .model.", NULL},
489 {&kw_mplot_cur, "str    Name of current output file for check command", NULL},
490 {&kw_nfreqs, "int    Number of frequencies in fourier command, default 10.", NULL},
491 {&kw_noasciiplotvalue, "bool   Don't print scale value in asciiplot.", NULL},
492 {&kw_noaskquit, "bool   Don't verify before termination.", NULL},
493 {&kw_nobjthack, "bool   Assume BJT's have 4 nodes.", NULL},
494 {&kw_nobreak, "bool   No break between pages in asciiplot.", NULL},
495 {&kw_nocc, "bool   No command completion.", _iv_nocc},
496 {&kw_noclobber, "bool   Don't overwrite files when redirecting output.", _iv_noclobber},
497 {&kw_node, "bool   Print node table.", _iv_node},
498 {&kw_noglob, "bool   Don't expand wildcard characters.", _iv_noglob},
499 {&kw_nogrid, "bool   Don't plot a grid.", NULL},
500 {&kw_noiter, "bool   No transient iterations past predictor.", _iv_noiter},
501 {&kw_nojjtp, "bool   No Josephson phase change timestep, use trunc error.", NULL},
502 {&kw_nomoremode, "bool   Turn off more mode.", _iv_nomoremode},
503 {&kw_nonomatch, "bool   Use wildcard characters literally if no match.", _iv_nonomatch},
504 {&kw_nopage, "bool   Supress page ejects.", _iv_nopage},
505 {&kw_noparse, "bool   Don't parse circuit.", NULL},
506 {&kw_noprintscale, "bool   Don't print scale in print command.", NULL},
507 {&kw_nosort, "bool   Supress sorting of variable names.", NULL},
508 {&kw_nosubckt, "bool   No subcircuit expansion.", NULL},
509 {&kw_nousertp, "bool   Save raw time point values in transient analysis.", NULL},
510 {&kw_numdgt, "int    Number of significant digits to print, default 4.", _iv_numdgt},
511 {&kw_opts, "bool   Print options.", _iv_opts},
512 {&kw_pivrel, "real   Relative pivot value, default 1e-3.", NULL},
513 {&kw_pivtol, "real   Minimum pivot value, default 1e-13.", NULL},
514 {&kw_plots, "list   Read only, list of plots.", _iv_plots},
515 {&kw_plotstyle, "str    Default plot type (linplot, combplot, pointplot).", NULL},
516 {&kw_pointchars, "str    Point characters for plotting.", NULL},
517 {&kw_polydegree, "int    Degree of interpolating polynomial.", NULL},
518 {&kw_polysteps, "int    Number of interpolating points, default 10.", NULL},
519 {&kw_printinfo, "bool   Print debugging info when plot starts.", NULL},
520 {&kw_program, "str    Program name.", _iv_program},
521 {&kw_prompt, "str    Prompt string.", _iv_prompt},
522 {&kw_rawfile, "str    Rawfile path.", _iv_rawfile},
523 {&kw_rawfileprec, "int    Significant digits in rawfile.", _iv_rawfileprec},
524 {&kw_reltol, "real   Relative error tolerance, default 1e-3.", NULL},
525 {&kw_renumber, "bool   Renumber source lines after subcircuit expansion.", NULL},
526 {&kw_rhost, "str    Remote host name, for UNIX remote simulations.", NULL},
527 {&kw_rprogram, "str    Remote simulation program name, for UNIX.", NULL},
528 {&kw_scedfont, "str    Name of X font used in SCED.", NULL},
529 {&kw_slowplot, "bool   Wait for input between plots.", NULL},
530 {&kw_sourcepath, "str    Path to search for source command.", NULL},
531 {&kw_spicepath, "str    Path to use in aspice command.", NULL},
532 {&kw_strictnumparse, "bool   Don't allow trailing characters after number.", _iv_strictnumparse},
533 {&kw_subend, "str    End subcircuits, default .ends.", NULL},
534 {&kw_subinvoke, "str    Prefix to invoke subcircuits, default x.", NULL},
535 {&kw_substart, "str    Start subcircuit definition, default .subckt.", NULL},
536 {&kw_term, "str    Name of current terminal, for MFB.", NULL},
537 {&kw_ticmarks, "bool   Plot tic marks, if int, set tic mark separation.", NULL},
538 {&kw_tnom, "real   Nominal temperature, default 27C.", NULL},
539 {&kw_trtol, "real   Truncation error tolerance, default 7.", NULL},
540 {&kw_units, "str    If \"degrees\", trig functions don't use radians.", _iv_units},
541 {&kw_unixcom, "bool   Execute operating system commands.", _iv_unixcom},
542 {&kw_vntol, "real   Voltage error tolerance, default 1e-6.", NULL},
543 {&kw_width, "int    Width of screen in characters.", _iv_width},
544 {&kw_wpboxh, "real   Graphics box height for WordPerfect plot, (4\").", NULL},
545 {&kw_wpboxw, "real   Graphics box width for WordPerfect plot (4\").", NULL},
546 {&kw_xglinewidth, "int    Pixel linewidth used in xgraph, default 1.", NULL},
547 {&kw_xgmarkers, "bool   Use markers in xgraph pointplot, else big pixels.", NULL},
548 {&kw_xfont, "str    Name of X font for graphics, default \"fixed\".", NULL}
549 } ;
550 
551 
552 static void *internalvars; /* hash table for dispatch functions */
553 
554 void
cp_internal_init()555 cp_internal_init()
556 
557 /* This has to be called before anything, it sets up the hash table */
558 {
559     int i;
560 
561     if (internalvars == NULL)
562         internalvars = htab_init();
563     for (i = 0; i < sizeof(int_vars)/sizeof(struct intvar); i++) {
564         if (int_vars[i].func) {
565             htab_add(*(int_vars[i].name),(void*)&int_vars[i],internalvars);
566             cp_addkword(CT_VARIABLES, *(int_vars[i].name));
567         }
568     }
569 }
570 
571 
572 void
com_usrset(wl)573 com_usrset(wl)
574 
575 /* print a listing of option keywords and descriptions */
576 wordlist *wl;
577 {
578     int i;
579 
580     out_init();
581     if (wl == NULL) {
582         for (i = 0; i < sizeof(int_vars)/sizeof(struct intvar); i++) {
583             out_printf("%-18s %s\n",*(int_vars[i].name),int_vars[i].descr);
584         }
585         return;
586     }
587     while (wl) {
588         for (i = 0; i < sizeof(int_vars)/sizeof(struct intvar); i++) {
589             if (eq(wl->wl_word,*(int_vars[i].name))) {
590                 out_printf("%-18s %s\n",*(int_vars[i].name),int_vars[i].descr);
591                 break;
592             }
593         }
594         if (i == sizeof(int_vars)/sizeof(struct intvar))
595             out_printf("%-18s %s\n",wl->wl_word,"not an internal variable");
596         wl = wl->wl_next;
597     }
598 }
599 
600 
601 int
cp_internalset(v,flag)602 cp_internalset(v,flag)
603 
604 /* The one variable that we consider read-only so far is plots.  The ones
605  * that are 'dontrecord' are curplottitle, curplotname, and curplotdate.
606  * Also things already in the plot env are 'dontrecord'.
607  */
608 struct variable *v;
609 bool flag;
610 {
611     struct intvar *x;
612     struct variable *tv;
613     int i;
614     char val[BSIZE_SP];
615     char *vv;
616     bool bv;
617     double dv;
618     int iv;
619 
620     x = (struct intvar *)htab_get(v->va_name,internalvars);
621     if (x)
622         i = (*x->func)(v,flag);
623     else
624         return (US_OK);
625 
626     if (i != US_OK)
627         return (i);
628 
629     if (plot_cur)
630         for (tv = plot_cur->pl_env; tv; tv = tv->va_next)
631             if (eq(tv->va_name, v->va_name))
632                 return (US_READONLY);
633 
634     if (!flag || ft_nutmeg)
635         return (US_OK);
636 
637     /* Now call the interface option routine. */
638     switch (v->va_type) {
639         case VT_BOOL:
640             if (v->va_bool) {
641                 val[0] = '\0';
642                 bv = true;
643                 vv = (char *) &bv;
644                 break;
645             }
646             else {
647                 bv = false;
648                 vv = (char *) &bv;
649             }
650         case VT_STRING:
651             (void) strcpy(val, v->va_string);
652             vv = val;
653             break;
654         case VT_NUM:
655             (void) sprintf(val, "%d", v->va_num);
656             iv = v->va_num;
657             vv = (char *) &iv;
658             break;
659         case VT_REAL:
660             (void) strcpy(val, printnum(v->va_real));
661             dv = v->va_real;
662             vv = (char *) &dv;
663             break;
664         case VT_LIST:
665             /* if_option can't handle lists anyway. */
666             break;
667         default:
668             fprintf(cp_err,
669             "cp_usrset: Internal Error: Bad var type %d\n",
670                     v->va_type);
671     }
672 
673     if (ft_curckt)
674         if_option(ft_curckt->ci_ckt, v->va_name, v->va_type, vv);
675 
676     return (US_OK);
677 }
678 
679 
680 /* The user-supplied routine to query the values of variables. This
681  * recognises the $&varname notation, and also searches the values of
682  * plot and circuit environment variables.
683  * This function now accepts a range extension for $& variables.
684  * It will also evaluate vector expressions encased in ( ).
685  */
686 
687 struct variable *
cp_enqvar(word)688 cp_enqvar(word)
689 
690 char *word;
691 {
692     struct dvec *d;
693     struct variable *vv = NULL, *tv;
694     struct plot *pl;
695     int i;
696     char **x;
697     char *range, *r;
698     char *tt = NULL;
699     int low, up;
700 
701     if (*word == '&') {
702         word++;
703 
704         low = 0;
705         up = -1;
706 
707         if (*word == '(') {
708             /* an expression */
709             tt = strrchr(word,')');
710             if (tt == NULL) {
711                 fprintf(cp_err,"Error: closing ')' not found.\n");
712                 return (NULL);
713             }
714             r = range = strchr(tt,'[');
715         }
716         else
717             r = range = strchr(word,'[');
718 
719         if (r) {
720             *r = '\0';
721             r++;
722             if (!isdigit(*r) && *r != '-')
723                 fprintf(cp_err,
724                     "Warning: nonparseable range specified, %s[%s\n",
725                     word,r);
726             for (low = 0; isdigit(*r); r++)
727                 low = low * 10 + *r - '0';
728             if ((*r == '-') && isdigit(r[1]))
729                 for (up = 0, r++; isdigit(*r); r++)
730                     up = up * 10 + *r - '0';
731             else if (*r != '-')
732                 up = low;
733         }
734         if (tt) {
735             /* evaluate the expression */
736             wordlist wl;
737             struct pnode *pn;
738 
739             wl.wl_word = word;
740             wl.wl_next = wl.wl_prev = NULL;
741             pn = ft_getpnames(&wl,true);
742             if (pn == NULL) {
743                 fprintf(cp_err,"Error: parse failed.\n");
744                 return (NULL);
745             }
746             d = ft_evaluate(pn);
747             inp_pnfree(pn);
748         }
749         else
750             d = vec_get(word);
751 
752         if (d) {
753             if (d->v_link2) {
754                 fprintf(cp_err,
755     "Warning: only one vector may be accessed with the $& notation.\n");
756                 d = d->v_link2->dl_dvec;
757             }
758             if (d->v_numdims <= 1) {
759                 d->v_numdims = 1;
760                 d->v_dims[0] = d->v_length;
761             }
762             if (up == -1)
763                 up = d->v_dims[0] - 1;
764             vv = vec2var(d,low,up);
765         }
766         if (range)
767             *range = '[';
768         return (vv);
769     }
770     if (eq(word, kw_display)) {
771         vv = alloc(struct variable);
772         vv->va_name = copy(word);
773         vv->va_type = VT_STRING;
774         vv->va_string = copy(cp_display);
775         return (vv);
776     }
777     if (plot_cur) {
778         for (vv = plot_cur->pl_env; vv; vv = vv->va_next)
779             if (eq(vv->va_name, word))
780                 break;
781         if (vv)
782             vv =  var_copy(vv);
783         else if (eq(word, kw_curplotname)) {
784             vv = alloc(struct variable);
785             vv->va_name = copy(word);
786             vv->va_type = VT_STRING;
787             vv->va_string = copy(plot_cur->pl_name);
788         }
789         else if (eq(word, kw_curplottitle)) {
790             vv = alloc(struct variable);
791             vv->va_name = copy(word);
792             vv->va_type = VT_STRING;
793             vv->va_string = copy(plot_cur->pl_title);
794         }
795         else if (eq(word, kw_curplotdate)) {
796             vv = alloc(struct variable);
797             vv->va_name = copy(word);
798             vv->va_type = VT_STRING;
799             vv->va_string = copy(plot_cur->pl_date);
800         }
801         else if (eq(word, kw_curplot)) {
802             vv = alloc(struct variable);
803             vv->va_name = copy(word);
804             vv->va_type = VT_STRING;
805             vv->va_string = copy(plot_cur->pl_typename);
806         }
807         else if (eq(word, kw_plots)) {
808             vv = alloc(struct variable);
809             vv->va_name = copy(word);
810             vv->va_type = VT_LIST;
811             for (pl = plot_list; pl; pl = pl->pl_next) {
812                 tv = alloc(struct variable);
813                 tv->va_type = VT_STRING;
814                 tv->va_string = copy(pl->pl_typename);
815                 tv->va_next = vv->va_vlist;
816                 vv->va_vlist = tv;
817             }
818         }
819         if (vv)
820             return (vv);
821     }
822     if (ft_curckt) {
823         for (vv = ft_curckt->ci_vars; vv; vv = vv->va_next)
824             if (eq(vv->va_name, word))
825                 break;
826         if (vv)
827             return var_copy(vv);
828     }
829     return (NULL);
830 }
831 
832 
833 static struct variable *
vec2var(d,lo,hi)834 vec2var(d,lo,hi)
835 
836 struct dvec *d;
837 int lo, hi;
838 {
839     int i, sz, sn;
840     struct variable *vv, *tv = NULL;
841     char *x;
842 
843     sn = ((hi < lo) ? -1 : 1);
844     sz = d->v_length/d->v_dims[0];
845 
846     for (i = lo; ((sn == 1) ? (i <= hi) : (i >= hi)); i += sn) {
847         if (i >= d->v_dims[0])
848             continue;
849         if (!tv)
850             tv = vv = alloc(struct variable);
851         else {
852             vv->va_next = alloc(struct variable);
853             vv = vv->va_next;
854         }
855         if (d->v_numdims == 1) {
856             if (isreal(d))
857                 vv->va_real = d->v_realdata[i];
858             else
859                 vv->va_real = realpart(&d->v_compdata[i]);
860             vv->va_type = VT_REAL;
861         }
862         else {
863             if (isreal(d))
864                 x = (char*)&d->v_realdata[i*sz];
865             else
866                 x = (char*)&d->v_compdata[i*sz];
867             vv->va_type = VT_LIST;
868             vv->va_vlist = getlist(d,1,&x);
869         }
870     }
871     if (tv) {
872         if (lo == hi)
873             return (tv);
874         vv = alloc(struct variable);
875         vv->va_type = VT_LIST;
876         vv->va_vlist = tv;
877         return (vv);
878     }
879     return (NULL);
880 }
881 
882 
883 static struct variable *
getlist(d,dim,x)884 getlist(d,dim,x)
885 
886 struct dvec *d;
887 int dim;
888 char **x;
889 {
890     struct variable *vv, *tv = NULL;
891     int i;
892 
893     for (i = d->v_dims[dim] - 1; i >= 0; i--) {
894         if (!tv)
895             tv = vv = alloc(struct variable);
896         else {
897             vv->va_next = alloc(struct variable);
898             vv = vv->va_next;
899         }
900         if (dim == d->v_numdims-1) {
901             if (isreal(d)) {
902                 vv->va_real = *(*(double**)x);
903                 *x += sizeof(double);
904             }
905             else {
906                 vv->va_real = (*(complex**)x)->cx_real;
907                 *x += sizeof(complex);
908             }
909             vv->va_type = VT_REAL;
910         }
911         else {
912             vv->va_vlist = getlist(d,dim+1,x);
913             vv->va_type = VT_LIST;
914         }
915     }
916     return (tv);
917 }
918 
919 
920 /* Return the plot and ckt env vars, $plots, and $curplot{name,title,date,} */
921 
922 void
cp_usrvars(v1,v2)923 cp_usrvars(v1, v2)
924 
925 struct variable **v1, **v2;
926 {
927     struct variable *v, *tv;
928 
929     if (plot_cur)
930         v =  var_copy(plot_cur->pl_env);
931     else
932         v = NULL;
933     if (tv = cp_enqvar(kw_plots)) {
934         tv->va_next = v;
935         v = tv;
936     }
937     if (tv = cp_enqvar(kw_curplot)) {
938         tv->va_next = v;
939         v = tv;
940     }
941     if (tv = cp_enqvar(kw_curplottitle)) {
942         tv->va_next = v;
943         v = tv;
944     }
945     if (tv = cp_enqvar(kw_curplotname)) {
946         tv->va_next = v;
947         v = tv;
948     }
949     if (tv = cp_enqvar(kw_curplotdate)) {
950         tv->va_next = v;
951         v = tv;
952     }
953     if (tv = cp_enqvar(kw_display)) {
954         tv->va_next = v;
955         v = tv;
956     }
957     *v1 = v;
958     if (ft_curckt)
959         *v2 = var_copy(ft_curckt->ci_vars);
960     else
961         *v2 = NULL;
962     return;
963 }
964 
965 
966 /* Extract the .option cards from the deck... */
967 
968 struct line *
inp_getopts(deck)969 inp_getopts(deck)
970 
971 struct line *deck;
972 {
973     struct line *last, *opts = NULL, *dd, *next;
974 
975     last = deck;
976     for (dd = deck->li_next; dd; dd = next) {
977         next = dd->li_next;
978 
979         if (ciprefix(".opt", dd->li_line)) {
980             inp_casefix(dd->li_line);
981             last->li_next = next;
982             dd->li_next = opts;
983             opts = dd;
984             continue;
985         }
986         last = dd;
987     }
988 
989     return (opts);
990 }
991