* src/frontend/com_ahelp.c src/frontend/com_ahelp.h

src/frontend/com_cdump.c src/frontend/com_cdump.h
	src/frontend/com_ghelp.c src/frontend/com_ghelp.h
	src/frontend/com_help.c src/frontend/com_help.h
	src/frontend/com_history.c src/frontend/com_history.h
	src/frontend/com_set.c src/frontend/com_shift.c
	src/frontend/com_strcmp.c src/frontend/com_strcmp.h
	src/frontend/com_unset.c src/frontend/control.c
	src/frontend/control.h src/frontend/ftehelp.h
	src/frontend/hcomp.c src/frontend/hcomp.h src/frontend/init.c
	src/frontend/init.h src/frontend/terminal.c
	src/frontend/terminal.h src/frontend/variable.c
	src/frontend/variable.h: New additions from the refactoring of
	the parser directory.
This commit is contained in:
arno 2000-06-27 16:15:43 +00:00
parent 489fc66afd
commit 839ade8236
26 changed files with 3189 additions and 0 deletions

88
src/frontend/com_ahelp.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdlib.h>
#include <bool.h>
#include <wordlist.h>
#include <fteext.h>
#include "variable.h"
#include "com_help.h"
#include "hcomp.h"
#include "ftehelp.h"
#include "plotting/plotting.h"
void
com_ahelp(wordlist *wl)
{
int i, n;
/* assert: number of commands must be less than 512 */
struct comm *cc[512];
int env = 0;
struct comm *com;
int level;
char slevel[256];
if (wl) {
com_help(wl);
return;
}
out_init();
/* determine environment */
if (plot_list->pl_next) { /* plots load */
env |= E_HASPLOTS;
} else {
env |= E_NOPLOTS;
}
/* determine level */
if (cp_getvar("level", VT_STRING, slevel)) {
switch (*slevel) {
case 'b': level = 1;
break;
case 'i': level = 2;
break;
case 'a': level = 4;
break;
default: level = 1;
break;
}
} else {
level = 1;
}
out_printf(
"For a complete description read the Spice3 User's Manual manual.\n");
out_printf(
"For a list of all commands type \"help all\", for a short\n");
out_printf(
"description of \"command\", type \"help command\".\n");
/* sort the commands */
for (n = 0; cp_coms[n].co_func != (void (*)()) NULL; n++) {
cc[n] = &cp_coms[n];
}
qsort((char *) cc, n, sizeof(struct comm *), hcomp);
/* filter the commands */
for (i=0; i< n; i++) {
com = cc[i];
if ((com->co_env < (level << 13)) && (!(com->co_env & 4095) ||
(env & com->co_env))) {
if ((com->co_spiceonly && ft_nutmeg) ||
(com->co_help == (char *) NULL)) {
continue;
}
out_printf("%s ", com->co_comname);
out_printf(com->co_help, cp_program);
out_send("\n");
}
}
out_send("\n");
return;
}

7
src/frontend/com_ahelp.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _COM_AHELP_H
#define _COM_AHELP_H
void com_ahelp(wordlist *wl);
#endif

140
src/frontend/com_cdump.c Normal file
View File

@ -0,0 +1,140 @@
#include <stdio.h>
#include <wordlist.h>
#include "control.h"
#include "streams.h"
static int indent;
static void
tab(int num)
{
int i;
for (i = 0; i < num; i++)
putc(' ', cp_out);
}
static void
dodump(struct control *cc)
{
struct control *tc;
switch (cc->co_type) {
case CO_UNFILLED:
tab(indent);
fprintf(cp_out, "(unfilled)\n");
break;
case CO_STATEMENT:
tab(indent);
wl_print(cc->co_text, cp_out);
putc('\n', cp_out);
break;
case CO_WHILE:
tab(indent);
fprintf(cp_out, "while ");
wl_print(cc->co_cond, cp_out);
putc('\n', cp_out);
indent += 8;
for (tc = cc->co_children; tc; tc = tc->co_next)
dodump(tc);
indent -= 8;
tab(indent);
fprintf(cp_out, "end\n");
break;
case CO_REPEAT:
tab(indent);
fprintf(cp_out, "repeat ");
if (cc->co_numtimes != -1)
fprintf(cp_out, "%d\n", cc->co_numtimes);
else
putc('\n', cp_out);
indent += 8;
for (tc = cc->co_children; tc; tc = tc->co_next)
dodump(tc);
indent -= 8;
tab(indent);
fprintf(cp_out, "end\n");
break;
case CO_DOWHILE:
tab(indent);
fprintf(cp_out, "dowhile ");
wl_print(cc->co_cond, cp_out);
putc('\n', cp_out);
indent += 8;
for (tc = cc->co_children; tc; tc = tc->co_next)
dodump(tc);
indent -= 8;
tab(indent);
fprintf(cp_out, "end\n");
break;
case CO_IF:
tab(indent);
fprintf(cp_out, "if ");
wl_print(cc->co_cond, cp_out);
putc('\n', cp_out);
indent += 8;
for (tc = cc->co_children; tc; tc = tc->co_next)
dodump(tc);
indent -= 8;
tab(indent);
fprintf(cp_out, "end\n");
break;
case CO_FOREACH:
tab(indent);
fprintf(cp_out, "foreach %s ", cc->co_foreachvar);
wl_print(cc->co_text, cp_out);
putc('\n', cp_out);
indent += 8;
for (tc = cc->co_children; tc; tc = tc->co_next)
dodump(tc);
indent -= 8;
tab(indent);
fprintf(cp_out, "end\n");
break;
case CO_BREAK:
tab(indent);
if (cc->co_numtimes != 1)
fprintf(cp_out, "break %d\n", cc->co_numtimes);
else
fprintf(cp_out, "break\n");
break;
case CO_CONTINUE:
tab(indent);
if (cc->co_numtimes != 1)
fprintf(cp_out, "continue %d\n",
cc->co_numtimes);
else
fprintf(cp_out, "continue\n");
break;
case CO_LABEL:
tab(indent);
fprintf(cp_out, "label %s\n", cc->co_text->wl_word);
break;
case CO_GOTO:
tab(indent);
fprintf(cp_out, "goto %s\n", cc->co_text->wl_word);
break;
default:
tab(indent);
fprintf(cp_out, "bad type %d\n", cc->co_type);
break;
}
return;
}
void
com_cdump(wordlist *wl)
{
struct control *c;
indent = 0;
for (c = control[stackp]; c; c = c->co_next)
dodump(c);
return;
}

6
src/frontend/com_cdump.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _COM_CDUMP_H
#define _COM_CDUMP_H
void com_cdump(wordlist *wl);
#endif

69
src/frontend/com_ghelp.c Normal file
View File

@ -0,0 +1,69 @@
#include <ngspice.h>
#include <wordlist.h>
#include <bool.h>
#include <variable.h>
#include <hlpdefs.h>
#include "com_ghelp.h"
#include "com_help.h"
#include "variable.h"
#include "streams.h"
void
com_ghelp(wordlist *wl)
{
char *npath;
char *path = Help_Path;
char buf[BSIZE_SP];
int i;
if (cp_getvar("helppath", VT_STRING, buf))
path = copy(buf);
if (!path) {
fprintf(cp_err, "Note: defaulting to old help.\n\n");
com_help(wl);
return;
}
if (!(npath = cp_tildexpand(path))) {
fprintf(cp_err, "Note: can't find help dir %s\n", path);
fprintf(cp_err, "Defaulting to old help.\n\n");
com_help(wl);
return;
}
path = npath;
if (cp_getvar("helpregfont", VT_STRING, buf))
hlp_regfontname = copy(buf);
if (cp_getvar("helpboldfont", VT_STRING, buf))
hlp_boldfontname = copy(buf);
if (cp_getvar("helpitalicfont", VT_STRING, buf))
hlp_italicfontname = copy(buf);
if (cp_getvar("helptitlefont", VT_STRING, buf))
hlp_titlefontname = copy(buf);
if (cp_getvar("helpbuttonfont", VT_STRING, buf))
hlp_buttonfontname = copy(buf);
if (cp_getvar("helpinitxpos", VT_NUM, (char *) &i))
hlp_initxpos = i;
if (cp_getvar("helpinitypos", VT_NUM, (char *) &i))
hlp_initypos = i;
if (cp_getvar("helpbuttonstyle", VT_STRING, buf)) {
if (cieq(buf, "left"))
hlp_buttonstyle = BS_LEFT;
else if (cieq(buf, "center"))
hlp_buttonstyle = BS_CENTER;
else if (cieq(buf, "unif"))
hlp_buttonstyle = BS_UNIF;
else
fprintf(cp_err, "Warning: no such button style %s\n",
buf);
}
if (cp_getvar("width", VT_NUM, (char *) &i))
hlp_width = i;
if (cp_getvar("display", VT_STRING, buf))
hlp_displayname = copy(buf);
else if (cp_getvar("device", VT_STRING, buf))
hlp_displayname = copy(buf);
else
hlp_displayname = NULL;
hlp_main(path, wl);
return;
}

8
src/frontend/com_ghelp.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _COM_GHELP_H
#define _COM_GHELP_H
void com_ghelp(wordlist *wl);
#endif

86
src/frontend/com_help.c Normal file
View File

@ -0,0 +1,86 @@
#include <stdlib.h>
#include <macros.h>
#include <wordlist.h>
#include <cpdefs.h>
#include <bool.h>
#include "hcomp.h"
void
com_help(wordlist *wl)
{
struct comm *c;
struct comm *ccc[512]; /* Should be enough. */
int numcoms, i;
bool allflag = FALSE;
if (wl && eq(wl->wl_word, "all")) {
allflag = TRUE;
wl = NULL; /* XXX Probably right */
}
/* We want to use more mode whether "moremode" is set or not. */
out_moremode = TRUE;
out_init();
out_moremode = FALSE;
if (wl == NULL) {
out_printf("For a complete description "
"read the Spice3 User's Manual.\n");
if (!allflag) {
out_printf("For a list of all commands "
"type \"help all\", for a short\n"
"description of \"command\", "
"type \"help command\".\n");
}
/* Sort the commands */
for (numcoms = 0; cp_coms[numcoms].co_func != NULL; numcoms++)
ccc[numcoms] = &cp_coms[numcoms];
qsort((char *) ccc, numcoms, sizeof (struct comm *), hcomp);
for (i = 0; i < numcoms; i++) {
if ((ccc[i]->co_spiceonly && ft_nutmeg) ||
(ccc[i]->co_help == NULL) ||
(!allflag && !ccc[i]->co_major))
continue;
out_printf("%s ", ccc[i]->co_comname);
out_printf(ccc[i]->co_help, cp_program);
out_send("\n");
}
} else {
while (wl != NULL) {
for (c = &cp_coms[0]; c->co_func != NULL; c++)
if (eq(wl->wl_word, c->co_comname)) {
out_printf("%s ", c->co_comname);
out_printf(c->co_help, cp_program);
if (c->co_spiceonly && ft_nutmeg)
out_send(" (Not available in nutmeg)");
out_send("\n");
break;
}
if (c->co_func == NULL) {
/* See if this is aliased. */
struct alias *al;
for (al = cp_aliases; al; al = al->al_next)
if (eq(al->al_name, wl->wl_word))
break;
if (al == NULL)
fprintf(cp_out, "Sorry, no help for %s.\n",
wl->wl_word);
else {
out_printf("%s is aliased to ", wl->wl_word);
/* Minor badness here... */
wl_print(al->al_text, cp_out);
out_send("\n");
}
}
wl = wl->wl_next;
}
}
out_send("\n");
return;
}

8
src/frontend/com_help.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _COM_HELP_H
#define _COM_HELP_H
void com_help(wordlist *wl);
#endif

488
src/frontend/com_history.c Normal file
View File

@ -0,0 +1,488 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/* Do history substitutions. */
#include <ngspice.h>
#include <cpdefs.h>
#include "com_history.h"
/* static declarations */
static wordlist * dohsubst(char *string);
static wordlist * dohmod(char **string, wordlist *wl);
static wordlist * hpattern(char *buf);
static wordlist * hprefix(char *buf);
static wordlist * getevent(int num);
static void freehist(int num);
static char * dohs(char *pat, char *str);
struct histent *cp_lastone = NULL;
int cp_maxhistlength = 10000; /* Chris Inbody */
char cp_hat = '^';
char cp_bang = '!';
bool cp_didhsubst;
static struct histent *histlist = NULL;
static int histlength = 0;
/* First check for a ^ at the beginning
* of the line, and then search each word for !. Following this can be any
* of string, number, ?string, -number ; then there may be a word specifier,
* the same as csh, and then the : modifiers. For the :s modifier,
* the syntax is :sXoooXnnnX, where X is any character, and ooo and nnn are
* strings not containing X.
*/
wordlist *
cp_histsubst(wordlist *wlist)
{
wordlist *nwl, *w, *n;
char buf[BSIZE_SP], *s, *b;
/* Replace ^old^new with !:s^old^new. */
cp_didhsubst = FALSE;
if (*wlist->wl_word == cp_hat) {
(void) sprintf(buf, "%c%c:s%s", cp_bang, cp_bang,
wlist->wl_word);
tfree(wlist->wl_word);
wlist->wl_word = copy(buf);
}
for (w = wlist; w; w = w->wl_next) {
b = w->wl_word;
for (s = b; *s; s++)
if (*s == cp_bang) {
cp_didhsubst = TRUE;
n = dohsubst(s + 1);
if (!n) {
wlist->wl_word = NULL;
return (wlist);
}
if (b < s) {
(void) sprintf(buf, "%.*s%s", s - b, b,
n->wl_word);
tfree(n->wl_word);
n->wl_word = copy(buf);
}
nwl = wl_splice(w, n);
if (wlist == w)
wlist = n;
w = nwl;
break;
}
}
return (wlist);
}
/* Do a history substitution on one word. Figure out which event is
* being referenced, then do word selections and modifications, and
* then stick anything left over on the end of the last word.
*/
static wordlist *
dohsubst(char *string)
{
wordlist *wl, *nwl;
char buf[BSIZE_SP], *s, *r = NULL, *t;
if (*string == cp_bang) {
if (cp_lastone) {
wl = cp_lastone->hi_wlist;
string++;
} else {
fprintf(cp_err, "0: event not found.\n");
return (NULL);
}
} else {
switch(*string) {
case '-':
wl = getevent(cp_event - scannum(++string));
if (!wl)
return (NULL);
while (isdigit(*string))
string++;
break;
case '?':
(void) strcpy(buf, string + 1);
if ((s =strchr(buf, '?')))
*s = '\0';
wl = hpattern(buf);
if (!wl)
return (NULL);
if (s == NULL) /* No modifiers on this one. */
return (wl_copy(wl));
break;
case '\0': /* Maybe this should be cp_event. */
wl = alloc(struct wordlist);
wl->wl_word = copy("!");
wl->wl_next = NULL;
wl->wl_prev = NULL;
cp_didhsubst = FALSE;
return (wl);
default:
if (isdigit(*string)) {
wl = getevent(scannum(string));
if (!wl)
return (NULL);
while (isdigit(*string))
string++;
} else {
(void) strcpy(buf, string);
for (s = ":^$*-%"; *s; s++) {
t =strchr(buf, *s);
if (t && ((t < r) || !r)) {
r = t;
string += r - buf;
}
}
if (r)
*r = '\0';
else
while (*string)
string++;
if ((buf[0] == '\0') && cp_lastone)
wl = cp_lastone->hi_wlist;
else
wl = hprefix(buf);
if (!wl)
return (NULL);
}
}
}
if (wl == NULL) { /* Shouldn't happen. */
fprintf(cp_err, "Event not found.\n");
return (NULL);
}
nwl = dohmod(&string, wl_copy(wl));
if (!nwl)
return (NULL);
if (*string) {
for (wl = nwl; wl->wl_next; wl = wl->wl_next)
;
(void) sprintf(buf, "%s%s", wl->wl_word, string);
tfree(wl->wl_word);
wl->wl_word = copy(buf);
}
return (nwl);
}
static wordlist *
dohmod(char **string, wordlist *wl)
{
wordlist *w;
char *s;
char *r = NULL, *t;
int numwords, eventlo, eventhi, i;
bool globalsubst;
anothermod:
numwords = wl_length(wl);
globalsubst = FALSE;
eventlo = 0;
eventhi = numwords - 1;
/* Now we know what wordlist we want. Take care of modifiers now. */
r = NULL;
for (s = ":^$*-%"; *s; s++) {
t =strchr(*string, *s);
if (t && ((t < r) || (r == NULL)))
r = t;
}
if (!r) /* No more modifiers. */
return (wl);
*string = r;
if (**string == ':')
(*string)++;
switch(**string) {
case '$': /* Last word. */
eventhi = eventlo = numwords - 1;
break;
case '*': /* Words 1 through $ */
if (numwords == 1)
return (NULL);
eventlo = 1;
eventhi = numwords - 1;
break;
case '-': /* Words 0 through ... */
eventlo = 0;
if (*(*string + 1))
eventhi = scannum(*string + 1);
else
eventhi = numwords - 1;
if (eventhi > numwords - 1)
eventhi = numwords - 1;
break;
case 'p': /* Print the command and don't execute it.
* This doesn't work quite like csh.
*/
wl_print(wl, cp_out);
(void) putc('\n', cp_out);
return (NULL);
case 's': /* Do a substitution. */
for (w = wl; w; w = w->wl_next) {
s = dohs(*string + 1, w->wl_word);
if (s) {
tfree(w->wl_word);
w->wl_word = s;
if (globalsubst == FALSE) {
while (**string)
(*string)++;
break;
}
}
}
/* In case globalsubst is TRUE... */
while (**string)
(*string)++;
break;
default:
if (!isdigit(**string)) {
fprintf(cp_err, "Error: %s: bad modifier.\n",
*string);
return (NULL);
}
i = scannum(*string);
if (i > eventhi) {
fprintf(cp_err, "Error: bad event number %d\n",
i);
return (NULL);
}
eventhi = eventlo = i;
while (isdigit(**string))
(*string)++;
if (**string == '*')
eventhi = numwords - 1;
if (**string == '-') {
if (!isdigit(*(*string + 1)))
eventhi = numwords - 1;
else {
eventhi = scannum(++*string);
while (isdigit(**string))
(*string)++;
}
}
}
/* Now change the word list accordingly and make another pass
* if there is more of the substitute left.
*/
wl = wl_range(wl, eventlo, eventhi);
numwords = wl_length(wl);
if (**string && *++*string)
goto anothermod;
return (wl);
}
/* Look for an event with a pattern in it... */
static wordlist *
hpattern(char *buf)
{
struct histent *hi;
wordlist *wl;
if (*buf == '\0') {
fprintf(cp_err, "Bad pattern specification.\n");
return (NULL);
}
for (hi = cp_lastone; hi; hi = hi->hi_prev)
for (wl = hi->hi_wlist; wl; wl = wl->wl_next)
if (substring(buf, wl->wl_word))
return (hi->hi_wlist);
fprintf(cp_err, "%s: event not found.\n", buf);
return (NULL);
}
static wordlist *
hprefix(char *buf)
{
struct histent *hi;
if (*buf == '\0') {
fprintf(cp_err, "Bad pattern specification.\n");
return (NULL);
}
for (hi = cp_lastone; hi; hi = hi->hi_prev)
if (hi->hi_wlist && prefix(buf, hi->hi_wlist->wl_word))
return (hi->hi_wlist);
fprintf(cp_err, "%s: event not found.\n", buf);
return (NULL);
}
/* Add a wordlist to the history list. (Done after the first parse.) Note
* that if event numbers are given in a random order that's how they'll
* show up in the history list.
*/
void
cp_addhistent(int event, wordlist *wlist)
{
if (cp_lastone && !cp_lastone->hi_wlist)
fprintf(cp_err, "Internal error: bad history list\n");
if (cp_lastone == NULL) {
cp_lastone = histlist = alloc(struct histent);
cp_lastone->hi_prev = NULL;
} else {
cp_lastone->hi_next = alloc(struct histent);
cp_lastone->hi_next->hi_prev = cp_lastone;
cp_lastone = cp_lastone->hi_next;
}
cp_lastone->hi_next = NULL;
cp_lastone->hi_event = event;
cp_lastone->hi_wlist = wl_copy(wlist);
freehist(histlength - cp_maxhistlength);
histlength++;
return;
}
/* Get a copy of the wordlist associated with an event. Error if out
* of range.
*/
static wordlist *
getevent(int num)
{
struct histent *hi;
for (hi = histlist; hi; hi = hi->hi_next)
if (hi->hi_event == num)
break;
if (hi == NULL) {
fprintf(cp_err, "%d: event not found.\n", num);
return (NULL);
}
return (wl_copy(hi->hi_wlist));
}
/* Print out history between eventhi and eventlo.
* This doesn't remember quoting, so 'hodedo' prints as hodedo.
*/
void
cp_hprint(int eventhi, int eventlo, bool rev)
{
struct histent *hi;
if (rev) {
for (hi = histlist; hi->hi_next; hi = hi->hi_next)
;
for (; hi; hi = hi->hi_prev)
if ((hi->hi_event <= eventhi) &&
(hi->hi_event >= eventlo) &&
hi->hi_wlist) {
fprintf(cp_out, "%d\t", hi->hi_event);
wl_print(hi->hi_wlist, cp_out);
(void) putc('\n', cp_out);
}
} else {
for (hi = histlist; hi; hi = hi->hi_next)
if ((hi->hi_event <= eventhi) &&
(hi->hi_event >= eventlo) &&
hi->hi_wlist) {
fprintf(cp_out, "%d\t", hi->hi_event);
wl_print(hi->hi_wlist, cp_out);
(void) putc('\n', cp_out);
}
}
return;
}
/* This just gets rid of the first num entries on the history list, and
* decrements histlength.
*/
static void
freehist(int num)
{
struct histent *hi;
if (num < 1)
return;
histlength -= num;
hi = histlist;
while (num-- && histlist->hi_next)
histlist = histlist->hi_next;
if (histlist->hi_prev) {
histlist->hi_prev->hi_next = NULL;
histlist->hi_prev = NULL;
} else
{
fprintf(cp_err, "Internal error: history list mangled\n");
exit(0); /* Chris Inbody */
}
while (hi->hi_next) {
wl_free(hi->hi_wlist);
hi = hi->hi_next;
tfree(hi->hi_prev);
}
wl_free(hi->hi_wlist);
tfree(hi);
return;
}
/* Do a :s substitution. */
static char *
dohs(char *pat, char *str)
{
char schar, *s, *p, buf[BSIZE_SP];
int i = 0, plen;
bool ok = FALSE;
pat = copy(pat); /* Don't want to mangle anything. */
schar = *pat++;
s =strchr(pat, schar);
if (s == NULL) {
fprintf(cp_err, "Bad substitute.\n");
return (NULL);
}
*s++ = '\0';
p =strchr(s, schar);
if (p)
*p = '\0';
plen = strlen(pat) - 1;
for (i = 0; *str; str++) {
if ((*str == *pat) && prefix(pat, str) && (ok == FALSE)) {
for (p = s; *p; p++)
buf[i++] = *p;
str += plen;
ok = TRUE;
} else
buf[i++] = *str;
}
buf[i] = '\0';
if (ok)
return (copy(buf));
else
return (NULL);
}
/* The "history" command. history [-r] [number] */
void
com_history(wordlist *wl)
{
bool rev = FALSE;
if (wl && eq(wl->wl_word, "-r")) {
wl = wl->wl_next;
rev = TRUE;
}
if (wl == NULL)
cp_hprint(cp_event - 1, cp_event - histlength, rev);
else
cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev);
return;
}

View File

@ -0,0 +1,16 @@
/*************
* Header file for history.c
* 1999 E. Rouat
************/
#ifndef _COM_HISTORY_H
#define _COM_HISTORY_H
wordlist * cp_histsubst(wordlist *wlist);
void cp_addhistent(int event, wordlist *wlist);
void cp_hprint(int eventhi, int eventlo, bool rev);
void com_history(wordlist *wl);
#endif

51
src/frontend/com_set.c Normal file
View File

@ -0,0 +1,51 @@
#include <config.h>
#include <stddef.h>
#include <bool.h>
#include <wordlist.h>
#include "variable.h"
/* The set command. Syntax is set [opt ...] [opt = val ...]. Val may
* be a string, an int, a float, or a list of the form (elt1 elt2
* ...). */
void
com_set(wordlist *wl)
{
struct variable *vars;
char *s;
if (wl == NULL) {
cp_vprint();
return;
}
vars = cp_setparse(wl);
/* This is sort of a hassle... */
while (vars) {
switch (vars->va_type) {
case VT_BOOL:
s = (char *) &vars->va_bool;
break;
case VT_NUM:
s = (char *) &vars->va_num;
break;
case VT_REAL:
s = (char *) &vars->va_real;
break;
case VT_STRING:
s = vars->va_string;
break;
case VT_LIST:
s = (char *) vars->va_vlist;
break;
default:
s = (char *) NULL;
}
cp_vset(vars->va_name, vars->va_type, s);
vars = vars->va_next;
}
return;
}

46
src/frontend/com_shift.c Normal file
View File

@ -0,0 +1,46 @@
#include <config.h>
#include <ngspice.h>
#include <bool.h>
#include <wordlist.h>
#include "variable.h"
#include "streams.h"
/* Shift a list variable, by default argv, one to the left (or more if
* a second argument is given. */
void
com_shift(wordlist *wl)
{
struct variable *v, *vv;
char *n = "argv";
int num = 1;
if (wl) {
n = wl->wl_word;
wl = wl->wl_next;
}
if (wl)
num = scannum(wl->wl_word);
for (v = variables; v; v = v->va_next)
if (eq(v->va_name, n))
break;
if (!v) {
fprintf(cp_err, "Error: %s: no such variable\n", n);
return;
}
if (v->va_type != VT_LIST) {
fprintf(cp_err, "Error: %s not of type list\n", n);
return;
}
for (vv = v->va_vlist; vv && (num > 0); num--)
vv = vv->va_next;
if (num) {
fprintf(cp_err, "Error: variable %s not long enough\n", n);
return;
}
v->va_vlist = vv;
return;
}

23
src/frontend/com_strcmp.c Normal file
View File

@ -0,0 +1,23 @@
#include <bool.h>
#include <wordlist.h>
#include "com_strcmp.h"
#include "variable.h"
/* This is a truly evil thing */
void
com_strcmp(wordlist *wl)
{
char *var, *s1, *s2;
int i;
var = wl->wl_word;
s1 = cp_unquote(wl->wl_next->wl_word);
s2 = cp_unquote(wl->wl_next->wl_next->wl_word);
i = strcmp(s1, s2);
cp_vset(var, VT_NUM, (char *) &i);
return;
}

View File

@ -0,0 +1,7 @@
#ifndef _COM_STRCMP_H
#define _COM_STRCMP_H
void com_strcmp(wordlist *wl);
#endif

30
src/frontend/com_unset.c Normal file
View File

@ -0,0 +1,30 @@
#include <config.h>
#include <stddef.h>
#include <macros.h>
#include <bool.h>
#include <wordlist.h>
#include "variable.h"
void
com_unset(wordlist *wl)
{
char *name;
struct variable *var, *nv;
if (eq(wl->wl_word, "*")) {
for (var = variables; var; var = nv) {
nv = var->va_next;
cp_remvar(var->va_name);
}
wl = wl->wl_next;
}
while (wl != NULL) {
name = wl->wl_word;
cp_remvar(name);
wl = wl->wl_next;
}
return;
}

799
src/frontend/control.c Normal file
View File

@ -0,0 +1,799 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/* The front-end command loop. */
#include <ngspice.h>
#include <cpdefs.h>
#include "control.h"
#include "com_cdump.h"
#include "variable.h"
/* Return values from doblock(). I am assuming that nobody will use
* these characters in a string. */
#define NORMAL '\001'
#define BROKEN '\002'
#define CONTINUED '\003'
#define NORMAL_STR "\001"
#define BROKEN_STR "\002"
#define CONTINUED_STR "\003"
/* Are we waiting for a command? This lets signal handling be
* more clever. */
bool cp_cwait = FALSE;
char *cp_csep = ";";
bool cp_dounixcom = FALSE;
/* We have to keep the control structures in a stack, so that when we
* do a 'source', we can push a fresh set onto the top... Actually
* there have to be two stacks -- one for the pointer to the list of
* control structs, and one for the 'current command' pointer... */
struct control *control[CONTROLSTACKSIZE];
struct control *cend[CONTROLSTACKSIZE];
int stackp = 0;
/* If there is an argument, give this to cshpar to use instead of
* stdin. In a few places, we call cp_evloop again if it returns 1 and
* exit (or close a file) if it returns 0... Because of the way
* sources are done, we can't allow the control structures to get
* blown away every time we return -- probably every time we type
* source at the keyboard and every time a source returns to keyboard
* input is ok though -- use ft_controlreset. */
static char *noredirect[] = { "stop", NULL } ; /* Only one?? */
static struct control *
findlabel(char *s, struct control *ct)
{
while (ct) {
if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word))
break;
ct = ct->co_next;
}
return (ct);
}
/* This is also in cshpar.c ... */
static void
pwlist(wordlist *wlist, char *name)
{
wordlist *wl;
if (!cp_debug)
return;
fprintf(cp_err, "%s : [ ", name);
for (wl = wlist; wl; wl = wl->wl_next)
fprintf(cp_err, "%s ", wl->wl_word);
fprintf(cp_err, "]\n");
return;
}
/* Note that we only do io redirection when we get to here - we also
* postpone some other things until now. */
static void
docommand(wordlist *wlist)
{
char *r, *s, *t;
char *lcom;
int nargs;
int i;
struct comm *command;
wordlist *wl, *nextc, *ee, *rwlist;
if (cp_debug) {
printf("docommand ");
wl_print(wlist, stdout);
putc('\n', stdout);
}
/* Do all the things that used to be done by cshpar when the line
* was read... */
wlist = cp_variablesubst(wlist);
pwlist(wlist, "After variable substitution");
wlist = cp_bquote(wlist);
pwlist(wlist, "After backquote substitution");
wlist = cp_doglob(wlist);
pwlist(wlist, "After globbing");
if (!wlist || !wlist->wl_word)
return;
/* Now loop through all of the commands given. */
rwlist = wlist;
do {
for (nextc = wlist; nextc; nextc = nextc->wl_next)
if (eq(nextc->wl_word, cp_csep))
break;
/* Temporarily hide the rest of the command... */
if (nextc && nextc->wl_prev)
nextc->wl_prev->wl_next = NULL;
ee = wlist->wl_prev;
if (ee)
wlist->wl_prev = NULL;
if (nextc == wlist) {
/* There was no text... */
goto out;
}
/* And do the redirection. */
cp_ioreset();
for (i = 0; noredirect[i]; i++)
if (eq(wlist->wl_word, noredirect[i]))
break;
if (!noredirect[i]) {
if (!(wlist = cp_redirect(wlist))) {
cp_ioreset();
return;
}
}
/* Get rid of all the 8th bits now... */
cp_striplist(wlist);
s = wlist->wl_word;
/* Look for the command in the command list. */
for (i = 0; cp_coms[i].co_comname; i++) {
/* strcmp(cp_coms[i].co_comname, s) ... */
for (t = cp_coms[i].co_comname, r = s; *t && *r;
t++, r++)
if (*t != *r)
break;
if (!*t && !*r)
break;
}
/* Now give the user-supplied command routine a try... */
if (!cp_coms[i].co_func && cp_oddcomm(s, wlist->wl_next))
goto out;
/* If it's not there, try it as a unix command. */
if (!cp_coms[i].co_comname) {
if (cp_dounixcom && cp_unixcom(wlist))
goto out;
fprintf(cp_err,"%s: no such command available in %s\n",
s, cp_program);
goto out;
/* If it's there but spiceonly, and this is nutmeg, error. */
} else if (!cp_coms[i].co_func && ft_nutmeg &&
(cp_coms[i].co_spiceonly)) {
fprintf(cp_err,"%s: command available only in spice\n",
s);
goto out;
}
/* The command was a valid spice/nutmeg command. */
command = &cp_coms[i];
nargs = 0;
for (wl = wlist->wl_next; wl; wl = wl->wl_next)
nargs++;
if (command->co_stringargs) {
lcom = wl_flatten(wlist->wl_next);
(*command->co_func) (lcom);
} else {
if (nargs < command->co_minargs) {
if (command->co_argfn) {
(*command->co_argfn) (wlist->wl_next, command);
} else {
fprintf(cp_err, "%s: too few args.\n", s);
}
} else if (nargs > command->co_maxargs) {
fprintf(cp_err, "%s: too many args.\n", s);
} else
(*command->co_func) (wlist->wl_next);
}
/* Now fix the pointers and advance wlist. */
out: wlist->wl_prev = ee;
if (nextc) {
if (nextc->wl_prev)
nextc->wl_prev->wl_next = nextc;
wlist = nextc->wl_next;
}
} while (nextc && wlist);
wl_free(rwlist);
/* Do periodic sorts of things... */
cp_periodic();
cp_ioreset();
return;
}
/* Execute a block. There can be a number of return values from this routine.
* NORMAL indicates a normal termination
* BROKEN indicates a break -- if the caller is a breakable loop,
* terminate it, otherwise pass the break upwards
* CONTINUED indicates a continue -- if the caller is a continuable loop,
* continue, else pass the continue upwards
* Any other return code is considered a pointer to a string which is
* a label somewhere -- if this label is present in the block,
* goto it, otherwise pass it up. Note that this prevents jumping
* into a loop, which is good.
*
* Note that here is where we expand variables, ``, and globs for
* controls.
*
* The 'num' argument is used by break n and continue n. */
static char *
doblock(struct control *bl, int *num)
{
struct control *ch, *cn = NULL;
wordlist *wl;
char *i;
int nn;
switch (bl->co_type) {
case CO_WHILE:
while (bl->co_cond && cp_isTRUE(bl->co_cond)) {
for (ch = bl->co_children; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
switch (*i) {
case NORMAL:
break;
case BROKEN: /* Break. */
if (nn < 2)
return (NORMAL_STR);
else {
*num = nn - 1;
return (BROKEN_STR);
}
case CONTINUED: /* Continue. */
if (nn < 2) {
cn = NULL;
break;
} else {
*num = nn - 1;
return (CONTINUED_STR);
}
default:
cn = findlabel(i, bl->co_children);
if (!cn)
return (i);
}
}
}
break;
case CO_DOWHILE:
do {
for (ch = bl->co_children; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
switch (*i) {
case NORMAL:
break;
case BROKEN: /* Break. */
if (nn < 2)
return (NORMAL_STR);
else {
*num = nn - 1;
return (BROKEN_STR);
}
case CONTINUED: /* Continue. */
if (nn < 2) {
cn = NULL;
break;
} else {
*num = nn - 1;
return (CONTINUED_STR);
}
default:
cn = findlabel(i, bl->co_children);
if (!cn)
return (i);
}
}
} while (bl->co_cond && cp_isTRUE(bl->co_cond));
break;
case CO_REPEAT:
while ((bl->co_numtimes > 0) ||
(bl->co_numtimes == -1)) {
if (bl->co_numtimes != -1)
bl->co_numtimes--;
for (ch = bl->co_children; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
switch (*i) {
case NORMAL:
break;
case BROKEN: /* Break. */
if (nn < 2)
return (NORMAL_STR);
else {
*num = nn - 1;
return (BROKEN_STR);
}
case CONTINUED: /* Continue. */
if (nn < 2) {
cn = NULL;
break;
} else {
*num = nn - 1;
return (CONTINUED_STR);
}
default:
cn = findlabel(i, bl->co_children);
if (!cn)
return (i);
}
}
}
break;
case CO_IF:
if (bl->co_cond && cp_isTRUE(bl->co_cond)) {
for (ch = bl->co_children; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
if (*i > 2) {
cn = findlabel(i,
bl->co_children);
if (!cn)
return (i);
} else if (*i != NORMAL) {
*num = nn;
return (i);
}
}
} else {
for (ch = bl->co_elseblock; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
if (*i > 2) {
cn = findlabel(i,
bl->co_elseblock);
if (!cn)
return (i);
} else if (*i != NORMAL) {
*num = nn;
return (i);
}
}
}
break;
case CO_FOREACH:
for (wl = cp_variablesubst(cp_bquote(cp_doglob(wl_copy(bl->co_text))));
wl;
wl = wl->wl_next) {
cp_vset(bl->co_foreachvar, VT_STRING, wl->wl_word);
for (ch = bl->co_children; ch; ch = cn) {
cn = ch->co_next;
i = doblock(ch, &nn);
switch (*i) {
case NORMAL:
break;
case BROKEN: /* Break. */
if (nn < 2)
return (NORMAL_STR);
else {
*num = nn - 1;
return (BROKEN_STR);
}
case CONTINUED: /* Continue. */
if (nn < 2) {
cn = NULL;
break;
} else {
*num = nn - 1;
return (CONTINUED_STR);
}
default:
cn = findlabel(i, bl->co_children);
if (!cn)
return (i);
}
}
}
break;
case CO_BREAK:
if (bl->co_numtimes > 0) {
*num = bl->co_numtimes;
return (BROKEN_STR);
} else {
fprintf(cp_err, "Warning: break %d a no-op\n",
bl->co_numtimes);
return (NORMAL_STR);
}
case CO_CONTINUE:
if (bl->co_numtimes > 0) {
*num = bl->co_numtimes;
return (CONTINUED_STR);
} else {
fprintf(cp_err, "Warning: continue %d a no-op\n",
bl->co_numtimes);
return (NORMAL_STR);
}
case CO_GOTO:
wl = cp_variablesubst(cp_bquote(cp_doglob(
wl_copy(bl->co_text))));
return (wl->wl_word);
case CO_LABEL:
/* Do nothing. */
break;
case CO_STATEMENT:
docommand(wl_copy(bl->co_text));
break;
case CO_UNFILLED:
/* There was probably an error here... */
fprintf(cp_err, "Warning: ignoring previous error\n");
break;
default:
fprintf(cp_err,
"doblock: Internal Error: bad block type %d\n",
bl->co_type);
return (NORMAL_STR);
}
return (NORMAL_STR);
}
/* Get a command. This does all the bookkeeping things like turning
* command completion on and off... */
static wordlist *
getcommand(char *string)
{
wordlist *wlist;
int i = 0, j;
static char buf[64];
struct control *c;
if (cp_debug)
fprintf(cp_err, "calling getcommand %s\n",
string ? string : "");
if (cend[stackp]) {
for (c = cend[stackp]->co_parent; c; c = c->co_parent)
i++;
if (i) {
for (j = 0; j < i; j++)
buf[j] = '>';
buf[j] = ' ';
buf[j + 1] = '\0';
cp_altprompt = buf;
} else
cp_altprompt = NULL;
} else
cp_altprompt = NULL;
cp_cwait = TRUE;
wlist = cp_parse(string);
cp_cwait = FALSE;
if (cp_debug) {
printf("getcommand ");
wl_print(wlist, stdout);
putc('\n', stdout);
}
return (wlist);
}
int
cp_evloop(char *string)
{
wordlist *wlist, *ww;
struct control *x;
char *i;
int nn;
#define newblock cend[stackp]->co_children = alloc(struct control); \
ZERO(cend[stackp]->co_children,struct control), \
cend[stackp]->co_children->co_parent = cend[stackp]; \
cend[stackp] = cend[stackp]->co_children; \
cend[stackp]->co_type = CO_UNFILLED;
for (;;) {
wlist = getcommand(string);
if (wlist == NULL) { /* End of file or end of user input. */
if (cend[stackp]->co_parent && !string) {
cp_resetcontrol();
continue;
} else
return (0);
}
if ((wlist->wl_word == NULL) || (*wlist->wl_word == '\0')) {
/* User just typed return. */
if (string)
return (1);
else {
cp_event--;
continue;
}
}
/* Just a check... */
for (ww = wlist; ww; ww = ww->wl_next)
if (!ww->wl_word) {
fprintf(cp_err,
"cp_evloop: Internal Error: NULL word pointer\n");
continue;
}
/* Add this to the control structure list. If cend->co_type is
* CO_UNFILLED, the last line was the beginning of a block,
* and this is the unfilled first statement. */
if (cend[stackp] && (cend[stackp]->co_type != CO_UNFILLED)) {
cend[stackp]->co_next = alloc(struct control);
ZERO(cend[stackp]->co_next, struct control);
cend[stackp]->co_next->co_prev = cend[stackp];
cend[stackp]->co_next->co_parent =
cend[stackp]->co_parent;
cend[stackp] = cend[stackp]->co_next;
} else if (!cend[stackp]) {
control[stackp] = cend[stackp] = alloc(struct control);
ZERO(cend[stackp], struct control);
}
if (eq(wlist->wl_word, "while")) {
cend[stackp]->co_type = CO_WHILE;
cend[stackp]->co_cond = wlist->wl_next;
if (!cend[stackp]->co_cond) {
fprintf(stderr,
"Error: missing while condition.\n");
}
newblock;
} else if (eq(wlist->wl_word, "dowhile")) {
cend[stackp]->co_type = CO_DOWHILE;
cend[stackp]->co_cond = wlist->wl_next;
if (!cend[stackp]->co_cond) {
fprintf(stderr,
"Error: missing dowhile condition.\n");
}
newblock;
} else if (eq(wlist->wl_word, "repeat")) {
cend[stackp]->co_type = CO_REPEAT;
if (!wlist->wl_next) {
cend[stackp]->co_numtimes = -1;
} else {
char *s;
double *dd;
wlist = cp_variablesubst(cp_bquote(
cp_doglob(wl_copy(wlist))));
s = wlist->wl_next->wl_word;
dd = ft_numparse(&s, FALSE);
if (dd) {
if (*dd < 0) {
fprintf(cp_err,
"Error: can't repeat a negative number of times\n");
*dd = 0.0;
}
cend[stackp]->co_numtimes = (int) *dd;
} else
fprintf(cp_err,
"Error: bad repeat argument %s\n",
wlist->wl_next->wl_word);
}
newblock;
} else if (eq(wlist->wl_word, "if")) {
cend[stackp]->co_type = CO_IF;
cend[stackp]->co_cond = wlist->wl_next;
if (!cend[stackp]->co_cond) {
fprintf(stderr,
"Error: missing if condition.\n");
}
newblock;
} else if (eq(wlist->wl_word, "foreach")) {
cend[stackp]->co_type = CO_FOREACH;
if (wlist->wl_next) {
wlist = wlist->wl_next;
cend[stackp]->co_foreachvar =
copy(wlist->wl_word);
wlist = wlist->wl_next;
} else
fprintf(stderr,
"Error: missing foreach variable.\n");
wlist = cp_doglob(wlist);
cend[stackp]->co_text = wl_copy(wlist);
newblock;
} else if (eq(wlist->wl_word, "label")) {
cend[stackp]->co_type = CO_LABEL;
if (wlist->wl_next) {
cend[stackp]->co_text = wl_copy(wlist->wl_next);
/* I think of everything, don't I? */
cp_addkword(CT_LABEL, wlist->wl_next->wl_word);
if (wlist->wl_next->wl_next)
fprintf(cp_err,
"Warning: ignored extra junk after label.\n");
} else
fprintf(stderr, "Error: missing label.\n");
} else if (eq(wlist->wl_word, "goto")) {
/* Incidentally, this won't work if the values 1 and 2 ever get
* to be valid character pointers -- I think it's reasonably
* safe to assume they aren't... */
cend[stackp]->co_type = CO_GOTO;
if (wlist->wl_next) {
cend[stackp]->co_text = wl_copy(wlist->wl_next);
if (wlist->wl_next->wl_next)
fprintf(cp_err,
"Warning: ignored extra junk after goto.\n");
} else
fprintf(stderr, "Error: missing label.\n");
} else if (eq(wlist->wl_word, "continue")) {
cend[stackp]->co_type = CO_CONTINUE;
if (wlist->wl_next) {
cend[stackp]->co_numtimes = scannum(wlist->
wl_next->wl_word);
if (wlist->wl_next->wl_next)
fprintf(cp_err,
"Warning: ignored extra junk after continue %d.\n",
cend[stackp]->co_numtimes);
} else
cend[stackp]->co_numtimes = 1;
} else if (eq(wlist->wl_word, "break")) {
cend[stackp]->co_type = CO_BREAK;
if (wlist->wl_next) {
cend[stackp]->co_numtimes = scannum(wlist->
wl_next->wl_word);
if (wlist->wl_next->wl_next)
fprintf(cp_err,
"Warning: ignored extra junk after break %d.\n",
cend[stackp]->co_numtimes);
} else
cend[stackp]->co_numtimes = 1;
} else if (eq(wlist->wl_word, "end")) {
/* Throw away this thing. */
if (!cend[stackp]->co_parent) {
fprintf(stderr, "Error: no block to end.\n");
cend[stackp]->co_type = CO_UNFILLED;
} else if (cend[stackp]->co_prev) {
cend[stackp]->co_prev->co_next = NULL;
x = cend[stackp];
cend[stackp] = cend[stackp]->co_parent;
tfree(x);
} else {
x = cend[stackp];
cend[stackp] = cend[stackp]->co_parent;
cend[stackp]->co_children = NULL;
tfree(x);
}
} else if (eq(wlist->wl_word, "else")) {
if (!cend[stackp]->co_parent ||
(cend[stackp]->co_parent->co_type !=
CO_IF)) {
fprintf(stderr, "Error: misplaced else.\n");
cend[stackp]->co_type = CO_UNFILLED;
} else {
if (cend[stackp]->co_prev)
cend[stackp]->co_prev->co_next = NULL;
else
cend[stackp]->co_parent->co_children = NULL;
cend[stackp]->co_parent->co_elseblock = cend[stackp];
cend[stackp]->co_prev = NULL;
}
} else {
cend[stackp]->co_type = CO_STATEMENT;
cend[stackp]->co_text = wlist;
}
if (!cend[stackp]->co_parent) {
x = cend[stackp];
/* We have to toss this do-while loop in here so
* that gotos at the top level will work.
*/
do {
i = doblock(x, &nn);
switch (*i) {
case NORMAL:
break;
case BROKEN:
fprintf(cp_err,
"Error: break not in loop or too many break levels given\n");
break;
case CONTINUED:
fprintf(cp_err,
"Error: continue not in loop or too many continue levels given\n");
break;
default:
x = findlabel(i, control[stackp]);
if (!x)
fprintf(cp_err, "Error: label %s not found\n", i);
}
if (x)
x = x->co_next;
} while (x);
}
if (string)
return (1); /* The return value is irrelevant. */
}
}
/* This blows away the control structures... */
void
cp_resetcontrol(void)
{
if (cend[stackp] && cend[stackp]->co_parent)
fprintf(cp_err, "Warning: EOF before block terminated\n");
/* We probably should free the control structures... */
control[0] = cend[0] = NULL;
stackp = 0;
cp_kwswitch(CT_LABEL, (char *) NULL);
return;
}
/* Push or pop a new control structure set... */
void
cp_popcontrol(void)
{
if (cp_debug)
fprintf(cp_err, "pop: stackp: %d -> %d\n", stackp, stackp - 1);
if (stackp < 1)
fprintf(cp_err, "cp_popcontrol: Internal Error: stack empty\n");
else
stackp--;
return;
}
void
cp_pushcontrol(void)
{
if (cp_debug)
fprintf(cp_err, "push: stackp: %d -> %d\n", stackp, stackp + 1);
if (stackp > CONTROLSTACKSIZE - 2) {
fprintf(cp_err, "Error: stack overflow -- max depth = %d\n",
CONTROLSTACKSIZE);
stackp = 0;
} else {
stackp++;
control[stackp] = cend[stackp] = NULL;
}
return;
}
/* And this returns to the top level (for use in the interrupt handlers). */
void
cp_toplevel(void)
{
stackp = 0;
if (cend[stackp])
while (cend[stackp]->co_parent)
cend[stackp] = cend[stackp]->co_parent;
return;
}

45
src/frontend/control.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _CONTROL_H
#define _CONTROL_H
/* Stuff to do control structures. We keep a history (seperate from
* the cshpar history, for now at least) of commands and their event
* numbers, with a block considered as a statement. In a goto, the
* first word in co_text is where to go, likewise for label. For
* conditional controls, we have to call ft_getpnames and ft_evaluate
* each time, since the dvec pointers will change... Also we should do
* variable and backquote substitution each time... */
struct control {
int co_type; /* One of CO_* ... */
wordlist *co_cond; /* if, while, dowhile */
char *co_foreachvar; /* foreach */
int co_numtimes; /* repeat, break & continue levels */
wordlist *co_text; /* Ordinary text and foreach values. */
struct control *co_parent; /* If this is inside a block. */
struct control *co_children; /* The contents of this block. */
struct control *co_elseblock; /* For if-then-else. */
struct control *co_next;
struct control *co_prev;
} ;
enum co_command {
CO_UNFILLED,
CO_STATEMENT,
CO_WHILE,
CO_DOWHILE,
CO_IF,
CO_FOREACH,
CO_BREAK,
CO_CONTINUE,
CO_LABEL,
CO_GOTO,
CO_REPEAT
};
#define CONTROLSTACKSIZE 256 /* Better be enough. */
extern struct control *control[CONTROLSTACKSIZE];
extern struct control *cend[CONTROLSTACKSIZE];
extern int stackp;
#endif

22
src/frontend/ftehelp.h Normal file
View File

@ -0,0 +1,22 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1987 Jeffrey M. Hsu
**********/
/*
Defines for help.
*/
#define E_HASPLOTS 1
#define E_NOPLOTS 2
#define E_HASGRAPHS 4
#define E_MENUMODE 8
#define E_BEGINNING 4096
#define E_INTERMED 8192
#define E_ADVANCED 16384
#define E_ALWAYS 32768
/* default is intermediate level */
#define E_DEFHMASK 8192

9
src/frontend/hcomp.c Normal file
View File

@ -0,0 +1,9 @@
#include <cpdefs.h>
int
hcomp(const void *a, const void *b)
{
struct comm **c1 = (struct comm **) a;
struct comm **c2 = (struct comm **) b;
return (strcmp((*c1)->co_comname, (*c2)->co_comname));
}

7
src/frontend/hcomp.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _HCOMP_H
#define _HCOMP_H
int hcomp(const void *a, const void *b);
#endif

36
src/frontend/init.c Normal file
View File

@ -0,0 +1,36 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/* Initialize stuff. */
#include <ngspice.h>
#include <cpdefs.h>
#include "init.h"
#include "variable.h"
char cp_chars[128];
static char *singlec = "<>;&";
void
cp_init(void)
{
char *s, *getenv(const char *);
bzero(cp_chars, 128);
for (s = singlec; *s; s++)
cp_chars[(int) *s] = (CPC_BRR | CPC_BRL);
cp_vset("history", VT_NUM, (char *) &cp_maxhistlength);
cp_curin = stdin;
cp_curout = stdout;
cp_curerr = stderr;
cp_ioreset();
return;
}

6
src/frontend/init.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _INIT_H
#define _INIT_H
#endif

326
src/frontend/terminal.c Normal file
View File

@ -0,0 +1,326 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/*
* Routines to handle "more"d output. There are some serious system
* dependencies in here, and it isn't clear that versions of this stuff
* can be written for every possible machine...
*/
#include <config.h>
#ifdef HAVE_SGTTY_H
#include <sgtty.h>
#endif
#if 0
/* Bad interaction with bool type in bool.h because curses also
defines this symbol. */
#ifdef HAVE_TERMCAP
#include <curses.h>
#include <term.h>
#endif
#endif
#include <ngspice.h>
#include <cpdefs.h>
#include "variable.h"
#include "terminal.h"
static char *motion_chars;
static char *clear_chars;
static char *home_chars;
static char *cleol_chars;
#define DEF_SCRHEIGHT 24
#define DEF_SCRWIDTH 80
bool out_moremode = TRUE;
bool out_isatty = TRUE;
static int xsize, ysize;
static int xpos, ypos;
static bool noprint, nopause;
/* out_printf doesn't handle double arguments correctly, so we
sprintf into this buf and call out_send w/ it */
char out_pbuf[BSIZE_SP];
/* Start output... */
void
out_init(void)
{
#ifdef TIOCGWINSZ
struct winsize ws;
#endif
bool moremode;
noprint = nopause = FALSE;
if (cp_getvar("nomoremode", VT_BOOL, (char *) &moremode))
out_moremode = FALSE;
else
out_moremode = TRUE;
if (!out_moremode || !cp_interactive)
out_isatty = FALSE;
if (!out_isatty)
return;
xsize = ysize = 0;
/* Figure out the screen size. We try, in order, TIOCGSIZE,
* tgetent(), and cp_getvar(height). Default is 24 x 80.
*/
#ifdef TIOCGWINSZ
if (!xsize || !ysize) {
(void) ioctl(fileno(stdout), TIOCGWINSZ, (char *) &ws);
xsize = ws.ws_col;
ysize = ws.ws_row;
}
#endif
if (!xsize)
(void) cp_getvar("width", VT_NUM, (char *) &xsize);
if (!ysize)
(void) cp_getvar("height", VT_NUM, (char *) &ysize);
if (!xsize)
xsize = DEF_SCRWIDTH;
if (!ysize)
ysize = DEF_SCRHEIGHT;
ysize -= 2; /* Fudge room... */
xpos = ypos = 0;
return;
}
/* Putc may not be buffered (sp?), so we do it ourselves. */
static char staticbuf[BUFSIZ];
struct {
int count;
char *ptr;
} ourbuf = { BUFSIZ, staticbuf };
/* send buffer out */
void
outbufputc(void)
{
if (ourbuf.count != BUFSIZ) {
fputs(staticbuf, cp_out);
memset(staticbuf, 0, BUFSIZ-ourbuf.count);
ourbuf.count = BUFSIZ;
ourbuf.ptr = staticbuf;
}
}
static void
bufputc(char c)
{
if (--ourbuf.count >= 0) {
*ourbuf.ptr++ = c;
} else {
/* Flush and reset the buffer */
outbufputc();
/* and store the character. */
ourbuf.count--;
*ourbuf.ptr++ = c;
}
}
/* prompt for a return */
void
promptreturn(void)
{
char buf[16];
moe:
fprintf(cp_out,
"\n\t-- hit return for more, ? for help -- ");
if (!fgets(buf, 16, cp_in)) {
clearerr(cp_in);
*buf = 'q';
}
switch (*buf) {
case '\n':
break;
case 'q':
noprint = TRUE;
break;
case 'c':
nopause = TRUE;
break;
case ' ':
break;
case '?':
fprintf(cp_out,
"\nPossible responses:\n\
\t<cr> : Print another screenful\n\
\tq <cr> : Discard the rest of the output\n\
\tc <cr> : Continuously print the rest of the output\n\
\t? <cr> : Print this help message\n");
goto moe;
default:
fprintf(cp_out, "Character %d is no good\n", *buf);
goto moe;
}
}
/* Print a string to the output. If this would cause the screen to scroll,
* print "more".
*/
void
out_send(char *string)
{
if (noprint)
return;
if (!out_isatty || nopause) {
fputs(string, cp_out);
return;
}
while (*string) {
switch (*string) {
case '\n':
xpos = 0;
ypos++;
break;
case '\f':
ypos = ysize;
xpos = 0;
break;
case '\t':
xpos = xpos / 8 + 1;
xpos *= 8;
break;
default:
xpos++;
break;
}
while (xpos >= xsize) {
xpos -= xsize;
ypos++;
}
if (ypos >= ysize) {
outbufputc(); /* out goes buffer */
promptreturn();
(void) fflush(cp_out);
ypos = xpos = 0;
}
bufputc(*string); /* we need to buffer these */
string++;
}
(void) outbufputc();
return;
}
/* Printf some stuff using more mode. */
#define MAXLEN 4096
void
out_printf(char *fmt, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6, char *s7, char *s8, char *s9, char *s10)
{
char buf[MAXLEN];
sprintf(buf, fmt, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
out_send(buf);
return;
}
static int
outfn(int c)
{
putc(c, stdout);
return c;
}
void
tcap_init(void)
{
char *s;
#ifdef HAVE_TERMCAP
char tbuf[1025];
static char buf2[100];
char *charbuf;
charbuf = buf2;
if ((s = getenv("TERM"))) {
if (tgetent(tbuf, s) != -1) {
xsize = tgetnum("co");
ysize = tgetnum("li");
if ((xsize <= 0) || (ysize <= 0))
xsize = ysize = 0;
clear_chars = (char *) tgetstr("cl", &charbuf);
motion_chars = (char *) tgetstr("cm", &charbuf);
home_chars = (char *) tgetstr("ho", &charbuf);
cleol_chars = (char *) tgetstr("ce", &charbuf);
}
}
#endif
if (!xsize) {
if ((s = getenv("COLS")))
xsize = atoi(s);
if (xsize <= 0)
xsize = 0;
}
if (!ysize) {
if ((s = getenv("LINES")))
ysize = atoi(s);
if (ysize <= 0)
ysize = 0;
}
}
void
term_clear(void)
{
#ifdef HAVE_TERMCAP
if (*clear_chars)
tputs(clear_chars, 1, outfn);
else
fputs("\n", stdout);
#endif
}
void
term_home(void)
{
#ifdef HAVE_TERMCAP
if (*home_chars)
tputs(home_chars, 1, outfn);
else if (*motion_chars)
tputs(tgoto(motion_chars, 1, 1), 1, outfn);
else
fputs("\n", stdout);
#endif
}
void
term_cleol(void)
{
#ifdef HAVE_TERMCAP
if (*cleol_chars)
tputs(cleol_chars, 1, outfn);
#endif
}

16
src/frontend/terminal.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _TERMINAL_H
#define _TERMINAL_H
void out_init(void);
void outbufputc(void);
void promptreturn(void);
void out_send(char *string);
void out_printf(char *fmt, char *s1, char *s2, char *s3,
char *s4, char *s5, char *s6,
char *s7, char *s8, char *s9, char *s10);
void term_clear(void);
void term_home(void);
void term_cleol(void);
void tcap_init(void);
#endif

797
src/frontend/variable.c Normal file
View File

@ -0,0 +1,797 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
#include <config.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ngspice.h>
#include <bool.h>
#include <wordlist.h>
#include <defines.h>
#include <macros.h>
#include <cpdefs.h>
#include <memory.h>
#include <inpdefs.h>
#include "circuits.h"
#include "variable.h"
#include "streams.h"
#include "com_history.h"
bool cp_noglob = TRUE;
bool cp_nonomatch = FALSE;
bool cp_noclobber = FALSE;
bool cp_ignoreeof = FALSE;
struct variable *variables = NULL;
wordlist *
cp_varwl(struct variable *var)
{
wordlist *wl = NULL, *w, *wx = NULL;
char buf[BSIZE_SP];
struct variable *vt;
switch(var->va_type) {
case VT_BOOL:
/* Can't ever be FALSE. */
sprintf(buf, "%s", var->va_bool ? "TRUE" : "FALSE");
break;
case VT_NUM:
sprintf(buf, "%d", var->va_num);
break;
case VT_REAL:
/* This is a case where printnum isn't too good... */
sprintf(buf, "%G", var->va_real);
break;
case VT_STRING:
strcpy(buf, cp_unquote(var->va_string));
break;
case VT_LIST: /* The tricky case. */
for (vt = var->va_vlist; vt; vt = vt->va_next) {
w = cp_varwl(vt);
if (wl == NULL)
wl = wx = w;
else {
wx->wl_next = w;
w->wl_prev = wx;
wx = w;
}
}
return (wl);
default:
fprintf(cp_err,
"cp_varwl: Internal Error: bad variable type %d\n",
var->va_type);
return (NULL);
}
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
wl->wl_word = copy(buf);
return (wl);
}
/* Set a variable. */
void
cp_vset(char *varname, char type, char *value)
{
struct variable *v, *u, *w;
int i;
bool alreadythere = FALSE;
varname = cp_unquote(varname);
w = NULL;
for (v = variables; v; v = v->va_next) {
if (eq(varname, v->va_name)) {
alreadythere = TRUE;
break;
}
w = v;
}
if (!v) {
v = alloc(struct variable);
v->va_name = copy(varname);
v->va_next = NULL;
}
switch (type) {
case VT_BOOL:
if (* ((bool *) value) == FALSE) {
cp_remvar(varname);
return;
} else
v->va_bool = TRUE;
break;
case VT_NUM:
v->va_num = * (int *) value;
break;
case VT_REAL:
v->va_real = * (double *) value;
break;
case VT_STRING:
v->va_string = copy(value);
break;
case VT_LIST:
v->va_vlist = (struct variable *) value;
break;
default:
fprintf(cp_err,
"cp_vset: Internal Error: bad variable type %d.\n",
type);
return;
}
v->va_type = type;
/* Now, see if there is anything interesting going on. We
* recognise these special variables: noglob, nonomatch, history,
* echo, noclobber, prompt, and verbose. cp_remvar looks for these
* variables too. The host program will get any others. */
if (eq(varname, "noglob"))
cp_noglob = TRUE;
else if (eq(varname, "nonomatch"))
cp_nonomatch = TRUE;
else if (eq(varname, "history") && (type == VT_NUM))
cp_maxhistlength = v->va_num;
else if (eq(varname, "history") && (type == VT_REAL))
cp_maxhistlength = v->va_real;
else if (eq(varname, "noclobber"))
cp_noclobber = TRUE;
else if (eq(varname, "prompt") && (type == VT_STRING))
cp_promptstring = copy(v->va_string);
else if (eq(varname, "ignoreeof"))
cp_ignoreeof = TRUE;
else if (eq(varname, "cpdebug")) {
cp_debug = TRUE;
#ifndef CPDEBUG
fprintf(cp_err,
"Warning: program not compiled with cshpar debug messages\n");
#endif
}
switch (i = cp_usrset(v, TRUE)) {
case US_OK:
/* Normal case. */
if (!alreadythere) {
v->va_next = variables;
variables = v;
}
break;
case US_DONTRECORD:
/* Do nothing... */
if (alreadythere) {
fprintf(cp_err, "cp_vset: Internal Error: "
"%s already there, but 'dont record'\n", v->va_name);
}
break;
case US_READONLY:
fprintf(cp_err, "Error: %s is a read-only variable.\n", v->va_name);
if (alreadythere)
fprintf(cp_err, "cp_vset: Internal Error: "
"it was already there too!!\n");
break;
case US_SIMVAR:
if (alreadythere) {
/* somehow it got into the front-end list of variables */
if (w) {
w->va_next = v->va_next;
} else {
variables = v->va_next;
}
}
alreadythere = FALSE;
if (ft_curckt) {
for (u = ft_curckt->ci_vars; u; u = u->va_next)
if (eq(varname, u->va_name)) {
alreadythere = TRUE;
break;
}
if (!alreadythere) {
v->va_next = ft_curckt->ci_vars;
ft_curckt->ci_vars = v;
} else {
w = u->va_next;
bcopy(v, u, sizeof(*u));
u->va_next = w;
}
}
break;
case US_NOSIMVAR:
/* What do you do? */
tfree(v);
break;
default:
fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i);
break;
}
return;
}
struct variable *
cp_setparse(wordlist *wl)
{
char *name, *val, *s, *ss;
double *td;
struct variable *listv = NULL, *vv, *lv = NULL;
struct variable *vars = NULL;
int balance;
while (wl) {
name = cp_unquote(wl->wl_word);
wl = wl->wl_next;
if (((wl == NULL) || (*wl->wl_word != '=')) &&
strchr(name, '=') == NULL) {
vv = alloc(struct variable);
vv->va_name = copy(name);
vv->va_type = VT_BOOL;
vv->va_bool = TRUE;
vv->va_next = vars;
vars = vv;
continue;
}
if (wl && eq(wl->wl_word, "=")) {
wl = wl->wl_next;
if (wl == NULL) {
fprintf(cp_err, "Error: bad set form.\n");
return (NULL);
}
val = wl->wl_word;
wl = wl->wl_next;
} else if (wl && (*wl->wl_word == '=')) {
val = wl->wl_word + 1;
wl = wl->wl_next;
} else if ((s =strchr(name, '='))) {
val = s + 1;
*s = '\0';
if (*val == '\0') {
if (!wl) {
fprintf(cp_err,
"Error: %s equals what?.\n",
name);
return (NULL);
} else {
val = wl->wl_word;
wl = wl->wl_next;
}
}
} else {
fprintf(cp_err, "Error: bad set form.\n");
return (NULL);
}
val = cp_unquote(val);
if (eq(val, "(")) { /* ) */
/* The beginning of a list... We have to walk down the
* list until we find a close paren... If there are nested
* ()'s, treat them as tokens... */
balance = 1;
while (wl && wl->wl_word) {
if (eq(wl->wl_word, "(")) {
balance++;
} else if (eq(wl->wl_word, ")")) {
if (!--balance)
break;
}
vv = alloc(struct variable);
vv->va_next = NULL;
ss = cp_unquote(wl->wl_word);
td = ft_numparse(&ss, FALSE);
if (td) {
vv->va_type = VT_REAL;
vv->va_real = *td;
} else {
vv->va_type = VT_STRING;
vv->va_string = copy(ss);
}
if (listv) {
lv->va_next = vv;
lv = vv;
} else
listv = lv = vv;
wl = wl->wl_next;
}
if (balance && !wl) {
fprintf(cp_err, "Error: bad set form.\n");
return (NULL);
}
vv = alloc(struct variable);
vv->va_name = copy(name);
vv->va_type = VT_LIST;
vv->va_vlist = listv;
vv->va_next = vars;
vars = vv;
wl = wl->wl_next;
continue;
}
ss = cp_unquote(val);
td = ft_numparse(&ss, FALSE);
vv = alloc(struct variable);
vv->va_name = copy(name);
vv->va_next = vars;
vars = vv;
if (td) {
/*** We should try to get VT_NUM's... */
vv->va_type = VT_REAL;
vv->va_real = *td;
} else {
vv->va_type = VT_STRING;
vv->va_string = copy(val);
}
}
return (vars);
}
void
cp_remvar(char *varname)
{
struct variable *v, *u, *lv = NULL;
bool found = TRUE;
int i;
for (v = variables; v; v = v->va_next) {
if (eq(v->va_name, varname))
break;
lv = v;
}
if (!v) {
/* Gotta make up a var struct for cp_usrset()... */
v = alloc(struct variable);
ZERO(v, struct variable);
v->va_name = varname;
v->va_type = VT_NUM;
v->va_bool = 0;
found = FALSE;
}
/* Note that 'unset history' doesn't do anything here... Causes
* trouble... */
if (eq(varname, "noglob"))
cp_noglob = FALSE;
else if (eq(varname, "nonomatch"))
cp_nonomatch = FALSE;
else if (eq(varname, "noclobber"))
cp_noclobber = FALSE;
else if (eq(varname, "prompt"))
cp_promptstring = "";
else if (eq(varname, "cpdebug"))
cp_debug = FALSE;
else if (eq(varname, "ignoreeof"))
cp_ignoreeof = FALSE;
switch (i = cp_usrset(v, FALSE)) {
case US_OK:
/* Normal case. */
if (found) {
if (lv)
lv->va_next = v->va_next;
else
variables = v->va_next;
}
break;
case US_DONTRECORD:
/* Do nothing... */
if (found)
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
break;
case US_READONLY:
/* Badness... */
fprintf(cp_err, "Error: %s is read-only.\n", v->va_name);
if (found)
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
break;
case US_SIMVAR:
lv = NULL;
if (ft_curckt) {
for (u = ft_curckt->ci_vars; u; u = u->va_next) {
if (eq(varname, u->va_name)) {
break;
}
lv = u;
}
if (u) {
if (lv)
lv->va_next = u->va_next;
else
ft_curckt->ci_vars = u->va_next;
tfree(u);
}
}
break;
default:
fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i);
break;
}
tfree(v);
return;
}
/* Determine the value of a variable. Fail if the variable is unset,
* and if the type doesn't match, try and make it work... */
bool
cp_getvar(char *name, int type, char *retval)
{
struct variable *v;
for (v = variables; v; v = v->va_next)
if (eq(name, v->va_name))
break;
if (v == NULL) {
if (type == VT_BOOL)
* (bool *) retval = FALSE;
return (FALSE);
}
if (v->va_type == type) {
switch (type) {
case VT_BOOL:
* (bool *) retval = TRUE;
break;
case VT_NUM: {
int *i;
i = (int *) retval;
*i = v->va_num;
break;
}
case VT_REAL: {
double *d;
d = (double *) retval;
*d = v->va_real;
break;
}
case VT_STRING: { /* Gotta be careful to have room. */
char *s;
s = cp_unquote(v->va_string);
cp_wstrip(s);
(void) strcpy(retval, s);
break;
}
case VT_LIST: { /* Funny case... */
struct variable **tv;
tv = (struct variable **) retval;
*tv = v->va_vlist;
break;
}
default:
fprintf(cp_err,
"cp_getvar: Internal Error: bad var type %d.\n",
type);
break;
}
return (TRUE);
} else {
/* Try to coerce it.. */
if ((type == VT_NUM) && (v->va_type == VT_REAL)) {
int *i;
i = (int *) retval;
*i = (int) v->va_real;
return (TRUE);
} else if ((type == VT_REAL) && (v->va_type == VT_NUM)) {
double *d;
d = (double *) retval;
*d = (double) v->va_num;
return (TRUE);
} else if ((type == VT_STRING) && (v->va_type == VT_NUM)) {
(void) sprintf(retval, "%d", v->va_num);
return (TRUE);
} else if ((type == VT_STRING) && (v->va_type == VT_REAL)) {
(void) sprintf(retval, "%f", v->va_real);
return (TRUE);
}
return (FALSE);
}
}
/* A variable substitution is indicated by a $, and the variable name
* is the following string of non-special characters. All variable
* values are inserted as a single word, except for lists, which are a
* list of words. A routine cp_usrset must be supplied by the host
* program to deal with variables that aren't used by cshpar -- it
* should be cp_usrset(var, isset), where var is a variable *, and
* isset is TRUE if the variable is being set, FALSE if unset. Also
* required is a routine cp_enqvar(name) which returns a struct
* variable *, which allows the host program to provide values for
* non-cshpar variables. */
char cp_dol = '$';
/* Non-alphanumeric characters that may appear in variable names. < is very
* special...
*/
#define VALIDCHARS "$-_<#?@.()[]&"
wordlist *
cp_variablesubst(wordlist *wlist)
{
wordlist *wl, *nwl;
char *s, *t, buf[BSIZE_SP], wbuf[BSIZE_SP], tbuf[BSIZE_SP];
/* MW. tbuf holds curret word after wl_splice() calls free() on it */
int i;
for (wl = wlist; wl; wl = wl->wl_next) {
t = wl->wl_word;
i = 0;
while ((s =strchr(t, cp_dol))) {
while (t < s)
wbuf[i++] = *t++;
wbuf[i] = '\0';
(void) strcpy(buf, ++s);
s = buf;
t++;
while (*s && (isalphanum(*s) ||
strchr(VALIDCHARS, *s))) {
/* Get s and t past the end of the var name. */
t++;
s++;
}
*s = '\0';
nwl = vareval(buf);
if (i) {
(void) strcpy(buf, wbuf);
if (nwl) {
(void) strcat(buf, nwl->wl_word);
tfree(nwl->wl_word);
} else {
nwl = alloc(struct wordlist);
nwl->wl_next = nwl->wl_prev = NULL;
}
nwl->wl_word = copy(buf);
}
(void) strcpy(tbuf, t); /* MW. Save t*/
if (!(wl = wl_splice(wl, nwl)))
return (NULL);
/* This is bad... */
for (wlist = wl; wlist->wl_prev; wlist = wlist->wl_prev)
;
(void) strcpy(buf, wl->wl_word);
i = strlen(buf);
(void) strcat(buf, tbuf); /* MW. tbuf is used here only */
tfree(wl->wl_word);
wl->wl_word = copy(buf);
t = &wl->wl_word[i];
s = wl->wl_word;
for (i = 0; s < t; s++)
wbuf[i++] = *s;
}
}
return (wlist);
}
/* Evaluate a variable. */
wordlist *
vareval(char *string)
{
struct variable *v;
wordlist *wl;
char buf[BSIZE_SP], *s;
char *oldstring = copy(string);
char *range = NULL;
int i, up, low;
cp_wstrip(string);
if ((s =strchr(string, '['))) {
*s = '\0';
range = s + 1;
}
switch (*string) {
case '$':
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
(void) sprintf(buf, "%d", getpid());
wl->wl_word = copy(buf);
return (wl);
case '<':
(void) fflush(cp_out);
if (!fgets(buf, BSIZE_SP, cp_in)) {
clearerr(cp_in);
(void) strcpy(buf, "EOF");
}
for (s = buf; *s && (*s != '\n'); s++)
;
*s = '\0';
wl = cp_lexer(buf);
/* This is a hack. */
if (!wl->wl_word)
wl->wl_word = copy("");
return (wl);
case '?':
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
string++;
for (v = variables; v; v = v->va_next)
if (eq(v->va_name, string))
break;
if (!v)
v = cp_enqvar(string);
wl->wl_word = copy(v ? "1" : "0");
return (wl);
case '#':
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
string++;
for (v = variables; v; v = v->va_next)
if (eq(v->va_name, string))
break;
if (!v)
v = cp_enqvar(string);
if (!v) {
fprintf(cp_err, "Error: %s: no such variable.\n",
string);
return (NULL);
}
if (v->va_type == VT_LIST)
for (v = v->va_vlist, i = 0; v; v = v->va_next)
i++;
else
i = (v->va_type != VT_BOOL);
(void) sprintf(buf, "%d", i);
wl->wl_word = copy(buf);
return (wl);
case '\0':
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
wl->wl_word = copy("$");
return (wl);
}
/* The notation var[stuff] has two meanings... If this is a real
* variable, then the [] denotes range, but if this is a strange
* (e.g, device parameter) variable, it could be anything...
*/
for (v = variables; v; v = v->va_next)
if (eq(v->va_name, string))
break;
if (!v && isdigit(*string)) {
for (v = variables; v; v = v->va_next)
if (eq(v->va_name, "argv"))
break;
range = string;
}
if (!v) {
range = NULL;
string = oldstring;
v = cp_enqvar(string);
}
if (!v && (s = getenv(string))) {
wl = alloc(struct wordlist);
wl->wl_next = wl->wl_prev = NULL;
wl->wl_word = copy(s);
return (wl);
}
if (!v) {
fprintf(cp_err, "Error: %s: no such variable.\n", string);
return (NULL);
}
wl = cp_varwl(v);
/* Now parse and deal with 'range' ... */
if (range) {
for (low = 0; isdigit(*range); range++)
low = low * 10 + *range - '0';
if ((*range == '-') && isdigit(range[1]))
for (up = 0, range++; isdigit(*range); range++)
up = up * 10 + *range - '0';
else if (*range == '-')
up = wl_length(wl);
else
up = low;
up--, low--;
wl = wl_range(wl, low, up);
}
return (wl);
}
static int
vcmp(const void *a, const void *b)
{
int i;
struct xxx *v1 = (struct xxx *) a;
struct xxx *v2 = (struct xxx *) b;
if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)))
return (i);
else
return (v1->x_char - v2->x_char);
}
/* Print the values of currently defined variables. */
void
cp_vprint(void)
{
struct variable *v;
struct variable *uv1, *uv2;
wordlist *wl;
int i, j;
char *s;
struct xxx *vars;
cp_usrvars(&uv1, &uv2);
for (v = uv1, i = 0; v; v = v->va_next)
i++;
for (v = uv2; v; v = v->va_next)
i++;
for (v = variables; v; v = v->va_next)
i++;
vars = (struct xxx *) tmalloc(sizeof (struct xxx) * i);
out_init();
for (v = variables, i = 0; v; v = v->va_next, i++) {
vars[i].x_v = v;
vars[i].x_char = ' ';
}
for (v = uv1; v; v = v->va_next, i++) {
vars[i].x_v = v;
vars[i].x_char = '*';
}
for (v = uv2; v; v = v->va_next, i++) {
vars[i].x_v = v;
vars[i].x_char = '+';
}
qsort((char *) vars, i, sizeof (struct xxx), vcmp);
for (j = 0; j < i; j++) {
if (j && eq(vars[j].x_v->va_name, vars[j - 1].x_v->va_name))
continue;
v = vars[j].x_v;
if (v->va_type == VT_BOOL) {
/* out_printf("%c %s\n", vars[j].x_char, v->va_name); */
sprintf(out_pbuf, "%c %s\n", vars[j].x_char, v->va_name);
out_send(out_pbuf);
} else {
out_printf("%c %s\t", vars[j].x_char, v->va_name);
wl = vareval(v->va_name);
s = wl_flatten(wl);
if (v->va_type == VT_LIST) {
out_printf("( %s )\n", s);
} else
out_printf("%s\n", s);
}
}
tfree(vars);
return;
}

53
src/frontend/variable.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef _VARIABLE_H
#define _VARIABLE_H
/* Variables that are accessible to the parser via $varname
* expansions. If the type is VT_LIST the value is a pointer to a
* list of the elements. */
struct variable {
char va_type;
char *va_name;
union {
bool vV_bool;
int vV_num;
double vV_real;
char *vV_string;
struct variable *vV_list;
} va_V;
struct variable *va_next; /* Link. */
} ;
#define va_bool va_V.vV_bool
#define va_num va_V.vV_num
#define va_real va_V.vV_real
#define va_string va_V.vV_string
#define va_vlist va_V.vV_list
enum vt_types {
VT_BOOL,
VT_NUM,
VT_REAL,
VT_STRING,
VT_LIST
};
struct xxx {
struct variable *x_v;
char x_char;
} ;
extern struct variable *variables;
// extern struct variable *variables;
wordlist * cp_varwl(struct variable *var);
void cp_vset(char *varname, char type, char *value);
struct variable * cp_setparse(wordlist *wl);
void cp_remvar(char *varname);
bool cp_getvar(char *name, int type, char *retval);
wordlist * cp_variablesubst(wordlist *wlist);
wordlist * vareval(char *string);
void cp_vprint(void);
#endif