* src/frontend/com_ahelp.c src/frontend/com_ahelp.h
src/frontend/com_cdump.c src/frontend/com_cdump.h src/frontend/com_ghelp.c src/frontend/com_ghelp.h src/frontend/com_help.c src/frontend/com_help.h src/frontend/com_history.c src/frontend/com_history.h src/frontend/com_set.c src/frontend/com_shift.c src/frontend/com_strcmp.c src/frontend/com_strcmp.h src/frontend/com_unset.c src/frontend/control.c src/frontend/control.h src/frontend/ftehelp.h src/frontend/hcomp.c src/frontend/hcomp.h src/frontend/init.c src/frontend/init.h src/frontend/terminal.c src/frontend/terminal.h src/frontend/variable.c src/frontend/variable.h: New additions from the refactoring of the parser directory.
This commit is contained in:
parent
489fc66afd
commit
839ade8236
|
|
@ -0,0 +1,88 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
#include <fteext.h>
|
||||
|
||||
#include "variable.h"
|
||||
#include "com_help.h"
|
||||
#include "hcomp.h"
|
||||
#include "ftehelp.h"
|
||||
|
||||
#include "plotting/plotting.h"
|
||||
|
||||
|
||||
void
|
||||
com_ahelp(wordlist *wl)
|
||||
{
|
||||
int i, n;
|
||||
/* assert: number of commands must be less than 512 */
|
||||
struct comm *cc[512];
|
||||
int env = 0;
|
||||
struct comm *com;
|
||||
int level;
|
||||
char slevel[256];
|
||||
|
||||
if (wl) {
|
||||
com_help(wl);
|
||||
return;
|
||||
}
|
||||
|
||||
out_init();
|
||||
|
||||
/* determine environment */
|
||||
if (plot_list->pl_next) { /* plots load */
|
||||
env |= E_HASPLOTS;
|
||||
} else {
|
||||
env |= E_NOPLOTS;
|
||||
}
|
||||
|
||||
/* determine level */
|
||||
if (cp_getvar("level", VT_STRING, slevel)) {
|
||||
switch (*slevel) {
|
||||
case 'b': level = 1;
|
||||
break;
|
||||
case 'i': level = 2;
|
||||
break;
|
||||
case 'a': level = 4;
|
||||
break;
|
||||
default: level = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
out_printf(
|
||||
"For a complete description read the Spice3 User's Manual manual.\n");
|
||||
out_printf(
|
||||
"For a list of all commands type \"help all\", for a short\n");
|
||||
out_printf(
|
||||
"description of \"command\", type \"help command\".\n");
|
||||
|
||||
/* sort the commands */
|
||||
for (n = 0; cp_coms[n].co_func != (void (*)()) NULL; n++) {
|
||||
cc[n] = &cp_coms[n];
|
||||
}
|
||||
qsort((char *) cc, n, sizeof(struct comm *), hcomp);
|
||||
|
||||
/* filter the commands */
|
||||
for (i=0; i< n; i++) {
|
||||
com = cc[i];
|
||||
if ((com->co_env < (level << 13)) && (!(com->co_env & 4095) ||
|
||||
(env & com->co_env))) {
|
||||
if ((com->co_spiceonly && ft_nutmeg) ||
|
||||
(com->co_help == (char *) NULL)) {
|
||||
continue;
|
||||
}
|
||||
out_printf("%s ", com->co_comname);
|
||||
out_printf(com->co_help, cp_program);
|
||||
out_send("\n");
|
||||
}
|
||||
}
|
||||
|
||||
out_send("\n");
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _COM_AHELP_H
|
||||
#define _COM_AHELP_H
|
||||
|
||||
|
||||
void com_ahelp(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <wordlist.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "streams.h"
|
||||
|
||||
|
||||
static int indent;
|
||||
|
||||
|
||||
static void
|
||||
tab(int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
putc(' ', cp_out);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dodump(struct control *cc)
|
||||
{
|
||||
struct control *tc;
|
||||
|
||||
switch (cc->co_type) {
|
||||
case CO_UNFILLED:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "(unfilled)\n");
|
||||
break;
|
||||
case CO_STATEMENT:
|
||||
tab(indent);
|
||||
wl_print(cc->co_text, cp_out);
|
||||
putc('\n', cp_out);
|
||||
break;
|
||||
case CO_WHILE:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "while ");
|
||||
wl_print(cc->co_cond, cp_out);
|
||||
putc('\n', cp_out);
|
||||
indent += 8;
|
||||
for (tc = cc->co_children; tc; tc = tc->co_next)
|
||||
dodump(tc);
|
||||
indent -= 8;
|
||||
tab(indent);
|
||||
fprintf(cp_out, "end\n");
|
||||
break;
|
||||
case CO_REPEAT:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "repeat ");
|
||||
if (cc->co_numtimes != -1)
|
||||
fprintf(cp_out, "%d\n", cc->co_numtimes);
|
||||
else
|
||||
putc('\n', cp_out);
|
||||
indent += 8;
|
||||
for (tc = cc->co_children; tc; tc = tc->co_next)
|
||||
dodump(tc);
|
||||
indent -= 8;
|
||||
tab(indent);
|
||||
fprintf(cp_out, "end\n");
|
||||
break;
|
||||
case CO_DOWHILE:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "dowhile ");
|
||||
wl_print(cc->co_cond, cp_out);
|
||||
putc('\n', cp_out);
|
||||
indent += 8;
|
||||
for (tc = cc->co_children; tc; tc = tc->co_next)
|
||||
dodump(tc);
|
||||
indent -= 8;
|
||||
tab(indent);
|
||||
fprintf(cp_out, "end\n");
|
||||
break;
|
||||
case CO_IF:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "if ");
|
||||
wl_print(cc->co_cond, cp_out);
|
||||
putc('\n', cp_out);
|
||||
indent += 8;
|
||||
for (tc = cc->co_children; tc; tc = tc->co_next)
|
||||
dodump(tc);
|
||||
indent -= 8;
|
||||
tab(indent);
|
||||
fprintf(cp_out, "end\n");
|
||||
break;
|
||||
case CO_FOREACH:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "foreach %s ", cc->co_foreachvar);
|
||||
wl_print(cc->co_text, cp_out);
|
||||
putc('\n', cp_out);
|
||||
indent += 8;
|
||||
for (tc = cc->co_children; tc; tc = tc->co_next)
|
||||
dodump(tc);
|
||||
indent -= 8;
|
||||
tab(indent);
|
||||
fprintf(cp_out, "end\n");
|
||||
break;
|
||||
case CO_BREAK:
|
||||
tab(indent);
|
||||
if (cc->co_numtimes != 1)
|
||||
fprintf(cp_out, "break %d\n", cc->co_numtimes);
|
||||
else
|
||||
fprintf(cp_out, "break\n");
|
||||
break;
|
||||
case CO_CONTINUE:
|
||||
tab(indent);
|
||||
if (cc->co_numtimes != 1)
|
||||
fprintf(cp_out, "continue %d\n",
|
||||
cc->co_numtimes);
|
||||
else
|
||||
fprintf(cp_out, "continue\n");
|
||||
break;
|
||||
case CO_LABEL:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "label %s\n", cc->co_text->wl_word);
|
||||
break;
|
||||
case CO_GOTO:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "goto %s\n", cc->co_text->wl_word);
|
||||
break;
|
||||
default:
|
||||
tab(indent);
|
||||
fprintf(cp_out, "bad type %d\n", cc->co_type);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
com_cdump(wordlist *wl)
|
||||
{
|
||||
struct control *c;
|
||||
|
||||
indent = 0;
|
||||
for (c = control[stackp]; c; c = c->co_next)
|
||||
dodump(c);
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _COM_CDUMP_H
|
||||
#define _COM_CDUMP_H
|
||||
|
||||
void com_cdump(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#include <ngspice.h>
|
||||
#include <wordlist.h>
|
||||
#include <bool.h>
|
||||
#include <variable.h>
|
||||
#include <hlpdefs.h>
|
||||
|
||||
#include "com_ghelp.h"
|
||||
#include "com_help.h"
|
||||
#include "variable.h"
|
||||
#include "streams.h"
|
||||
|
||||
void
|
||||
com_ghelp(wordlist *wl)
|
||||
{
|
||||
char *npath;
|
||||
char *path = Help_Path;
|
||||
char buf[BSIZE_SP];
|
||||
int i;
|
||||
|
||||
if (cp_getvar("helppath", VT_STRING, buf))
|
||||
path = copy(buf);
|
||||
if (!path) {
|
||||
fprintf(cp_err, "Note: defaulting to old help.\n\n");
|
||||
com_help(wl);
|
||||
return;
|
||||
}
|
||||
if (!(npath = cp_tildexpand(path))) {
|
||||
fprintf(cp_err, "Note: can't find help dir %s\n", path);
|
||||
fprintf(cp_err, "Defaulting to old help.\n\n");
|
||||
com_help(wl);
|
||||
return;
|
||||
}
|
||||
path = npath;
|
||||
if (cp_getvar("helpregfont", VT_STRING, buf))
|
||||
hlp_regfontname = copy(buf);
|
||||
if (cp_getvar("helpboldfont", VT_STRING, buf))
|
||||
hlp_boldfontname = copy(buf);
|
||||
if (cp_getvar("helpitalicfont", VT_STRING, buf))
|
||||
hlp_italicfontname = copy(buf);
|
||||
if (cp_getvar("helptitlefont", VT_STRING, buf))
|
||||
hlp_titlefontname = copy(buf);
|
||||
if (cp_getvar("helpbuttonfont", VT_STRING, buf))
|
||||
hlp_buttonfontname = copy(buf);
|
||||
if (cp_getvar("helpinitxpos", VT_NUM, (char *) &i))
|
||||
hlp_initxpos = i;
|
||||
if (cp_getvar("helpinitypos", VT_NUM, (char *) &i))
|
||||
hlp_initypos = i;
|
||||
if (cp_getvar("helpbuttonstyle", VT_STRING, buf)) {
|
||||
if (cieq(buf, "left"))
|
||||
hlp_buttonstyle = BS_LEFT;
|
||||
else if (cieq(buf, "center"))
|
||||
hlp_buttonstyle = BS_CENTER;
|
||||
else if (cieq(buf, "unif"))
|
||||
hlp_buttonstyle = BS_UNIF;
|
||||
else
|
||||
fprintf(cp_err, "Warning: no such button style %s\n",
|
||||
buf);
|
||||
}
|
||||
if (cp_getvar("width", VT_NUM, (char *) &i))
|
||||
hlp_width = i;
|
||||
if (cp_getvar("display", VT_STRING, buf))
|
||||
hlp_displayname = copy(buf);
|
||||
else if (cp_getvar("device", VT_STRING, buf))
|
||||
hlp_displayname = copy(buf);
|
||||
else
|
||||
hlp_displayname = NULL;
|
||||
hlp_main(path, wl);
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _COM_GHELP_H
|
||||
#define _COM_GHELP_H
|
||||
|
||||
|
||||
void com_ghelp(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <macros.h>
|
||||
#include <wordlist.h>
|
||||
#include <cpdefs.h>
|
||||
#include <bool.h>
|
||||
|
||||
#include "hcomp.h"
|
||||
|
||||
|
||||
void
|
||||
com_help(wordlist *wl)
|
||||
{
|
||||
struct comm *c;
|
||||
struct comm *ccc[512]; /* Should be enough. */
|
||||
int numcoms, i;
|
||||
bool allflag = FALSE;
|
||||
|
||||
if (wl && eq(wl->wl_word, "all")) {
|
||||
allflag = TRUE;
|
||||
wl = NULL; /* XXX Probably right */
|
||||
}
|
||||
|
||||
/* We want to use more mode whether "moremode" is set or not. */
|
||||
out_moremode = TRUE;
|
||||
out_init();
|
||||
out_moremode = FALSE;
|
||||
if (wl == NULL) {
|
||||
out_printf("For a complete description "
|
||||
"read the Spice3 User's Manual.\n");
|
||||
|
||||
if (!allflag) {
|
||||
out_printf("For a list of all commands "
|
||||
"type \"help all\", for a short\n"
|
||||
"description of \"command\", "
|
||||
"type \"help command\".\n");
|
||||
}
|
||||
|
||||
/* Sort the commands */
|
||||
for (numcoms = 0; cp_coms[numcoms].co_func != NULL; numcoms++)
|
||||
ccc[numcoms] = &cp_coms[numcoms];
|
||||
qsort((char *) ccc, numcoms, sizeof (struct comm *), hcomp);
|
||||
|
||||
for (i = 0; i < numcoms; i++) {
|
||||
if ((ccc[i]->co_spiceonly && ft_nutmeg) ||
|
||||
(ccc[i]->co_help == NULL) ||
|
||||
(!allflag && !ccc[i]->co_major))
|
||||
continue;
|
||||
out_printf("%s ", ccc[i]->co_comname);
|
||||
out_printf(ccc[i]->co_help, cp_program);
|
||||
out_send("\n");
|
||||
}
|
||||
} else {
|
||||
while (wl != NULL) {
|
||||
for (c = &cp_coms[0]; c->co_func != NULL; c++)
|
||||
if (eq(wl->wl_word, c->co_comname)) {
|
||||
out_printf("%s ", c->co_comname);
|
||||
out_printf(c->co_help, cp_program);
|
||||
if (c->co_spiceonly && ft_nutmeg)
|
||||
out_send(" (Not available in nutmeg)");
|
||||
out_send("\n");
|
||||
break;
|
||||
}
|
||||
if (c->co_func == NULL) {
|
||||
/* See if this is aliased. */
|
||||
struct alias *al;
|
||||
|
||||
for (al = cp_aliases; al; al = al->al_next)
|
||||
if (eq(al->al_name, wl->wl_word))
|
||||
break;
|
||||
if (al == NULL)
|
||||
fprintf(cp_out, "Sorry, no help for %s.\n",
|
||||
wl->wl_word);
|
||||
else {
|
||||
out_printf("%s is aliased to ", wl->wl_word);
|
||||
/* Minor badness here... */
|
||||
wl_print(al->al_text, cp_out);
|
||||
out_send("\n");
|
||||
}
|
||||
}
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
out_send("\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _COM_HELP_H
|
||||
#define _COM_HELP_H
|
||||
|
||||
|
||||
void com_help(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
||||
**********/
|
||||
|
||||
/* Do history substitutions. */
|
||||
|
||||
#include <ngspice.h>
|
||||
#include <cpdefs.h>
|
||||
|
||||
#include "com_history.h"
|
||||
|
||||
|
||||
/* static declarations */
|
||||
static wordlist * dohsubst(char *string);
|
||||
static wordlist * dohmod(char **string, wordlist *wl);
|
||||
static wordlist * hpattern(char *buf);
|
||||
static wordlist * hprefix(char *buf);
|
||||
static wordlist * getevent(int num);
|
||||
static void freehist(int num);
|
||||
static char * dohs(char *pat, char *str);
|
||||
|
||||
|
||||
struct histent *cp_lastone = NULL;
|
||||
int cp_maxhistlength = 10000; /* Chris Inbody */
|
||||
char cp_hat = '^';
|
||||
char cp_bang = '!';
|
||||
bool cp_didhsubst;
|
||||
|
||||
static struct histent *histlist = NULL;
|
||||
static int histlength = 0;
|
||||
|
||||
/* First check for a ^ at the beginning
|
||||
* of the line, and then search each word for !. Following this can be any
|
||||
* of string, number, ?string, -number ; then there may be a word specifier,
|
||||
* the same as csh, and then the : modifiers. For the :s modifier,
|
||||
* the syntax is :sXoooXnnnX, where X is any character, and ooo and nnn are
|
||||
* strings not containing X.
|
||||
*/
|
||||
|
||||
wordlist *
|
||||
cp_histsubst(wordlist *wlist)
|
||||
{
|
||||
wordlist *nwl, *w, *n;
|
||||
char buf[BSIZE_SP], *s, *b;
|
||||
|
||||
/* Replace ^old^new with !:s^old^new. */
|
||||
|
||||
cp_didhsubst = FALSE;
|
||||
if (*wlist->wl_word == cp_hat) {
|
||||
(void) sprintf(buf, "%c%c:s%s", cp_bang, cp_bang,
|
||||
wlist->wl_word);
|
||||
tfree(wlist->wl_word);
|
||||
wlist->wl_word = copy(buf);
|
||||
}
|
||||
for (w = wlist; w; w = w->wl_next) {
|
||||
b = w->wl_word;
|
||||
for (s = b; *s; s++)
|
||||
if (*s == cp_bang) {
|
||||
cp_didhsubst = TRUE;
|
||||
n = dohsubst(s + 1);
|
||||
if (!n) {
|
||||
wlist->wl_word = NULL;
|
||||
return (wlist);
|
||||
}
|
||||
if (b < s) {
|
||||
(void) sprintf(buf, "%.*s%s", s - b, b,
|
||||
n->wl_word);
|
||||
tfree(n->wl_word);
|
||||
n->wl_word = copy(buf);
|
||||
}
|
||||
nwl = wl_splice(w, n);
|
||||
if (wlist == w)
|
||||
wlist = n;
|
||||
w = nwl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (wlist);
|
||||
}
|
||||
|
||||
/* Do a history substitution on one word. Figure out which event is
|
||||
* being referenced, then do word selections and modifications, and
|
||||
* then stick anything left over on the end of the last word.
|
||||
*/
|
||||
|
||||
static wordlist *
|
||||
dohsubst(char *string)
|
||||
{
|
||||
wordlist *wl, *nwl;
|
||||
char buf[BSIZE_SP], *s, *r = NULL, *t;
|
||||
|
||||
if (*string == cp_bang) {
|
||||
if (cp_lastone) {
|
||||
wl = cp_lastone->hi_wlist;
|
||||
string++;
|
||||
} else {
|
||||
fprintf(cp_err, "0: event not found.\n");
|
||||
return (NULL);
|
||||
}
|
||||
} else {
|
||||
switch(*string) {
|
||||
|
||||
case '-':
|
||||
wl = getevent(cp_event - scannum(++string));
|
||||
if (!wl)
|
||||
return (NULL);
|
||||
while (isdigit(*string))
|
||||
string++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
(void) strcpy(buf, string + 1);
|
||||
if ((s =strchr(buf, '?')))
|
||||
*s = '\0';
|
||||
wl = hpattern(buf);
|
||||
if (!wl)
|
||||
return (NULL);
|
||||
if (s == NULL) /* No modifiers on this one. */
|
||||
return (wl_copy(wl));
|
||||
break;
|
||||
|
||||
case '\0': /* Maybe this should be cp_event. */
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_word = copy("!");
|
||||
wl->wl_next = NULL;
|
||||
wl->wl_prev = NULL;
|
||||
cp_didhsubst = FALSE;
|
||||
return (wl);
|
||||
|
||||
default:
|
||||
if (isdigit(*string)) {
|
||||
wl = getevent(scannum(string));
|
||||
if (!wl)
|
||||
return (NULL);
|
||||
while (isdigit(*string))
|
||||
string++;
|
||||
} else {
|
||||
(void) strcpy(buf, string);
|
||||
for (s = ":^$*-%"; *s; s++) {
|
||||
t =strchr(buf, *s);
|
||||
if (t && ((t < r) || !r)) {
|
||||
r = t;
|
||||
string += r - buf;
|
||||
}
|
||||
}
|
||||
if (r)
|
||||
*r = '\0';
|
||||
else
|
||||
while (*string)
|
||||
string++;
|
||||
if ((buf[0] == '\0') && cp_lastone)
|
||||
wl = cp_lastone->hi_wlist;
|
||||
else
|
||||
wl = hprefix(buf);
|
||||
if (!wl)
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wl == NULL) { /* Shouldn't happen. */
|
||||
fprintf(cp_err, "Event not found.\n");
|
||||
return (NULL);
|
||||
}
|
||||
nwl = dohmod(&string, wl_copy(wl));
|
||||
if (!nwl)
|
||||
return (NULL);
|
||||
if (*string) {
|
||||
for (wl = nwl; wl->wl_next; wl = wl->wl_next)
|
||||
;
|
||||
(void) sprintf(buf, "%s%s", wl->wl_word, string);
|
||||
tfree(wl->wl_word);
|
||||
wl->wl_word = copy(buf);
|
||||
}
|
||||
return (nwl);
|
||||
}
|
||||
|
||||
static wordlist *
|
||||
dohmod(char **string, wordlist *wl)
|
||||
{
|
||||
wordlist *w;
|
||||
char *s;
|
||||
char *r = NULL, *t;
|
||||
int numwords, eventlo, eventhi, i;
|
||||
bool globalsubst;
|
||||
|
||||
anothermod:
|
||||
numwords = wl_length(wl);
|
||||
globalsubst = FALSE;
|
||||
eventlo = 0;
|
||||
eventhi = numwords - 1;
|
||||
|
||||
/* Now we know what wordlist we want. Take care of modifiers now. */
|
||||
r = NULL;
|
||||
for (s = ":^$*-%"; *s; s++) {
|
||||
t =strchr(*string, *s);
|
||||
if (t && ((t < r) || (r == NULL)))
|
||||
r = t;
|
||||
}
|
||||
if (!r) /* No more modifiers. */
|
||||
return (wl);
|
||||
|
||||
*string = r;
|
||||
if (**string == ':')
|
||||
(*string)++;
|
||||
|
||||
switch(**string) {
|
||||
case '$': /* Last word. */
|
||||
eventhi = eventlo = numwords - 1;
|
||||
break;
|
||||
case '*': /* Words 1 through $ */
|
||||
if (numwords == 1)
|
||||
return (NULL);
|
||||
eventlo = 1;
|
||||
eventhi = numwords - 1;
|
||||
break;
|
||||
case '-': /* Words 0 through ... */
|
||||
eventlo = 0;
|
||||
if (*(*string + 1))
|
||||
eventhi = scannum(*string + 1);
|
||||
else
|
||||
eventhi = numwords - 1;
|
||||
if (eventhi > numwords - 1)
|
||||
eventhi = numwords - 1;
|
||||
break;
|
||||
case 'p': /* Print the command and don't execute it.
|
||||
* This doesn't work quite like csh.
|
||||
*/
|
||||
wl_print(wl, cp_out);
|
||||
(void) putc('\n', cp_out);
|
||||
return (NULL);
|
||||
case 's': /* Do a substitution. */
|
||||
for (w = wl; w; w = w->wl_next) {
|
||||
s = dohs(*string + 1, w->wl_word);
|
||||
if (s) {
|
||||
tfree(w->wl_word);
|
||||
w->wl_word = s;
|
||||
if (globalsubst == FALSE) {
|
||||
while (**string)
|
||||
(*string)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* In case globalsubst is TRUE... */
|
||||
while (**string)
|
||||
(*string)++;
|
||||
break;
|
||||
default:
|
||||
if (!isdigit(**string)) {
|
||||
fprintf(cp_err, "Error: %s: bad modifier.\n",
|
||||
*string);
|
||||
return (NULL);
|
||||
}
|
||||
i = scannum(*string);
|
||||
if (i > eventhi) {
|
||||
fprintf(cp_err, "Error: bad event number %d\n",
|
||||
i);
|
||||
return (NULL);
|
||||
}
|
||||
eventhi = eventlo = i;
|
||||
while (isdigit(**string))
|
||||
(*string)++;
|
||||
if (**string == '*')
|
||||
eventhi = numwords - 1;
|
||||
if (**string == '-') {
|
||||
if (!isdigit(*(*string + 1)))
|
||||
eventhi = numwords - 1;
|
||||
else {
|
||||
eventhi = scannum(++*string);
|
||||
while (isdigit(**string))
|
||||
(*string)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now change the word list accordingly and make another pass
|
||||
* if there is more of the substitute left.
|
||||
*/
|
||||
|
||||
wl = wl_range(wl, eventlo, eventhi);
|
||||
numwords = wl_length(wl);
|
||||
if (**string && *++*string)
|
||||
goto anothermod;
|
||||
return (wl);
|
||||
}
|
||||
|
||||
/* Look for an event with a pattern in it... */
|
||||
|
||||
static wordlist *
|
||||
hpattern(char *buf)
|
||||
{
|
||||
struct histent *hi;
|
||||
wordlist *wl;
|
||||
|
||||
if (*buf == '\0') {
|
||||
fprintf(cp_err, "Bad pattern specification.\n");
|
||||
return (NULL);
|
||||
}
|
||||
for (hi = cp_lastone; hi; hi = hi->hi_prev)
|
||||
for (wl = hi->hi_wlist; wl; wl = wl->wl_next)
|
||||
if (substring(buf, wl->wl_word))
|
||||
return (hi->hi_wlist);
|
||||
fprintf(cp_err, "%s: event not found.\n", buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static wordlist *
|
||||
hprefix(char *buf)
|
||||
{
|
||||
struct histent *hi;
|
||||
|
||||
if (*buf == '\0') {
|
||||
fprintf(cp_err, "Bad pattern specification.\n");
|
||||
return (NULL);
|
||||
}
|
||||
for (hi = cp_lastone; hi; hi = hi->hi_prev)
|
||||
if (hi->hi_wlist && prefix(buf, hi->hi_wlist->wl_word))
|
||||
return (hi->hi_wlist);
|
||||
fprintf(cp_err, "%s: event not found.\n", buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Add a wordlist to the history list. (Done after the first parse.) Note
|
||||
* that if event numbers are given in a random order that's how they'll
|
||||
* show up in the history list.
|
||||
*/
|
||||
|
||||
void
|
||||
cp_addhistent(int event, wordlist *wlist)
|
||||
{
|
||||
if (cp_lastone && !cp_lastone->hi_wlist)
|
||||
fprintf(cp_err, "Internal error: bad history list\n");
|
||||
if (cp_lastone == NULL) {
|
||||
cp_lastone = histlist = alloc(struct histent);
|
||||
cp_lastone->hi_prev = NULL;
|
||||
} else {
|
||||
cp_lastone->hi_next = alloc(struct histent);
|
||||
cp_lastone->hi_next->hi_prev = cp_lastone;
|
||||
cp_lastone = cp_lastone->hi_next;
|
||||
}
|
||||
cp_lastone->hi_next = NULL;
|
||||
cp_lastone->hi_event = event;
|
||||
cp_lastone->hi_wlist = wl_copy(wlist);
|
||||
freehist(histlength - cp_maxhistlength);
|
||||
histlength++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get a copy of the wordlist associated with an event. Error if out
|
||||
* of range.
|
||||
*/
|
||||
|
||||
static wordlist *
|
||||
getevent(int num)
|
||||
{
|
||||
struct histent *hi;
|
||||
|
||||
for (hi = histlist; hi; hi = hi->hi_next)
|
||||
if (hi->hi_event == num)
|
||||
break;
|
||||
if (hi == NULL) {
|
||||
fprintf(cp_err, "%d: event not found.\n", num);
|
||||
return (NULL);
|
||||
}
|
||||
return (wl_copy(hi->hi_wlist));
|
||||
}
|
||||
|
||||
/* Print out history between eventhi and eventlo.
|
||||
* This doesn't remember quoting, so 'hodedo' prints as hodedo.
|
||||
*/
|
||||
|
||||
void
|
||||
cp_hprint(int eventhi, int eventlo, bool rev)
|
||||
{
|
||||
struct histent *hi;
|
||||
|
||||
if (rev) {
|
||||
for (hi = histlist; hi->hi_next; hi = hi->hi_next)
|
||||
;
|
||||
for (; hi; hi = hi->hi_prev)
|
||||
if ((hi->hi_event <= eventhi) &&
|
||||
(hi->hi_event >= eventlo) &&
|
||||
hi->hi_wlist) {
|
||||
fprintf(cp_out, "%d\t", hi->hi_event);
|
||||
wl_print(hi->hi_wlist, cp_out);
|
||||
(void) putc('\n', cp_out);
|
||||
}
|
||||
} else {
|
||||
for (hi = histlist; hi; hi = hi->hi_next)
|
||||
if ((hi->hi_event <= eventhi) &&
|
||||
(hi->hi_event >= eventlo) &&
|
||||
hi->hi_wlist) {
|
||||
fprintf(cp_out, "%d\t", hi->hi_event);
|
||||
wl_print(hi->hi_wlist, cp_out);
|
||||
(void) putc('\n', cp_out);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* This just gets rid of the first num entries on the history list, and
|
||||
* decrements histlength.
|
||||
*/
|
||||
|
||||
static void
|
||||
freehist(int num)
|
||||
{
|
||||
struct histent *hi;
|
||||
|
||||
if (num < 1)
|
||||
return;
|
||||
histlength -= num;
|
||||
hi = histlist;
|
||||
while (num-- && histlist->hi_next)
|
||||
histlist = histlist->hi_next;
|
||||
if (histlist->hi_prev) {
|
||||
histlist->hi_prev->hi_next = NULL;
|
||||
histlist->hi_prev = NULL;
|
||||
} else
|
||||
{
|
||||
fprintf(cp_err, "Internal error: history list mangled\n");
|
||||
exit(0); /* Chris Inbody */
|
||||
}
|
||||
while (hi->hi_next) {
|
||||
wl_free(hi->hi_wlist);
|
||||
hi = hi->hi_next;
|
||||
tfree(hi->hi_prev);
|
||||
}
|
||||
wl_free(hi->hi_wlist);
|
||||
tfree(hi);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do a :s substitution. */
|
||||
|
||||
static char *
|
||||
dohs(char *pat, char *str)
|
||||
{
|
||||
char schar, *s, *p, buf[BSIZE_SP];
|
||||
int i = 0, plen;
|
||||
bool ok = FALSE;
|
||||
|
||||
pat = copy(pat); /* Don't want to mangle anything. */
|
||||
schar = *pat++;
|
||||
s =strchr(pat, schar);
|
||||
if (s == NULL) {
|
||||
fprintf(cp_err, "Bad substitute.\n");
|
||||
return (NULL);
|
||||
}
|
||||
*s++ = '\0';
|
||||
p =strchr(s, schar);
|
||||
if (p)
|
||||
*p = '\0';
|
||||
plen = strlen(pat) - 1;
|
||||
for (i = 0; *str; str++) {
|
||||
if ((*str == *pat) && prefix(pat, str) && (ok == FALSE)) {
|
||||
for (p = s; *p; p++)
|
||||
buf[i++] = *p;
|
||||
str += plen;
|
||||
ok = TRUE;
|
||||
} else
|
||||
buf[i++] = *str;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
if (ok)
|
||||
return (copy(buf));
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* The "history" command. history [-r] [number] */
|
||||
|
||||
void
|
||||
com_history(wordlist *wl)
|
||||
{
|
||||
bool rev = FALSE;
|
||||
|
||||
if (wl && eq(wl->wl_word, "-r")) {
|
||||
wl = wl->wl_next;
|
||||
rev = TRUE;
|
||||
}
|
||||
if (wl == NULL)
|
||||
cp_hprint(cp_event - 1, cp_event - histlength, rev);
|
||||
else
|
||||
cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/*************
|
||||
* Header file for history.c
|
||||
* 1999 E. Rouat
|
||||
************/
|
||||
|
||||
#ifndef _COM_HISTORY_H
|
||||
#define _COM_HISTORY_H
|
||||
|
||||
wordlist * cp_histsubst(wordlist *wlist);
|
||||
void cp_addhistent(int event, wordlist *wlist);
|
||||
void cp_hprint(int eventhi, int eventlo, bool rev);
|
||||
void com_history(wordlist *wl);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include <config.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
/* The set command. Syntax is set [opt ...] [opt = val ...]. Val may
|
||||
* be a string, an int, a float, or a list of the form (elt1 elt2
|
||||
* ...). */
|
||||
void
|
||||
com_set(wordlist *wl)
|
||||
{
|
||||
struct variable *vars;
|
||||
char *s;
|
||||
|
||||
if (wl == NULL) {
|
||||
cp_vprint();
|
||||
return;
|
||||
}
|
||||
vars = cp_setparse(wl);
|
||||
|
||||
/* This is sort of a hassle... */
|
||||
while (vars) {
|
||||
switch (vars->va_type) {
|
||||
case VT_BOOL:
|
||||
s = (char *) &vars->va_bool;
|
||||
break;
|
||||
case VT_NUM:
|
||||
s = (char *) &vars->va_num;
|
||||
break;
|
||||
case VT_REAL:
|
||||
s = (char *) &vars->va_real;
|
||||
break;
|
||||
case VT_STRING:
|
||||
s = vars->va_string;
|
||||
break;
|
||||
case VT_LIST:
|
||||
s = (char *) vars->va_vlist;
|
||||
break;
|
||||
default:
|
||||
s = (char *) NULL;
|
||||
}
|
||||
cp_vset(vars->va_name, vars->va_type, s);
|
||||
vars = vars->va_next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#include <config.h>
|
||||
#include <ngspice.h>
|
||||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
|
||||
#include "variable.h"
|
||||
#include "streams.h"
|
||||
|
||||
|
||||
/* Shift a list variable, by default argv, one to the left (or more if
|
||||
* a second argument is given. */
|
||||
void
|
||||
com_shift(wordlist *wl)
|
||||
{
|
||||
struct variable *v, *vv;
|
||||
char *n = "argv";
|
||||
int num = 1;
|
||||
|
||||
if (wl) {
|
||||
n = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
if (wl)
|
||||
num = scannum(wl->wl_word);
|
||||
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(v->va_name, n))
|
||||
break;
|
||||
if (!v) {
|
||||
fprintf(cp_err, "Error: %s: no such variable\n", n);
|
||||
return;
|
||||
}
|
||||
if (v->va_type != VT_LIST) {
|
||||
fprintf(cp_err, "Error: %s not of type list\n", n);
|
||||
return;
|
||||
}
|
||||
for (vv = v->va_vlist; vv && (num > 0); num--)
|
||||
vv = vv->va_next;
|
||||
if (num) {
|
||||
fprintf(cp_err, "Error: variable %s not long enough\n", n);
|
||||
return;
|
||||
}
|
||||
|
||||
v->va_vlist = vv;
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
|
||||
#include "com_strcmp.h"
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
/* This is a truly evil thing */
|
||||
void
|
||||
com_strcmp(wordlist *wl)
|
||||
{
|
||||
char *var, *s1, *s2;
|
||||
int i;
|
||||
|
||||
var = wl->wl_word;
|
||||
s1 = cp_unquote(wl->wl_next->wl_word);
|
||||
s2 = cp_unquote(wl->wl_next->wl_next->wl_word);
|
||||
|
||||
i = strcmp(s1, s2);
|
||||
|
||||
cp_vset(var, VT_NUM, (char *) &i);
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _COM_STRCMP_H
|
||||
#define _COM_STRCMP_H
|
||||
|
||||
|
||||
void com_strcmp(wordlist *wl);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#include <config.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <macros.h>
|
||||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
void
|
||||
com_unset(wordlist *wl)
|
||||
{
|
||||
char *name;
|
||||
struct variable *var, *nv;
|
||||
|
||||
if (eq(wl->wl_word, "*")) {
|
||||
for (var = variables; var; var = nv) {
|
||||
nv = var->va_next;
|
||||
cp_remvar(var->va_name);
|
||||
}
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
while (wl != NULL) {
|
||||
name = wl->wl_word;
|
||||
cp_remvar(name);
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,799 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
||||
**********/
|
||||
|
||||
/* The front-end command loop. */
|
||||
|
||||
#include <ngspice.h>
|
||||
#include <cpdefs.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "com_cdump.h"
|
||||
#include "variable.h"
|
||||
|
||||
/* Return values from doblock(). I am assuming that nobody will use
|
||||
* these characters in a string. */
|
||||
#define NORMAL '\001'
|
||||
#define BROKEN '\002'
|
||||
#define CONTINUED '\003'
|
||||
#define NORMAL_STR "\001"
|
||||
#define BROKEN_STR "\002"
|
||||
#define CONTINUED_STR "\003"
|
||||
|
||||
/* Are we waiting for a command? This lets signal handling be
|
||||
* more clever. */
|
||||
|
||||
bool cp_cwait = FALSE;
|
||||
char *cp_csep = ";";
|
||||
|
||||
bool cp_dounixcom = FALSE;
|
||||
|
||||
/* We have to keep the control structures in a stack, so that when we
|
||||
* do a 'source', we can push a fresh set onto the top... Actually
|
||||
* there have to be two stacks -- one for the pointer to the list of
|
||||
* control structs, and one for the 'current command' pointer... */
|
||||
struct control *control[CONTROLSTACKSIZE];
|
||||
struct control *cend[CONTROLSTACKSIZE];
|
||||
int stackp = 0;
|
||||
|
||||
|
||||
/* If there is an argument, give this to cshpar to use instead of
|
||||
* stdin. In a few places, we call cp_evloop again if it returns 1 and
|
||||
* exit (or close a file) if it returns 0... Because of the way
|
||||
* sources are done, we can't allow the control structures to get
|
||||
* blown away every time we return -- probably every time we type
|
||||
* source at the keyboard and every time a source returns to keyboard
|
||||
* input is ok though -- use ft_controlreset. */
|
||||
|
||||
static char *noredirect[] = { "stop", NULL } ; /* Only one?? */
|
||||
|
||||
|
||||
static struct control *
|
||||
findlabel(char *s, struct control *ct)
|
||||
{
|
||||
while (ct) {
|
||||
if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word))
|
||||
break;
|
||||
ct = ct->co_next;
|
||||
}
|
||||
return (ct);
|
||||
}
|
||||
|
||||
|
||||
/* This is also in cshpar.c ... */
|
||||
static void
|
||||
pwlist(wordlist *wlist, char *name)
|
||||
{
|
||||
wordlist *wl;
|
||||
|
||||
if (!cp_debug)
|
||||
return;
|
||||
fprintf(cp_err, "%s : [ ", name);
|
||||
for (wl = wlist; wl; wl = wl->wl_next)
|
||||
fprintf(cp_err, "%s ", wl->wl_word);
|
||||
fprintf(cp_err, "]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Note that we only do io redirection when we get to here - we also
|
||||
* postpone some other things until now. */
|
||||
static void
|
||||
docommand(wordlist *wlist)
|
||||
{
|
||||
char *r, *s, *t;
|
||||
char *lcom;
|
||||
int nargs;
|
||||
int i;
|
||||
struct comm *command;
|
||||
wordlist *wl, *nextc, *ee, *rwlist;
|
||||
|
||||
if (cp_debug) {
|
||||
printf("docommand ");
|
||||
wl_print(wlist, stdout);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
|
||||
/* Do all the things that used to be done by cshpar when the line
|
||||
* was read... */
|
||||
wlist = cp_variablesubst(wlist);
|
||||
pwlist(wlist, "After variable substitution");
|
||||
|
||||
wlist = cp_bquote(wlist);
|
||||
pwlist(wlist, "After backquote substitution");
|
||||
|
||||
wlist = cp_doglob(wlist);
|
||||
pwlist(wlist, "After globbing");
|
||||
|
||||
if (!wlist || !wlist->wl_word)
|
||||
return;
|
||||
|
||||
/* Now loop through all of the commands given. */
|
||||
rwlist = wlist;
|
||||
do {
|
||||
for (nextc = wlist; nextc; nextc = nextc->wl_next)
|
||||
if (eq(nextc->wl_word, cp_csep))
|
||||
break;
|
||||
|
||||
/* Temporarily hide the rest of the command... */
|
||||
if (nextc && nextc->wl_prev)
|
||||
nextc->wl_prev->wl_next = NULL;
|
||||
ee = wlist->wl_prev;
|
||||
if (ee)
|
||||
wlist->wl_prev = NULL;
|
||||
|
||||
if (nextc == wlist) {
|
||||
/* There was no text... */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* And do the redirection. */
|
||||
cp_ioreset();
|
||||
for (i = 0; noredirect[i]; i++)
|
||||
if (eq(wlist->wl_word, noredirect[i]))
|
||||
break;
|
||||
if (!noredirect[i]) {
|
||||
if (!(wlist = cp_redirect(wlist))) {
|
||||
cp_ioreset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get rid of all the 8th bits now... */
|
||||
cp_striplist(wlist);
|
||||
|
||||
s = wlist->wl_word;
|
||||
|
||||
/* Look for the command in the command list. */
|
||||
for (i = 0; cp_coms[i].co_comname; i++) {
|
||||
/* strcmp(cp_coms[i].co_comname, s) ... */
|
||||
for (t = cp_coms[i].co_comname, r = s; *t && *r;
|
||||
t++, r++)
|
||||
if (*t != *r)
|
||||
break;
|
||||
if (!*t && !*r)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now give the user-supplied command routine a try... */
|
||||
if (!cp_coms[i].co_func && cp_oddcomm(s, wlist->wl_next))
|
||||
goto out;
|
||||
|
||||
/* If it's not there, try it as a unix command. */
|
||||
if (!cp_coms[i].co_comname) {
|
||||
if (cp_dounixcom && cp_unixcom(wlist))
|
||||
goto out;
|
||||
fprintf(cp_err,"%s: no such command available in %s\n",
|
||||
s, cp_program);
|
||||
goto out;
|
||||
|
||||
/* If it's there but spiceonly, and this is nutmeg, error. */
|
||||
} else if (!cp_coms[i].co_func && ft_nutmeg &&
|
||||
(cp_coms[i].co_spiceonly)) {
|
||||
fprintf(cp_err,"%s: command available only in spice\n",
|
||||
s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The command was a valid spice/nutmeg command. */
|
||||
command = &cp_coms[i];
|
||||
nargs = 0;
|
||||
for (wl = wlist->wl_next; wl; wl = wl->wl_next)
|
||||
nargs++;
|
||||
if (command->co_stringargs) {
|
||||
lcom = wl_flatten(wlist->wl_next);
|
||||
(*command->co_func) (lcom);
|
||||
} else {
|
||||
if (nargs < command->co_minargs) {
|
||||
if (command->co_argfn) {
|
||||
(*command->co_argfn) (wlist->wl_next, command);
|
||||
} else {
|
||||
fprintf(cp_err, "%s: too few args.\n", s);
|
||||
}
|
||||
} else if (nargs > command->co_maxargs) {
|
||||
fprintf(cp_err, "%s: too many args.\n", s);
|
||||
} else
|
||||
(*command->co_func) (wlist->wl_next);
|
||||
}
|
||||
|
||||
/* Now fix the pointers and advance wlist. */
|
||||
out: wlist->wl_prev = ee;
|
||||
if (nextc) {
|
||||
if (nextc->wl_prev)
|
||||
nextc->wl_prev->wl_next = nextc;
|
||||
wlist = nextc->wl_next;
|
||||
}
|
||||
} while (nextc && wlist);
|
||||
|
||||
wl_free(rwlist);
|
||||
|
||||
/* Do periodic sorts of things... */
|
||||
cp_periodic();
|
||||
|
||||
cp_ioreset();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Execute a block. There can be a number of return values from this routine.
|
||||
* NORMAL indicates a normal termination
|
||||
* BROKEN indicates a break -- if the caller is a breakable loop,
|
||||
* terminate it, otherwise pass the break upwards
|
||||
* CONTINUED indicates a continue -- if the caller is a continuable loop,
|
||||
* continue, else pass the continue upwards
|
||||
* Any other return code is considered a pointer to a string which is
|
||||
* a label somewhere -- if this label is present in the block,
|
||||
* goto it, otherwise pass it up. Note that this prevents jumping
|
||||
* into a loop, which is good.
|
||||
*
|
||||
* Note that here is where we expand variables, ``, and globs for
|
||||
* controls.
|
||||
*
|
||||
* The 'num' argument is used by break n and continue n. */
|
||||
static char *
|
||||
doblock(struct control *bl, int *num)
|
||||
{
|
||||
struct control *ch, *cn = NULL;
|
||||
wordlist *wl;
|
||||
char *i;
|
||||
int nn;
|
||||
|
||||
switch (bl->co_type) {
|
||||
case CO_WHILE:
|
||||
while (bl->co_cond && cp_isTRUE(bl->co_cond)) {
|
||||
for (ch = bl->co_children; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
switch (*i) {
|
||||
|
||||
case NORMAL:
|
||||
break;
|
||||
|
||||
case BROKEN: /* Break. */
|
||||
if (nn < 2)
|
||||
return (NORMAL_STR);
|
||||
else {
|
||||
*num = nn - 1;
|
||||
return (BROKEN_STR);
|
||||
}
|
||||
|
||||
case CONTINUED: /* Continue. */
|
||||
if (nn < 2) {
|
||||
cn = NULL;
|
||||
break;
|
||||
} else {
|
||||
*num = nn - 1;
|
||||
return (CONTINUED_STR);
|
||||
}
|
||||
|
||||
default:
|
||||
cn = findlabel(i, bl->co_children);
|
||||
if (!cn)
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CO_DOWHILE:
|
||||
do {
|
||||
for (ch = bl->co_children; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
switch (*i) {
|
||||
|
||||
case NORMAL:
|
||||
break;
|
||||
|
||||
case BROKEN: /* Break. */
|
||||
if (nn < 2)
|
||||
return (NORMAL_STR);
|
||||
else {
|
||||
*num = nn - 1;
|
||||
return (BROKEN_STR);
|
||||
}
|
||||
|
||||
case CONTINUED: /* Continue. */
|
||||
if (nn < 2) {
|
||||
cn = NULL;
|
||||
break;
|
||||
} else {
|
||||
*num = nn - 1;
|
||||
return (CONTINUED_STR);
|
||||
}
|
||||
|
||||
default:
|
||||
cn = findlabel(i, bl->co_children);
|
||||
if (!cn)
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
} while (bl->co_cond && cp_isTRUE(bl->co_cond));
|
||||
break;
|
||||
|
||||
case CO_REPEAT:
|
||||
while ((bl->co_numtimes > 0) ||
|
||||
(bl->co_numtimes == -1)) {
|
||||
if (bl->co_numtimes != -1)
|
||||
bl->co_numtimes--;
|
||||
for (ch = bl->co_children; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
switch (*i) {
|
||||
|
||||
case NORMAL:
|
||||
break;
|
||||
|
||||
case BROKEN: /* Break. */
|
||||
if (nn < 2)
|
||||
return (NORMAL_STR);
|
||||
else {
|
||||
*num = nn - 1;
|
||||
return (BROKEN_STR);
|
||||
}
|
||||
|
||||
case CONTINUED: /* Continue. */
|
||||
if (nn < 2) {
|
||||
cn = NULL;
|
||||
break;
|
||||
} else {
|
||||
*num = nn - 1;
|
||||
return (CONTINUED_STR);
|
||||
}
|
||||
|
||||
default:
|
||||
cn = findlabel(i, bl->co_children);
|
||||
if (!cn)
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CO_IF:
|
||||
if (bl->co_cond && cp_isTRUE(bl->co_cond)) {
|
||||
for (ch = bl->co_children; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
if (*i > 2) {
|
||||
cn = findlabel(i,
|
||||
bl->co_children);
|
||||
if (!cn)
|
||||
return (i);
|
||||
} else if (*i != NORMAL) {
|
||||
*num = nn;
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ch = bl->co_elseblock; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
if (*i > 2) {
|
||||
cn = findlabel(i,
|
||||
bl->co_elseblock);
|
||||
if (!cn)
|
||||
return (i);
|
||||
} else if (*i != NORMAL) {
|
||||
*num = nn;
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CO_FOREACH:
|
||||
for (wl = cp_variablesubst(cp_bquote(cp_doglob(wl_copy(bl->co_text))));
|
||||
wl;
|
||||
wl = wl->wl_next) {
|
||||
cp_vset(bl->co_foreachvar, VT_STRING, wl->wl_word);
|
||||
for (ch = bl->co_children; ch; ch = cn) {
|
||||
cn = ch->co_next;
|
||||
i = doblock(ch, &nn);
|
||||
switch (*i) {
|
||||
|
||||
case NORMAL:
|
||||
break;
|
||||
|
||||
case BROKEN: /* Break. */
|
||||
if (nn < 2)
|
||||
return (NORMAL_STR);
|
||||
else {
|
||||
*num = nn - 1;
|
||||
return (BROKEN_STR);
|
||||
}
|
||||
|
||||
case CONTINUED: /* Continue. */
|
||||
if (nn < 2) {
|
||||
cn = NULL;
|
||||
break;
|
||||
} else {
|
||||
*num = nn - 1;
|
||||
return (CONTINUED_STR);
|
||||
}
|
||||
|
||||
default:
|
||||
cn = findlabel(i, bl->co_children);
|
||||
if (!cn)
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CO_BREAK:
|
||||
if (bl->co_numtimes > 0) {
|
||||
*num = bl->co_numtimes;
|
||||
return (BROKEN_STR);
|
||||
} else {
|
||||
fprintf(cp_err, "Warning: break %d a no-op\n",
|
||||
bl->co_numtimes);
|
||||
return (NORMAL_STR);
|
||||
}
|
||||
|
||||
case CO_CONTINUE:
|
||||
if (bl->co_numtimes > 0) {
|
||||
*num = bl->co_numtimes;
|
||||
return (CONTINUED_STR);
|
||||
} else {
|
||||
fprintf(cp_err, "Warning: continue %d a no-op\n",
|
||||
bl->co_numtimes);
|
||||
return (NORMAL_STR);
|
||||
}
|
||||
|
||||
case CO_GOTO:
|
||||
wl = cp_variablesubst(cp_bquote(cp_doglob(
|
||||
wl_copy(bl->co_text))));
|
||||
return (wl->wl_word);
|
||||
|
||||
case CO_LABEL:
|
||||
/* Do nothing. */
|
||||
break;
|
||||
|
||||
case CO_STATEMENT:
|
||||
docommand(wl_copy(bl->co_text));
|
||||
break;
|
||||
|
||||
case CO_UNFILLED:
|
||||
/* There was probably an error here... */
|
||||
fprintf(cp_err, "Warning: ignoring previous error\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(cp_err,
|
||||
"doblock: Internal Error: bad block type %d\n",
|
||||
bl->co_type);
|
||||
return (NORMAL_STR);
|
||||
}
|
||||
return (NORMAL_STR);
|
||||
}
|
||||
|
||||
|
||||
/* Get a command. This does all the bookkeeping things like turning
|
||||
* command completion on and off... */
|
||||
static wordlist *
|
||||
getcommand(char *string)
|
||||
{
|
||||
wordlist *wlist;
|
||||
int i = 0, j;
|
||||
static char buf[64];
|
||||
struct control *c;
|
||||
|
||||
if (cp_debug)
|
||||
fprintf(cp_err, "calling getcommand %s\n",
|
||||
string ? string : "");
|
||||
if (cend[stackp]) {
|
||||
for (c = cend[stackp]->co_parent; c; c = c->co_parent)
|
||||
i++;
|
||||
if (i) {
|
||||
for (j = 0; j < i; j++)
|
||||
buf[j] = '>';
|
||||
buf[j] = ' ';
|
||||
buf[j + 1] = '\0';
|
||||
cp_altprompt = buf;
|
||||
} else
|
||||
cp_altprompt = NULL;
|
||||
} else
|
||||
cp_altprompt = NULL;
|
||||
|
||||
cp_cwait = TRUE;
|
||||
wlist = cp_parse(string);
|
||||
cp_cwait = FALSE;
|
||||
if (cp_debug) {
|
||||
printf("getcommand ");
|
||||
wl_print(wlist, stdout);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
return (wlist);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cp_evloop(char *string)
|
||||
{
|
||||
wordlist *wlist, *ww;
|
||||
struct control *x;
|
||||
char *i;
|
||||
int nn;
|
||||
|
||||
#define newblock cend[stackp]->co_children = alloc(struct control); \
|
||||
ZERO(cend[stackp]->co_children,struct control), \
|
||||
cend[stackp]->co_children->co_parent = cend[stackp]; \
|
||||
cend[stackp] = cend[stackp]->co_children; \
|
||||
cend[stackp]->co_type = CO_UNFILLED;
|
||||
|
||||
for (;;) {
|
||||
wlist = getcommand(string);
|
||||
if (wlist == NULL) { /* End of file or end of user input. */
|
||||
if (cend[stackp]->co_parent && !string) {
|
||||
cp_resetcontrol();
|
||||
continue;
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
if ((wlist->wl_word == NULL) || (*wlist->wl_word == '\0')) {
|
||||
/* User just typed return. */
|
||||
if (string)
|
||||
return (1);
|
||||
else {
|
||||
cp_event--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Just a check... */
|
||||
for (ww = wlist; ww; ww = ww->wl_next)
|
||||
if (!ww->wl_word) {
|
||||
fprintf(cp_err,
|
||||
"cp_evloop: Internal Error: NULL word pointer\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* Add this to the control structure list. If cend->co_type is
|
||||
* CO_UNFILLED, the last line was the beginning of a block,
|
||||
* and this is the unfilled first statement. */
|
||||
if (cend[stackp] && (cend[stackp]->co_type != CO_UNFILLED)) {
|
||||
cend[stackp]->co_next = alloc(struct control);
|
||||
ZERO(cend[stackp]->co_next, struct control);
|
||||
cend[stackp]->co_next->co_prev = cend[stackp];
|
||||
cend[stackp]->co_next->co_parent =
|
||||
cend[stackp]->co_parent;
|
||||
cend[stackp] = cend[stackp]->co_next;
|
||||
} else if (!cend[stackp]) {
|
||||
control[stackp] = cend[stackp] = alloc(struct control);
|
||||
ZERO(cend[stackp], struct control);
|
||||
}
|
||||
|
||||
if (eq(wlist->wl_word, "while")) {
|
||||
cend[stackp]->co_type = CO_WHILE;
|
||||
cend[stackp]->co_cond = wlist->wl_next;
|
||||
if (!cend[stackp]->co_cond) {
|
||||
fprintf(stderr,
|
||||
"Error: missing while condition.\n");
|
||||
}
|
||||
newblock;
|
||||
} else if (eq(wlist->wl_word, "dowhile")) {
|
||||
cend[stackp]->co_type = CO_DOWHILE;
|
||||
cend[stackp]->co_cond = wlist->wl_next;
|
||||
if (!cend[stackp]->co_cond) {
|
||||
fprintf(stderr,
|
||||
"Error: missing dowhile condition.\n");
|
||||
}
|
||||
newblock;
|
||||
} else if (eq(wlist->wl_word, "repeat")) {
|
||||
cend[stackp]->co_type = CO_REPEAT;
|
||||
if (!wlist->wl_next) {
|
||||
cend[stackp]->co_numtimes = -1;
|
||||
} else {
|
||||
char *s;
|
||||
double *dd;
|
||||
wlist = cp_variablesubst(cp_bquote(
|
||||
cp_doglob(wl_copy(wlist))));
|
||||
s = wlist->wl_next->wl_word;
|
||||
|
||||
dd = ft_numparse(&s, FALSE);
|
||||
if (dd) {
|
||||
if (*dd < 0) {
|
||||
fprintf(cp_err,
|
||||
"Error: can't repeat a negative number of times\n");
|
||||
*dd = 0.0;
|
||||
}
|
||||
cend[stackp]->co_numtimes = (int) *dd;
|
||||
} else
|
||||
fprintf(cp_err,
|
||||
"Error: bad repeat argument %s\n",
|
||||
wlist->wl_next->wl_word);
|
||||
}
|
||||
newblock;
|
||||
} else if (eq(wlist->wl_word, "if")) {
|
||||
cend[stackp]->co_type = CO_IF;
|
||||
cend[stackp]->co_cond = wlist->wl_next;
|
||||
if (!cend[stackp]->co_cond) {
|
||||
fprintf(stderr,
|
||||
"Error: missing if condition.\n");
|
||||
}
|
||||
newblock;
|
||||
} else if (eq(wlist->wl_word, "foreach")) {
|
||||
cend[stackp]->co_type = CO_FOREACH;
|
||||
if (wlist->wl_next) {
|
||||
wlist = wlist->wl_next;
|
||||
cend[stackp]->co_foreachvar =
|
||||
copy(wlist->wl_word);
|
||||
wlist = wlist->wl_next;
|
||||
} else
|
||||
fprintf(stderr,
|
||||
"Error: missing foreach variable.\n");
|
||||
wlist = cp_doglob(wlist);
|
||||
cend[stackp]->co_text = wl_copy(wlist);
|
||||
newblock;
|
||||
} else if (eq(wlist->wl_word, "label")) {
|
||||
cend[stackp]->co_type = CO_LABEL;
|
||||
if (wlist->wl_next) {
|
||||
cend[stackp]->co_text = wl_copy(wlist->wl_next);
|
||||
/* I think of everything, don't I? */
|
||||
cp_addkword(CT_LABEL, wlist->wl_next->wl_word);
|
||||
if (wlist->wl_next->wl_next)
|
||||
fprintf(cp_err,
|
||||
"Warning: ignored extra junk after label.\n");
|
||||
} else
|
||||
fprintf(stderr, "Error: missing label.\n");
|
||||
} else if (eq(wlist->wl_word, "goto")) {
|
||||
/* Incidentally, this won't work if the values 1 and 2 ever get
|
||||
* to be valid character pointers -- I think it's reasonably
|
||||
* safe to assume they aren't... */
|
||||
cend[stackp]->co_type = CO_GOTO;
|
||||
if (wlist->wl_next) {
|
||||
cend[stackp]->co_text = wl_copy(wlist->wl_next);
|
||||
if (wlist->wl_next->wl_next)
|
||||
fprintf(cp_err,
|
||||
"Warning: ignored extra junk after goto.\n");
|
||||
} else
|
||||
fprintf(stderr, "Error: missing label.\n");
|
||||
} else if (eq(wlist->wl_word, "continue")) {
|
||||
cend[stackp]->co_type = CO_CONTINUE;
|
||||
if (wlist->wl_next) {
|
||||
cend[stackp]->co_numtimes = scannum(wlist->
|
||||
wl_next->wl_word);
|
||||
if (wlist->wl_next->wl_next)
|
||||
fprintf(cp_err,
|
||||
"Warning: ignored extra junk after continue %d.\n",
|
||||
cend[stackp]->co_numtimes);
|
||||
} else
|
||||
cend[stackp]->co_numtimes = 1;
|
||||
} else if (eq(wlist->wl_word, "break")) {
|
||||
cend[stackp]->co_type = CO_BREAK;
|
||||
if (wlist->wl_next) {
|
||||
cend[stackp]->co_numtimes = scannum(wlist->
|
||||
wl_next->wl_word);
|
||||
if (wlist->wl_next->wl_next)
|
||||
fprintf(cp_err,
|
||||
"Warning: ignored extra junk after break %d.\n",
|
||||
cend[stackp]->co_numtimes);
|
||||
} else
|
||||
cend[stackp]->co_numtimes = 1;
|
||||
} else if (eq(wlist->wl_word, "end")) {
|
||||
/* Throw away this thing. */
|
||||
if (!cend[stackp]->co_parent) {
|
||||
fprintf(stderr, "Error: no block to end.\n");
|
||||
cend[stackp]->co_type = CO_UNFILLED;
|
||||
} else if (cend[stackp]->co_prev) {
|
||||
cend[stackp]->co_prev->co_next = NULL;
|
||||
x = cend[stackp];
|
||||
cend[stackp] = cend[stackp]->co_parent;
|
||||
tfree(x);
|
||||
} else {
|
||||
x = cend[stackp];
|
||||
cend[stackp] = cend[stackp]->co_parent;
|
||||
cend[stackp]->co_children = NULL;
|
||||
tfree(x);
|
||||
}
|
||||
} else if (eq(wlist->wl_word, "else")) {
|
||||
if (!cend[stackp]->co_parent ||
|
||||
(cend[stackp]->co_parent->co_type !=
|
||||
CO_IF)) {
|
||||
fprintf(stderr, "Error: misplaced else.\n");
|
||||
cend[stackp]->co_type = CO_UNFILLED;
|
||||
} else {
|
||||
if (cend[stackp]->co_prev)
|
||||
cend[stackp]->co_prev->co_next = NULL;
|
||||
else
|
||||
cend[stackp]->co_parent->co_children = NULL;
|
||||
cend[stackp]->co_parent->co_elseblock = cend[stackp];
|
||||
cend[stackp]->co_prev = NULL;
|
||||
}
|
||||
} else {
|
||||
cend[stackp]->co_type = CO_STATEMENT;
|
||||
cend[stackp]->co_text = wlist;
|
||||
}
|
||||
if (!cend[stackp]->co_parent) {
|
||||
x = cend[stackp];
|
||||
/* We have to toss this do-while loop in here so
|
||||
* that gotos at the top level will work.
|
||||
*/
|
||||
do {
|
||||
i = doblock(x, &nn);
|
||||
switch (*i) {
|
||||
case NORMAL:
|
||||
break;
|
||||
case BROKEN:
|
||||
fprintf(cp_err,
|
||||
"Error: break not in loop or too many break levels given\n");
|
||||
break;
|
||||
case CONTINUED:
|
||||
fprintf(cp_err,
|
||||
"Error: continue not in loop or too many continue levels given\n");
|
||||
break;
|
||||
default:
|
||||
x = findlabel(i, control[stackp]);
|
||||
if (!x)
|
||||
fprintf(cp_err, "Error: label %s not found\n", i);
|
||||
}
|
||||
if (x)
|
||||
x = x->co_next;
|
||||
} while (x);
|
||||
}
|
||||
if (string)
|
||||
return (1); /* The return value is irrelevant. */
|
||||
}
|
||||
}
|
||||
|
||||
/* This blows away the control structures... */
|
||||
void
|
||||
cp_resetcontrol(void)
|
||||
{
|
||||
if (cend[stackp] && cend[stackp]->co_parent)
|
||||
fprintf(cp_err, "Warning: EOF before block terminated\n");
|
||||
/* We probably should free the control structures... */
|
||||
control[0] = cend[0] = NULL;
|
||||
stackp = 0;
|
||||
cp_kwswitch(CT_LABEL, (char *) NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Push or pop a new control structure set... */
|
||||
void
|
||||
cp_popcontrol(void)
|
||||
{
|
||||
if (cp_debug)
|
||||
fprintf(cp_err, "pop: stackp: %d -> %d\n", stackp, stackp - 1);
|
||||
if (stackp < 1)
|
||||
fprintf(cp_err, "cp_popcontrol: Internal Error: stack empty\n");
|
||||
else
|
||||
stackp--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cp_pushcontrol(void)
|
||||
{
|
||||
if (cp_debug)
|
||||
fprintf(cp_err, "push: stackp: %d -> %d\n", stackp, stackp + 1);
|
||||
if (stackp > CONTROLSTACKSIZE - 2) {
|
||||
fprintf(cp_err, "Error: stack overflow -- max depth = %d\n",
|
||||
CONTROLSTACKSIZE);
|
||||
stackp = 0;
|
||||
} else {
|
||||
stackp++;
|
||||
control[stackp] = cend[stackp] = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* And this returns to the top level (for use in the interrupt handlers). */
|
||||
void
|
||||
cp_toplevel(void)
|
||||
{
|
||||
stackp = 0;
|
||||
if (cend[stackp])
|
||||
while (cend[stackp]->co_parent)
|
||||
cend[stackp] = cend[stackp]->co_parent;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef _CONTROL_H
|
||||
#define _CONTROL_H
|
||||
|
||||
|
||||
/* Stuff to do control structures. We keep a history (seperate from
|
||||
* the cshpar history, for now at least) of commands and their event
|
||||
* numbers, with a block considered as a statement. In a goto, the
|
||||
* first word in co_text is where to go, likewise for label. For
|
||||
* conditional controls, we have to call ft_getpnames and ft_evaluate
|
||||
* each time, since the dvec pointers will change... Also we should do
|
||||
* variable and backquote substitution each time... */
|
||||
struct control {
|
||||
int co_type; /* One of CO_* ... */
|
||||
wordlist *co_cond; /* if, while, dowhile */
|
||||
char *co_foreachvar; /* foreach */
|
||||
int co_numtimes; /* repeat, break & continue levels */
|
||||
wordlist *co_text; /* Ordinary text and foreach values. */
|
||||
struct control *co_parent; /* If this is inside a block. */
|
||||
struct control *co_children; /* The contents of this block. */
|
||||
struct control *co_elseblock; /* For if-then-else. */
|
||||
struct control *co_next;
|
||||
struct control *co_prev;
|
||||
} ;
|
||||
|
||||
enum co_command {
|
||||
CO_UNFILLED,
|
||||
CO_STATEMENT,
|
||||
CO_WHILE,
|
||||
CO_DOWHILE,
|
||||
CO_IF,
|
||||
CO_FOREACH,
|
||||
CO_BREAK,
|
||||
CO_CONTINUE,
|
||||
CO_LABEL,
|
||||
CO_GOTO,
|
||||
CO_REPEAT
|
||||
};
|
||||
|
||||
#define CONTROLSTACKSIZE 256 /* Better be enough. */
|
||||
|
||||
extern struct control *control[CONTROLSTACKSIZE];
|
||||
extern struct control *cend[CONTROLSTACKSIZE];
|
||||
extern int stackp;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1987 Jeffrey M. Hsu
|
||||
**********/
|
||||
|
||||
/*
|
||||
|
||||
Defines for help.
|
||||
*/
|
||||
|
||||
#define E_HASPLOTS 1
|
||||
#define E_NOPLOTS 2
|
||||
#define E_HASGRAPHS 4
|
||||
#define E_MENUMODE 8
|
||||
|
||||
#define E_BEGINNING 4096
|
||||
#define E_INTERMED 8192
|
||||
#define E_ADVANCED 16384
|
||||
#define E_ALWAYS 32768
|
||||
|
||||
/* default is intermediate level */
|
||||
#define E_DEFHMASK 8192
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include <cpdefs.h>
|
||||
|
||||
int
|
||||
hcomp(const void *a, const void *b)
|
||||
{
|
||||
struct comm **c1 = (struct comm **) a;
|
||||
struct comm **c2 = (struct comm **) b;
|
||||
return (strcmp((*c1)->co_comname, (*c2)->co_comname));
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _HCOMP_H
|
||||
#define _HCOMP_H
|
||||
|
||||
|
||||
int hcomp(const void *a, const void *b);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
||||
**********/
|
||||
|
||||
/* Initialize stuff. */
|
||||
|
||||
#include <ngspice.h>
|
||||
#include <cpdefs.h>
|
||||
|
||||
#include "init.h"
|
||||
#include "variable.h"
|
||||
|
||||
|
||||
char cp_chars[128];
|
||||
|
||||
static char *singlec = "<>;&";
|
||||
|
||||
void
|
||||
cp_init(void)
|
||||
{
|
||||
char *s, *getenv(const char *);
|
||||
|
||||
bzero(cp_chars, 128);
|
||||
for (s = singlec; *s; s++)
|
||||
cp_chars[(int) *s] = (CPC_BRR | CPC_BRL);
|
||||
cp_vset("history", VT_NUM, (char *) &cp_maxhistlength);
|
||||
|
||||
cp_curin = stdin;
|
||||
cp_curout = stdout;
|
||||
cp_curerr = stderr;
|
||||
|
||||
cp_ioreset();
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _INIT_H
|
||||
#define _INIT_H
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
|
||||
**********/
|
||||
|
||||
/*
|
||||
* Routines to handle "more"d output. There are some serious system
|
||||
* dependencies in here, and it isn't clear that versions of this stuff
|
||||
* can be written for every possible machine...
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_SGTTY_H
|
||||
#include <sgtty.h>
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Bad interaction with bool type in bool.h because curses also
|
||||
defines this symbol. */
|
||||
#ifdef HAVE_TERMCAP
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <ngspice.h>
|
||||
#include <cpdefs.h>
|
||||
|
||||
#include "variable.h"
|
||||
#include "terminal.h"
|
||||
|
||||
static char *motion_chars;
|
||||
static char *clear_chars;
|
||||
static char *home_chars;
|
||||
static char *cleol_chars;
|
||||
|
||||
|
||||
#define DEF_SCRHEIGHT 24
|
||||
#define DEF_SCRWIDTH 80
|
||||
|
||||
bool out_moremode = TRUE;
|
||||
bool out_isatty = TRUE;
|
||||
|
||||
static int xsize, ysize;
|
||||
static int xpos, ypos;
|
||||
static bool noprint, nopause;
|
||||
|
||||
|
||||
/* out_printf doesn't handle double arguments correctly, so we
|
||||
sprintf into this buf and call out_send w/ it */
|
||||
char out_pbuf[BSIZE_SP];
|
||||
|
||||
/* Start output... */
|
||||
|
||||
void
|
||||
out_init(void)
|
||||
{
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize ws;
|
||||
#endif
|
||||
bool moremode;
|
||||
|
||||
noprint = nopause = FALSE;
|
||||
|
||||
if (cp_getvar("nomoremode", VT_BOOL, (char *) &moremode))
|
||||
out_moremode = FALSE;
|
||||
else
|
||||
out_moremode = TRUE;
|
||||
if (!out_moremode || !cp_interactive)
|
||||
out_isatty = FALSE;
|
||||
|
||||
if (!out_isatty)
|
||||
return;
|
||||
|
||||
xsize = ysize = 0;
|
||||
|
||||
/* Figure out the screen size. We try, in order, TIOCGSIZE,
|
||||
* tgetent(), and cp_getvar(height). Default is 24 x 80.
|
||||
*/
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
if (!xsize || !ysize) {
|
||||
(void) ioctl(fileno(stdout), TIOCGWINSZ, (char *) &ws);
|
||||
xsize = ws.ws_col;
|
||||
ysize = ws.ws_row;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!xsize)
|
||||
(void) cp_getvar("width", VT_NUM, (char *) &xsize);
|
||||
if (!ysize)
|
||||
(void) cp_getvar("height", VT_NUM, (char *) &ysize);
|
||||
|
||||
if (!xsize)
|
||||
xsize = DEF_SCRWIDTH;
|
||||
if (!ysize)
|
||||
ysize = DEF_SCRHEIGHT;
|
||||
ysize -= 2; /* Fudge room... */
|
||||
xpos = ypos = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Putc may not be buffered (sp?), so we do it ourselves. */
|
||||
|
||||
static char staticbuf[BUFSIZ];
|
||||
struct {
|
||||
int count;
|
||||
char *ptr;
|
||||
} ourbuf = { BUFSIZ, staticbuf };
|
||||
|
||||
/* send buffer out */
|
||||
void
|
||||
outbufputc(void)
|
||||
{
|
||||
|
||||
if (ourbuf.count != BUFSIZ) {
|
||||
fputs(staticbuf, cp_out);
|
||||
memset(staticbuf, 0, BUFSIZ-ourbuf.count);
|
||||
ourbuf.count = BUFSIZ;
|
||||
ourbuf.ptr = staticbuf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
bufputc(char c)
|
||||
{
|
||||
if (--ourbuf.count >= 0) {
|
||||
*ourbuf.ptr++ = c;
|
||||
} else {
|
||||
/* Flush and reset the buffer */
|
||||
outbufputc();
|
||||
/* and store the character. */
|
||||
ourbuf.count--;
|
||||
*ourbuf.ptr++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* prompt for a return */
|
||||
void
|
||||
promptreturn(void)
|
||||
{
|
||||
char buf[16];
|
||||
moe:
|
||||
fprintf(cp_out,
|
||||
"\n\t-- hit return for more, ? for help -- ");
|
||||
if (!fgets(buf, 16, cp_in)) {
|
||||
clearerr(cp_in);
|
||||
*buf = 'q';
|
||||
}
|
||||
switch (*buf) {
|
||||
case '\n':
|
||||
break;
|
||||
case 'q':
|
||||
noprint = TRUE;
|
||||
break;
|
||||
case 'c':
|
||||
nopause = TRUE;
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
case '?':
|
||||
fprintf(cp_out,
|
||||
"\nPossible responses:\n\
|
||||
\t<cr> : Print another screenful\n\
|
||||
\tq <cr> : Discard the rest of the output\n\
|
||||
\tc <cr> : Continuously print the rest of the output\n\
|
||||
\t? <cr> : Print this help message\n");
|
||||
goto moe;
|
||||
default:
|
||||
fprintf(cp_out, "Character %d is no good\n", *buf);
|
||||
goto moe;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Print a string to the output. If this would cause the screen to scroll,
|
||||
* print "more".
|
||||
*/
|
||||
|
||||
void
|
||||
out_send(char *string)
|
||||
{
|
||||
|
||||
if (noprint)
|
||||
return;
|
||||
if (!out_isatty || nopause) {
|
||||
fputs(string, cp_out);
|
||||
return;
|
||||
}
|
||||
while (*string) {
|
||||
switch (*string) {
|
||||
case '\n':
|
||||
xpos = 0;
|
||||
ypos++;
|
||||
break;
|
||||
case '\f':
|
||||
ypos = ysize;
|
||||
xpos = 0;
|
||||
break;
|
||||
case '\t':
|
||||
xpos = xpos / 8 + 1;
|
||||
xpos *= 8;
|
||||
break;
|
||||
default:
|
||||
xpos++;
|
||||
break;
|
||||
}
|
||||
while (xpos >= xsize) {
|
||||
xpos -= xsize;
|
||||
ypos++;
|
||||
}
|
||||
if (ypos >= ysize) {
|
||||
outbufputc(); /* out goes buffer */
|
||||
promptreturn();
|
||||
(void) fflush(cp_out);
|
||||
ypos = xpos = 0;
|
||||
}
|
||||
bufputc(*string); /* we need to buffer these */
|
||||
string++;
|
||||
}
|
||||
(void) outbufputc();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Printf some stuff using more mode. */
|
||||
|
||||
#define MAXLEN 4096
|
||||
|
||||
|
||||
void
|
||||
out_printf(char *fmt, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6, char *s7, char *s8, char *s9, char *s10)
|
||||
{
|
||||
char buf[MAXLEN];
|
||||
|
||||
sprintf(buf, fmt, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
|
||||
|
||||
out_send(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
outfn(int c)
|
||||
{
|
||||
putc(c, stdout);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tcap_init(void)
|
||||
{
|
||||
char *s;
|
||||
#ifdef HAVE_TERMCAP
|
||||
char tbuf[1025];
|
||||
static char buf2[100];
|
||||
char *charbuf;
|
||||
|
||||
charbuf = buf2;
|
||||
|
||||
if ((s = getenv("TERM"))) {
|
||||
if (tgetent(tbuf, s) != -1) {
|
||||
xsize = tgetnum("co");
|
||||
ysize = tgetnum("li");
|
||||
if ((xsize <= 0) || (ysize <= 0))
|
||||
xsize = ysize = 0;
|
||||
clear_chars = (char *) tgetstr("cl", &charbuf);
|
||||
motion_chars = (char *) tgetstr("cm", &charbuf);
|
||||
home_chars = (char *) tgetstr("ho", &charbuf);
|
||||
cleol_chars = (char *) tgetstr("ce", &charbuf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!xsize) {
|
||||
if ((s = getenv("COLS")))
|
||||
xsize = atoi(s);
|
||||
if (xsize <= 0)
|
||||
xsize = 0;
|
||||
}
|
||||
|
||||
if (!ysize) {
|
||||
if ((s = getenv("LINES")))
|
||||
ysize = atoi(s);
|
||||
if (ysize <= 0)
|
||||
ysize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_clear(void)
|
||||
{
|
||||
#ifdef HAVE_TERMCAP
|
||||
if (*clear_chars)
|
||||
tputs(clear_chars, 1, outfn);
|
||||
else
|
||||
fputs("\n", stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_home(void)
|
||||
{
|
||||
#ifdef HAVE_TERMCAP
|
||||
if (*home_chars)
|
||||
tputs(home_chars, 1, outfn);
|
||||
else if (*motion_chars)
|
||||
tputs(tgoto(motion_chars, 1, 1), 1, outfn);
|
||||
else
|
||||
fputs("\n", stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_cleol(void)
|
||||
{
|
||||
#ifdef HAVE_TERMCAP
|
||||
if (*cleol_chars)
|
||||
tputs(cleol_chars, 1, outfn);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _TERMINAL_H
|
||||
#define _TERMINAL_H
|
||||
|
||||
void out_init(void);
|
||||
void outbufputc(void);
|
||||
void promptreturn(void);
|
||||
void out_send(char *string);
|
||||
void out_printf(char *fmt, char *s1, char *s2, char *s3,
|
||||
char *s4, char *s5, char *s6,
|
||||
char *s7, char *s8, char *s9, char *s10);
|
||||
void term_clear(void);
|
||||
void term_home(void);
|
||||
void term_cleol(void);
|
||||
void tcap_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,797 @@
|
|||
/**********
|
||||
Copyright 1990 Regents of the University of California. All rights reserved.
|
||||
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
|
||||
**********/
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ngspice.h>
|
||||
#include <bool.h>
|
||||
#include <wordlist.h>
|
||||
#include <defines.h>
|
||||
#include <macros.h>
|
||||
#include <cpdefs.h>
|
||||
#include <memory.h>
|
||||
#include <inpdefs.h>
|
||||
|
||||
#include "circuits.h"
|
||||
#include "variable.h"
|
||||
#include "streams.h"
|
||||
#include "com_history.h"
|
||||
|
||||
|
||||
bool cp_noglob = TRUE;
|
||||
bool cp_nonomatch = FALSE;
|
||||
bool cp_noclobber = FALSE;
|
||||
bool cp_ignoreeof = FALSE;
|
||||
|
||||
struct variable *variables = NULL;
|
||||
|
||||
wordlist *
|
||||
cp_varwl(struct variable *var)
|
||||
{
|
||||
wordlist *wl = NULL, *w, *wx = NULL;
|
||||
char buf[BSIZE_SP];
|
||||
struct variable *vt;
|
||||
|
||||
switch(var->va_type) {
|
||||
case VT_BOOL:
|
||||
/* Can't ever be FALSE. */
|
||||
sprintf(buf, "%s", var->va_bool ? "TRUE" : "FALSE");
|
||||
break;
|
||||
case VT_NUM:
|
||||
sprintf(buf, "%d", var->va_num);
|
||||
break;
|
||||
case VT_REAL:
|
||||
/* This is a case where printnum isn't too good... */
|
||||
sprintf(buf, "%G", var->va_real);
|
||||
break;
|
||||
case VT_STRING:
|
||||
strcpy(buf, cp_unquote(var->va_string));
|
||||
break;
|
||||
case VT_LIST: /* The tricky case. */
|
||||
for (vt = var->va_vlist; vt; vt = vt->va_next) {
|
||||
w = cp_varwl(vt);
|
||||
if (wl == NULL)
|
||||
wl = wx = w;
|
||||
else {
|
||||
wx->wl_next = w;
|
||||
w->wl_prev = wx;
|
||||
wx = w;
|
||||
}
|
||||
}
|
||||
return (wl);
|
||||
default:
|
||||
fprintf(cp_err,
|
||||
"cp_varwl: Internal Error: bad variable type %d\n",
|
||||
var->va_type);
|
||||
return (NULL);
|
||||
}
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
wl->wl_word = copy(buf);
|
||||
return (wl);
|
||||
}
|
||||
|
||||
|
||||
/* Set a variable. */
|
||||
void
|
||||
cp_vset(char *varname, char type, char *value)
|
||||
{
|
||||
struct variable *v, *u, *w;
|
||||
int i;
|
||||
bool alreadythere = FALSE;
|
||||
|
||||
varname = cp_unquote(varname);
|
||||
w = NULL;
|
||||
for (v = variables; v; v = v->va_next) {
|
||||
if (eq(varname, v->va_name)) {
|
||||
alreadythere = TRUE;
|
||||
break;
|
||||
}
|
||||
w = v;
|
||||
}
|
||||
if (!v) {
|
||||
v = alloc(struct variable);
|
||||
v->va_name = copy(varname);
|
||||
v->va_next = NULL;
|
||||
}
|
||||
switch (type) {
|
||||
case VT_BOOL:
|
||||
if (* ((bool *) value) == FALSE) {
|
||||
cp_remvar(varname);
|
||||
return;
|
||||
} else
|
||||
v->va_bool = TRUE;
|
||||
break;
|
||||
|
||||
case VT_NUM:
|
||||
v->va_num = * (int *) value;
|
||||
break;
|
||||
|
||||
case VT_REAL:
|
||||
v->va_real = * (double *) value;
|
||||
break;
|
||||
|
||||
case VT_STRING:
|
||||
v->va_string = copy(value);
|
||||
break;
|
||||
|
||||
case VT_LIST:
|
||||
v->va_vlist = (struct variable *) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(cp_err,
|
||||
"cp_vset: Internal Error: bad variable type %d.\n",
|
||||
type);
|
||||
return;
|
||||
}
|
||||
v->va_type = type;
|
||||
|
||||
/* Now, see if there is anything interesting going on. We
|
||||
* recognise these special variables: noglob, nonomatch, history,
|
||||
* echo, noclobber, prompt, and verbose. cp_remvar looks for these
|
||||
* variables too. The host program will get any others. */
|
||||
if (eq(varname, "noglob"))
|
||||
cp_noglob = TRUE;
|
||||
else if (eq(varname, "nonomatch"))
|
||||
cp_nonomatch = TRUE;
|
||||
else if (eq(varname, "history") && (type == VT_NUM))
|
||||
cp_maxhistlength = v->va_num;
|
||||
else if (eq(varname, "history") && (type == VT_REAL))
|
||||
cp_maxhistlength = v->va_real;
|
||||
else if (eq(varname, "noclobber"))
|
||||
cp_noclobber = TRUE;
|
||||
else if (eq(varname, "prompt") && (type == VT_STRING))
|
||||
cp_promptstring = copy(v->va_string);
|
||||
else if (eq(varname, "ignoreeof"))
|
||||
cp_ignoreeof = TRUE;
|
||||
else if (eq(varname, "cpdebug")) {
|
||||
cp_debug = TRUE;
|
||||
#ifndef CPDEBUG
|
||||
fprintf(cp_err,
|
||||
"Warning: program not compiled with cshpar debug messages\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (i = cp_usrset(v, TRUE)) {
|
||||
|
||||
case US_OK:
|
||||
/* Normal case. */
|
||||
if (!alreadythere) {
|
||||
v->va_next = variables;
|
||||
variables = v;
|
||||
}
|
||||
break;
|
||||
|
||||
case US_DONTRECORD:
|
||||
/* Do nothing... */
|
||||
if (alreadythere) {
|
||||
fprintf(cp_err, "cp_vset: Internal Error: "
|
||||
"%s already there, but 'dont record'\n", v->va_name);
|
||||
}
|
||||
break;
|
||||
|
||||
case US_READONLY:
|
||||
fprintf(cp_err, "Error: %s is a read-only variable.\n", v->va_name);
|
||||
if (alreadythere)
|
||||
fprintf(cp_err, "cp_vset: Internal Error: "
|
||||
"it was already there too!!\n");
|
||||
break;
|
||||
|
||||
case US_SIMVAR:
|
||||
if (alreadythere) {
|
||||
/* somehow it got into the front-end list of variables */
|
||||
if (w) {
|
||||
w->va_next = v->va_next;
|
||||
} else {
|
||||
variables = v->va_next;
|
||||
}
|
||||
}
|
||||
alreadythere = FALSE;
|
||||
if (ft_curckt) {
|
||||
for (u = ft_curckt->ci_vars; u; u = u->va_next)
|
||||
if (eq(varname, u->va_name)) {
|
||||
alreadythere = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!alreadythere) {
|
||||
v->va_next = ft_curckt->ci_vars;
|
||||
ft_curckt->ci_vars = v;
|
||||
} else {
|
||||
w = u->va_next;
|
||||
bcopy(v, u, sizeof(*u));
|
||||
u->va_next = w;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case US_NOSIMVAR:
|
||||
/* What do you do? */
|
||||
tfree(v);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct variable *
|
||||
cp_setparse(wordlist *wl)
|
||||
{
|
||||
char *name, *val, *s, *ss;
|
||||
double *td;
|
||||
struct variable *listv = NULL, *vv, *lv = NULL;
|
||||
struct variable *vars = NULL;
|
||||
int balance;
|
||||
|
||||
while (wl) {
|
||||
name = cp_unquote(wl->wl_word);
|
||||
wl = wl->wl_next;
|
||||
if (((wl == NULL) || (*wl->wl_word != '=')) &&
|
||||
strchr(name, '=') == NULL) {
|
||||
vv = alloc(struct variable);
|
||||
vv->va_name = copy(name);
|
||||
vv->va_type = VT_BOOL;
|
||||
vv->va_bool = TRUE;
|
||||
vv->va_next = vars;
|
||||
vars = vv;
|
||||
continue;
|
||||
}
|
||||
if (wl && eq(wl->wl_word, "=")) {
|
||||
wl = wl->wl_next;
|
||||
if (wl == NULL) {
|
||||
fprintf(cp_err, "Error: bad set form.\n");
|
||||
return (NULL);
|
||||
}
|
||||
val = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
} else if (wl && (*wl->wl_word == '=')) {
|
||||
val = wl->wl_word + 1;
|
||||
wl = wl->wl_next;
|
||||
} else if ((s =strchr(name, '='))) {
|
||||
val = s + 1;
|
||||
*s = '\0';
|
||||
if (*val == '\0') {
|
||||
if (!wl) {
|
||||
fprintf(cp_err,
|
||||
"Error: %s equals what?.\n",
|
||||
name);
|
||||
return (NULL);
|
||||
} else {
|
||||
val = wl->wl_word;
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(cp_err, "Error: bad set form.\n");
|
||||
return (NULL);
|
||||
}
|
||||
val = cp_unquote(val);
|
||||
if (eq(val, "(")) { /* ) */
|
||||
/* The beginning of a list... We have to walk down the
|
||||
* list until we find a close paren... If there are nested
|
||||
* ()'s, treat them as tokens... */
|
||||
balance = 1;
|
||||
while (wl && wl->wl_word) {
|
||||
if (eq(wl->wl_word, "(")) {
|
||||
balance++;
|
||||
} else if (eq(wl->wl_word, ")")) {
|
||||
if (!--balance)
|
||||
break;
|
||||
}
|
||||
vv = alloc(struct variable);
|
||||
vv->va_next = NULL;
|
||||
ss = cp_unquote(wl->wl_word);
|
||||
td = ft_numparse(&ss, FALSE);
|
||||
if (td) {
|
||||
vv->va_type = VT_REAL;
|
||||
vv->va_real = *td;
|
||||
} else {
|
||||
vv->va_type = VT_STRING;
|
||||
vv->va_string = copy(ss);
|
||||
}
|
||||
if (listv) {
|
||||
lv->va_next = vv;
|
||||
lv = vv;
|
||||
} else
|
||||
listv = lv = vv;
|
||||
wl = wl->wl_next;
|
||||
}
|
||||
if (balance && !wl) {
|
||||
fprintf(cp_err, "Error: bad set form.\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
vv = alloc(struct variable);
|
||||
vv->va_name = copy(name);
|
||||
vv->va_type = VT_LIST;
|
||||
vv->va_vlist = listv;
|
||||
vv->va_next = vars;
|
||||
vars = vv;
|
||||
|
||||
wl = wl->wl_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ss = cp_unquote(val);
|
||||
td = ft_numparse(&ss, FALSE);
|
||||
vv = alloc(struct variable);
|
||||
vv->va_name = copy(name);
|
||||
vv->va_next = vars;
|
||||
vars = vv;
|
||||
if (td) {
|
||||
/*** We should try to get VT_NUM's... */
|
||||
vv->va_type = VT_REAL;
|
||||
vv->va_real = *td;
|
||||
} else {
|
||||
vv->va_type = VT_STRING;
|
||||
vv->va_string = copy(val);
|
||||
}
|
||||
}
|
||||
return (vars);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cp_remvar(char *varname)
|
||||
{
|
||||
struct variable *v, *u, *lv = NULL;
|
||||
bool found = TRUE;
|
||||
int i;
|
||||
|
||||
for (v = variables; v; v = v->va_next) {
|
||||
if (eq(v->va_name, varname))
|
||||
break;
|
||||
lv = v;
|
||||
}
|
||||
if (!v) {
|
||||
/* Gotta make up a var struct for cp_usrset()... */
|
||||
v = alloc(struct variable);
|
||||
ZERO(v, struct variable);
|
||||
v->va_name = varname;
|
||||
v->va_type = VT_NUM;
|
||||
v->va_bool = 0;
|
||||
found = FALSE;
|
||||
}
|
||||
|
||||
/* Note that 'unset history' doesn't do anything here... Causes
|
||||
* trouble... */
|
||||
if (eq(varname, "noglob"))
|
||||
cp_noglob = FALSE;
|
||||
else if (eq(varname, "nonomatch"))
|
||||
cp_nonomatch = FALSE;
|
||||
else if (eq(varname, "noclobber"))
|
||||
cp_noclobber = FALSE;
|
||||
else if (eq(varname, "prompt"))
|
||||
cp_promptstring = "";
|
||||
else if (eq(varname, "cpdebug"))
|
||||
cp_debug = FALSE;
|
||||
else if (eq(varname, "ignoreeof"))
|
||||
cp_ignoreeof = FALSE;
|
||||
|
||||
switch (i = cp_usrset(v, FALSE)) {
|
||||
|
||||
case US_OK:
|
||||
/* Normal case. */
|
||||
if (found) {
|
||||
if (lv)
|
||||
lv->va_next = v->va_next;
|
||||
else
|
||||
variables = v->va_next;
|
||||
}
|
||||
break;
|
||||
|
||||
case US_DONTRECORD:
|
||||
/* Do nothing... */
|
||||
if (found)
|
||||
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
|
||||
break;
|
||||
|
||||
case US_READONLY:
|
||||
/* Badness... */
|
||||
fprintf(cp_err, "Error: %s is read-only.\n", v->va_name);
|
||||
if (found)
|
||||
fprintf(cp_err, "cp_remvar: Internal Error: var %d\n", *varname);
|
||||
break;
|
||||
|
||||
case US_SIMVAR:
|
||||
lv = NULL;
|
||||
if (ft_curckt) {
|
||||
for (u = ft_curckt->ci_vars; u; u = u->va_next) {
|
||||
if (eq(varname, u->va_name)) {
|
||||
break;
|
||||
}
|
||||
lv = u;
|
||||
}
|
||||
if (u) {
|
||||
if (lv)
|
||||
lv->va_next = u->va_next;
|
||||
else
|
||||
ft_curckt->ci_vars = u->va_next;
|
||||
tfree(u);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
tfree(v);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Determine the value of a variable. Fail if the variable is unset,
|
||||
* and if the type doesn't match, try and make it work... */
|
||||
bool
|
||||
cp_getvar(char *name, int type, char *retval)
|
||||
{
|
||||
struct variable *v;
|
||||
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(name, v->va_name))
|
||||
break;
|
||||
if (v == NULL) {
|
||||
if (type == VT_BOOL)
|
||||
* (bool *) retval = FALSE;
|
||||
return (FALSE);
|
||||
}
|
||||
if (v->va_type == type) {
|
||||
switch (type) {
|
||||
case VT_BOOL:
|
||||
* (bool *) retval = TRUE;
|
||||
break;
|
||||
case VT_NUM: {
|
||||
int *i;
|
||||
i = (int *) retval;
|
||||
*i = v->va_num;
|
||||
break;
|
||||
}
|
||||
case VT_REAL: {
|
||||
double *d;
|
||||
d = (double *) retval;
|
||||
*d = v->va_real;
|
||||
break;
|
||||
}
|
||||
case VT_STRING: { /* Gotta be careful to have room. */
|
||||
char *s;
|
||||
s = cp_unquote(v->va_string);
|
||||
cp_wstrip(s);
|
||||
(void) strcpy(retval, s);
|
||||
break;
|
||||
}
|
||||
case VT_LIST: { /* Funny case... */
|
||||
struct variable **tv;
|
||||
tv = (struct variable **) retval;
|
||||
*tv = v->va_vlist;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(cp_err,
|
||||
"cp_getvar: Internal Error: bad var type %d.\n",
|
||||
type);
|
||||
break;
|
||||
}
|
||||
return (TRUE);
|
||||
} else {
|
||||
/* Try to coerce it.. */
|
||||
if ((type == VT_NUM) && (v->va_type == VT_REAL)) {
|
||||
int *i;
|
||||
i = (int *) retval;
|
||||
*i = (int) v->va_real;
|
||||
return (TRUE);
|
||||
} else if ((type == VT_REAL) && (v->va_type == VT_NUM)) {
|
||||
double *d;
|
||||
d = (double *) retval;
|
||||
*d = (double) v->va_num;
|
||||
return (TRUE);
|
||||
} else if ((type == VT_STRING) && (v->va_type == VT_NUM)) {
|
||||
(void) sprintf(retval, "%d", v->va_num);
|
||||
return (TRUE);
|
||||
} else if ((type == VT_STRING) && (v->va_type == VT_REAL)) {
|
||||
(void) sprintf(retval, "%f", v->va_real);
|
||||
return (TRUE);
|
||||
}
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* A variable substitution is indicated by a $, and the variable name
|
||||
* is the following string of non-special characters. All variable
|
||||
* values are inserted as a single word, except for lists, which are a
|
||||
* list of words. A routine cp_usrset must be supplied by the host
|
||||
* program to deal with variables that aren't used by cshpar -- it
|
||||
* should be cp_usrset(var, isset), where var is a variable *, and
|
||||
* isset is TRUE if the variable is being set, FALSE if unset. Also
|
||||
* required is a routine cp_enqvar(name) which returns a struct
|
||||
* variable *, which allows the host program to provide values for
|
||||
* non-cshpar variables. */
|
||||
|
||||
char cp_dol = '$';
|
||||
|
||||
/* Non-alphanumeric characters that may appear in variable names. < is very
|
||||
* special...
|
||||
*/
|
||||
|
||||
#define VALIDCHARS "$-_<#?@.()[]&"
|
||||
|
||||
wordlist *
|
||||
cp_variablesubst(wordlist *wlist)
|
||||
{
|
||||
wordlist *wl, *nwl;
|
||||
char *s, *t, buf[BSIZE_SP], wbuf[BSIZE_SP], tbuf[BSIZE_SP];
|
||||
/* MW. tbuf holds curret word after wl_splice() calls free() on it */
|
||||
int i;
|
||||
|
||||
for (wl = wlist; wl; wl = wl->wl_next) {
|
||||
t = wl->wl_word;
|
||||
i = 0;
|
||||
while ((s =strchr(t, cp_dol))) {
|
||||
while (t < s)
|
||||
wbuf[i++] = *t++;
|
||||
wbuf[i] = '\0';
|
||||
(void) strcpy(buf, ++s);
|
||||
s = buf;
|
||||
t++;
|
||||
while (*s && (isalphanum(*s) ||
|
||||
strchr(VALIDCHARS, *s))) {
|
||||
/* Get s and t past the end of the var name. */
|
||||
t++;
|
||||
s++;
|
||||
}
|
||||
*s = '\0';
|
||||
nwl = vareval(buf);
|
||||
if (i) {
|
||||
(void) strcpy(buf, wbuf);
|
||||
if (nwl) {
|
||||
(void) strcat(buf, nwl->wl_word);
|
||||
tfree(nwl->wl_word);
|
||||
} else {
|
||||
nwl = alloc(struct wordlist);
|
||||
nwl->wl_next = nwl->wl_prev = NULL;
|
||||
}
|
||||
nwl->wl_word = copy(buf);
|
||||
}
|
||||
|
||||
(void) strcpy(tbuf, t); /* MW. Save t*/
|
||||
if (!(wl = wl_splice(wl, nwl)))
|
||||
return (NULL);
|
||||
/* This is bad... */
|
||||
for (wlist = wl; wlist->wl_prev; wlist = wlist->wl_prev)
|
||||
;
|
||||
(void) strcpy(buf, wl->wl_word);
|
||||
i = strlen(buf);
|
||||
(void) strcat(buf, tbuf); /* MW. tbuf is used here only */
|
||||
|
||||
tfree(wl->wl_word);
|
||||
wl->wl_word = copy(buf);
|
||||
t = &wl->wl_word[i];
|
||||
s = wl->wl_word;
|
||||
for (i = 0; s < t; s++)
|
||||
wbuf[i++] = *s;
|
||||
}
|
||||
}
|
||||
return (wlist);
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate a variable. */
|
||||
wordlist *
|
||||
vareval(char *string)
|
||||
{
|
||||
struct variable *v;
|
||||
wordlist *wl;
|
||||
char buf[BSIZE_SP], *s;
|
||||
char *oldstring = copy(string);
|
||||
char *range = NULL;
|
||||
int i, up, low;
|
||||
|
||||
cp_wstrip(string);
|
||||
if ((s =strchr(string, '['))) {
|
||||
*s = '\0';
|
||||
range = s + 1;
|
||||
}
|
||||
|
||||
switch (*string) {
|
||||
|
||||
case '$':
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
|
||||
|
||||
(void) sprintf(buf, "%d", getpid());
|
||||
|
||||
wl->wl_word = copy(buf);
|
||||
return (wl);
|
||||
|
||||
case '<':
|
||||
(void) fflush(cp_out);
|
||||
if (!fgets(buf, BSIZE_SP, cp_in)) {
|
||||
clearerr(cp_in);
|
||||
(void) strcpy(buf, "EOF");
|
||||
}
|
||||
for (s = buf; *s && (*s != '\n'); s++)
|
||||
;
|
||||
*s = '\0';
|
||||
wl = cp_lexer(buf);
|
||||
/* This is a hack. */
|
||||
if (!wl->wl_word)
|
||||
wl->wl_word = copy("");
|
||||
return (wl);
|
||||
|
||||
case '?':
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
string++;
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(v->va_name, string))
|
||||
break;
|
||||
if (!v)
|
||||
v = cp_enqvar(string);
|
||||
wl->wl_word = copy(v ? "1" : "0");
|
||||
return (wl);
|
||||
|
||||
case '#':
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
string++;
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(v->va_name, string))
|
||||
break;
|
||||
if (!v)
|
||||
v = cp_enqvar(string);
|
||||
if (!v) {
|
||||
fprintf(cp_err, "Error: %s: no such variable.\n",
|
||||
string);
|
||||
return (NULL);
|
||||
}
|
||||
if (v->va_type == VT_LIST)
|
||||
for (v = v->va_vlist, i = 0; v; v = v->va_next)
|
||||
i++;
|
||||
else
|
||||
i = (v->va_type != VT_BOOL);
|
||||
(void) sprintf(buf, "%d", i);
|
||||
wl->wl_word = copy(buf);
|
||||
return (wl);
|
||||
|
||||
case '\0':
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
wl->wl_word = copy("$");
|
||||
return (wl);
|
||||
}
|
||||
|
||||
/* The notation var[stuff] has two meanings... If this is a real
|
||||
* variable, then the [] denotes range, but if this is a strange
|
||||
* (e.g, device parameter) variable, it could be anything...
|
||||
*/
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(v->va_name, string))
|
||||
break;
|
||||
if (!v && isdigit(*string)) {
|
||||
for (v = variables; v; v = v->va_next)
|
||||
if (eq(v->va_name, "argv"))
|
||||
break;
|
||||
range = string;
|
||||
}
|
||||
if (!v) {
|
||||
range = NULL;
|
||||
string = oldstring;
|
||||
v = cp_enqvar(string);
|
||||
}
|
||||
if (!v && (s = getenv(string))) {
|
||||
wl = alloc(struct wordlist);
|
||||
wl->wl_next = wl->wl_prev = NULL;
|
||||
wl->wl_word = copy(s);
|
||||
return (wl);
|
||||
}
|
||||
if (!v) {
|
||||
fprintf(cp_err, "Error: %s: no such variable.\n", string);
|
||||
return (NULL);
|
||||
}
|
||||
wl = cp_varwl(v);
|
||||
|
||||
/* Now parse and deal with 'range' ... */
|
||||
if (range) {
|
||||
for (low = 0; isdigit(*range); range++)
|
||||
low = low * 10 + *range - '0';
|
||||
if ((*range == '-') && isdigit(range[1]))
|
||||
for (up = 0, range++; isdigit(*range); range++)
|
||||
up = up * 10 + *range - '0';
|
||||
else if (*range == '-')
|
||||
up = wl_length(wl);
|
||||
else
|
||||
up = low;
|
||||
up--, low--;
|
||||
wl = wl_range(wl, low, up);
|
||||
}
|
||||
|
||||
return (wl);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
vcmp(const void *a, const void *b)
|
||||
{
|
||||
int i;
|
||||
struct xxx *v1 = (struct xxx *) a;
|
||||
struct xxx *v2 = (struct xxx *) b;
|
||||
if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name)))
|
||||
return (i);
|
||||
else
|
||||
return (v1->x_char - v2->x_char);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Print the values of currently defined variables. */
|
||||
void
|
||||
cp_vprint(void)
|
||||
{
|
||||
struct variable *v;
|
||||
struct variable *uv1, *uv2;
|
||||
wordlist *wl;
|
||||
int i, j;
|
||||
char *s;
|
||||
struct xxx *vars;
|
||||
|
||||
cp_usrvars(&uv1, &uv2);
|
||||
|
||||
for (v = uv1, i = 0; v; v = v->va_next)
|
||||
i++;
|
||||
for (v = uv2; v; v = v->va_next)
|
||||
i++;
|
||||
for (v = variables; v; v = v->va_next)
|
||||
i++;
|
||||
|
||||
vars = (struct xxx *) tmalloc(sizeof (struct xxx) * i);
|
||||
|
||||
out_init();
|
||||
for (v = variables, i = 0; v; v = v->va_next, i++) {
|
||||
vars[i].x_v = v;
|
||||
vars[i].x_char = ' ';
|
||||
}
|
||||
for (v = uv1; v; v = v->va_next, i++) {
|
||||
vars[i].x_v = v;
|
||||
vars[i].x_char = '*';
|
||||
}
|
||||
for (v = uv2; v; v = v->va_next, i++) {
|
||||
vars[i].x_v = v;
|
||||
vars[i].x_char = '+';
|
||||
}
|
||||
|
||||
qsort((char *) vars, i, sizeof (struct xxx), vcmp);
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (j && eq(vars[j].x_v->va_name, vars[j - 1].x_v->va_name))
|
||||
continue;
|
||||
v = vars[j].x_v;
|
||||
if (v->va_type == VT_BOOL) {
|
||||
/* out_printf("%c %s\n", vars[j].x_char, v->va_name); */
|
||||
sprintf(out_pbuf, "%c %s\n", vars[j].x_char, v->va_name);
|
||||
out_send(out_pbuf);
|
||||
} else {
|
||||
out_printf("%c %s\t", vars[j].x_char, v->va_name);
|
||||
wl = vareval(v->va_name);
|
||||
s = wl_flatten(wl);
|
||||
if (v->va_type == VT_LIST) {
|
||||
out_printf("( %s )\n", s);
|
||||
} else
|
||||
out_printf("%s\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
tfree(vars);
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef _VARIABLE_H
|
||||
#define _VARIABLE_H
|
||||
|
||||
/* Variables that are accessible to the parser via $varname
|
||||
* expansions. If the type is VT_LIST the value is a pointer to a
|
||||
* list of the elements. */
|
||||
struct variable {
|
||||
char va_type;
|
||||
char *va_name;
|
||||
union {
|
||||
bool vV_bool;
|
||||
int vV_num;
|
||||
double vV_real;
|
||||
char *vV_string;
|
||||
struct variable *vV_list;
|
||||
} va_V;
|
||||
struct variable *va_next; /* Link. */
|
||||
} ;
|
||||
|
||||
#define va_bool va_V.vV_bool
|
||||
#define va_num va_V.vV_num
|
||||
#define va_real va_V.vV_real
|
||||
#define va_string va_V.vV_string
|
||||
#define va_vlist va_V.vV_list
|
||||
|
||||
enum vt_types {
|
||||
VT_BOOL,
|
||||
VT_NUM,
|
||||
VT_REAL,
|
||||
VT_STRING,
|
||||
VT_LIST
|
||||
};
|
||||
|
||||
struct xxx {
|
||||
struct variable *x_v;
|
||||
char x_char;
|
||||
} ;
|
||||
|
||||
|
||||
extern struct variable *variables;
|
||||
|
||||
// extern struct variable *variables;
|
||||
wordlist * cp_varwl(struct variable *var);
|
||||
void cp_vset(char *varname, char type, char *value);
|
||||
struct variable * cp_setparse(wordlist *wl);
|
||||
void cp_remvar(char *varname);
|
||||
bool cp_getvar(char *name, int type, char *retval);
|
||||
wordlist * cp_variablesubst(wordlist *wlist);
|
||||
wordlist * vareval(char *string);
|
||||
void cp_vprint(void);
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue