67 changed files with 185 additions and 3199 deletions
-
6ChangeLog
-
1src/Makefile.am
-
2src/circuit/Makefile.am
-
18src/circuit/ifnewuid.c
-
27src/frontend/Makefile.am
-
4src/frontend/aspice.c
-
32src/frontend/circuits.h
-
3src/frontend/com_display.c
-
1src/frontend/com_hardcopy.c
-
15src/frontend/commands.c
-
3src/frontend/commands.h
-
1src/frontend/cpitf.c
-
2src/frontend/debugcom.c
-
4src/frontend/device.c
-
1src/frontend/diff.c
-
2src/frontend/display.c
-
2src/frontend/dotcards.c
-
2src/frontend/fourier.c
-
3src/frontend/inp.c
-
3src/frontend/inpcom.c
-
2src/frontend/linear.c
-
233src/frontend/misccoms.c
-
4src/frontend/mw_coms.c
-
3src/frontend/nutinp.c
-
4src/frontend/options.c
-
3src/frontend/outitf.c
-
4src/frontend/parse.c
-
2src/frontend/plotting/Makefile.am
-
2src/frontend/plotting/agraf.c
-
1src/frontend/plotting/graf.c
-
1src/frontend/plotting/plotcurv.c
-
3src/frontend/plotting/plotit.c
-
1src/frontend/plotting/x11.c
-
1src/frontend/plotting/xgraph.c
-
1src/frontend/postcoms.c
-
3src/frontend/postsc.c
-
3src/frontend/rawfile.c
-
6src/frontend/resource.c
-
4src/frontend/runcoms.c
-
4src/frontend/runcoms2.c
-
2src/frontend/shyu.c
-
2src/frontend/spec.c
-
4src/frontend/spiceif.c
-
3src/frontend/subckt.c
-
4src/frontend/vectors.c
-
3src/frontend/where.c
-
2src/help.c
-
3src/include/Makefile.am
-
6src/include/cpdefs.h
-
5src/include/cpextern.h
-
29src/include/ftedefs.h
-
22src/include/ftehelp.h
-
1src/include/plot.h
-
36src/include/variable.h
-
1src/main.c
-
35src/maths/cmaths/cmath4.c
-
326src/misc/terminal.c
-
16src/misc/terminal.h
-
21src/parser/cshpar.c
-
951src/parser/front.c
-
40src/parser/front.h
-
489src/parser/history.c
-
16src/parser/history.h
-
38src/parser/modify.c
-
478src/parser/var2.c
-
5src/parser/var2.h
-
429src/parser/variable.c
@ -1,22 +0,0 @@ |
|||
/********** |
|||
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 |
|||
@ -1,36 +0,0 @@ |
|||
#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 |
|||
}; |
|||
|
|||
|
|||
#endif |
|||
@ -1,326 +0,0 @@ |
|||
/********** |
|||
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 "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 |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
#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 |
|||
@ -1,951 +0,0 @@ |
|||
/********** |
|||
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 "front.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; |
|||
|
|||
|
|||
|
|||
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 |
|||
}; |
|||
|
|||
/* 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... |
|||
*/ |
|||
|
|||
#define CONTROLSTACKSIZE 256 /* Better be enough. */ |
|||
static struct control *control[CONTROLSTACKSIZE], *cend[CONTROLSTACKSIZE]; |
|||
|
|||
|
|||
/* static declarations */ |
|||
static char * doblock(struct control *bl, int *num); |
|||
static struct control * findlabel(char *s, struct control *ct); |
|||
static void docommand(register wordlist *wlist); |
|||
static wordlist * getcommand(char *string); |
|||
static void pwlist(wordlist *wlist, char *name); |
|||
static void dodump(struct control *cc); |
|||
|
|||
|
|||
static 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?? */ |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
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. */ |
|||
} |
|||
} |
|||
|
|||
/* 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); |
|||
} |
|||
|
|||
|
|||
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 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; |
|||
} |
|||
|
|||
|
|||
/* Note that we only do io redirection when we get to here - we also |
|||
* postpone some other things until now. */ |
|||
static void |
|||
docommand(register wordlist *wlist) |
|||
{ |
|||
register char *r, *s, *t; |
|||
char *lcom; |
|||
int nargs; |
|||
register 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; |
|||
} |
|||
|
|||
|
|||
/* 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); |
|||
} |
|||
|
|||
|
|||
/* 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; |
|||
} |
|||
|
|||
static int indent; |
|||
|
|||
|
|||
void |
|||
com_cdump(wordlist *wl) |
|||
{ |
|||
struct control *c; |
|||
|
|||
indent = 0; |
|||
for (c = control[stackp]; c; c = c->co_next) |
|||
dodump(c); |
|||
return; |
|||
} |
|||
|
|||
#define tab(num) for (i = 0; i < num; i++) putc(' ', cp_out); |
|||
|
|||
static void |
|||
dodump(struct control *cc) |
|||
{ |
|||
int i; |
|||
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; |
|||
} |
|||
|
|||
@ -1,40 +0,0 @@ |
|||
/************* |
|||
* Header file for front.c |
|||
* 1999 E. Rouat |
|||
************/ |
|||
|
|||
#ifndef FRONT_H_INCLUDED |
|||
#define FRONT_H_INCLUDED |
|||
|
|||
/* 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; |
|||
} ; |
|||
|
|||
int cp_evloop(char *string); |
|||
void cp_resetcontrol(void); |
|||
void cp_popcontrol(void); |
|||
void cp_pushcontrol(void); |
|||
void cp_toplevel(void); |
|||
void com_cdump(wordlist *wl); |
|||
|
|||
|
|||
|
|||
#endif |
|||
@ -1,489 +0,0 @@ |
|||
/********** |
|||
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 "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; |
|||
} |
|||
|
|||
@ -1,16 +0,0 @@ |
|||
/************* |
|||
* Header file for history.c |
|||
* 1999 E. Rouat |
|||
************/ |
|||
|
|||
#ifndef HISTORY_H_INCLUDED |
|||
#define HISTORY_H_INCLUDED |
|||
|
|||
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 |
|||
@ -1,38 +0,0 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group |
|||
**********/ |
|||
|
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice.h" |
|||
#include "cpdefs.h" |
|||
#include "modify.h" |
|||
|
|||
|
|||
char cp_chars[128]; |
|||
|
|||
static char *singlec = "<>;&"; |
|||
|
|||
/* Initialize stuff. */ |
|||
|
|||
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; |
|||
} |
|||
|
|||
@ -1,429 +0,0 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group |
|||
**********/ |
|||
|
|||
#include "ngspice.h" |
|||
#include "cpdefs.h" |
|||
#include "fteext.h" |
|||
#include "ftedefs.h" |
|||
#include "variable.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. */ |
|||
(void) sprintf(buf, "%s", var->va_bool ? "TRUE" : |
|||
"FALSE"); |
|||
break; |
|||
case VT_NUM: |
|||
(void) sprintf(buf, "%d", var->va_num); |
|||
break; |
|||
case VT_REAL: |
|||
/* This is a case where printnum isn't too good... */ |
|||
(void) sprintf(buf, "%G", var->va_real); |
|||
break; |
|||
case VT_STRING: |
|||
(void) 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; |
|||
|
|||
/* for (v = variables; v; v = v->va_next) ; printf("ok while setting %s\n", |
|||
varname);*/ |
|||
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; |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue