ngspice/src/frontend/define.c

464 lines
12 KiB
C
Raw Normal View History

2000-04-27 22:03:57 +02:00
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/*
* User-defined functions. The user defines the function with
* define func(arg1, arg2, arg3) <expression involving args...>
* Then when he types "func(1, 2, 3)", the commas are interpreted as
* binary operations of the lowest priority by the parser, and ft_substdef()
* below is given a chance to fill things in and return what the parse tree
* would have been had the entire thing been typed.
* Note that we have to take some care to distinguish between functions
* with the same name and different arities.
*/
#include "ngspice/ngspice.h"
#include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h"
#include "ngspice/dvec.h"
#include "ngspice/fteparse.h"
2000-04-27 22:03:57 +02:00
#include "define.h"
* src/Makefile.am src/main.c src/sconvert.c src/analysis/cktdisto.c src/analysis/cktnoise.c src/analysis/noisean.c: Updates for the new header files. * src/maths/cmaths/cmath1.c src/maths/cmaths/cmath2.c src/maths/cmaths/cmath3.c src/maths/cmaths/cmath4.c: Updates for the new header files. * src/frontend/.cvsignore src/frontend/Makefile.am: Updates for the new files. * src/frontend/agraf.c src/frontend/aspice.c src/frontend/breakp.c src/frontend/breakp2.c src/frontend/circuits.c src/frontend/cpitf.c src/frontend/debugcom.c src/frontend/define.c src/frontend/diff.c src/frontend/dimens.c src/frontend/display.c src/frontend/doplot.c src/frontend/dotcards.c src/frontend/evaluate.c src/frontend/fourier.c src/frontend/graf.c src/frontend/grid.c src/frontend/inp.c src/frontend/inpcom.c src/frontend/interp.c src/frontend/linear.c src/frontend/misccoms.c src/frontend/misccoms.h src/frontend/miscvars.c src/frontend/mw_coms.c src/frontend/newcoms.c src/frontend/nutinp.c src/frontend/options.c src/frontend/outitf.c src/frontend/parse.c src/frontend/plotcurv.c src/frontend/points.c src/frontend/postcoms.c src/frontend/rawfile.c src/frontend/runcoms.c src/frontend/runcoms2.c src/frontend/shyu.c src/frontend/spec.c src/frontend/spiceif.c src/frontend/typesdef.c src/frontend/vectors.c src/frontend/where.c src/frontend/postcoms.c: Updates for the new header files. Some commands have moved into the new files below. * src/frontend/README src/frontend/com_compose.c src/frontend/com_compose.h src/frontend/com_display.c src/frontend/com_display.h src/frontend/com_let.c src/frontend/com_let.h src/frontend/com_setscale.c src/frontend/com_setscale.h src/frontend/commands.c src/frontend/commands.h src/frontend/completion.h src/frontend/streams.h src/frontend/testcommands.c: Separation into different com_* commands. This is a start. The rest of the subdirectory needs doing. * src/include/complex.h src/include/cpdefs.h src/include/cpextern.h src/include/cpstd.h src/include/fteconst.h src/include/ftedata.h src/include/ftedev.h src/include/fteext.h src/include/ftegraph.h src/include/fteparse.h src/include/dvec.h src/include/grid.h src/include/plot.h src/include/pnode.h src/include/sim.h src/include/variable.h src/include/wordlist.h src/include/bool.h: Separation of header files into smaller pieces. This limits recompilation to only the affected source files. The original header files have a warning message embedded to flag obsoleted use. * src/frontend/compose.c src/frontend/compose.h src/frontend/nutctab.c src/frontend/nutctab.h src/frontend/plot5.c src/frontend/plot5.h src/frontend/spcmdtab.c src/frontend/x11.c src/frontend/x11.h src/frontend/xgraph.c src/frontend/xgraph.h: Moved these files into src/frontend/plotting subdirectory. * src/frontend/plotting/.cvsignore src/frontend/plotting/Makefile.am src/frontend/plotting/plot5.c src/frontend/plotting/plot5.h src/frontend/plotting/plotting.c src/frontend/plotting/plotting.h src/frontend/plotting/pvec.c src/frontend/plotting/pvec.h src/frontend/plotting/x11.c src/frontend/plotting/x11.h src/frontend/plotting/xgraph.c src/frontend/plotting/xgraph.h: The new libplotting library with automake and CVS infrastructure.
2000-05-06 16:12:51 +02:00
#include "completion.h"
2000-04-27 22:03:57 +02:00
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
static void savetree(struct pnode *pn);
static void prdefs(char *name);
2015-11-11 19:56:58 +01:00
static void prtree(struct udfunc *ud, FILE *fp);
2000-04-27 22:03:57 +02:00
static void prtree1(struct pnode *pn, FILE *fp);
static struct pnode *trcopy(struct pnode *tree, char *arg_names, struct pnode *args);
static struct pnode *ntharg(int num, struct pnode *args);
static int numargs(struct pnode *args);
2000-04-27 22:03:57 +02:00
static struct udfunc *udfuncs = NULL;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* Set up a function definition. */
void
com_define(wordlist *wlist)
{
int arity = 0, i;
char buf[BSIZE_SP], tbuf[BSIZE_SP], *s, *t, *b;
wordlist *wl;
struct pnode *names;
2000-04-27 22:03:57 +02:00
struct udfunc *udf;
/* If there's nothing then print all the definitions. */
if (wlist == NULL) {
2011-04-28 17:59:36 +02:00
prdefs(NULL);
2000-04-27 22:03:57 +02:00
return;
}
/* Accumulate the function head in the buffer, w/out spaces. A
* useful thing here would be to check to make sure that there
* are no formal parameters here called "list". But you have
* to try really hard to break this here.
*/
buf[0] = '\0';
2012-09-13 21:18:02 +02:00
for (wl = wlist; wl && (strchr(wl->wl_word, ')') == NULL);
2012-09-13 21:18:02 +02:00
wl = wl->wl_next)
2000-04-27 22:03:57 +02:00
(void) strcat(buf, wl->wl_word);
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if (wl) {
t = strchr(buf, '\0');
2015-11-11 21:20:50 +01:00
for (s = wl->wl_word; *s && (*s != ')');)
*t++ = *s++;
*t++ = ')';
2000-04-27 22:03:57 +02:00
*t = '\0';
if (*++s)
wl->wl_word = copy(s);
else
wl = wl->wl_next;
}
/* If that's all, then print the definition. */
if (wl == NULL) {
2015-11-12 17:55:58 +01:00
s = strchr(buf, '(');
if (s)
*s = '\0';
2000-04-27 22:03:57 +02:00
prdefs(buf);
return;
}
/* Now check to see if this is a valid name for a function (i.e,
* there isn't a predefined function of the same name).
*/
(void) strcpy(tbuf, buf);
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
for (b = tbuf; *b; b++)
if (isspace(*b) || (*b == '(')) {
2000-04-27 22:03:57 +02:00
*b = '\0';
break;
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
for (i = 0; ft_funcs[i].fu_name; i++)
if (eq(ft_funcs[i].fu_name, tbuf)) {
fprintf(cp_err, "Error: %s is a predefined function.\n",
tbuf);
return;
}
/* Parse the rest of it. We can't know if there are the right
* number of undefined variables in the expression.
*/
if ((names = ft_getpnames(wl, FALSE)) == NULL)
2000-04-27 22:03:57 +02:00
return;
/* This is a pain -- when things are garbage-collected, any
* vectors that may have been mentioned here will be thrown
* away. So go down the tree and save any vectors that aren't
* formal parameters.
*/
savetree(names);
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* Format the name properly and add to the list. */
b = copy(buf);
for (s = b; *s; s++) {
if (*s == '(') {
2000-04-27 22:03:57 +02:00
*s = '\0';
if (s[1] != ')')
2000-04-27 22:03:57 +02:00
arity++; /* It will have been 0. */
} else if (*s == ')') {
2000-04-27 22:03:57 +02:00
*s = '\0';
} else if (*s == ',') {
*s = '\0';
arity++;
}
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
for (udf = udfuncs; udf; udf = udf->ud_next)
if (prefix(b, udf->ud_name) && (arity == udf->ud_arity))
break;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if (udf == NULL) {
udf = alloc(struct udfunc);
udf->ud_next = udfuncs;
udfuncs = udf;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
udf->ud_text = names;
2000-04-27 22:03:57 +02:00
udf->ud_name = b;
udf->ud_arity = arity;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
cp_addkword(CT_UDFUNCS, b);
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* Kludge. */
static void
savetree(struct pnode *pn)
{
struct dvec *d;
if (pn->pn_value) {
/* We specifically don't add this to the plot list
* so it won't get gc'ed.
*/
d = pn->pn_value;
if ((d->v_length != 0) || eq(d->v_name, "list")) {
pn->pn_value = alloc(struct dvec);
2012-09-13 21:18:02 +02:00
ZERO(pn->pn_value, struct dvec);
2000-04-27 22:03:57 +02:00
pn->pn_value->v_name = copy(d->v_name);
pn->pn_value->v_length = d->v_length;
pn->pn_value->v_type = d->v_type;
pn->pn_value->v_flags = d->v_flags;
pn->pn_value->v_plot = NULL; /* this dvec isn't member of any plot */
2000-04-27 22:03:57 +02:00
if (isreal(d)) {
pn->pn_value->v_realdata = TMALLOC(double, d->v_length);
bcopy(d->v_realdata,
2012-09-13 21:18:02 +02:00
pn->pn_value->v_realdata,
sizeof(double) * (size_t) d->v_length);
2000-04-27 22:03:57 +02:00
} else {
pn->pn_value->v_compdata = TMALLOC(ngcomplex_t, d->v_length);
bcopy(d->v_compdata,
2012-09-13 21:18:02 +02:00
pn->pn_value->v_compdata,
sizeof(ngcomplex_t) * (size_t) d->v_length);
2000-04-27 22:03:57 +02:00
}
}
} else if (pn->pn_op) {
savetree(pn->pn_left);
if (pn->pn_op->op_arity == 2)
savetree(pn->pn_right);
} else if (pn->pn_func) {
savetree(pn->pn_left);
}
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* A bunch of junk to print out nodes. */
static void
prdefs(char *name)
{
struct udfunc *udf;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if (name && *name) { /* You never know what people will do */
for (udf = udfuncs; udf; udf = udf->ud_next)
if (eq(name, udf->ud_name))
2015-11-11 19:56:58 +01:00
prtree(udf, cp_out);
2012-09-13 21:21:46 +02:00
} else {
2000-04-27 22:03:57 +02:00
for (udf = udfuncs; udf; udf = udf->ud_next)
2015-11-11 19:56:58 +01:00
prtree(udf, cp_out);
2012-09-13 21:21:46 +02:00
}
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* Print out one definition. */
static void
2015-11-11 19:56:58 +01:00
prtree(struct udfunc *ud, FILE *fp)
2000-04-27 22:03:57 +02:00
{
2015-11-11 19:56:58 +01:00
const char *s = ud->ud_name;
2000-04-27 22:03:57 +02:00
2015-11-11 19:56:58 +01:00
/* print the function name */
fprintf(fp, "%s (", s);
s = strchr(s, '\0') + 1;
/* print the formal args */
2000-04-27 22:03:57 +02:00
while (*s) {
2015-11-11 19:56:58 +01:00
fputs(s, fp);
s = strchr(s, '\0') + 1;
if (*s)
fputs(", ", fp);
2000-04-27 22:03:57 +02:00
}
2015-11-11 19:56:58 +01:00
fputs(") = ", fp);
/* print the function body */
prtree1(ud->ud_text, fp);
putc('\n', fp);
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
static void
prtree1(struct pnode *pn, FILE *fp)
{
if (pn->pn_value) {
fputs(pn->pn_value->v_name, fp);
} else if (pn->pn_func) {
fprintf(fp, "%s (", pn->pn_func->fu_name);
prtree1(pn->pn_left, fp);
fputs(")", fp);
} else if (pn->pn_op && (pn->pn_op->op_arity == 2)) {
fputs("(", fp);
prtree1(pn->pn_left, fp);
fprintf(fp, ")%s(", pn->pn_op->op_name);
prtree1(pn->pn_right, fp);
fputs(")", fp);
} else if (pn->pn_op && (pn->pn_op->op_arity == 1)) {
fprintf(fp, "%s(", pn->pn_op->op_name);
prtree1(pn->pn_left, fp);
fputs(")", fp);
2012-09-13 21:21:46 +02:00
} else {
2000-04-27 22:03:57 +02:00
fputs("<something strange>", fp);
2012-09-13 21:21:46 +02:00
}
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
struct pnode *
ft_substdef(const char *name, struct pnode *args)
2000-04-27 22:03:57 +02:00
{
2015-11-12 17:57:40 +01:00
struct udfunc *udf, *wrong_udf = NULL;
char *arg_names;
2000-04-27 22:03:57 +02:00
int arity = numargs(args);
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
for (udf = udfuncs; udf; udf = udf->ud_next)
if (eq(name, udf->ud_name)) {
2015-11-12 17:57:40 +01:00
if (arity == udf->ud_arity)
2000-04-27 22:03:57 +02:00
break;
2015-11-12 17:57:40 +01:00
wrong_udf = udf;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if (udf == NULL) {
2015-11-12 17:57:40 +01:00
if (wrong_udf)
2000-04-27 22:03:57 +02:00
fprintf(cp_err,
2012-09-13 21:18:02 +02:00
"Warning: the user-defined function %s has %d args\n",
2015-11-12 17:57:40 +01:00
name, wrong_udf->ud_arity);
2015-11-11 21:20:50 +01:00
return NULL;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
arg_names = strchr(udf->ud_name, '\0') + 1;
2000-04-27 22:03:57 +02:00
/* Now we have to traverse the tree and copy it over,
* substituting args.
*/
return trcopy(udf->ud_text, arg_names, args);
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
/* Copy the tree and replace formal args with the right stuff. The way
* we know that something might be a formal arg is when it is a dvec
* with length 0 and a name that isn't "list". I hope nobody calls their
* formal parameters "list".
*/
static struct pnode *
trcopy(struct pnode *tree, char *arg_names, struct pnode *args)
2000-04-27 22:03:57 +02:00
{
struct pnode *pn;
struct dvec *d;
char *s;
int i;
if (tree->pn_value) {
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
d = tree->pn_value;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if ((d->v_length == 0) && strcmp(d->v_name, "list")) {
/* Yep, it's a formal parameter. Substitute for it.
* IMPORTANT: we never free parse trees, so we
* needn't worry that they aren't trees here.
*/
s = arg_names;
2000-04-27 22:03:57 +02:00
i = 1;
while (*s) {
if (eq(s, d->v_name))
break;
else
i++;
s = strchr(s, '\0') + 1;
2000-04-27 22:03:57 +02:00
}
2000-04-27 22:03:57 +02:00
if (*s)
return ntharg(i, args);
2000-04-27 22:03:57 +02:00
else
2015-11-11 21:20:50 +01:00
return tree;
2012-09-13 21:21:46 +02:00
} else {
2015-11-11 21:20:50 +01:00
return tree;
2012-09-13 21:21:46 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
} else if (tree->pn_func) {
pn = alloc_pnode();
2012-09-13 21:18:02 +02:00
/* pn_func are pointers to a global constant struct */
2003-08-24 00:27:36 +02:00
pn->pn_func = tree->pn_func;
pn->pn_left = trcopy(tree->pn_left, arg_names, args);
2012-09-13 21:18:02 +02:00
pn->pn_left->pn_use++;
2000-04-27 22:03:57 +02:00
} else if (tree->pn_op) {
pn = alloc_pnode();
2012-09-13 21:18:02 +02:00
/* pn_op are pointers to a global constant struct */
2003-08-24 00:27:36 +02:00
pn->pn_op = tree->pn_op;
pn->pn_left = trcopy(tree->pn_left, arg_names, args);
2012-09-13 21:18:02 +02:00
pn->pn_left->pn_use++;
if (pn->pn_op->op_arity == 2) {
pn->pn_right = trcopy(tree->pn_right, arg_names, args);
2012-09-13 21:18:02 +02:00
pn->pn_right->pn_use++;
2012-09-13 21:21:46 +02:00
}
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
} else {
fprintf(cp_err, "trcopy: Internal Error: bad parse node\n");
2015-11-11 21:20:50 +01:00
return NULL;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
2015-11-11 21:20:50 +01:00
return pn;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
/* Find the n'th arg in the arglist, returning NULL if there isn't one.
2000-04-27 22:03:57 +02:00
* Since comma has such a low priority and associates to the right,
* we can just follow the right branch of the tree num times.
* Note that we start at 1 when numbering the args.
*/
static struct pnode *
ntharg(int num, struct pnode *args)
{
for (; args; args = args->pn_right, --num) {
if (num <= 1) {
if (args->pn_op && (args->pn_op->op_num == PT_OP_COMMA))
return args->pn_left;
return args;
}
if (!(args->pn_op && (args->pn_op->op_num == PT_OP_COMMA)))
return NULL;
}
return NULL;
2000-04-27 22:03:57 +02:00
}
2012-09-13 21:18:02 +02:00
static int
numargs(struct pnode *args)
{
2015-11-12 21:12:35 +01:00
int arity;
2015-11-12 21:12:35 +01:00
if (!args)
return 0;
2015-11-12 21:12:35 +01:00
for (arity = 1; args; args = args->pn_right, arity++)
if (!(args->pn_op && (args->pn_op->op_num == PT_OP_COMMA)))
return arity;
2015-11-12 21:12:35 +01:00
// note: a trailing NULL pn_right will be counted too
return arity;
}
2000-04-27 22:03:57 +02:00
void
com_undefine(wordlist *wlist)
{
struct udfunc *udf;
2000-04-27 22:03:57 +02:00
if (!wlist)
return;
2012-09-13 21:18:02 +02:00
2000-04-27 22:03:57 +02:00
if (*wlist->wl_word == '*') {
for (udf = udfuncs; udf;) {
struct udfunc *next = udf->ud_next;
cp_remkword(CT_UDFUNCS, udf->ud_name);
free_pnode(udf->ud_text);
free(udf->ud_name);
free(udf);
udf = next;
}
udfuncs = NULL;
2000-04-27 22:03:57 +02:00
return;
}
2012-09-13 21:18:02 +02:00
2012-09-13 21:21:46 +02:00
for (; wlist; wlist = wlist->wl_next) {
struct udfunc *prev_udf = NULL;
for (udf = udfuncs; udf;) {
struct udfunc *next = udf->ud_next;
2000-04-27 22:03:57 +02:00
if (eq(wlist->wl_word, udf->ud_name)) {
if (prev_udf)
prev_udf->ud_next = udf->ud_next;
2000-04-27 22:03:57 +02:00
else
udfuncs = udf->ud_next;
cp_remkword(CT_UDFUNCS, wlist->wl_word);
free_pnode(udf->ud_text);
free(udf->ud_name);
free(udf);
2012-09-13 21:21:46 +02:00
} else {
prev_udf = udf;
2012-09-13 21:21:46 +02:00
}
udf = next;
2000-04-27 22:03:57 +02:00
}
}
}
2012-09-13 21:18:02 +02:00
2015-11-11 21:20:50 +01:00
/*
* This is only here so I can "call" it from gdb/dbx
2000-04-27 22:03:57 +02:00
*/
void
* src/Makefile.am src/main.c src/sconvert.c src/analysis/cktdisto.c src/analysis/cktnoise.c src/analysis/noisean.c: Updates for the new header files. * src/maths/cmaths/cmath1.c src/maths/cmaths/cmath2.c src/maths/cmaths/cmath3.c src/maths/cmaths/cmath4.c: Updates for the new header files. * src/frontend/.cvsignore src/frontend/Makefile.am: Updates for the new files. * src/frontend/agraf.c src/frontend/aspice.c src/frontend/breakp.c src/frontend/breakp2.c src/frontend/circuits.c src/frontend/cpitf.c src/frontend/debugcom.c src/frontend/define.c src/frontend/diff.c src/frontend/dimens.c src/frontend/display.c src/frontend/doplot.c src/frontend/dotcards.c src/frontend/evaluate.c src/frontend/fourier.c src/frontend/graf.c src/frontend/grid.c src/frontend/inp.c src/frontend/inpcom.c src/frontend/interp.c src/frontend/linear.c src/frontend/misccoms.c src/frontend/misccoms.h src/frontend/miscvars.c src/frontend/mw_coms.c src/frontend/newcoms.c src/frontend/nutinp.c src/frontend/options.c src/frontend/outitf.c src/frontend/parse.c src/frontend/plotcurv.c src/frontend/points.c src/frontend/postcoms.c src/frontend/rawfile.c src/frontend/runcoms.c src/frontend/runcoms2.c src/frontend/shyu.c src/frontend/spec.c src/frontend/spiceif.c src/frontend/typesdef.c src/frontend/vectors.c src/frontend/where.c src/frontend/postcoms.c: Updates for the new header files. Some commands have moved into the new files below. * src/frontend/README src/frontend/com_compose.c src/frontend/com_compose.h src/frontend/com_display.c src/frontend/com_display.h src/frontend/com_let.c src/frontend/com_let.h src/frontend/com_setscale.c src/frontend/com_setscale.h src/frontend/commands.c src/frontend/commands.h src/frontend/completion.h src/frontend/streams.h src/frontend/testcommands.c: Separation into different com_* commands. This is a start. The rest of the subdirectory needs doing. * src/include/complex.h src/include/cpdefs.h src/include/cpextern.h src/include/cpstd.h src/include/fteconst.h src/include/ftedata.h src/include/ftedev.h src/include/fteext.h src/include/ftegraph.h src/include/fteparse.h src/include/dvec.h src/include/grid.h src/include/plot.h src/include/pnode.h src/include/sim.h src/include/variable.h src/include/wordlist.h src/include/bool.h: Separation of header files into smaller pieces. This limits recompilation to only the affected source files. The original header files have a warning message embedded to flag obsoleted use. * src/frontend/compose.c src/frontend/compose.h src/frontend/nutctab.c src/frontend/nutctab.h src/frontend/plot5.c src/frontend/plot5.h src/frontend/spcmdtab.c src/frontend/x11.c src/frontend/x11.h src/frontend/xgraph.c src/frontend/xgraph.h: Moved these files into src/frontend/plotting subdirectory. * src/frontend/plotting/.cvsignore src/frontend/plotting/Makefile.am src/frontend/plotting/plot5.c src/frontend/plotting/plot5.h src/frontend/plotting/plotting.c src/frontend/plotting/plotting.h src/frontend/plotting/pvec.c src/frontend/plotting/pvec.h src/frontend/plotting/x11.c src/frontend/plotting/x11.h src/frontend/plotting/xgraph.c src/frontend/plotting/xgraph.h: The new libplotting library with automake and CVS infrastructure.
2000-05-06 16:12:51 +02:00
ft_pnode(struct pnode *pn)
2000-04-27 22:03:57 +02:00
{
prtree1(pn, cp_err);
}