rawspice fixed.


To ng-spice@ieee.ing.uniroma1.it
From Herbert Widlok <widlok@uci.agh.edu.pl>
Date Wed, 22 Mar 2000 12:07:55 +0100
Delivered-To mailing list ng-spice@ieee.ing.uniroma1.it
Mailing-List contact ng-spice-help@ieee.ing.uniroma1.it; run by ezmlm
References <Pine.LNX.3.96.1000314162315.20031A-100000@ieee.ing.uniroma1.it > <38D77C88.9AC8E5AC@uci.agh.edu.pl >
Reply-To ng-spice@ieee.ing.uniroma1.it

Hello,

    This is my fixes. ng-spice had some problems with ac analysis, and rawfile
generation, now it works right. Like usually I have marked all my additions 
by /* MW. .
. . */.
    spicelib.tar contains (tared and gziped) mslib, two small scripts and 
spiceprm -
quite useful for using libraries, please copy it to contrib. directory.

Michael Widlok


/**********
Copyright 1990 Regents of the University of California.  All rights reserved.
Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/

/*
 *
 * Read and write the ascii and binary rawfile formats.
 */

#include "spice.h"
#include "cpdefs.h"
#include "ftedefs.h"
#include "ftedata.h"
#include "suffix.h"

static void fixdims(struct dvec *v, char *s);

int raw_prec = -1;        /* How many sigfigs to use, default 15 (max).  */

#define DEFPREC 15

/* Write a raw file.  We write everything in the plot pointed to. */

void
raw_write(char *name, struct plot *pl, bool app, bool binary)
{
    FILE *fp;
    bool realflag = true, writedims;
    bool raw_padding;
    int length, numdims, dims[MAXDIMS];
    int nvars, i, j, prec;
    struct dvec *v, *lv;
    wordlist *wl;
    struct variable *vv;
    double dd;

    if (!cp_getvar("nopadding", VT_BOOL, (char *) &raw_padding))
        raw_padding = false;
    /* Invert since we want to know if we should pad. */
    raw_padding = !raw_padding;

    /* Why bother printing out an empty plot? */
    if (!pl->pl_dvecs) {
        fprintf(cp_err, "Error: plot is empty, nothing written.\n");
        return;
    }

    if (raw_prec != -1)
        prec = raw_prec;
    else
        prec = DEFPREC;

    if (!(fp = fopen(name, app ? "a" : "w"))) {
        perror(name);
        return;
    }

    numdims = nvars = length = 0;
    for (v = pl->pl_dvecs; v; v = v->v_next) {
        if (iscomplex(v))
            realflag = false;
        nvars++;
        /* Find the length and dimensions of the longest vector
         * in the plot.
         * Be paranoid and assume somewhere we may have
         * forgotten to set the dimensions of 1-D vectors.
         */
        if (v->v_numdims <= 1) {
            v->v_numdims = 1;
            v->v_dims[0] = v->v_length;
        }
        if (v->v_length > length) {
            length = v->v_length;
            numdims = v->v_numdims;
            for (j = 0; j < numdims; j++) {
                dims[j] = v->v_dims[j];
            }
        }
    }

    fprintf(fp, "Title: %s\n", pl->pl_title);
    fprintf(fp, "Date: %s\n", pl->pl_date);
    fprintf(fp, "Plotname: %s\n", pl->pl_name);
    fprintf(fp, "Flags: %s%s\n",
            realflag ? "real" : "complex", raw_padding ? "" : " unpadded" );
    fprintf(fp, "No. Variables: %d\n", nvars);
    fprintf(fp, "No. Points: %d\n", length);
    if (numdims > 1) {
        fprintf(fp, "Dimensions: %s\n", dimstring(dims, numdims));
    }

    for (wl = pl->pl_commands; wl; wl = wl->wl_next)
        fprintf(fp, "Command: %s\n", wl->wl_word);

    for (vv = pl->pl_env; vv; vv = vv->va_next) {
        wl = cp_varwl(vv);
        if (vv->va_type == VT_BOOL) {
            fprintf(fp, "Option: %s\n", vv->va_name);
        } else {
            fprintf(fp, "Option: %s = ", vv->va_name);
            if (vv->va_type == VT_LIST)
                fprintf(fp, "( ");
            wl_print(wl, fp);
            if (vv->va_type == VT_LIST)
                fprintf(fp, " )");
            (void) putc('\n', fp);
        }
    }

    /* Before we write the stuff out, make sure that the scale is the first
     * in the list.
     */
    for (lv = NULL, v = pl->pl_dvecs; v != pl->pl_scale; v = v->v_next)
        lv = v;
    if (lv) {
        lv->v_next = v->v_next;
        v->v_next = pl->pl_dvecs;
        pl->pl_dvecs = v;
    }

    fprintf(fp, "Variables:\n");
    for (i = 0, v = pl->pl_dvecs; v; v = v->v_next) {
        fprintf(fp, "\t%d\t%s\t%s", i++, v->v_name,
                ft_typenames(v->v_type));
        if (v->v_flags & VF_MINGIVEN)
            fprintf(fp, " min=%e", v->v_minsignal);
        if (v->v_flags & VF_MAXGIVEN)
            fprintf(fp, " max=%e", v->v_maxsignal);
        if (v->v_defcolor)
            fprintf(fp, " color=%s", v->v_defcolor);
        if (v->v_gridtype)
            fprintf(fp, " grid=%d", v->v_gridtype);
        if (v->v_plottype)
            fprintf(fp, " plot=%d", v->v_gridtype);
        /* Only write dims if they are different from default. */
        writedims = false;
        if (v->v_numdims != numdims) {
          writedims = true;
        } else {
            for (j = 0; j < numdims; j++)
                if (dims[j] != v->v_dims[j])
                    writedims = true;
        }
        if (writedims) {
            fprintf(fp, " dims=%s", dimstring(v->v_dims, v->v_numdims));
        }
        (void) putc('\n', fp);
    }

    if (binary) {
        fprintf(fp, "Binary:\n");
        for (i = 0; i < length; i++) {
            for (v = pl->pl_dvecs; v; v = v->v_next) {
                /* Don't run off the end of this vector's data. */
                if (i < v->v_length) {
                    if (realflag) {
                        dd = (isreal(v) ? v->v_realdata[i] :
                            realpart(&v->v_compdata[i]));
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                    } else if (isreal(v)) {
                        dd = v->v_realdata[i];
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                        dd = 0.0;
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                    } else {
                        dd = realpart(&v->v_compdata[i]);
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                        dd = imagpart(&v->v_compdata[i]);
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                    }
                } else if (raw_padding) {
                    dd = 0.0;
                    if (realflag) {
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                    } else {
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                        (void) fwrite((char *) &dd, sizeof
                                (double), 1, fp);
                    }
                }
            }
        }
    } else {
        fprintf(fp, "Values:\n");
        for (i = 0; i < length; i++) {
            fprintf(fp, " %d", i);
            for (v = pl->pl_dvecs; v; v = v->v_next) {
                if (i < v->v_length) {
                    if (realflag)
                        fprintf(fp, "\t%.*e\n", prec,
                            isreal(v) ? v->v_realdata[i] :
                            realpart(&v->v_compdata[i]));
                    else if (isreal(v))
                        fprintf(fp, "\t%.*e,0.0\n", prec,
                            v->v_realdata[i]);
                    else
                        fprintf(fp, "\t%.*e,%.*e\n", prec,
                            realpart(&v->v_compdata[i]),
                            prec,
                            imagpart(&v->v_compdata[i]));
                } else if (raw_padding) {
                    if (realflag) {
                        fprintf(fp, "\t%.*e\n", prec, 0.0);
                    } else {
                        fprintf(fp, "\t%.*e,%.*e\n",
                                prec, 0.0, prec, 0.0);
                    }
                }
            }
            (void) putc('\n', fp);
        }
    }
    (void) fclose(fp);
    return;
}

/* Read a raw file.  Returns a list of plot structures.  This routine should 
be
 * very flexible about what it expects to see in the rawfile.  Really all we
 * require is that there be one variables and one values section per plot
 * and that the variables precede the values.
 */

#define skip(s) while (*(s) && !isspace(*(s)))(s)++; while 
(isspace(*(s)))(s)++
#define nonl(s) r = (s); while (*r && (*r != '\n')) r++; *r = '\0'

struct plot *
raw_read(char *name)
{
    char *title = "default title";
    char *date = 0;
    struct plot *plots = NULL, *curpl = NULL;
    char buf[BSIZE_SP], buf2[BSIZE_SP], *s, *t, *r;
    int flags, nvars, npoints, i, j;
    int ndimpoints, numdims=0, dims[MAXDIMS];
    bool raw_padded = true;
    double junk;
    struct dvec *v, *nv;
    struct variable *vv;
    wordlist *wl, *nwl;
    FILE *fp, *lastin, *lastout, *lasterr;

    if (!(fp = fopen(name, "r"))) {
        perror(name);
        return (NULL);
    }

    /* Since we call cp_evloop() from here, we have to do this junk. */
    lastin = cp_curin;
    lastout = cp_curout;
    lasterr = cp_curerr;
    cp_curin = cp_in;
    cp_curout = cp_out;
    cp_curerr = cp_err;

    cp_pushcontrol();

    while (fgets(buf, BSIZE_SP, fp)) {
        /* Figure out what this line is... */
        if (ciprefix("title:", buf)) {
            s = buf;
            skip(s);
            nonl(s);
            title = copy(s);
        } else if (ciprefix("date:", buf)) {
            s = buf;
            skip(s);
            nonl(s);
            date = copy(s);
        } else if (ciprefix("plotname:", buf)) {
            s = buf;
            skip(s);
            nonl(s);
            if (curpl) {    /* reverse commands list */
                for (wl=curpl->pl_commands,
                        curpl->pl_commands=NULL; wl &&
                        wl->wl_next; wl=nwl) {
                    nwl = wl->wl_next;
                    wl->wl_next = curpl->pl_commands;
                    curpl->pl_commands = wl;
                }
            }
            curpl = alloc(struct plot);
            curpl->pl_next = plots;
            plots = curpl;
            curpl->pl_name = copy(s);
            if (!date)
                date = copy(datestring( ));
            curpl->pl_date = date;
            curpl->pl_title = copy(title);
            flags = VF_PERMANENT;
            nvars = npoints = 0;
        } else if (ciprefix("flags:", buf)) {
            s = buf;
            skip(s);
            while (t = gettok(&s)) {
                if (cieq(t, "real"))
                    flags |= VF_REAL;
                else if (cieq(t, "complex"))
                    flags |= VF_COMPLEX;
                else if (cieq(t, "unpadded"))
                    raw_padded = false;
                else if (cieq(t, "padded"))
                    raw_padded = true;
                else
                    fprintf(cp_err,
                        "Warning: unknown flag %s\n",
                        t);
            }
        } else if (ciprefix("no. variables:", buf)) {
            s = buf;
            skip(s);
            skip(s);
            nvars = scannum(s);
        } else if (ciprefix("no. points:", buf)) {
            s = buf;
            skip(s);
            skip(s);
            npoints = scannum(s);
        } else if (ciprefix("dimensions:", buf)) {
            if (npoints == 0) {
                fprintf(cp_err, 
                    "Error: misplaced Dimensions: line\n");
                continue;
            }
            s = buf;
            skip(s);
            if (atodims(s, dims, &numdims)) { /* Something's wrong. */
                fprintf(cp_err, 
                    "Warning: syntax error in dimensions, ignored.\n");
                numdims = 0;
                continue;
            }
            if (numdims > MAXDIMS) {
                numdims = 0;
                continue;
            }
            /* Let's just make sure that the no. of points
             * and the dimensions are consistent.
             */
            for (j = 0, ndimpoints = 1; j < numdims; j++) {
                ndimpoints *= dims[j];
            }

            if (ndimpoints != npoints) {
                fprintf(cp_err,
            "Warning: dimensions inconsistent with no. of points, 
ignored.\n");
                numdims = 0;
            }
        } else if (ciprefix("command:", buf)) {
            /* Note that we reverse these commands eventually... */
            s = buf;
            skip(s);
            nonl(s);
            if (curpl) {
                wl = alloc(struct wordlist);
                wl->wl_word = copy(s);
                wl->wl_next = curpl->pl_commands;
                if (curpl->pl_commands)
                    curpl->pl_commands->wl_prev = wl;
                curpl->pl_commands = wl;
            } else
                fprintf(cp_err, 
                    "Error: misplaced Command: line\n");
            /* Now execute the command if we can. */
            (void) cp_evloop(s);
        } else if (ciprefix("option:", buf)) {
            s = buf;
            skip(s);
            nonl(s);
            if (curpl) {
                wl = cp_lexer(s);
                for (vv = curpl->pl_env; vv && vv->va_next;
                        vv = vv->va_next)
                    ;
                if (vv)
                    vv->va_next = cp_setparse(wl);
                else
                    curpl->pl_env = cp_setparse(wl);
            } else
                fprintf(cp_err, 
                    "Error: misplaced Option: line\n");
        } else if (ciprefix("variables:", buf)) {
            /* We reverse the dvec list eventually... */
            if (!curpl) {
                fprintf(cp_err, "Error: no plot name given\n");
                plots = NULL;
                break;
            }
            s = buf;
            skip(s);
            if (!*s) {
                (void) fgets(buf, BSIZE_SP, fp);
                s = buf;
            }
            if (numdims == 0) {
                numdims = 1;
                dims[0] = npoints;
            }
            /* Now read all the variable lines in. */
            for (i = 0; i < nvars; i++) {
                v = alloc(struct dvec);
                ZERO(v, struct dvec);
                v->v_next = curpl->pl_dvecs;
                curpl->pl_dvecs = v;
                if (!curpl->pl_scale)
                    curpl->pl_scale = v;
                v->v_flags = flags;
                v->v_plot = curpl;
                v->v_length = npoints;
                v->v_numdims = 0;
                /* Length and dims might be changed by options. */

                if (!i)
                    curpl->pl_scale = v;
                else {
                    (void) fgets(buf, BSIZE_SP, fp);
                    s = buf;
                }
                (void) gettok(&s);  /* The index field. */
                if (t = gettok(&s)) {
                    v->v_name = t;
                } else {
                    fprintf(cp_err, 
                        "Error: bad var line %s\n",
                        buf);

/* MW. v_name must be valid in the case that no. points = 0 */
                    v->v_name = "no vars\n";
                    }
                    
                t = gettok(&s); /* The type name. */
                if (t)
                    v->v_type = ft_typnum(t);
                else
                    fprintf(cp_err, 
                        "Error: bad var line %s\n",
                        buf);
                
                /* Fix the name... */
                if (isdigit(*v->v_name) && (r = ft_typabbrev(v
                        ->v_type))) {
                    (void) sprintf(buf2, "%s(%s)", r,
                            v->v_name);
                    v->v_name = copy(buf2);
                }
                /* Now come the strange options... */
                while (t = gettok(&s)) {
                    if (ciprefix("min=", t)) {
                        if (sscanf(t + 4, "%lf",
                            &v->v_minsignal) != 1)
                            fprintf(cp_err,
                            "Error: bad arg %s\n",
                            t);
                        v->v_flags |= VF_MINGIVEN;
                    } else if (ciprefix("max=", t)) {
                        if (sscanf(t + 4, "%lf",
                            &v->v_maxsignal) != 1)
                            fprintf(cp_err,
                            "Error: bad arg %s\n",
                            t);
                        v->v_flags |= VF_MAXGIVEN;
                    } else if (ciprefix("color=", t)) {
                        v->v_defcolor = copy(t + 6);
                    } else if (ciprefix("scale=", t)) {
                        /* This is bad, but... */
                        v->v_scale = (struct dvec *)
                                copy(t + 6);
                    } else if (ciprefix("grid=", t)) {
                        v->v_gridtype = (GRIDTYPE)
                                scannum(t + 5);
                    } else if (ciprefix("plot=", t)) {
                        v->v_plottype = (PLOTTYPE)
                                scannum(t + 5);
                    } else if (ciprefix("dims=", t)) {
                        fixdims(v, t + 5);
                    } else {
                        fprintf(cp_err, 
                        "Warning: bad var param %s\n",
                            t);
                    }
                }
                /* Now we default any missing dimensions. */
                if (!v->v_numdims) {
                    v->v_numdims = numdims;
                    for (j = 0; j < numdims; j++)
                        v->v_dims[j] = dims[j];
                }
                /* And allocate the data array. We would use
                 * the desired vector length, but this would
                 * be dangerous if the file is invalid.
                 */
                if (isreal(v))
                    v->v_realdata = (double *) tmalloc(
                        npoints * sizeof (double));
                else
                    v->v_compdata = (complex *) tmalloc(
                        npoints * sizeof (complex));
            }
        } else if (ciprefix("values:", buf) || 
                ciprefix("binary:", buf)) {
            if (!curpl) {
                fprintf(cp_err, "Error: no plot name given\n");
                plots = NULL;
                break;
            }

            /* We'd better reverse the dvec list now... */
            for (v = curpl->pl_dvecs, curpl->pl_dvecs = NULL; v;
                    v = nv) {
                nv = v->v_next;
                v->v_next = curpl->pl_dvecs;
                curpl->pl_dvecs = v;
            }
                
            /* And fix the scale pointers. */
            for (v = curpl->pl_dvecs; v; v = v->v_next) {
                if (v->v_scale) {
                    for (nv = curpl->pl_dvecs; nv; nv =
                            nv->v_next)
                        if (cieq((char *) v->v_scale,
                                nv->v_name)) {
                            v->v_scale = nv;
                            break;
                        }
                    if (!nv) {
                        fprintf(cp_err,
                        "Error: no such vector %s\n",
                            (char *) v->v_scale);
                        v->v_scale = NULL;
                    }
                }
            }
            for (i = 0; i < npoints; i++) {
                if ((*buf == 'v') || (*buf == 'V')) {
                    /* It's an ASCII file. */
                    (void) fscanf(fp, " %d", &j);
                    for (v = curpl->pl_dvecs; v; v = v->v_next) {
                        if (i < v->v_length) {
                            if (flags & VF_REAL) {
                                if (fscanf(fp, " %lf", 
                                        &v->v_realdata[i]) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            } else {
                                if (fscanf(fp, " %lf, %lf",
                                        &realpart(&v->v_compdata[i]),
                                        &imagpart(&v->v_compdata[i])) != 2)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            }
                        } else if (raw_padded) {
                            if (flags & VF_REAL) {
                                if (fscanf(fp, " %lf", 
                                        &junk) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            } else {
                                if (fscanf(fp, " %lf, %lf",
                                        &junk, &junk) != 2)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            }
                        }
                    }
                } else {
                    /* It's a Binary file. */
                    for (v = curpl->pl_dvecs; v; v = v->v_next) {
                        if (i < v->v_length) {
                            if (flags & VF_REAL) {
                                if (fread((char *) &v->v_realdata[i],
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            } else {
                                if (fread((char *) &v->v_compdata[i].cx_real,
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                        "Error: bad rawfile\n");
                                if (fread((char *) &v->v_compdata[i].cx_imag,
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            }
                        } else if (raw_padded) {
                            if (flags & VF_REAL) {
                                if (fread((char *) &junk,
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            } else {
                                if (fread((char *) &junk,
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                                if (fread((char *) &junk,
                                        sizeof (double), 1, fp) != 1)
                                    fprintf(cp_err,
                                            "Error: bad rawfile\n");
                            }
                        }
                    }
                }
            }
        } else {
            s = buf;
            skip(s);
            if (*s) {
                fprintf(cp_err, 
            "Error: strange line in rawfile;\n\t\"%s\"\nload aborted.\n", s);
                return (NULL);
            }
        }
    }

    if (curpl) {    /* reverse commands list */
        for (wl=curpl->pl_commands,
                curpl->pl_commands=NULL; wl &&
                wl->wl_next; wl=nwl) {
            nwl = wl->wl_next;
            wl->wl_next = curpl->pl_commands;
            curpl->pl_commands = wl;
        }
    }

    /* Fix everything up nicely again. */
    cp_popcontrol();
    cp_curin = lastin;
    cp_curout = lastout;
    cp_curerr = lasterr;
    (void) fclose(fp);
    return (plots);
}

/* s is a string of the form d1,d2,d3... */

static void
fixdims(struct dvec *v, char *s)
{
    int i, ndimpoints;

    if (atodims(s, v->v_dims, &(v->v_numdims))) { /* Something's wrong. */
        fprintf(cp_err, 
            "Warning: syntax error in dimensions, ignored.\n");
        return;
    } else if (v->v_numdims > MAXDIMS) {
        return;
    }

    /* If the no. of points is less than the the total data length,
     * truncate the vector length.  If it's greater in length, we
     * have serious problems with this vector.  Try to fix
     * by setting to default dimensions when we return.
     */
    for (i = 0, ndimpoints = 1; i < v->v_numdims; i++) {
        ndimpoints *= v->v_dims[i];
    }

    if (ndimpoints > v->v_length) {
        v->v_numdims = 0;
    } else {
        v->v_length = ndimpoints;
    }
    return;
}
/**********
Copyright 1990 Regents of the University of California.  All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/

/*
 * Interface routines. These are specific to spice. The only changes to FTE
 * that should be needed to make FTE work with a different simulator is
 * to rewrite this file. What each routine is expected to do can be
 * found in the programmer's manual. This file should be the only one
 * that includes spice header files.
 */

#include "spice.h"
#include "cpdefs.h"
#include "ftedefs.h"
#include "fteinp.h"
#include "fteconst.h"
#include "inpdefs.h"
#include "iferrmsg.h"
#include "ifsim.h"
#include "suffix.h"

static IFvalue *doask(char *ckt, int typecode, GENinstance *dev, GENmodel 
*mod, IFparm *opt, int ind);
static int doset(char *ckt, int typecode, GENinstance *dev, GENmodel *mod, 
IFparm *opt, struct dvec *val);
static int finddev(char *ck, char *name, GENERIC **devptr, GENERIC **modptr);
static IFparm * parmlookup(IFdevice *dev, GENinstance **inptr, char *param, 
int do_model, int inout);
static struct variable *parmtovar(IFvalue *pv, IFparm *opt);

/* Input a single deck, and return a pointer to the circuit. */

char *
if_inpdeck(struct line *deck, INPtables **tab)
{
    GENERIC *ckt;
    int err, i, j;
    struct line *ll;
    IFuid taskUid;
    IFuid optUid;
    int which = -1;

    for (i = 0, ll = deck; ll; ll = ll->li_next)
        i++;
    *tab = INPtabInit(i);
    ft_curckt->ci_symtab = *tab;
    if ((err = (*(ft_sim->newCircuit))(&ckt))
            != OK) {
        ft_sperror(err, "CKTinit");
        return (NULL);
    }
    err = 
IFnewUid(ckt,&taskUid,(IFuid)NULL,"default",UID_TASK,(GENERIC**)NULL);
    if(err) {
        ft_sperror(err,"newUid");
        return(NULL);
    }
    err = 
(*(ft_sim->newTask))(ckt,(GENERIC**)&(ft_curckt->ci_defTask),taskUid);
    if(err) {
        ft_sperror(err,"newTask");
        return(NULL);
    }
    for(j=0;j<ft_sim->numAnalyses;j++) {
        if(strcmp(ft_sim->analyses[j]->name,"options")==0) {
            which = j;
            break;
        }
    } 
    if(which != -1) {
        err = IFnewUid(ckt,&optUid,(IFuid)NULL,"options",UID_ANALYSIS,
                (GENERIC**)NULL);
        if(err) {
            ft_sperror(err,"newUid");
            return(NULL);
        }
        err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid,
                (GENERIC**)&(ft_curckt->ci_defOpt),
                (GENERIC*)ft_curckt->ci_defTask);
        if(err) {
            ft_sperror(err,"createOptions");
            return(NULL);
        }
        ft_curckt->ci_curOpt  = ft_curckt->ci_defOpt;
    }
    ft_curckt->ci_curTask = ft_curckt->ci_defTask;
    INPpas1((GENERIC *) ckt, (card *) deck->li_next,(INPtables *)*tab);
    INPpas2((GENERIC *) ckt, (card *) deck->li_next,
            (INPtables *) *tab,ft_curckt->ci_defTask);
    INPkillMods();
    return (ckt);
}

/* Do a run of the circuit, of the given type. Type "resume" is special --
 * it means to resume whatever simulation that was in progress. The
 * return value of this routine is 0 if the exit was ok, and 1 if there was
 * a reason to interrupt the circuit (interrupt typed at the keyboard,
 * error in the simulation, etc). args should be the entire command line,
 * e.g. "tran 1 10 20 uic"
 */

int
if_run(char *t, char *what, wordlist *args, char *tab)
{
    GENERIC *ckt = (GENERIC *) t;
    int err;
    struct line deck;
    char buf[BSIZE_SP];
    int j;
    int which = -1;
    IFuid specUid,optUid;

    /* First parse the line... */
    if (eq(what, "tran") || eq(what, "ac") || eq(what, "dc")
            || eq(what, "op") || eq(what, "pz") || eq(what,"disto")
            || eq(what, "adjsen") || eq(what, "sens") || eq(what,"tf")
            || eq(what, "noise")) {
        (void) sprintf(buf, ".%s", wl_flatten(args));
        deck.li_next = deck.li_actual = NULL;
        deck.li_error = NULL;
        deck.li_linenum = 0;
        deck.li_line = buf;
        if(ft_curckt->ci_specTask) {
            err=(*(ft_sim->deleteTask))(ft_curckt->ci_ckt,
                    ft_curckt->ci_specTask);
            if(err) {
                ft_sperror(err,"deleteTask");
                return(2);
            }
        }
        err = IFnewUid(ft_curckt->ci_ckt,&specUid,(IFuid)NULL,"special",
                UID_TASK,(GENERIC**)NULL);
        if(err) {
            ft_sperror(err,"newUid");
            return(2);
        }
        err = (*(ft_sim->newTask))(ft_curckt->ci_ckt,
                (GENERIC**)&(ft_curckt->ci_specTask),specUid);
        if(err) {
            ft_sperror(err,"newTask");
            return(2);
        }
        for(j=0;j<ft_sim->numAnalyses;j++) {
            if(strcmp(ft_sim->analyses[j]->name,"options")==0) {
                which = j;
                break;
            }
        } 
        if(which != -1) {
            err = IFnewUid(ft_curckt->ci_ckt,&optUid,(IFuid)NULL,"options",
                    UID_ANALYSIS,(GENERIC**)NULL);
            if(err) {
                ft_sperror(err,"newUid");
                return(2);
            }
            err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid,
                    (GENERIC**)&(ft_curckt->ci_specOpt),
                    (GENERIC*)ft_curckt->ci_specTask);
            if(err) {
                ft_sperror(err,"createOptions");
                return(2);
            }
            ft_curckt->ci_curOpt  = ft_curckt->ci_specOpt;
        }
        ft_curckt->ci_curTask = ft_curckt->ci_specTask;
        INPpas2(ckt, (card *) &deck, (INPtables *)tab, 
ft_curckt->ci_specTask);
        if (deck.li_error) {
            fprintf(cp_err, "Warning: %s\n", deck.li_error);
            return 2;
        }
    }
    if( eq(what,"run") ) {
        ft_curckt->ci_curTask = ft_curckt->ci_defTask;
        ft_curckt->ci_curOpt = ft_curckt->ci_defOpt;
    }

    if (  (eq(what, "tran"))  ||
          (eq(what, "ac"))  ||
          (eq(what, "dc")) ||
          (eq(what, "op")) ||
          (eq(what, "pz")) ||
          (eq(what, "disto")) ||
          (eq(what, "noise")) ||
            eq(what, "adjsen") || eq(what, "sens") || eq(what,"tf") ||
          (eq(what, "run"))     )  {
        if ((err = (*(ft_sim->doAnalyses))(ckt, 1, 
ft_curckt->ci_curTask))!=OK){
            ft_sperror(err, "doAnalyses");
            /* wrd_end(); */
            if (err == E_PAUSE)
                return (1);
            else
                return (2);
        }
    } else if (eq(what, "resume")) {
        if ((err = (*(ft_sim->doAnalyses))(ckt, 0, 
ft_curckt->ci_curTask))!=OK){
            ft_sperror(err, "doAnalyses");
            /* wrd_end(); */
            if (err == E_PAUSE)
                return (1);
            else
                return (2);
        }
    } else {
        fprintf(cp_err, "if_run: Internal Error: bad run type %s\n",
                what);
        return (2);
    }
    return (0);
}

/* Set an option in the circuit. Arguments are option name, type, and
 * value (the last a char *), suitable for casting to whatever needed...
 */

static char *unsupported[] = {
    "itl3",
    "itl5",
    "lvltim",
    "maxord",
    "method",
    NULL
} ;

static char *obsolete[] = {
    "limpts",
    "limtim",
    "lvlcod",
    NULL
} ;

int
if_option(char *ckt, char *name, int type, char *value)
{
    IFvalue pval;
    int err, i;
    GENERIC *cc = (GENERIC *) ckt;
    char **vv;
    int which = -1;

    if (eq(name, "acct")) {
        ft_acctprint = true;
        return 0;
    } else if (eq(name, "list")) {
        ft_listprint = true;
        return 0;
    } else if (eq(name, "node")) {
        ft_nodesprint = true;
        return 0;
    } else if (eq(name, "opts")) {
        ft_optsprint = true;
        return 0;
    } else if (eq(name, "nopage")) {
        ft_nopage = true;
        return 0;
    } else if (eq(name, "nomod")) {
        ft_nomod = true;
        return 0;
    }

    for(i=0;i<ft_sim->numAnalyses;i++) {
        if(strcmp(ft_sim->analyses[i]->name,"options")==0) {
            which = i;
            break;
        }
    }
    if(which==-1) {
        fprintf(cp_err,"Warning:  .options line unsupported\n");
        return 0;
    }

    for (i = 0; i < ft_sim->analyses[which]->numParms; i++)
        if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name) &&
                (ft_sim->analyses[which]->analysisParms[i].dataType & IF_SET))
            break;
    if (i == ft_sim->analyses[which]->numParms) {
        /* See if this is unsupported or obsolete. */
        for (vv = unsupported; *vv; vv++)
            if (eq(name, *vv)) {
                fprintf(cp_err, 
            "Warning: option %s is currently unsupported.\n", name);
                return 1;
            }
        for (vv = obsolete; *vv; vv++)
            if (eq(name, *vv)) {
                fprintf(cp_err, 
                "Warning: option %s is obsolete.\n", name);
                return 1;
            }
        return 0;
    }

    switch (ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) 
{
        case IF_REAL:
            if (type == VT_REAL)
                pval.rValue = *((double *) value);
            else if (type == VT_NUM)
                pval.rValue = *((int *) value);
            else
                goto badtype;
            break;
        case IF_INTEGER:
            if (type == VT_NUM)
                pval.iValue = *((int *) value);
            else if (type == VT_REAL)
                pval.iValue = *((double *) value);
            else
                goto badtype;
            break;
        case IF_STRING:
            if (type == VT_STRING)
                pval.sValue = copy(value);
            else
                goto badtype;
            break;
        case IF_FLAG:
            /* Do nothing. */
            pval.iValue = *((int *) value);
            break;
        default:
            fprintf(cp_err, 
            "if_option: Internal Error: bad option type %d.\n",
                    ft_sim->analyses[which]->analysisParms[i].dataType);
    }

    if (!ckt) {
        /* XXX No circuit loaded */
        fprintf(cp_err, "Simulation parameter \"%s\" can't be set until\n",
                name);
        fprintf(cp_err, "a circuit has been loaded.\n");
        return 1;
    }

    if ((err = (*(ft_sim->setAnalysisParm))(cc, (GENERIC 
*)ft_curckt->ci_curOpt,
            ft_sim->analyses[which]->analysisParms[i].id, &pval,
            (IFvalue *)NULL)) != OK)
        ft_sperror(err, "setAnalysisParm(options)");
    return 1;
badtype:
    fprintf(cp_err, "Error: bad type given for option %s --\n", name);
    fprintf(cp_err, "\ttype given was ");
    switch (type) {
        case VT_BOOL:   fputs("boolean", cp_err); break;
        case VT_NUM:    fputs("integer", cp_err); break;
        case VT_REAL:   fputs("real", cp_err); break;
        case VT_STRING: fputs("string", cp_err); break;
        case VT_LIST:   fputs("list", cp_err); break;
        default:    fputs("something strange", cp_err); break;
    }
    fprintf(cp_err, ", type expected was ");
    switch(ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) {
        case IF_REAL:   fputs("real.\n", cp_err); break;
        case IF_INTEGER:fputs("integer.\n", cp_err); break;
        case IF_STRING: fputs("string.\n", cp_err); break;
        case IF_FLAG:   fputs("flag.\n", cp_err); break;
        default:    fputs("something strange.\n", cp_err); break;
    }
    if (type == VT_BOOL)
fputs("\t(Note that you must use an = to separate option name and value.)\n", 
                    cp_err); 
    return 0;
}

/* ARGSUSED */
void
if_dump(char *ckt, FILE *file)
{
    /*GENERIC *cc = (GENERIC *) ckt;*/

    fprintf(file,"diagnostic output dump unavailable.");
    return;
}

void
if_cktfree(char *ckt, char *tab)
{
    GENERIC *cc = (GENERIC *) ckt;

    (*(ft_sim->deleteCircuit))(cc);
    INPtabEnd((INPtables *) tab);
    return;
}

/* Return a string describing an error code. */


/* BLOW THIS AWAY.... */

char *
if_errstring(int code)
{
    return (INPerror(code));
}

/* Get a parameter value from the circuit. If name is left unspecified,
 * we want a circuit parameter.
 */

struct variable *
spif_getparam(char *ckt, char **name, char *param, int ind, int do_model)
{
    struct variable *vv = NULL, *tv;
    IFvalue *pv;
    IFparm *opt;
    int typecode, i;
    GENinstance *dev=(GENinstance *)NULL;
    GENmodel *mod=(GENmodel *)NULL;
    IFdevice *device;

    /* fprintf(cp_err, "Calling if_getparam(%s, %s)\n", *name, param); */

    if (param && eq(param, "all")) {
    
        /* MW. My "special routine here" */
        INPretrieve(name,(INPtables *)ft_curckt->ci_symtab);
        
        typecode = finddev(ckt, *name,(GENERIC**) &dev,(GENERIC**) &mod);
        if (typecode == -1) {
            fprintf(cp_err,
                "Error: no such device or model name %s\n",
                    *name);
            return (NULL);
        }
        device = ft_sim->devices[typecode];
        for (i = 0; i < *(device->numInstanceParms); i++) {
            opt = &device->instanceParms[i];
            if(opt->dataType & IF_REDUNDANT || !opt->description)
                    continue;
            if(!(opt->dataType & IF_ASK)) continue;
            pv = doask(ckt, typecode, dev, mod, opt, ind);
            if (pv) {
                tv = parmtovar(pv, opt);
                if (vv)
                    tv->va_next = vv;
                vv = tv;
            } else
                fprintf(cp_err,
            "Internal Error: no parameter '%s' on device '%s'\n",
                    device->instanceParms[i].keyword,
                    device->name);
        }
        return (vv);
    } else if (param) {
    
        /* MW.  */
        INPretrieve(name,(INPtables *)ft_curckt->ci_symtab);
        typecode = finddev(ckt, *name, (GENERIC**)&dev, (GENERIC**)&mod);
        if (typecode == -1) {
            fprintf(cp_err,
                "Error: no such device or model name %s\n",
                    *name);
            return (NULL);
        }
        device = ft_sim->devices[typecode];
        opt = parmlookup(device, &dev, param, do_model, 0);
        if (!opt) {
            fprintf(cp_err, "Error: no such parameter %s.\n",
                    param);
            return (NULL);
        }
        pv = doask(ckt, typecode, dev, mod, opt, ind);
        if (pv)
            vv = parmtovar(pv, opt);
        return (vv);
    } else
        return (if_getstat(ckt, *name));
}

void
if_setparam(char *ckt, char **name, char *param, struct dvec *val, int 
do_model)
{
    IFparm *opt;
    IFdevice *device;
    GENmodel *mod=(GENmodel *)NULL;
    GENinstance *dev=(GENinstance *)NULL;
    int typecode;

        /* PN  */
    INPretrieve(name,(INPtables *)ft_curckt->ci_symtab);
    typecode = finddev(ckt, *name, (GENERIC**)&dev, (GENERIC**)&mod);
    if (typecode == -1) {
        fprintf(cp_err, "Error: no such device or model name %s\n", *name);
        return;
    }
    device = ft_sim->devices[typecode];
    opt = parmlookup(device, &dev, param, do_model, 1);
    if (!opt) {
        if (param)
                fprintf(cp_err, "Error: no such parameter %s.\n", param);
        else
                fprintf(cp_err, "Error: no default parameter.\n");
        return;
    }
    if (do_model && !mod) {
        mod = dev->GENmodPtr;
        dev = (GENinstance *)NULL;
    }
    doset(ckt, typecode, dev, mod, opt, val);
}

static struct variable *
parmtovar(IFvalue *pv, IFparm *opt)
{
    struct variable *vv = alloc(struct variable);
    struct variable *nv;
    int i = 0;

    switch (opt->dataType & IF_VARTYPES) {
        case IF_INTEGER:
            vv->va_type = VT_NUM;
            vv->va_num = pv->iValue;
            break;
        case IF_REAL:
        case IF_COMPLEX:
            vv->va_type = VT_REAL;
            vv->va_real = pv->rValue;
            break;
        case IF_STRING:
            vv->va_type = VT_STRING;
            vv->va_string = pv->sValue;
            break;
        case IF_FLAG:
            vv->va_type = VT_BOOL;
            vv->va_bool = pv->iValue ? true : false;
            break;
        case IF_REALVEC:
            vv->va_type = VT_LIST;
            for (i = 0; i < pv->v.numValue; i++) {
                nv = alloc(struct variable);
                nv->va_next = vv->va_vlist;
                vv->va_vlist = nv;
                nv->va_type = VT_REAL;
                nv->va_real = pv->v.vec.rVec[i];
            }
            break;
        default:
            fprintf(cp_err,  
            "parmtovar: Internal Error: bad PARM type %d.\n",
                    opt->dataType);
            return (NULL);
    }

    /* It's not clear whether we want the keyword or the desc here... */
    vv->va_name = copy(opt->description);
    vv->va_next = NULL;
    return (vv);
}

/* Extract the IFparm structure from the device. If isdev is true, then get
 * the DEVmodQuest, otherwise get the DEVquest.
 */

static IFparm *
parmlookup(IFdevice *dev, GENinstance **inptr, char *param, int do_model, int 
inout)
{
    int i;

    /* fprintf(cp_err, "Called: parmlookup(%x, %c, %s)\n", 
            dev, isdev, param); */

    /* First try the device questions... */
    if (!do_model && dev->numInstanceParms) {
        for (i = 0; i < *(dev->numInstanceParms); i++) {
            if (!param && (dev->instanceParms[i].dataType & IF_PRINCIPAL))
                return (&dev->instanceParms[i]);
            else if (!param)
                continue;
            else if ((((dev->instanceParms[i].dataType & IF_SET) && inout == 
1)
                || ((dev->instanceParms[i].dataType & IF_ASK) && inout == 0))
                && eq(dev->instanceParms[i].keyword, param))
            {
                if (dev->instanceParms[i].dataType & IF_REDUNDANT)
                    i -= 1;
                return (&dev->instanceParms[i]);
            }
        }
        return NULL;
    }

    if (dev->numModelParms) {
        for (i = 0; i < *(dev->numModelParms); i++)
            if ((((dev->modelParms[i].dataType & IF_SET) && inout == 1)
                    || ((dev->modelParms[i].dataType & IF_ASK) && inout == 0))
                    && eq(dev->modelParms[i].keyword, param))
            {
                if (dev->modelParms[i].dataType & IF_REDUNDANT)
                    i -= 1;
                return (&dev->modelParms[i]);
            }
    }

    return (NULL);
}

/* Perform the CKTask call. We have both 'fast' and 'modfast', so the other
 * parameters aren't necessary.
 */

/* ARGSUSED */
static IFvalue *
doask(char *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, 
int ind)
{
    static IFvalue pv;
    int err;

    pv.iValue = ind;    /* Sometimes this will be junk and ignored... */

    /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n", 
            typecode, dev, mod, opt); */
    if (dev)
        err = (*(ft_sim->askInstanceQuest))((GENERIC *)ckt, (GENERIC *)dev, 
                opt->id, &pv, (IFvalue *)NULL);
    else
        err = (*(ft_sim->askModelQuest))((GENERIC*)ckt, (GENERIC*) mod, 
                opt->id, &pv, (IFvalue *)NULL);
    if (err != OK) {
        ft_sperror(err, "if_getparam");
        return (NULL);
    }

    return (&pv);
}

/* Perform the CKTset call. We have both 'fast' and 'modfast', so the other
 * parameters aren't necessary.
 */

/* ARGSUSED */
static int
doset(char *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, 
struct dvec *val)
{
    IFvalue nval;
    int err;
    int n;
    int *iptr;
    double *dptr;
    int i;

    /* Count items */
    if (opt->dataType & IF_VECTOR) {
        n = nval.v.numValue = val->v_length;

        dptr = val->v_realdata;
        /* XXXX compdata!!! */

        switch (opt->dataType & (IF_VARTYPES & ~IF_VECTOR)) {
            case IF_FLAG:
            case IF_INTEGER:
                iptr = nval.v.vec.iVec = NEWN(int, n);

                for (i = 0; i < n; i++)
                    *iptr++ = *dptr++;
                break;

            case IF_REAL:
                nval.v.vec.rVec = val->v_realdata;
                break;

            default:
                fprintf(cp_err,
                    "Can't assign value to \"%s\" (unsupported vector 
type)\n",
                    opt->keyword);
                return E_UNSUPP;
        }
    } else {
        switch (opt->dataType & IF_VARTYPES) {
            case IF_FLAG:
            case IF_INTEGER:
                nval.iValue = *val->v_realdata;
                break;

            case IF_REAL:

/*kensmith don't blow up with NULL dereference*/
                if (!val->v_realdata) {
                        fprintf(cp_err,"Unable to determine the value\n");
                        return E_UNSUPP;
                        }
            
                nval.rValue = *val->v_realdata;
                break;

            default:
                fprintf(cp_err,
                    "Can't assign value to \"%s\" (unsupported type)\n",
                    opt->keyword);
                return E_UNSUPP;
        }
    }

    /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n", 
            typecode, dev, mod, opt); */

    if (dev)
        err = (*(ft_sim->setInstanceParm))((GENERIC *)ckt, (GENERIC *)dev, 
                opt->id, &nval, (IFvalue *)NULL);
    else
        err = (*(ft_sim->setModelParm))((GENERIC*)ckt, (GENERIC*) mod, 
                opt->id, &nval, (IFvalue *)NULL);

    return err;
}



/* Get pointers to a device, its model, and its type number given the name. If
 * there is no such device, try to find a model with that name.
 */

static int
finddev(char *ck, char *name, GENERIC **devptr, GENERIC **modptr)
{
    int err;
    int type = -1;

    err = (*(ft_sim->findInstance))((GENERIC 
*)ck,&type,devptr,name,NULL,NULL);
    if(err == OK) return(type);
    type = -1;
    *devptr = (GENERIC *)NULL;
    err = (*(ft_sim->findModel))((GENERIC *)ck,&type,modptr,name);
    if(err == OK) return(type);
    *modptr = (GENERIC *)NULL;
    return(-1);

}

#ifdef notdef
/* XXX Not useful */
/* Extract the node and device names from the line and add them to the command
 * completion structure.  This is probably not a good thing to do if it
 * takes too much time.
 */

 /* BLOW THIS AWAY */

void
if_setndnames(line)
    char *line;
{
    char *t;
    int i;

    while (isspace(*line))
        line++;

    if (!*line || (*line == '*') || (*line == '.'))
        return;
    t = gettok(&line);

    if (!(i = inp_numnodes(*t)))
        return;
    if ((*t == 'q') || (*t == 'Q'))
        i = 3;
    
    cp_addkword(CT_DEVNAMES, t);
    while (i-- > 0) {
        t = gettok(&line);
        if (t)
            cp_addkword(CT_NODENAMES, t);
    }
    return;
}
#endif

/* get an analysis parameter by name instead of id */

int if_analQbyName(GENERIC *ckt, int which, GENERIC *anal, char *name, 
IFvalue *parm)
{
    int i;
    for(i=0;i<ft_sim->analyses[which]->numParms;i++) {
        if(strcmp(ft_sim->analyses[which]->analysisParms[i].keyword,name)==0) 
{
            return( (*(ft_sim->askAnalysisQuest))(ckt,anal,
                    ft_sim->analyses[which]->analysisParms[i].id,parm,
                    (IFvalue *)NULL) );
        }
    }
    return(E_BADPARM);
}

/* Get the parameters tstart, tstop, and tstep from the CKT struct. */

/* BLOW THIS AWAY TOO */

bool
if_tranparams(struct circ *ci, double *start, double *stop, double *step)
{
    IFvalue tmp;
    int err;
    int which = -1;
    int i;
    GENERIC *anal;
    IFuid tranUid;

    if(!ci->ci_curTask) return(false);
    for(i=0;i<ft_sim->numAnalyses;i++) {
        if(strcmp(ft_sim->analyses[i]->name,"TRAN")==0){
            which = i;
            break;
        }
    }
    if(which == -1) return(false);

    err = IFnewUid(ci->ci_ckt,&tranUid,(IFuid)NULL,"Transient Analysis",
        UID_ANALYSIS, (GENERIC**)NULL);
    if(err != OK) return(false);
    err =(*(ft_sim->findAnalysis))(ci->ci_ckt,&which, &anal,tranUid,
            ci->ci_curTask,(IFuid *)NULL);
    if(err != OK) return(false);
    err = if_analQbyName(ci->ci_ckt,which,anal,"tstart",&tmp);
    if(err != OK) return(false);
    *start = tmp.rValue;
    err = if_analQbyName(ci->ci_ckt,which,anal,"tstop",&tmp);
    if(err != OK) return(false);
    *stop = tmp.rValue;
    err = if_analQbyName(ci->ci_ckt,which,anal,"tstep",&tmp);
    if(err != OK) return(false);
    *step = tmp.rValue;
    return (true);
}

/* Get the statistic called 'name'.  If this is NULL get all statistics
 * available.
 */

struct variable *
if_getstat(char *ckt, char *name)
{
    int i;
    struct variable *v, *vars;
    IFvalue parm;
    int which = -1;

    for(i=0;i<ft_sim->numAnalyses;i++) {
        if(strcmp(ft_sim->analyses[i]->name,"options")==0) {
            which = i;
            break;
        }
    }
    if(which==-1) {
        fprintf(cp_err,"Warning:  statistics unsupported\n");
        return(NULL);
    }

    if (name) {
        for (i = 0; i < ft_sim->analyses[which]->numParms; i++)
            if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name))
                break;
        if (i == ft_sim->analyses[which]->numParms)
            return (NULL);
        if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask,
                ft_sim->analyses[which]->analysisParms[i].id, &parm, 
                (IFvalue *)NULL) == -1) {
            fprintf(cp_err, 
                "if_getstat: Internal Error: can't get %s\n",
                name);
            return (NULL);
        }
        return (parmtovar(&parm, 
&(ft_sim->analyses[which]->analysisParms[i])));
    } else {
        for (i = 0, vars = v = NULL; i<ft_sim->analyses[which]->numParms; 
i++) {
            if(!(ft_sim->analyses[which]->analysisParms[i].dataType&IF_ASK)) {
                continue;
            }
            if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask, 
                    ft_sim->analyses[which]->analysisParms[i].id, 
                    &parm, (IFvalue *)NULL) == -1) {
                fprintf(cp_err, 
                "if_getstat: Internal Error: can't get %s\n",
                    name);
                return (NULL);
            }
            if (v) {
                v->va_next = parmtovar(&parm, 
                        &(ft_sim->analyses[which]->analysisParms[i]));
                v = v->va_next;
            } else {
                vars = v = parmtovar(&parm, 
                        &(ft_sim->analyses[which]->analysisParms[i])); 
            }
        }
        return (vars);
    }
}

Spicelib.tar


Partial thread listing: