📄 control.c
字号:
/**********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"#include "fteext.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. */ /* Notes by CDHW: * This routine leaked like a sieve because each getcommand() created a * wordlist that was never freed because it might have been added into * the control structure. I've tackled this by making sure that everything * put into the cend[stackp] is a copy. This means that wlist can be * destroyed safely */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 voidpwlist(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;}/* CDHW defined functions */static voidpwlist_echo(wlist, name) /*CDHW used to perform function of set echo */ wordlist *wlist; char *name;{ wordlist *wl; if ((!cp_echo)||cp_debug) /* cpdebug prints the same info */ 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;}/*CDHW Remove control structure and free the memory its hogging CDHW*/void ctl_free(struct control *ctrl) { if (!ctrl) return; wl_free(ctrl->co_cond); ctrl->co_cond = NULL; tfree(ctrl->co_foreachvar); ctrl->co_foreachvar = NULL; wl_free(ctrl->co_text); ctrl->co_text = NULL; ctl_free(ctrl->co_children); ctrl->co_children = NULL; ctl_free(ctrl->co_elseblock); ctrl->co_elseblock = NULL; ctl_free(ctrl->co_next); ctrl->co_next = NULL; tfree(ctrl); ctrl = NULL;}/* Note that we only do io redirection when we get to here - we also * postpone some other things until now. */static voiddocommand(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"); pwlist_echo(wlist, "Becomes >"); if (!wlist || !wlist->wl_word) /*CDHW need to free wlist in second case? CDHW*/ 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); /*CDHW lcom will need freeing CDHW*/ (*command->co_func) ((void *)(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; nn = *num + 1 ; /*CDHW this is a guess... CDHW*/ switch (bl->co_type) { case CO_WHILE: if (!bl->co_children) { fprintf(cp_err, "Warning: Executing empty 'while' block.\n"); fprintf(cp_err, " (Use a label statement as a no-op to suppress this warning.)\n"); } while (bl->co_cond && cp_istrue(bl->co_cond)) { if (!bl->co_children) cp_periodic(); /*CDHW*/ 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: if (!bl->co_children) { fprintf(cp_err, "Warning: Executing empty 'repeat' block.\n"); fprintf(cp_err, " (Use a label statement as a no-op to suppress this warning.)\n"); } if (!bl->co_timestodo) bl->co_timestodo = bl->co_numtimes; /*...CDHW*/ while ((bl->co_timestodo > 0) || (bl->co_timestodo == -1)) { if (bl->co_numtimes != -1) bl->co_numtimes--; if (!bl->co_children) cp_periodic(); /*CDHW*/ if (bl->co_timestodo != -1) bl->co_timestodo--; 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -