コード例 #1
0
ファイル: backq.c プロジェクト: Anastien/ngspice
static wordlist *
backeval(char *string)
{
#ifdef HAVE_POPEN
    FILE *proc, *old;
    wordlist *wl;
    bool intv;

    proc = popen(string, "r");
    if (proc == NULL) {
        fprintf(cp_err, "Error: can't evaluate %s.\n", string);
        return (NULL);
    }
    old = cp_inp_cur;
    cp_inp_cur = proc;
    intv = cp_interactive;
    cp_interactive = FALSE;
    cp_bqflag = TRUE;
    wl = cp_lexer(NULL);
    cp_bqflag = FALSE;
    cp_inp_cur = old;
    cp_interactive = intv;
    (void) pclose(proc);
    return (wl);
#else
    wordlist *wl = wl_cons(copy(string), NULL);
    return (wl);
#endif
}
コード例 #2
0
ファイル: cpitf.c プロジェクト: Trussroads/RZE-ngspice
bool
cp_oddcomm(char *s, wordlist *wl)
{
    FILE *fp;

    if ((fp = inp_pathopen(s, "r")) != NULL) {
        char buf[BSIZE_SP];
        wordlist *setarg;
        (void) fclose(fp);
        (void) sprintf(buf, "argc = %d argv = ( ", wl_length(wl));
        while (wl) {
            (void) strcat(buf, wl->wl_word);
            (void) strcat(buf, " ");
            wl = wl->wl_next;
        }
        (void) strcat(buf, ")");
        setarg = cp_lexer(buf);
        com_set(setarg);
        wl_free(setarg);
        inp_source(s);
        cp_remvar("argc");
        cp_remvar("argv");
        return (TRUE);
    }

    if (wl && eq(wl->wl_word, "=")) {
        wordlist *ww = wl_cons(copy(s), wl);
        com_let(ww);
        wl_delete_slice(ww, ww->wl_next);
        return (TRUE);
    }

    return (FALSE);
}
コード例 #3
0
wordlist *
cp_varwl(struct variable *var)
{
    wordlist *wl = NULL, *w, *wx = NULL;
    char *buf;
    struct variable *vt;

    switch (var->va_type) {
    case CP_BOOL:
        /* Can't ever be FALSE. */
        buf = copy(var->va_bool ? "TRUE" : "FALSE");
        break;
    case CP_NUM:
        buf = tprintf("%d", var->va_num);
        break;
    case CP_REAL:
        /* This is a case where printnum isn't too good... */
        buf = tprintf("%G", var->va_real);
        break;
    case CP_STRING:
        buf = cp_unquote(var->va_string);
        break;
    case CP_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);
    }

    return wl_cons(buf, NULL);
}
コード例 #4
0
ファイル: measure.c プロジェクト: fengmm521/myspice
void
com_meas(wordlist *wl)
{
    /* wl: in, input line of meas command */
    char *line_in, *outvar;
    wordlist *wl_count, *wl_let;

    char *vec_found, *token, *equal_ptr;
    wordlist *wl_index;
    struct dvec *d;
    int err = 0;

    int fail;
    double result = 0;

    if (!wl) {
        com_display(NULL);
        return;
    }
    wl_count = wl;

    /* check each wl entry, if it contain '=' and if the following token is
       a single valued vector. If yes, replace this vector by its value.
       Vectors may stem from other meas commands, or be generated elsewhere
       within the .control .endc script. All other right hand side vectors are
       treated in com_measure2.c. */
    wl_index = wl;

    while (wl_index) {
        token = wl_index->wl_word;
        /* find the vector vec_found, next token after each '=' sign.
           May be in the next wl_word */
        if (token[strlen(token) - 1] == '=') {
            wl_index = wl_index->wl_next;
            vec_found = wl_index->wl_word;
            /* token may be already a value, maybe 'LAST', which we have to keep, or maybe a vector */
            if (!cieq(vec_found, "LAST")) {
                INPevaluate(&vec_found, &err, 1);
                /* if not a valid number */
                if (err) {
                    /* check if vec_found is a valid vector */
                    d = vec_get(vec_found);
                    /* Only if we have a single valued vector, replacing
                       of the rigt hand side does make sense */
                    if (d && (d->v_length == 1) && (d->v_numdims == 1)) {
                        /* get its value */
                        wl_index->wl_word = tprintf("%e", d->v_realdata[0]);
                        tfree(vec_found);
                    }
                }
            }
        }
        /* may be inside the same wl_word */
        else if ((equal_ptr = strstr(token, "=")) != NULL) {
            vec_found = equal_ptr + 1;
            if (!cieq(vec_found, "LAST")) {
                INPevaluate(&vec_found, &err, 1);
                if (err) {
                    d = vec_get(vec_found);
                    /* Only if we have a single valued vector, replacing
                    of the rigt hand side does make sense */
                    if (d && (d->v_length == 1) && (d->v_numdims == 1)) {
                        int lhs_len = (int)(equal_ptr - token);
                        wl_index->wl_word =
                            tprintf("%.*s=%e", lhs_len, token, d->v_realdata[0]);
                        tfree(token);
                    }
                }
            }
        } else {
            ;                   // nothing
        }
        wl_index = wl_index->wl_next;
    }

    line_in = wl_flatten(wl);

    /* get output var name */
    wl_count = wl_count->wl_next;
    if (!wl_count) {
        fprintf(stdout,
                " meas %s failed!\n"
                "   unspecified output var name\n\n", line_in);
        return;
    }
    outvar = wl_count->wl_word;

    fail = get_measure2(wl, &result, NULL, FALSE);

    if (fail) {
        fprintf(stdout, " meas %s failed!\n\n", line_in);
        return;
    }

    wl_let = wl_cons(tprintf("%s = %e", outvar, result), NULL);
    com_let(wl_let);
    wl_free(wl_let);
    tfree(line_in);
}
コード例 #5
0
ファイル: dotcards.c プロジェクト: Trussroads/RZE-ngspice
wordlist *
gettoks(char *s)
{
    char        *t, *s0;
    char        *l, *r, *c;     /* left, right, center/comma */
    wordlist    *wl, *list, **prevp;


    list = NULL;
    prevp = &list;

    /* stripWhite.... uses copy() to return a malloc'ed s, so we have to free it,
       using s0 as its starting address */
    if (strstr(s, "("))
        s0 = s = stripWhiteSpacesInsideParens(s);
    else
        s0 = s = copy(s);

    while ((t = gettok(&s)) != NULL) {
        if (*t == '(') {
            /* gettok uses copy() to return a malloc'ed t, so we have to free it */
            tfree(t);
            continue;
        }
        l = strrchr(t, '('/*)*/);
        if (!l) {
            wl = wl_cons(copy(t), NULL);
            *prevp = wl;
            prevp = &wl->wl_next;
            tfree(t);
            continue;
        }

        r = strchr(t, /*(*/')');

        c = strchr(t, ',');
        if (!c)
            c = r;

        if (c)
            *c = '\0';

        wl = wl_cons(NULL, NULL);
        *prevp = wl;
        prevp = &wl->wl_next;

        if (*(l - 1) == 'i' || *(l - 1) == 'I') {
            char buf[513];
            sprintf(buf, "%s#branch", l + 1);
            wl->wl_word = copy(buf);
            c = r = NULL;
        } else {
            wl->wl_word = copy(l + 1);
        }

        if (c != r) {
            *r = '\0';
            wl = wl_cons(copy(c + 1), NULL);
            *prevp = wl;
            prevp = &wl->wl_next;
        }
        tfree(t);
    }
    tfree(s0);
    return list;
}
コード例 #6
0
/* 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, '[')) != NULL) {
        *s = '\0';
        range = s + 1;
    }

    switch (*string) {

    case '$':
        wl = wl_cons(tprintf("%d", getpid()), NULL);
        tfree(oldstring);
        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("");
        tfree(oldstring);
        return (wl);

    case '?':
        string++;
        for (v = variables; v; v = v->va_next)
            if (eq(v->va_name, string))
                break;
        if (!v)
            v = cp_enqvar(string);
        wl = wl_cons(copy(v ? "1" : "0"), NULL);
        tfree(oldstring);
        return (wl);

    case '#':
        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);
            tfree(oldstring);
            return (NULL);
        }
        if (v->va_type == CP_LIST)
            for (v = v->va_vlist, i = 0; v; v = v->va_next)
                i++;
        else
            i = (v->va_type != CP_BOOL);
        wl = wl_cons(tprintf("%d", i), NULL);
        tfree(oldstring);
        return (wl);

    case '\0':
        wl = wl_cons(copy("$"), NULL);
        tfree(oldstring);
        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_c(*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)) != NULL) {
        wl = wl_cons(copy(s), NULL);
        tfree(oldstring);
        return (wl);
    }
    if (!v) {
        fprintf(cp_err, "Error: %s: no such variable.\n", string);
        tfree(oldstring);
        return (NULL);
    }
    wl = cp_varwl(v);

    /* Now parse and deal with 'range' ... */
    if (range) {
        /* rather crude fix when range itself is a $expression */
        wordlist *r = NULL;
        if (*range == '$') {
            char *t = ++range;
            if (*t == '&')
                t++;
            while (isalnum_c(*t))
                t++;
            *t = '\0';
            r = vareval(range);
            if (!r || r->wl_next) {
                fprintf(cp_err, "Error: %s: illegal index.\n", string);
                tfree(oldstring);
                wl_free(r);
                return NULL;
            }
            range = r->wl_word;
        }
        for (low = 0; isdigit_c(*range); range++)
            low = low * 10 + *range - '0';
        if ((*range == '-') && isdigit_c(range[1]))
            for (up = 0, range++; isdigit_c(*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);
        wl_free(r);
    }
    tfree(oldstring);
    return (wl);
}
コード例 #7
0
ファイル: runcoms.c プロジェクト: Trussroads/RZE-ngspice
static int
dosim(
    char *what, /* in: command (pz,op,dc,ac,tf,tran,sens,disto,noise,run) */
    wordlist *wl /* in: command option */
    /* global variables in: ft_curckt, ft_circuits,
       out: ft_setflag, ft_intrpt, rawfileFp, rawfileBinary,
       last_used_rawfile
    */
    )
{
    wordlist *ww = NULL;
    bool dofile = FALSE;
    char buf[BSIZE_SP];
    struct circ *ct;
    int err = 0;
    /* set file type to binary or to what is given by environmental
       variable SPICE_ASCIIRAWFILE in ivars.c */
    bool ascii = AsciiRawFile;
    if (eq(what, "run") && wl)
        dofile = TRUE;
    /* add "what" to beginning of wordlist wl, except "what" equals "run"
       and a rawfile name is given (in wl) */
    if (!dofile) {
        ww = wl_cons(copy(what), wl);
    }
    /* reset output file type according to variable given in spinit */
    if (cp_getvar("filetype", CP_STRING, buf)) {
        if (eq(buf, "binary"))
            ascii = FALSE;
        else if (eq(buf, "ascii"))
            ascii = TRUE;
        else {
            fprintf(cp_err,
                    "Warning: strange file type \"%s\" (using \"ascii\")\n", buf);
            ascii = TRUE;
        }
    }

    if (!ft_curckt) {
        fprintf(cp_err, "Error: there aren't any circuits loaded.\n");
        return 1;
    } else if (ft_curckt->ci_ckt == NULL) { /* Set noparse? */
        fprintf(cp_err, "Error: circuit not parsed.\n");
        return 1;
    }
    for (ct = ft_circuits; ct; ct = ct->ci_next)
        if (ct->ci_inprogress && (ct != ft_curckt)) {
            fprintf(cp_err,
                    "Warning: losing old state for circuit '%s'\n",
                    ct->ci_name);
            ct->ci_inprogress = FALSE;
        }
    /* "resume" will never occur in ngspice */
    if (ft_curckt->ci_inprogress && eq(what, "resume")) {
        ft_setflag = TRUE;  /* don't allow abort upon interrupt during run  */
        ft_intrpt = FALSE;
        fprintf(cp_err, "Warning: resuming run in progress.\n");
        com_resume(NULL);
        ft_setflag = FALSE;  /* Now allow aborts again  */
        return 0;
    }

    /* From now on until the next prompt, an interrupt will just
     * set a flag and let spice finish up, then control will be
     * passed back to the user.
     */
    ft_setflag = TRUE;  /* Don't allow abort upon interrupt during run.  */
    ft_intrpt = FALSE;
    /* command "run" is given with rawfile name in wl */
    if (dofile) {
        if (!*wl->wl_word)
            rawfileFp = stdout;
#if defined(__MINGW32__) || defined(_MSC_VER)
        /* ask if binary or ASCII, open file with wb or w */
        else if (ascii) {
            if ((rawfileFp = fopen(wl->wl_word, "w")) == NULL) {
                perror(wl->wl_word);
                ft_setflag = FALSE;
                return 1;
            }
            fprintf(cp_out, "ASCII raw file\n");
        }
        else if (!ascii) {
            if ((rawfileFp = fopen(wl->wl_word, "wb")) == NULL) {
                perror(wl->wl_word);
                ft_setflag = FALSE;
                return 1;
            }
            fprintf(cp_out, "binary raw file\n");
        }
/*---------------------------------------------------------------------------*/
#else
        else if (!(rawfileFp = fopen(wl->wl_word, "w"))) {
            setvbuf(rawfileFp, rawfileBuf, _IOFBF, RAWBUF_SIZE);
            perror(wl->wl_word);
            ft_setflag = FALSE;
            return 1;
        }
#endif /* __MINGW32__ */
        rawfileBinary = !ascii;
    } else {
        rawfileFp = NULL;
    }

    /*save rawfile name */
    if (last_used_rawfile)
        tfree(last_used_rawfile);
    if (rawfileFp)
        last_used_rawfile = copy(wl->wl_word);
    else
        last_used_rawfile = NULL;

    ft_curckt->ci_inprogress = TRUE;
    /* "sens2" not used in ngspice */
    if (eq(what, "sens2")) {
        if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) {
            /* The circuit was interrupted somewhere. */
            fprintf(cp_err, "%s simulation interrupted\n", what);
#ifdef XSPICE
            /* gtri - add - 12/12/90 - wbk - record error and return errchk */
            g_ipc.run_error = IPC_TRUE;
            if (g_ipc.enabled)
                ipc_send_errchk();
            /* gtri - end - 12/12/90 */
#endif
        } else {
            ft_curckt->ci_inprogress = FALSE;
        }
        /* Do a run of the circuit */
    } else {
        err = if_run(ft_curckt->ci_ckt, what, ww, ft_curckt->ci_symtab);
        if (err == 1) {
            /* The circuit was interrupted somewhere. */
            fprintf(cp_err, "%s simulation interrupted\n", what);
#ifdef XSPICE
            /* record error and return errchk */
            g_ipc.run_error = IPC_TRUE;
            if (g_ipc.enabled)
                ipc_send_errchk();
            /* gtri - end - 12/12/90 */
#endif
            err = 0;
        } else if (err == 2) {
            fprintf(cp_err, "%s simulation(s) aborted\n", what);
            ft_curckt->ci_inprogress = FALSE;
            err = 1;
        } else {
            ft_curckt->ci_inprogress = FALSE;
        }
    }
    /* close the rawfile */
    if (rawfileFp) {
        if (ftell(rawfileFp) == 0) {
            (void) fclose(rawfileFp);
            (void) unlink(wl->wl_word);
        } else {
            (void) fclose(rawfileFp);
        }
    }
    ft_curckt->ci_runonce = TRUE;
    ft_setflag = FALSE;

    /* va: garbage collection: unlink first word (inserted here) and tfree it */
    if (!dofile) {
        tfree(ww->wl_word);
        if (wl)
            wl->wl_prev = NULL;
        tfree(ww);
    }

    /* execute the .measure statements */
    if (!err && ft_curckt->ci_last_an && ft_curckt->ci_meas)
        do_measure(ft_curckt->ci_last_an, FALSE);

    return err;
}
コード例 #8
0
ファイル: mw_coms.c プロジェクト: imr/ngspice
void
com_removecirc(wordlist *wl)
{
    struct variable *v, *next;
    struct circ *ct;
    struct circ *caux = NULL;
    struct plot *p;
    struct plot *paux;
    int auxCir = 1, i, auxPlot;

    char* namecircuit;

    NG_IGNORE(wl);

    if (!ft_curckt) {
        fprintf(cp_err, "Error: there is no circuit loaded.\n");
        return;
    }

    ct = ft_curckt;

    if_cktfree(ct->ci_ckt, ct->ci_symtab);

    for (v = ct->ci_vars; v; v = next) {
        next = v->va_next;
        tfree(v);
    }

    /* PN FTESTATS*/
    tfree(ct->FTEstats);

    ct->ci_vars = NULL;
    caux = ft_circuits;
    namecircuit = copy(ft_curckt->ci_name);

    /* The circuit  being removed is the first loaded and you have more circuits */
    if (ft_curckt == ft_circuits  &&  ft_circuits->ci_next)
        ft_circuits = ft_circuits->ci_next;

    /* The circuit being removed id the first loaded and there are no more circuits */
    else if (ft_circuits->ci_next == NULL)
        ft_circuits = NULL;

    else {

        /* Run over the circuit list to find how many of them are
         * in front of the one to be removed
         */
        for (; ft_curckt != caux && caux; caux = caux->ci_next)
            auxCir++;

        caux = ft_circuits;

        /* Remove the circuit and move pointer to the next one */
        for (i = 1; i < auxCir-1; i++)
            caux = caux->ci_next;

        caux->ci_next = caux->ci_next->ci_next;
        /* ft_curckt = ft_circuits; */

    }


    /* If the plot is the first one and there are no other plots */
    if (!plot_list->pl_next && strcmp(plot_list->pl_title, namecircuit) == 0)
        plot_list = NULL;

    else if (plot_list && plot_list->pl_next) {
        p = plot_list;
        while (p) {
            auxPlot = 1;
            /* If the plot is in the first position */
            if (plot_list->pl_next && strcmp(plot_list->pl_title, namecircuit) == 0)
                plot_list = plot_list->pl_next;
            /* otherwise we run over the list of plots */
            else {
                for (; strcmp(p->pl_title, namecircuit) != 0 && p->pl_next; p = p->pl_next)
                    auxPlot++;
                if (strcmp(p->pl_title, namecircuit) == 0) {
                    paux = plot_list;
                    for (i = 1; i < auxPlot-1; i++)
                        paux = paux->pl_next;
                    paux->pl_next = paux->pl_next->pl_next;
                }
            }
            p = p->pl_next;
        }
    }

    /* if (ft_curckt) {
        ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES, ft_circuits->ci_devices);
        ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, ft_circuits->ci_nodes);
    } */

    if (ft_circuits && caux->ci_next) {
        struct wordlist *wlist;
        wlist = wl_cons(tprintf("%d", auxCir), NULL);
        com_scirc(wlist);
        wl_free(wlist);
    }
    else if (ft_circuits) {
        struct wordlist *wlist;
        wlist = wl_cons(tprintf("%d", auxCir - 1), NULL);
        com_scirc(wlist);
        wl_free(wlist);
    }
    else
        ft_curckt = NULL;
}
コード例 #9
0
ファイル: nutinp.c プロジェクト: fengmm521/myspice
//void
//inp_nutsource(FILE *fp, bool comfile, char *filename)
void
inp_nutsource(FILE *fp, int comfile, char *filename)
{
    struct line *deck, *dd, *ld;
    struct line *realdeck, *options = NULL;
    char *tt = NULL, name[BSIZE_SP], *s, *t;
    //bool commands = FALSE;
    int commands = FALSE;
    wordlist *wl = NULL, *end = NULL;
    wordlist *controls = NULL;
    FILE *lastin, *lastout, *lasterr;

    deck = inp_readall(fp, NULL, comfile, FALSE); /* still to check if . or filename instead of NULL */
    if (!deck)
        return;

    realdeck = inp_deckcopy(deck);

    if (!comfile) {
        /* Save the title before INPgetTitle gets it. */
        tt = copy(deck->li_line);
        if (!deck->li_next)
            fprintf(cp_err, "Warning: no lines in deck...\n");
    }
    (void) fclose(fp);

    /* Now save the IO context and start a new control set...  After
     * we are done with the source we'll put the old file descriptors
     * back.  I guess we could use a FILE stack, but since this routine
     * is recursive anyway...
     */
    lastin = cp_curin;
    lastout = cp_curout;
    lasterr = cp_curerr;
    cp_curin = cp_in;
    cp_curout = cp_out;
    cp_curerr = cp_err;

    cp_pushcontrol();

    /* We should now go through the deck and execute front-end
     * commands and remove them. Front-end commands are enclosed by
     * the lines .control and .endc, unless comfile
     * is TRUE, in which case every line must be a front-end command.
     * There are too many problems with matching the first word on
     * the line.
     */
    ld = deck;
    if (comfile) {
        /* This is easy. */
        for (dd = deck; dd; dd = ld) {
            ld = dd->li_next;
            if ((dd->li_line[0] == '*') && (dd->li_line[1] != '#'))
                continue;
            if (!ciprefix(".control", dd->li_line) &&
                !ciprefix(".endc", dd->li_line)) {
                if (dd->li_line[0] == '*')
                    (void) cp_evloop(dd->li_line + 2);
                else
                    (void) cp_evloop(dd->li_line);
            }
            tfree(dd->li_line);
            tfree(dd);
        }
    } else {
        for (dd = deck->li_next; dd; dd = ld->li_next) {
            if ((dd->li_line[0] == '*') && (dd->li_line[1] != '#')) {
                ld = dd;
                continue;
            }
            (void) strncpy(name, dd->li_line, BSIZE_SP);
            for (s = name; *s && isspace(*s); s++)
                ;
            for (t = s; *t && !isspace(*t); t++)
                ;
            *t = '\0';

            if (ciprefix(".control", dd->li_line)) {
                ld->li_next = dd->li_next;
                tfree(dd->li_line);
                tfree(dd);
                if (commands)
                    fprintf(cp_err, "Warning: redundant .control line\n");
                else
                    commands = TRUE;
            } else if (ciprefix(".endc", dd->li_line)) {
                ld->li_next = dd->li_next;
                tfree(dd->li_line);
                tfree(dd);
                if (commands)
                    commands = FALSE;
                else
                    fprintf(cp_err, "Warning: misplaced .endc line\n");
            } else if (commands || prefix("*#", dd->li_line)) {
                controls = wl_cons(NULL, controls);
                wl = controls;
                if (prefix("*#", dd->li_line))
                    wl->wl_word = copy(dd->li_line + 2);
                else
                    wl->wl_word = dd->li_line;
                ld->li_next = dd->li_next;
                tfree(dd);
            } else if (!*dd->li_line) {
                /* So blank lines in com files don't get
                 * considered as circuits.
                 */
                ld->li_next = dd->li_next;
                tfree(dd->li_line);
                tfree(dd);
            } else {
                inp_casefix(s);
                inp_casefix(dd->li_line);
                if (eq(s, ".width") || ciprefix(".four", s) ||
                    eq(s, ".plot")  ||
                    eq(s, ".print") ||
                    eq(s, ".save"))
                {
                    wl_append_word(&wl, &end, copy(dd->li_line));
                    ld->li_next = dd->li_next;
                    tfree(dd->li_line);
                    tfree(dd);
                } else {
                    ld = dd;
                }
            }
        }
        if (deck->li_next) {
            /* There is something left after the controls. */
            fprintf(cp_out, "\nCircuit: %s\n\n", tt);
            fprintf(stderr, "\nCircuit: %s\n\n", tt);

            /* Now expand subcircuit macros. Note that we have to
             * fix the case before we do this but after we
             * deal with the commands.
             */
            if (!cp_getvar("nosubckt", CP_BOOL, NULL))
                deck->li_next = inp_subcktexpand(deck->li_next);
            deck->li_actual = realdeck;
            nutinp_dodeck(deck, tt, wl, FALSE, options, filename);
        }

        /* Now that the deck is loaded, do the commands... */
        controls = wl_reverse(controls);
        for (wl = controls; wl; wl = wl->wl_next)
            (void) cp_evloop(wl->wl_word);
        wl_free(controls);
    }

    /* Now reset everything.  Pop the control stack, and fix up the IO
     * as it was before the source.
     */
    cp_popcontrol();

    cp_curin = lastin;
    cp_curout = lastout;
    cp_curerr = lasterr;

    tfree(tt);
}