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