--- /dev/null
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = -I$(top_srcdir)/lefty
+
+if WITH_X
+noinst_LTLIBRARIES = libos.la
+endif
+
+libos_la_SOURCES = io.c
+
+EXTRA_DIST = $(libos_la_SOURCES)
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#include "common.h"
+#include "io.h"
+#ifdef FEATURE_CS
+#include "cs2l.h"
+#endif
+#include "mem.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#ifndef HAVE_TERMIOS_H
+#include <termio.h>
+#else
+#include <termios.h>
+#endif
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVEVFORK
+#define FORK vfork
+#else
+#define FORK fork
+#endif
+#include <netdb.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+io_t *iop;
+int ion;
+
+static char *shell;
+static char *shbname;
+
+static FILE *serverconnect(char *);
+static void ptyopen(char *, FILE **, FILE **, int *);
+static int findpty(int *);
+static void pipeopen(char *, FILE **, FILE **, int *);
+static void socketopen(char *, int, FILE **, FILE **, int *);
+
+static void sigchldhandler(int);
+
+void IOinit(void)
+{
+ struct stat statbuf;
+ int ioi;
+
+ if (!(shell = getenv("SHELL")))
+ shell = "/bin/sh";
+ if (shell[0] != '/' && shell[0] != '.') {
+ if (!(shell = buildpath(shell, TRUE)))
+ shell = "/bin/sh";
+ else
+ shell = strdup(shell);
+ }
+ shbname = shell + strlen(shell) - 1;
+ while (shbname >= shell && *shbname != '/')
+ shbname--;
+ if (*shbname == '/')
+ shbname++;
+ ion = IOINCR;
+ for (ioi = FD_SETSIZE - 1; ioi >= 0; ioi--) {
+ if (fstat(ioi, &statbuf) == 0) {
+ ion = (ioi / IOINCR + 1) * IOINCR;
+ break;
+ }
+ }
+ iop = Marrayalloc((long) ion * IOSIZE);
+ for (ioi = 0; ioi < ion; ioi++)
+ iop[ioi].inuse = FALSE;
+ for (ioi = 0; ioi < ion; ioi++) {
+ if (fstat(ioi, &statbuf) == 0) {
+ if ((iop[ioi].ifp = iop[ioi].ofp = fdopen(ioi,
+ (ioi ==
+ 0 ? "r" : "w")))) {
+ iop[ioi].inuse = TRUE;
+ iop[ioi].type = IO_FILE;
+ iop[ioi].ismonitored = FALSE;
+ iop[ioi].pid = -1;
+ iop[ioi].buf = NULL;
+ }
+ }
+ }
+ signal(SIGCHLD, sigchldhandler);
+ signal(SIGPIPE, SIG_IGN);
+}
+
+void IOterm(void)
+{
+ int ioi;
+
+ for (ioi = 3; ioi < ion; ioi++)
+ if (iop[ioi].inuse)
+ IOclose(ioi, NULL);
+ Marrayfree(iop), iop = NULL, ion = 0;
+}
+
+int IOopen(char *kind, char *name, char *mode, char *fmt)
+{
+ io_t *p;
+ iotype_t type;
+ char *path, *command;
+ char hname[200];
+ int sfd;
+ socklen_t slen;
+ int i;
+ struct sockaddr_in sname;
+
+ if (Strcmp(kind, "file") == 0)
+ type = IO_FILE;
+ else if (Strcmp(kind, "pty") == 0)
+ type = IO_PTY;
+ else if (Strcmp(kind, "pipe") == 0)
+ type = IO_PIPE;
+ else if (Strcmp(kind, "socket") == 0)
+ type = IO_SOCKET;
+#ifdef FEATURE_CS
+ else if (Strcmp(kind, "cs") == 0)
+ type = IO_CS;
+#endif
+ else
+ return -1;
+ for (i = 0; i < ion; i++)
+ if (!iop[i].inuse)
+ break;
+ if (i == ion) {
+ iop = Marraygrow(iop, (long) (ion + IOINCR) * IOSIZE);
+ for (i = ion + IOINCR - 1; i >= ion; i--)
+ iop[i].inuse = FALSE;
+ i++, ion += IOINCR;
+ }
+ p = &iop[i];
+ p->type = type;
+ p->pid = -1;
+ switch (type) {
+ case IO_FILE:
+ if (!(p->ifp = p->ofp = fopen(name, mode))) {
+ if (strncmp(name, "/dev/tcp/", 9) == 0) {
+ if (!(p->ifp = p->ofp = serverconnect(name)))
+ return -1;
+ break;
+ }
+ path = buildpath(name, FALSE);
+ if (!path || !(p->ifp = p->ofp = fopen(path, mode)))
+ return -1;
+ }
+ break;
+ case IO_PTY:
+ if (!fmt)
+ fmt = "%e";
+ if (!(path = buildpath(name, TRUE)) ||
+ !(command = buildcommand(path, NULL, -1, -1, fmt)))
+ return -1;
+ ptyopen(command, &p->ifp, &p->ofp, &p->pid);
+ if (!p->ifp || !p->ofp)
+ return -1;
+ break;
+ case IO_PIPE:
+ if (!fmt)
+ fmt = "%e";
+ if (!(path = buildpath(name, TRUE)) ||
+ !(command = buildcommand(path, NULL, -1, -1, fmt)))
+ return -1;
+ pipeopen(command, &p->ifp, &p->ofp, &p->pid);
+ if (!p->ifp || !p->ofp)
+ return -1;
+ break;
+ case IO_SOCKET:
+ if (!fmt)
+ fmt = "%e";
+ if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return -1;
+ sname.sin_family = AF_INET;
+ sname.sin_port = 0;
+ sname.sin_addr.s_addr = htonl(INADDR_ANY);
+ slen = sizeof(sname);
+ if (bind(sfd, (struct sockaddr *) &sname, slen) < 0 ||
+ getsockname(sfd, (struct sockaddr *) &sname, &slen) < 0)
+ return -1;
+ if (listen(sfd, 5) < 0)
+ return -1;
+ gethostname(hname, sizeof(hname));
+ if (!(path = buildpath(name, TRUE)) ||
+ !(command = buildcommand(path, hname,
+ (int) ntohs(sname.sin_port),
+ (int) ntohs(sname.sin_port), fmt)))
+ return -1;
+ socketopen(command, sfd, &p->ifp, &p->ofp, &p->pid);
+ if (!p->ifp || !p->ofp)
+ return -1;
+ close(sfd);
+ break;
+#ifdef FEATURE_CS
+ case IO_CS:
+ if (C2Lopen(name, mode, &p->ifp, &p->ofp) == -1)
+ return -1;
+ break;
+#endif
+ default:
+ break;
+ }
+ p->inuse = TRUE;
+ FD_CLR(fileno(p->ifp), &inputfds);
+ FD_CLR(fileno(p->ofp), &inputfds);
+ return i;
+}
+
+int IOclose(int ioi, char *action)
+{
+ io_t *p;
+
+ if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
+ return -1;
+ p = &iop[ioi];
+ FD_CLR(fileno(p->ifp), &inputfds);
+ FD_CLR(fileno(p->ofp), &inputfds);
+ if (p->ifp != p->ofp)
+ fclose(p->ifp);
+ fclose(p->ofp);
+ p->inuse = FALSE;
+ if (action && Strcmp(action, "kill") == 0 && p->pid != -1)
+ kill(p->pid, 15);
+ return 0;
+}
+
+int IOreadline(int ioi, char *bufp, int bufn)
+{
+ io_t *p;
+ int l;
+
+ if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
+ return -1;
+ p = &iop[ioi];
+ fseek(p->ofp, 0L, 1);
+ if (fgets(bufp, bufn, p->ifp) == NULL)
+ return -1;
+ l = strlen(bufp) - 1;
+ while (bufp[l] == '\n' || bufp[l] == '\r')
+ bufp[l--] = '\000';
+ return l + 1;
+}
+
+int IOread(int ioi, char *bufp, int bufn)
+{
+ io_t *p;
+ int l;
+
+ if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
+ return -1;
+ p = &iop[ioi];
+ if ((l = read(fileno(p->ifp), bufp, bufn - 1)) == -1)
+ return -1;
+ else if (l == 0)
+ return 0;
+ bufp[l] = '\000';
+ return l;
+}
+
+int IOwriteline(int ioi, char *bufp)
+{
+ io_t *p;
+
+ if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
+ return -1;
+ p = &iop[ioi];
+ fseek(p->ofp, 0L, 1);
+ if (fputs(bufp, p->ofp) == EOF || fputs("\n", p->ofp) == EOF)
+ return -1;
+ fflush(p->ofp);
+ fseek(p->ofp, 0L, 1);
+ return 0;
+}
+
+static FILE *serverconnect(char *name)
+{
+ char *host, *portp, buf[1024];
+ int port;
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ int cfd;
+
+ strcpy(buf, name);
+ host = buf + 9;
+ portp = strchr(host, '/');
+ if (*host == 0 || !portp)
+ return NULL;
+ *portp++ = 0, port = atoi(portp);
+ if (!(hp = gethostbyname(host)))
+ return NULL;
+ memset((char *) &sin, 1, sizeof(sin));
+ memcpy((char *) &sin.sin_addr, hp->h_addr, hp->h_length);
+ sin.sin_family = hp->h_addrtype;
+ sin.sin_port = htons(port);
+ if ((cfd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
+ return NULL;
+ if (connect(cfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+ return NULL;
+ return fdopen(cfd, "w+");
+}
+
+static void ptyopen(char *cmd, FILE ** ifp, FILE ** ofp, int *pidp)
+{
+ int fd[2];
+
+ if (findpty(fd) == -1) {
+ *ifp = NULL;
+ return;
+ }
+ switch ((*pidp = FORK())) {
+ case -1:
+ panic2(POS, "ptyopen", "cannot fork");
+ case 0:
+ close(fd[0]), close(0), dup(fd[1]);
+ close(1), dup(fd[1]), close(fd[1]);
+ execl(shell, shbname, "-c", cmd, (void *) NULL);
+ panic2(POS, "ptyopen", "child cannot exec: %s\n", cmd);
+ default:
+ close(fd[1]);
+ }
+ fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ *ifp = fdopen(fd[0], "r"), *ofp = fdopen(fd[0], "a+");
+ return;
+}
+
+static int findpty(int *fd)
+{
+ char *majorp, *minorp;
+ char pty[32], tty[32];
+#ifndef HAVE_TERMIOS_H
+ struct termio tio;
+#else
+ struct termios tio;
+#endif
+ static char ptymajor[] = "pqrs";
+ static char ptyminor[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+ for (majorp = ptymajor; *majorp; majorp++) {
+ for (minorp = ptyminor; *minorp; minorp++) {
+ sprintf(pty, "/dev/pty%c%c", *majorp, *minorp);
+ if ((fd[0] = open(pty, O_RDWR)) >= 0) {
+ sprintf(tty, "/dev/tty%c%c", *majorp, *minorp);
+ if ((fd[1] = open(tty, O_RDWR)) >= 0) {
+#ifndef HAVE_TERMIOS_H
+ ioctl(fd[1], TCGETA, &tio);
+ tio.c_lflag &= ~ECHO;
+ ioctl(fd[1], TCSETA, &tio);
+#else
+ tcgetattr(fd[1], &tio);
+ tio.c_lflag &= ~ECHO;
+ tcsetattr(fd[1], TCSANOW, &tio);
+#endif
+ return 0;
+ }
+ close(fd[0]);
+ }
+ }
+ }
+ return -1;
+}
+
+static void pipeopen(char *cmd, FILE ** ifp, FILE ** ofp, int *pidp)
+{
+ int p1[2], p2[2];
+ char cmd2[1024];
+ char *s;
+
+ if (pipe(p1) == -1 || pipe(p2) == -1) {
+ *ifp = NULL;
+ return;
+ }
+ switch ((*pidp = FORK())) {
+ case -1:
+ panic2(POS, "pipeopen", "cannot fork");
+ case 0:
+ close(p1[0]), close(p2[1]);
+ for (s = cmd; *s; s++)
+ if (*s == '%' && *(s + 1) && *(s + 1) == 'd') {
+ sprintf(cmd2, cmd, p2[0], p1[1]);
+ execl(shell, shbname, "-c", cmd2, (void *) NULL);
+ panic2(POS, "pipeopen", "child cannot exec: %s\n", cmd2);
+ }
+ close(1), dup(p1[1]), close(p1[1]);
+ close(0), dup(p2[0]), close(p2[0]);
+ execl(shell, shbname, "-c", cmd, NULL);
+ panic2(POS, "pipeopen", "child cannot exec: %s\n", cmd);
+ default:
+ close(p1[1]), close(p2[0]);
+ }
+ fcntl(p1[0], F_SETFD, FD_CLOEXEC);
+ fcntl(p2[1], F_SETFD, FD_CLOEXEC);
+ *ifp = fdopen(p1[0], "r"), *ofp = fdopen(p2[1], "a");
+ return;
+}
+
+static void socketopen(char *cmd, int sfd, FILE ** ifp, FILE ** ofp,
+ int *pidp)
+{
+ int fd;
+
+ switch ((*pidp = FORK())) {
+ case -1:
+ panic2(POS, "socketopen", "cannot fork");
+ case 0:
+ execl(shell, shbname, "-c", cmd, NULL);
+ panic2(POS, "socketopen", "child cannot exec: %s\n", cmd);
+ default:
+ if ((fd = accept(sfd, NULL, NULL)) < 0) {
+ *ifp = NULL;
+ return;
+ }
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ *ifp = fdopen(fd, "r"), *ofp = fdopen(fd, "a+");
+ return;
+}
+
+static void sigchldhandler(int data)
+{
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+ signal(SIGCHLD, sigchldhandler);
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#include "common.h"
+#include "mem.h"
+#include "code.h"
+#include "tbl.h"
+#include "lex.h"
+#include "parse.h"
+#include "internal.h"
+
+static jmp_buf eljbuf;
+
+#define GTOKIFEQ(t) { \
+ if (Ltok == (t)) \
+ Lgtok (); \
+ else \
+ err ("expected token: '%s', found: '%s'", Lnames[t], Lnames[Ltok]); \
+}
+
+typedef struct lv_t {
+ int si, vi;
+} lv_t;
+static lv_t *lvp;
+static int lvn, flvi, llvi;
+#define GETLVSTR(i) (char *) Cgetstring (lvp[i].si)
+#define GETLVNUM(i) lvp[i].vi
+#define LVINCR 1000
+#define LVSIZE sizeof (lv_t)
+
+static int pexpr(void);
+static int getop(int, int);
+static int pexpi(int);
+static int pexp5(void);
+static int pexp6(void);
+static int pexp7(void);
+static int pargs(void);
+static int pcons(void);
+static int pvar(void);
+static int pfunc(void);
+static int pdecl(int *);
+static int ptcons(void);
+static int pstmt(void);
+static int pifst(void);
+static int pwhilest(void);
+static int pforst(void);
+static int pbreakst(void);
+static int pcontinuest(void);
+static int preturnst(void);
+
+static void addlv(int, int);
+static void err(char *, ...);
+
+void Pinit(void)
+{
+ lvp = Marrayalloc((long) LVINCR * LVSIZE);
+ lvn = LVINCR;
+ flvi = llvi = 0;
+}
+
+void Pterm(void)
+{
+ Marrayfree(lvp);
+ lvp = NULL;
+ lvn = flvi = llvi = 0;
+}
+
+Tobj Punit(Psrc_t * sp)
+{
+ int ui, ei;
+
+ Lsetsrc(sp->flag, sp->s, sp->fp, sp->tok, sp->lnum);
+ Creset();
+ flvi = llvi = 0;
+
+ if (setjmp(eljbuf) != 0)
+ return NULL;
+
+ while (Ltok == L_SEMI)
+ Lgtok();
+ if (Ltok == L_EOF)
+ return NULL;
+
+ ui = Cnew(C_CODE);
+ ei = pexpr();
+ Csetfp(ui, ei);
+ Lgetsrc(&sp->flag, &sp->s, &sp->fp, &sp->tok, &sp->lnum);
+ return Tcode(cbufp, 0, cbufi);
+}
+
+/* shortcut: this function creates a piece of code that corresponds to
+ <internal func name> = function () internal "<internal func name>";
+*/
+Tobj Pfunction(char *ifnam, int ifnum)
+{
+ int ui, ai, vi, si, fi, li1, li2, di, ifi, ifn;
+
+ Creset();
+ ui = Cnew(C_CODE);
+ ai = Cnew(C_ASSIGN);
+ Csetfp(ui, ai);
+ vi = Cnew(C_GVAR);
+ si = Cstring(ifnam);
+ Csetfp(vi, si);
+ Csetfp(ai, vi);
+ fi = Cnew(C_FUNCTION);
+ Csetnext(vi, fi);
+ li1 = Cinteger(0);
+ Csetfp(fi, li1);
+ li2 = Cinteger(0);
+ Csetnext(li1, li2);
+ di = Cnew(C_DECL);
+ Csetfp(di, C_NULL);
+ Csetnext(li2, di);
+ ifi = Cnew(C_INTERNAL);
+ ifn = Cinteger((long) ifnum);
+ Csetfp(ifi, ifn);
+ Csetnext(di, ifi);
+ Csetinteger(li1, (long) (Cgetindex() - fi));
+ Csetinteger(li2, 0);
+ return Tcode(cbufp, 0, cbufi);
+}
+
+/* shortcut: this function creates a piece of code that corresponds to
+ <func name> (<args>); where <args> is the second argument (ao)
+*/
+Tobj Pfcall(Tobj fo, Tobj ao)
+{
+ int ui, fi, ffi, ai, aai;
+
+ Creset();
+ ui = Cnew(C_CODE);
+ fi = Cnew(C_FCALL);
+ Csetfp(ui, fi);
+ ffi = Cnew(C_PVAR);
+ Csetobject(ffi, fo);
+ Csetfp(fi, ffi);
+ ai = Cnew(C_ARGS);
+ Csetnext(ffi, ai);
+ if (ao) {
+ aai = Cnew(C_PVAR);
+ Csetobject(aai, ao);
+ Csetfp(ai, aai);
+ } else
+ Csetfp(ai, C_NULL);
+ return Tcode(cbufp, 0, cbufi);
+}
+
+static int pexpr(void)
+{
+ int ai, ei0, ei1;
+
+ ei0 = pexpi(0);
+ if (Ltok != C_ASSIGN)
+ return ei0;
+
+ ai = Cnew(C_ASSIGN);
+ Csetfp(ai, ei0);
+ Lgtok();
+ ei1 = pexpr();
+ Csetnext(ei0, ei1);
+ return ai;
+}
+
+static int lextab[][7] = {
+ {L_OR, 0, 0, 0, 0, 0, 0},
+ {L_AND, 0, 0, 0, 0, 0, 0},
+ {L_EQ, L_NE, L_LT, L_LE, L_GT, L_GE, 0},
+ {L_PLUS, L_MINUS, 0, 0, 0, 0, 0},
+ {L_MUL, L_DIV, L_MOD, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int parsetab[][7] = {
+ {C_OR, 0, 0, 0, 0, 0, 0},
+ {C_AND, 0, 0, 0, 0, 0, 0},
+ {C_EQ, C_NE, C_LT, C_LE, C_GT, C_GE, 0},
+ {C_PLUS, C_MINUS, 0, 0, 0, 0, 0},
+ {C_MUL, C_DIV, C_MOD, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int getop(int t, int i)
+{
+ int j;
+
+ for (j = 0; lextab[i][j] != 0; j++)
+ if (t == lextab[i][j])
+ return parsetab[i][j];
+ return -1;
+}
+
+static int pexpi(int k)
+{
+ int ei0, ei1, ei2, ptok;
+
+ if (lextab[k][0] == 0)
+ return pexp5();
+
+ ei0 = pexpi(k + 1);
+ while ((ptok = getop(Ltok, k)) != -1) {
+ ei1 = Cnew((Ctype_t) ptok);
+ Csetfp(ei1, ei0);
+ Lgtok();
+ ei2 = pexpi(k + 1);
+ Csetnext(ei0, ei2);
+ ei0 = ei1;
+ }
+ return ei0;
+}
+
+static int pexp5(void)
+{
+ int ei0, ei1;
+
+ if (Ltok == L_MINUS) {
+ ei0 = Cnew(C_UMINUS);
+ Lgtok();
+ ei1 = pexp5();
+ Csetfp(ei0, ei1);
+ return ei0;
+ }
+ return pexp6();
+}
+
+static int pexp6(void)
+{
+ int ei0, ei1;
+
+ if (Ltok == L_NOT) {
+ ei0 = Cnew(C_NOT);
+ Lgtok();
+ ei1 = pexp6();
+ Csetfp(ei0, ei1);
+ return ei0;
+ }
+ return pexp7();
+}
+
+static int pexp7(void)
+{
+ int ei0 = 0, ei1, ei2;
+
+ switch (Ltok) {
+ case L_FUNCTION:
+ Lgtok();
+ ei0 = pfunc();
+ break;
+ case L_LP:
+ ei0 = Cnew(C_PEXPR);
+ Lgtok();
+ ei1 = pexpr();
+ GTOKIFEQ(L_RP);
+ Csetfp(ei0, ei1);
+ break;
+ case L_LB:
+ ei0 = ptcons();
+ break;
+ case L_STRING:
+ case L_NUMBER:
+ ei0 = pcons();
+ break;
+ case L_ID:
+ ei0 = pvar();
+ if (Ltok == L_LP) { /* ie: it's really a function call */
+ ei1 = ei0;
+ ei0 = Cnew(C_FCALL);
+ Csetfp(ei0, ei1);
+ Lgtok();
+ ei2 = pargs();
+ Csetnext(ei1, ei2);
+ GTOKIFEQ(L_RP);
+ }
+ break;
+ default:
+ err("expected EXP7 type token, found: %s", Lnames[Ltok]);
+ }
+ return ei0;
+}
+
+static int pargs(void)
+{
+ int ai, ei0, ei1;
+
+ ai = Cnew(C_ARGS);
+ if (Ltok == L_RP) {
+ Csetfp(ai, C_NULL);
+ return ai;
+ }
+ ei0 = pexpr();
+ Csetfp(ai, ei0);
+ while (Ltok != L_RP) {
+ GTOKIFEQ(L_COMMA);
+ if (Ltok == L_RP)
+ err("expected expression, found: %s", Lnames[Ltok]);
+
+ ei1 = pexpr();
+ Csetnext(ei0, ei1);
+ ei0 = ei1;
+ }
+ return ai;
+}
+
+static int pcons(void)
+{
+ int ci = 0;
+ double d;
+
+ switch (Ltok) {
+ case L_NUMBER:
+ d = atof(Lstrtok);
+ ci = (d == (double) (long) d) ? Cinteger((long) d) : Creal(d);
+ break;
+ case L_STRING:
+ ci = Cstring(Lstrtok);
+ break;
+ default:
+ err("expected scalar constant, found: %s", Lnames[Ltok]);
+ }
+ Lgtok();
+ return ci;
+}
+
+static int pvar(void)
+{
+ int vi, ci0, ci1, i;
+
+ vi = Cnew(C_GVAR);
+ ci0 = Cstring(Lstrtok);
+ Csetfp(vi, ci0);
+ for (i = flvi; i < llvi; i++) {
+ if (Strcmp(GETLVSTR(i), Lstrtok) == 0) {
+ Csettype(vi, C_LVAR);
+ ci1 = Cinteger((long) GETLVNUM(i));
+ Csetnext(ci0, ci1);
+ ci0 = ci1;
+ break;
+ }
+ }
+ Lgtok();
+ if (Ltok != L_DOT && Ltok != L_LB)
+ return vi;
+
+ while (Ltok == L_DOT || Ltok == L_LB) {
+ if (Ltok == L_DOT) {
+ Lgtok();
+ if (Ltok != L_ID)
+ err("expected identifier, found: %s", Lnames[Ltok]);
+ ci1 = Cstring(Lstrtok);
+ Csetnext(ci0, ci1);
+ Lgtok();
+ } else {
+ Lgtok();
+ ci1 = pexpr();
+ Csetnext(ci0, ci1);
+ GTOKIFEQ(L_RB);
+ }
+ ci0 = ci1;
+ }
+ return vi;
+}
+
+static int pfunc(void)
+{
+ int fi, di, si, ifi, ifn, ldi, i, li1, li2;
+ int owncbufi, ownflvi, ownllvi, flvn, ifnum;
+
+ owncbufi = Cgetindex();
+ ownflvi = flvi, ownllvi = llvi;
+ flvi = llvi;
+ flvn = 0;
+
+ fi = Cnew(C_FUNCTION);
+ GTOKIFEQ(L_LP);
+ li1 = Cinteger(0);
+ Csetfp(fi, li1);
+ li2 = Cinteger(0);
+ Csetnext(li1, li2);
+ di = pdecl(&flvn);
+ Csetnext(li2, di);
+ i = di;
+ GTOKIFEQ(L_RP);
+ if (Ltok == L_INTERNAL) {
+ Lgtok();
+ if (Ltok == L_STRING) {
+ if ((ifnum = Igetfunc(Lstrtok)) == -1)
+ err("no such internal function: %s", Lstrtok);
+ ifi = Cnew(C_INTERNAL);
+ ifn = Cinteger((long) ifnum);
+ Csetfp(ifi, ifn);
+ Csetnext(i, ifi);
+ Lgtok();
+ } else
+ err("expected token: STRING, found: '%s'", Lnames[Ltok]);
+ } else {
+ GTOKIFEQ(L_LCB);
+ while (Ltok == L_LOCAL) {
+ Lgtok();
+ ldi = pdecl(&flvn);
+ Csetnext(i, ldi);
+ i = ldi;
+ GTOKIFEQ(L_SEMI);
+ }
+ while (Ltok != L_RCB) {
+ si = pstmt();
+ Csetnext(i, si);
+ i = si;
+ }
+ GTOKIFEQ(L_RCB);
+ }
+ Csetinteger(li1, (long) (Cgetindex() - owncbufi));
+ Csetinteger(li2, (long) flvn);
+ flvi = ownflvi, llvi = ownllvi;
+ return fi;
+}
+
+static int pdecl(int *lvnp)
+{
+ int di, si, i;
+
+ di = Cnew(C_DECL);
+ if (Ltok != L_ID) {
+ Csetfp(di, C_NULL);
+ return di;
+ }
+ si = Cstring(Lstrtok);
+ addlv(si, (*lvnp)++);
+ Csetfp(di, si);
+ i = si;
+ Lgtok();
+ if (Ltok != L_COMMA)
+ return di;
+ Lgtok();
+ while (Ltok == L_ID) {
+ si = Cstring(Lstrtok);
+ addlv(si, (*lvnp)++);
+ Lgtok();
+ Csetnext(i, si);
+ i = si;
+ if (Ltok == L_COMMA) {
+ Lgtok();
+ if (Ltok != L_ID)
+ err("expected identifier, found %s", Lnames[Ltok]);
+ }
+ }
+ return di;
+}
+
+static int ptcons(void)
+{
+ int ti, ei0, ei1;
+
+ ti = Cnew(C_TCONS);
+ Lgtok();
+ if (Ltok == L_RB) {
+ Csetfp(ti, C_NULL);
+ Lgtok();
+ return ti;
+ }
+ ei1 = pexpi(0);
+ Csetfp(ti, ei1);
+ ei0 = ei1;
+ GTOKIFEQ(L_ASSIGN);
+ ei1 = pexpr();
+ Csetnext(ei0, ei1);
+ ei0 = ei1;
+ GTOKIFEQ(L_SEMI);
+ while (Ltok != L_RB) {
+ ei1 = pexpi(0);
+ Csetnext(ei0, ei1);
+ ei0 = ei1;
+ GTOKIFEQ(L_ASSIGN);
+ ei1 = pexpr();
+ Csetnext(ei0, ei1);
+ ei0 = ei1;
+ GTOKIFEQ(L_SEMI);
+ }
+ Lgtok();
+ return ti;
+}
+
+static int pstmt(void)
+{
+ int si, i0, i1;
+
+ si = Cnew(C_STMT);
+ switch (Ltok) {
+ case L_SEMI:
+ Csetfp(si, C_NULL);
+ Lgtok();
+ break;
+ case L_LCB:
+ Lgtok();
+ if (Ltok == L_RCB) {
+ Csetfp(si, C_NULL);
+ } else {
+ i1 = pstmt();
+ Csetfp(si, i1);
+ i0 = i1;
+ while (Ltok != L_RCB) {
+ i1 = pstmt();
+ Csetnext(i0, i1);
+ i0 = i1;
+ }
+ }
+ Lgtok();
+ break;
+ case L_IF:
+ i0 = pifst();
+ Csetfp(si, i0);
+ break;
+ case L_WHILE:
+ i0 = pwhilest();
+ Csetfp(si, i0);
+ break;
+ case L_FOR:
+ i0 = pforst();
+ Csetfp(si, i0);
+ break;
+ case L_BREAK:
+ i0 = pbreakst();
+ Csetfp(si, i0);
+ break;
+ case L_CONTINUE:
+ i0 = pcontinuest();
+ Csetfp(si, i0);
+ break;
+ case L_RETURN:
+ i0 = preturnst();
+ Csetfp(si, i0);
+ break;
+ default:
+ i0 = pexpr();
+ Csetfp(si, i0);
+ GTOKIFEQ(L_SEMI);
+ }
+ return si;
+}
+
+static int pifst(void)
+{
+ int isi, ii, ti, ei;
+
+ isi = Cnew(C_IF);
+ Lgtok();
+ GTOKIFEQ(L_LP);
+ ii = pexpr();
+ Csetfp(isi, ii);
+ GTOKIFEQ(L_RP);
+ ti = pstmt();
+ Csetnext(ii, ti);
+ if (Ltok == L_ELSE) {
+ Lgtok();
+ ei = pstmt();
+ Csetnext(ti, ei);
+ }
+ return isi;
+}
+
+static int pwhilest(void)
+{
+ int wi, ei, si;
+
+ wi = Cnew(C_WHILE);
+ Lgtok();
+ GTOKIFEQ(L_LP);
+ ei = pexpr();
+ Csetfp(wi, ei);
+ GTOKIFEQ(L_RP);
+ si = pstmt();
+ Csetnext(ei, si);
+ return wi;
+}
+
+static int pforst(void)
+{
+ int fi, i0, i1, si;
+
+ fi = Cnew(C_FOR);
+ Lgtok();
+ GTOKIFEQ(L_LP);
+ i0 = (Ltok == L_SEMI) ? Cnew(C_NOP) : pexpr();
+ Csetfp(fi, i0);
+ if (Ltok == L_IN) {
+ Csettype(fi, C_FORIN);
+ Lgtok();
+ i1 = pexpr();
+ Csetnext(i0, i1);
+ i0 = i1;
+ } else {
+ GTOKIFEQ(L_SEMI);
+ i1 = (Ltok == L_SEMI) ? Cnew(C_NOP) : pexpr();
+ Csetnext(i0, i1);
+ i0 = i1;
+ GTOKIFEQ(L_SEMI);
+ i1 = (Ltok == L_SEMI) ? Cnew(C_NOP) : pexpr();
+ Csetnext(i0, i1);
+ i0 = i1;
+ }
+ GTOKIFEQ(L_RP);
+ si = pstmt();
+ Csetnext(i0, si);
+ return fi;
+}
+
+static int pbreakst(void)
+{
+ int bi;
+
+ bi = Cnew(C_BREAK);
+ Csetfp(bi, C_NULL);
+ Lgtok();
+ GTOKIFEQ(L_SEMI);
+ return bi;
+}
+
+static int pcontinuest(void)
+{
+ int ci;
+
+ ci = Cnew(C_CONTINUE);
+ Csetfp(ci, C_NULL);
+ Lgtok();
+ GTOKIFEQ(L_SEMI);
+ return ci;
+}
+
+static int preturnst(void)
+{
+ int ri, ei;
+
+ ri = Cnew(C_RETURN);
+ Lgtok();
+ if (Ltok == L_SEMI) {
+ Csetfp(ri, C_NULL);
+ GTOKIFEQ(L_SEMI);
+ return ri;
+ }
+ ei = pexpr();
+ Csetfp(ri, ei);
+ GTOKIFEQ(L_SEMI);
+ return ri;
+}
+
+static void addlv(int si, int vi)
+{
+ int i;
+
+ if (llvi >= lvn) {
+ lvp = Marraygrow(lvp, (long) (lvn + LVINCR) + LVSIZE);
+ lvn += LVINCR;
+ }
+ lvp[llvi].si = si, lvp[llvi].vi = vi, llvi++;
+ for (i = llvi - 2; i >= flvi; i--)
+ if (Strcmp(GETLVSTR(i), GETLVSTR(llvi - 1)) == 0)
+ err("local variable %s multiply defined", GETLVSTR(i));
+}
+
+static void err(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ Lprintpos();
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ longjmp(eljbuf, 1);
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#ifndef _PARSE_H
+#define _PARSE_H
+ typedef struct Psrc_t {
+ int flag;
+ char *s;
+ FILE *fp;
+ int tok;
+ int lnum;
+ } Psrc_t;
+
+ void Pinit(void);
+ void Pterm(void);
+ Tobj Punit(Psrc_t *);
+ Tobj Pfcall(Tobj, Tobj);
+ Tobj Pfunction(char *, int);
+#endif /* _PARSE_H */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#include "common.h"
+#include "mem.h"
+#include "code.h"
+#include "tbl.h"
+#include "str.h"
+#include "internal.h"
+
+static int highci;
+static int indent;
+#define INDINC(i) (indent += (i))
+#define INDDEC(i) (indent -= (i))
+
+static char *sbufp;
+static int sbufi, sbufn;
+#define SBUFINCR 1000
+#define SBUFSIZE sizeof (char)
+
+static void scalarstr(Tobj);
+static void codestr(Tobj, int);
+static void appends(char *);
+static void appendi(long);
+static void appendd(double);
+static void appendnl(void);
+static void growsbuf(int);
+static char *copysbuf(void);
+
+void Sinit(void)
+{
+ if (!(sbufp = malloc(SBUFINCR * SBUFSIZE)))
+ panic(POS, "Sinit", "sbuf malloc failed");
+ sbufi = 0;
+ sbufn = SBUFINCR;
+ indent = 0;
+ highci = -1;
+}
+
+void Sterm(void)
+{
+ indent = 0;
+ free(sbufp), sbufp = NULL;
+ sbufn = sbufi = 0;
+}
+
+char *Spath(char *path, Tobj ko)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ appends((path) ? path : "");
+ scalarstr(ko);
+ return copysbuf();
+}
+
+char *Sseen(Tobj ko, char *path)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ scalarstr(ko), appends(" = "), appends(path), appends(";");
+ return copysbuf();
+}
+
+char *Sabstract(Tobj ko, Tobj vo)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ scalarstr(ko), appends(" = ");
+ switch (Tgettype(vo)) {
+ case T_STRING:
+ case T_INTEGER:
+ case T_REAL:
+ scalarstr(vo);
+ break;
+ case T_CODE:
+ appends("function (...) { ... }");
+ break;
+ case T_TABLE:
+ appends("[ ... ]");
+ break;
+ case T_SIZE:
+ break;
+ }
+ appends(";");
+ return copysbuf();
+}
+
+char *Stfull(Tobj ko)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ scalarstr(ko), appends(" = [");
+ return copysbuf();
+}
+
+char *Ssfull(Tobj ko, Tobj vo)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ if (ko)
+ scalarstr(ko), appends(" = ");
+ switch (Tgettype(vo)) {
+ case T_STRING:
+ case T_INTEGER:
+ case T_REAL:
+ case T_CODE:
+ scalarstr(vo);
+ break;
+ case T_TABLE:
+ case T_SIZE:
+ break;
+ }
+ appends(";");
+ return copysbuf();
+}
+
+char *Scfull(Tobj co, int ci, int mci)
+{
+ sbufp[(sbufi = 0)] = '\000';
+ highci = mci;
+ codestr(co, ci);
+ highci = -1;
+ return copysbuf();
+}
+
+static void scalarstr(Tobj to)
+{
+ switch (Tgettype(to)) {
+ case T_INTEGER:
+ appendi(Tgetinteger(to));
+ break;
+ case T_REAL:
+ appendd(Tgetreal(to));
+ break;
+ case T_STRING:
+ appends("\""), appends(Tgetstring(to)), appends("\"");
+ break;
+ case T_CODE:
+ codestr(to, 0);
+ break;
+ case T_TABLE:
+ case T_SIZE:
+ break;
+ }
+}
+
+static void codestr(Tobj co, int ci)
+{
+ Ctype_t ct, ct1;
+ int ci1, ci2;
+
+ if (highci == ci)
+ appends(" >> ");
+ switch ((ct = TCgettype(co, ci))) {
+ case C_ASSIGN:
+ codestr(co, (ci1 = TCgetfp(co, ci)));
+ appends(" = ");
+ codestr(co, TCgetnext(co, ci1));
+ break;
+ case C_OR:
+ case C_AND:
+ case C_EQ:
+ case C_NE:
+ case C_LT:
+ case C_LE:
+ case C_GT:
+ case C_GE:
+ case C_PLUS:
+ case C_MINUS:
+ case C_MUL:
+ case C_DIV:
+ case C_MOD:
+ codestr(co, (ci1 = TCgetfp(co, ci)));
+ switch (ct) {
+ case C_OR:
+ appends(" | ");
+ break;
+ case C_AND:
+ appends(" & ");
+ break;
+ case C_EQ:
+ appends(" == ");
+ break;
+ case C_NE:
+ appends(" ~= ");
+ break;
+ case C_LT:
+ appends(" < ");
+ break;
+ case C_LE:
+ appends(" <= ");
+ break;
+ case C_GT:
+ appends(" > ");
+ break;
+ case C_GE:
+ appends(" >= ");
+ break;
+ case C_PLUS:
+ appends(" + ");
+ break;
+ case C_MINUS:
+ appends(" - ");
+ break;
+ case C_MUL:
+ appends(" * ");
+ break;
+ case C_DIV:
+ appends(" / ");
+ break;
+ case C_MOD:
+ appends(" % ");
+ break;
+ default:
+ break;
+ }
+ codestr(co, TCgetnext(co, ci1));
+ break;
+ case C_NOT:
+ appends("~");
+ codestr(co, TCgetfp(co, ci));
+ break;
+ case C_UMINUS:
+ appends("-");
+ codestr(co, TCgetfp(co, ci));
+ break;
+ case C_PEXPR:
+ appends("(");
+ codestr(co, TCgetfp(co, ci));
+ appends(")");
+ break;
+ case C_FCALL:
+ codestr(co, (ci1 = TCgetfp(co, ci)));
+ appends(" (");
+ codestr(co, TCgetnext(co, ci1));
+ appends(")");
+ break;
+ case C_INTEGER:
+ appendi(TCgetinteger(co, ci));
+ break;
+ case C_REAL:
+ appendd(TCgetreal(co, ci));
+ break;
+ case C_STRING:
+ appends("\""), appends(TCgetstring(co, ci)), appends("\"");
+ break;
+ case C_GVAR:
+ case C_LVAR:
+ ci1 = TCgetfp(co, ci);
+ appends(TCgetstring(co, ci1));
+ if (ct == C_LVAR)
+ ci1 = TCgetnext(co, ci1);
+ for (ci1 = TCgetnext(co, ci1); ci1 != C_NULL;
+ ci1 = TCgetnext(co, ci1)) {
+ switch (TCgettype(co, ci1)) {
+ case C_STRING:
+ appends("."), appends(TCgetstring(co, ci1));
+ break;
+ case C_INTEGER:
+ appends("[");
+ appendi(TCgetinteger(co, ci1));
+ appends("]");
+ break;
+ case C_REAL:
+ appends("[");
+ appendd(TCgetreal(co, ci1));
+ appends("]");
+ break;
+ default:
+ appends("[");
+ codestr(co, ci1);
+ appends("]");
+ }
+ }
+ break;
+ case C_PVAR:
+ appends("<var>");
+ break;
+ case C_FUNCTION:
+ ci1 = TCgetnext(co, TCgetnext(co, TCgetfp(co, ci)));
+ appends("function (");
+ codestr(co, ci1);
+ ci1 = TCgetnext(co, ci1);
+ if (TCgettype(co, ci1) == C_INTERNAL) {
+ appends(") internal \"");
+ appends(Ifuncs[TCgetinteger(co, TCgetfp(co, ci1))].name);
+ appends("\"");
+ } else {
+ appends(") {");
+ INDINC(2);
+ for (; ci1 != C_NULL; ci1 = TCgetnext(co, ci1)) {
+ appendnl();
+ if (TCgettype(co, ci1) == C_DECL)
+ appends("local "), codestr(co, ci1), appends(";");
+ else
+ codestr(co, ci1);
+ }
+ INDDEC(2);
+ appendnl();
+ appends("}");
+ }
+ break;
+ case C_TCONS:
+ appends("[");
+ INDINC(2);
+ ci1 = TCgetfp(co, ci);
+ while (ci1 != C_NULL) {
+ appendnl();
+ codestr(co, ci1);
+ appends(" = ");
+ ci1 = TCgetnext(co, ci1);
+ codestr(co, ci1);
+ appends(";");
+ ci1 = TCgetnext(co, ci1);
+ }
+ INDDEC(2);
+ appendnl();
+ appends("]");
+ break;
+ case C_DECL:
+ ci1 = TCgetfp(co, ci);
+ while (ci1 != C_NULL) {
+ appends(TCgetstring(co, ci1));
+ ci1 = TCgetnext(co, ci1);
+ if (ci1 != C_NULL)
+ appends(", ");
+ }
+ break;
+ case C_STMT:
+ ci1 = TCgetfp(co, ci);
+ if (ci1 == C_NULL) {
+ appends(";");
+ break;
+ }
+ if (TCgetnext(co, ci1) == C_NULL) {
+ codestr(co, ci1);
+ ct1 = TCgettype(co, ci1);
+ if (!C_ISSTMT(ct1))
+ appends(";");
+ } else {
+ appends(" {");
+ INDINC(2);
+ for (; ci1 != C_NULL; ci1 = TCgetnext(co, ci1)) {
+ appendnl();
+ codestr(co, ci1);
+ }
+ INDDEC(2);
+ appendnl();
+ appends("}");
+ }
+ break;
+ case C_IF:
+ ci1 = TCgetfp(co, ci);
+ appends("if (");
+ codestr(co, ci1);
+ appends(")");
+ ci1 = TCgetnext(co, ci1);
+ ci2 = TCgetfp(co, ci1);
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ INDINC(2);
+ appendnl();
+ codestr(co, ci1);
+ INDDEC(2);
+ } else {
+ codestr(co, ci1);
+ }
+ ci1 = TCgetnext(co, ci1);
+ if (ci1 == C_NULL)
+ break;
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ appendnl();
+ appends("else");
+ } else {
+ appends(" else");
+ }
+ ci2 = TCgetfp(co, ci1);
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ INDINC(2);
+ appendnl();
+ codestr(co, ci1);
+ INDDEC(2);
+ } else {
+ codestr(co, ci1);
+ }
+ break;
+ case C_WHILE:
+ ci1 = TCgetfp(co, ci);
+ appends("while (");
+ codestr(co, ci1);
+ ci1 = TCgetnext(co, ci1);
+ ci2 = TCgetfp(co, ci1);
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ appends(")");
+ INDINC(2);
+ appendnl();
+ codestr(co, ci1);
+ INDDEC(2);
+ } else {
+ appends(")");
+ codestr(co, ci1);
+ }
+ break;
+ case C_FOR:
+ ci1 = TCgetfp(co, ci);
+ appends("for (");
+ codestr(co, ci1);
+ appends("; ");
+ ci1 = TCgetnext(co, ci1);
+ codestr(co, ci1);
+ appends("; ");
+ ci1 = TCgetnext(co, ci1);
+ codestr(co, ci1);
+ ci1 = TCgetnext(co, ci1);
+ ci2 = TCgetfp(co, ci1);
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ appends(")");
+ INDINC(2);
+ appendnl();
+ codestr(co, ci1);
+ INDDEC(2);
+ } else {
+ appends(")");
+ codestr(co, ci1);
+ }
+ break;
+ case C_FORIN:
+ ci1 = TCgetfp(co, ci);
+ appends("for (");
+ codestr(co, ci1);
+ appends(" in ");
+ ci1 = TCgetnext(co, ci1);
+ codestr(co, ci1);
+ ci1 = TCgetnext(co, ci1);
+ ci2 = TCgetfp(co, ci1);
+ if (ci2 == C_NULL || TCgetnext(co, ci2) == C_NULL) {
+ appends(")");
+ INDINC(2);
+ appendnl();
+ codestr(co, ci1);
+ INDDEC(2);
+ } else {
+ appends(")");
+ codestr(co, ci1);
+ }
+ break;
+ case C_BREAK:
+ appends("break;");
+ break;
+ case C_CONTINUE:
+ appends("continue;");
+ break;
+ case C_RETURN:
+ ci1 = TCgetfp(co, ci);
+ appends("return");
+ if (ci1 != C_NULL) {
+ appends(" ");
+ codestr(co, ci1);
+ }
+ appends(";");
+ break;
+ case C_ARGS:
+ ci1 = TCgetfp(co, ci);
+ while (ci1 != C_NULL) {
+ codestr(co, ci1);
+ ci1 = TCgetnext(co, ci1);
+ if (ci1 != C_NULL)
+ appends(", ");
+ }
+ break;
+ default:
+ panic(POS, "codestr", "bad object type: %d", ct);
+ }
+}
+
+static void appends(char *s)
+{
+ int n;
+
+ n = strlen(s) + 1;
+ if (sbufi + n > sbufn)
+ growsbuf(n);
+ strcpy(&sbufp[sbufi], s);
+ sbufi += (n - 1);
+}
+
+static void appendi(long i)
+{
+ char buf[40];
+ int n;
+
+ sprintf(buf, "%ld", i);
+ n = strlen(buf) + 1;
+ if (sbufi + n > sbufn)
+ growsbuf(n);
+ strcpy(&sbufp[sbufi], buf);
+ sbufi += (n - 1);
+}
+
+static void appendd(double d)
+{
+ char buf[40];
+ int n;
+
+ sprintf(buf, "%f", d);
+ n = strlen(buf) + 1;
+ if (sbufi + n > sbufn)
+ growsbuf(n);
+ strcpy(&sbufp[sbufi], buf);
+ sbufi += (n - 1);
+}
+
+static void appendnl(void)
+{
+ int i, n;
+
+ n = indent + 1;
+ if (sbufi + n > sbufn)
+ growsbuf(n);
+ sbufp[sbufi++] = '\n';
+ for (i = 0; i < indent; i++)
+ sbufp[sbufi++] = ' ';
+}
+
+static void growsbuf(int ssize)
+{
+ int nsize;
+
+ nsize = ((sbufn + ssize) / SBUFINCR + 1) * SBUFINCR;
+ if (!(sbufp = realloc(sbufp, nsize * SBUFSIZE)))
+ panic(POS, "growsbuf", "sbuf realloc failed");
+ sbufn = nsize;
+}
+
+static char *copysbuf(void)
+{
+ char *newsbufp;
+
+ sbufp[sbufi++] = '\000';
+ if (!(newsbufp = malloc(sbufi * sizeof(char))))
+ panic(POS, "copysbuf", "newsbuf malloc failed");
+ strcpy(newsbufp, sbufp);
+ return newsbufp;
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#ifndef _STR_H
+#define _STR_H
+ void Sinit(void);
+ void Sterm(void);
+ char *Spath(char *, Tobj);
+ char *Sseen(Tobj, char *);
+ char *Sabstract(Tobj, Tobj);
+ char *Stfull(Tobj);
+ char *Ssfull(Tobj, Tobj);
+ char *Scfull(Tobj, int, int);
+#endif /* _STR_H */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#include "common.h"
+#include "mem.h"
+#include "code.h"
+#include "tbl.h"
+
+long Ttime = 0;
+int Tstringoffset, Tcodeoffset, Tkvoffset;
+Tobj Ttrue, Tfalse;
+
+#define ISEQIK(ik, ko) \
+ (T_ISNUMBER (ko) && Tgetnumber (ko) == (ik))
+#define ISEQRK(rk, ko) \
+ (T_ISNUMBER (ko) && Tgetnumber (ko) == (rk))
+#define ISEQSK(sk, ko) \
+ (T_ISSTRING (ko) && Strcmp (((Tstring_t *) (ko))->s, (sk)) == 0)
+
+#define GETIKINDEX(tp, ik) (unsigned long) ik % tp->ln
+#define GETRKINDEX(tp, rk) (unsigned long) rk % tp->ln
+#define GETSKINDEX(tp, sk) (unsigned long) *sk % tp->ln
+
+typedef struct mapentry_t {
+ struct mapentry_t *next;
+ Tobj fmo, too;
+} mapentry_t;
+#define MAPENTRYSIZE sizeof (mapentry_t)
+#define MAPLISTN 100
+typedef struct Map_t {
+ struct mapentry_t *list[MAPLISTN];
+} Map_t;
+static Map_t map;
+static long mapentrybyte2size;
+
+static long truem, falsem;
+
+static Tinteger_t keyi;
+static Treal_t keyr;
+static Tstring_t keys;
+
+static void insert(Ttable_t *, Tobj, char *, Tobj);
+static Tobj find(Ttable_t *, Tobj, char *);
+static void delete(Ttable_t *, Tobj, char *);
+static void copytable(Ttable_t *, long);
+static void reccopytable(Ttable_t *, Ttable_t *);
+static void mapinit(void);
+static void mapterm(void);
+static void mapinsert(Tobj, Tobj);
+static Tobj mapfind(Tobj);
+
+void Tinit(void)
+{
+ Tstring_t s;
+ Tcode_t c;
+ Tkvlist_t kvl;
+
+ Mhaspointers[T_INTEGER] = FALSE;
+ Mhaspointers[T_REAL] = FALSE;
+ Mhaspointers[T_STRING] = FALSE;
+ Mhaspointers[T_CODE] = FALSE;
+ Mhaspointers[T_TABLE] = TRUE;
+ Ttrue = Tinteger(1);
+ truem = Mpushmark(Ttrue);
+ Tfalse = Tinteger(0);
+ falsem = Mpushmark(Tfalse);
+ Tstringoffset = (char *) &s.s[0] - (char *) &s + 1;
+ /* the + 1 above accounts for the null character */
+ Tcodeoffset = (char *) &c.c[0] - (char *) &c;
+ Tkvoffset = (char *) &kvl.kv[0] - (char *) &kvl;
+ keyi.head.type = T_INTEGER;
+ keyr.head.type = T_REAL;
+ keys.head.type = T_STRING;
+ mapentrybyte2size = M_BYTE2SIZE(MAPENTRYSIZE);
+}
+
+void Tterm(void)
+{
+ Mpopmark(falsem);
+ Tfalse = NULL;
+ Mpopmark(truem);
+ Ttrue = NULL;
+ Mdogc(M_GCFULL);
+ Mdogc(M_GCFULL);
+}
+
+void Tgchelper(void *p)
+{
+ Ttable_t *tp;
+ Tkvlist_t *kvlp;
+ long i, j;
+
+ /* must be a table */
+ tp = (Ttable_t *) p;
+ for (i = 0; i < tp->ln; i++)
+ if ((kvlp = tp->lp[i]))
+ for (j = 0; j < kvlp->i; j++)
+ Mmkcurr(kvlp->kv[j].ko), Mmkcurr(kvlp->kv[j].vo);
+}
+
+void Tfreehelper(void *p)
+{
+ Ttable_t *tp;
+ Tkvlist_t *kvlp;
+ long i;
+
+ /* must be a table */
+ tp = (Ttable_t *) p;
+ for (i = 0; i < tp->ln; i++)
+ if ((kvlp = tp->lp[i]))
+ Mfree(kvlp, M_BYTE2SIZE(T_KVLISTSIZE(kvlp->n)));
+ Mfree(tp->lp, M_BYTE2SIZE(tp->ln * T_KVLISTPTRSIZE));
+}
+
+Tobj Tinteger(long i)
+{
+ Tinteger_t *ip;
+
+ ip = Mnew(T_INTEGERSIZE, T_INTEGER);
+ ip->i = i;
+ return ip;
+}
+
+Tobj Treal(double d)
+{
+ Treal_t *rp;
+
+ if (d == (double) (long) d)
+ return Tinteger((long) d);
+ rp = Mnew(T_REALSIZE, T_REAL);
+ rp->d = d;
+ return rp;
+}
+
+Tobj Tstring(char *s)
+{
+ Tstring_t *sp;
+
+ sp = Mnew((long) T_STRINGSIZE(strlen(s)), T_STRING);
+ strcpy(&sp->s[0], s);
+ return sp;
+}
+
+Tobj Tcode(Code_t * cp, int ci, int cl)
+{
+ Tcode_t *codep;
+ Code_t *cp2;
+ char *s;
+ int i, j, cn;
+
+ codep = Mnew((long) T_CODESIZE(cl), T_CODE);
+ cp2 = codep->c;
+ for (i = 0; i < cl; i++) {
+ switch (cp[i].ctype) {
+ case C_INTEGER:
+ cp2[i] = cp[i];
+ if (cp2[i].next != C_NULL)
+ cp2[i].next -= ci;
+ break;
+ case C_REAL:
+ cp2[i] = cp[i];
+ if (cp2[i].next != C_NULL)
+ cp2[i].next -= ci;
+ break;
+ case C_STRING:
+ cp2[i] = cp[i];
+ if (cp2[i].next != C_NULL)
+ cp2[i].next -= ci;
+ s = (char *) &cp[i].u.s;
+ while (*s)
+ s++;
+ cn = (long) (s - (char *) &cp[i]) / sizeof(Code_t);
+ for (j = 0; j < cn; j++)
+ i++, cp2[i] = cp[i];
+ break;
+ default:
+ cp2[i] = cp[i];
+ if (cp2[i].next != C_NULL)
+ cp2[i].next -= ci;
+ if (cp2[i].u.fp != C_NULL)
+ cp2[i].u.fp -= ci;
+ break;
+ }
+ }
+ return codep;
+}
+
+Tobj Ttable(long sizehint)
+{
+ Ttable_t *tp;
+ Tkvlist_t **lp;
+ long i;
+
+ sizehint = (sizehint < 2) ? 2 : sizehint;
+ tp = Mnew(T_TABLESIZE, T_TABLE);
+ lp = Mallocate((long) (sizehint * T_KVLISTPTRSIZE));
+ tp->lp = lp;
+ tp->ln = sizehint;
+ tp->n = 0;
+ tp->time = Ttime;
+ for (i = 0; i < sizehint; i++)
+ lp[i] = NULL;
+ return tp;
+}
+
+
+void Tinsi(Tobj to, long ik, Tobj vo)
+{
+ long tm;
+
+ if (!to || !T_ISTABLE(to))
+ panic(POS, "Tinsi", "insert attempted on non-table");
+ tm = Mpushmark(to);
+ if (vo)
+ Mpushmark(vo);
+ keyi.i = ik;
+ insert(to, &keyi, NULL, vo);
+ Mpopmark(tm);
+}
+
+void Tinsr(Tobj to, double rk, Tobj vo)
+{
+ long tm;
+
+ if (!to || !T_ISTABLE(to))
+ panic(POS, "Tinsr", "insert attempted on non-table");
+ tm = Mpushmark(to);
+ if (vo)
+ Mpushmark(vo);
+ keyr.d = rk;
+ insert(to, &keyr, NULL, vo);
+ Mpopmark(tm);
+}
+
+void Tinss(Tobj to, char *sk, Tobj vo)
+{
+ long tm;
+
+ if (!to || !T_ISTABLE(to))
+ panic(POS, "Tinss", "insert attempted on non-table");
+ tm = Mpushmark(to);
+ if (vo)
+ Mpushmark(vo);
+ insert(to, &keys, sk, vo);
+ Mpopmark(tm);
+}
+
+void Tinso(Tobj to, Tobj ko, Tobj vo)
+{
+ long tm;
+
+ if (!to || !T_ISTABLE(to))
+ panic(POS, "Tinso", "insert attempted on non-table");
+ if (!ko || !(T_ISINTEGER(ko) || T_ISREAL(ko) || T_ISSTRING(ko)))
+ panic(POS, "Tinso", "bad key");
+ tm = Mpushmark(to);
+ Mpushmark(ko);
+ if (vo)
+ Mpushmark(vo);
+ insert(to, ko, NULL, vo);
+ Mpopmark(tm);
+}
+
+Tobj Tfindi(Tobj to, long ik)
+{
+ if (!to)
+ return NULL;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tfindi", "find attempted on non-table");
+ keyi.i = ik;
+ return find(to, &keyi, NULL);
+}
+
+Tobj Tfindr(Tobj to, double rk)
+{
+ if (!to)
+ return NULL;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tfindr", "find attempted on non-table");
+ keyr.d = rk;
+ return find(to, &keyr, NULL);
+}
+
+Tobj Tfinds(Tobj to, char *sk)
+{
+ if (!to)
+ return NULL;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tfinds", "find attempted on non-table");
+ return find(to, &keys, sk);
+}
+
+Tobj Tfindo(Tobj to, Tobj ko)
+{
+ if (!to || !ko)
+ return NULL;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tfindo", "find attempted on non-table");
+ if (!(T_ISINTEGER(ko) || T_ISREAL(ko) || T_ISSTRING(ko)))
+ panic(POS, "Tfindo", "bad key");
+ return find(to, ko, NULL);
+}
+
+void Tdeli(Tobj to, long ik)
+{
+ if (!to)
+ return;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tdeli", "delete attempted on non-table");
+ keyi.i = ik;
+ delete(to, &keyi, NULL);
+}
+
+void Tdelr(Tobj to, double rk)
+{
+ if (!to)
+ return;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tdelr", "delete attempted on non-table");
+ keyr.d = rk;
+ delete(to, &keyr, NULL);
+}
+
+void Tdels(Tobj to, char *sk)
+{
+ if (!to)
+ return;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tdels", "delete attempted on non-table");
+ delete(to, &keys, sk);
+}
+
+void Tdelo(Tobj to, Tobj ko)
+{
+ if (!to || !ko)
+ return;
+ if (!T_ISTABLE(to))
+ panic(POS, "Tdelo", "delete attempted on non-table");
+ if (!(T_ISINTEGER(ko) || T_ISREAL(ko) || T_ISSTRING(ko)))
+ panic(POS, "Tdelo", "bad key");
+ delete(to, ko, NULL);
+}
+
+Tobj Tcopy(Tobj fmvo)
+{
+ Tobj tovo = NULL;
+ long m;
+
+ switch (M_TYPEOF(fmvo)) {
+ case T_INTEGER:
+ case T_REAL:
+ case T_STRING:
+ case T_CODE:
+ tovo = fmvo;
+ break;
+ case T_TABLE:
+ mapinit();
+ m = Mpushmark(fmvo);
+ tovo = Mnew(T_TABLESIZE, T_TABLE);
+ mapinsert(fmvo, tovo);
+ reccopytable(fmvo, tovo);
+ Mpopmark(m);
+ mapterm();
+ break;
+ }
+ return tovo;
+}
+
+void Tgetfirst(Tobj to, Tkvindex_t * p)
+{
+ if (!to || !T_ISTABLE(to))
+ return;
+ p->tp = to, p->kvp = NULL, p->i = 0, p->j = 0;
+ for (; p->i < p->tp->ln; p->i++) {
+ if (!p->tp->lp[p->i])
+ continue;
+ for (; p->j < p->tp->lp[p->i]->i; p->j++) {
+ if ((p->kvp = &p->tp->lp[p->i]->kv[p->j]))
+ return;
+ }
+ p->j = 0;
+ }
+}
+
+void Tgetnext(Tkvindex_t * p)
+{
+ p->kvp = NULL;
+ p->j++;
+ for (; p->i < p->tp->ln; p->i++) {
+ if (!p->tp->lp[p->i])
+ continue;
+ for (; p->j < p->tp->lp[p->i]->i; p->j++) {
+ if ((p->kvp = &p->tp->lp[p->i]->kv[p->j]))
+ return;
+ }
+ p->j = 0;
+ }
+}
+
+static void insert(Ttable_t * tp, Tobj ko, char *sk, Tobj vo)
+{
+ Tkvlist_t *kvlp = NULL, *nkvlp;
+ Tkv_t *kvp;
+ Ttype_t kt;
+ long ik = 0, i, ind = 0, nln;
+ double rk = 0.0;
+
+ switch ((kt = (Ttype_t) M_TYPEOF(ko))) {
+ case T_INTEGER:
+ ik = ((Tinteger_t *) ko)->i;
+ if ((kvlp = tp->lp[(ind = GETIKINDEX(tp, ik))]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQIK(ik, kvp[i].ko))
+ goto found;
+ break;
+ case T_REAL:
+ rk = ((Treal_t *) ko)->d;
+ if ((kvlp = tp->lp[(ind = GETRKINDEX(tp, rk))]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQRK(rk, kvp[i].ko))
+ goto found;
+ break;
+ case T_STRING:
+ if (M_AREAOF(ko) != 0)
+ sk = ((Tstring_t *) ko)->s;
+ if ((kvlp = tp->lp[(ind = GETSKINDEX(tp, sk))]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQSK(sk, kvp[i].ko))
+ goto found;
+ break;
+ default:
+ break;
+ }
+ if ((nln = tp->n + 1) > 4 * tp->ln && nln < M_SIZEMAX) {
+ copytable(tp, nln);
+ switch (kt) {
+ case T_INTEGER:
+ ind = GETIKINDEX(tp, ik);
+ break;
+ case T_REAL:
+ ind = GETRKINDEX(tp, rk);
+ break;
+ case T_STRING:
+ ind = GETSKINDEX(tp, sk);
+ break;
+ default:
+ break;
+ }
+ kvlp = tp->lp[ind];
+ }
+ if (!kvlp) {
+ tp->lp[ind] = kvlp = Mallocate((long) T_KVLISTSIZE(1));
+ kvlp->i = 0, kvlp->n = 1;
+ } else if (kvlp->i == kvlp->n) {
+ tp->lp[ind] = nkvlp = Mallocate((long) T_KVLISTSIZE(kvlp->n * 2));
+ nkvlp->n = kvlp->n * 2;
+ for (i = 0; i < kvlp->n; i++)
+ nkvlp->kv[i] = kvlp->kv[i];
+ nkvlp->i = kvlp->i;
+ Mfree(kvlp, M_BYTE2SIZE(T_KVLISTSIZE(kvlp->n))), kvlp = nkvlp;
+ }
+ if (M_AREAOF(ko) == 0) { /* ko must be allocated */
+ switch (kt) {
+ case T_INTEGER:
+ ko = Tinteger(ik);
+ break;
+ case T_REAL:
+ ko = Treal(rk);
+ break;
+ case T_STRING:
+ ko = Tstring(sk);
+ break;
+ default:
+ break;
+ }
+ }
+
+ kvlp->kv[kvlp->i].ko = ko, kvlp->kv[kvlp->i++].vo = vo;
+ tp->n++;
+ tp->time = Ttime;
+ return;
+
+ found:
+ kvp[i].vo = vo;
+ tp->time = Ttime;
+}
+
+static Tobj find(Ttable_t * tp, Tobj ko, char *sk)
+{
+ Tkvlist_t *kvlp;
+ Tkv_t *kvp;
+ long ik, i;
+ double rk;
+
+ switch (M_TYPEOF(ko)) {
+ case T_INTEGER:
+ ik = ((Tinteger_t *) ko)->i;
+ if ((kvlp = tp->lp[GETIKINDEX(tp, ik)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQIK(ik, kvp[i].ko))
+ goto found;
+ break;
+ case T_REAL:
+ rk = ((Treal_t *) ko)->d;
+ if ((kvlp = tp->lp[GETRKINDEX(tp, rk)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQRK(rk, kvp[i].ko))
+ goto found;
+ break;
+ case T_STRING:
+ if (M_AREAOF(ko) != 0)
+ sk = ((Tstring_t *) ko)->s;
+ if (sk == NULL)
+ return NULL;
+ if ((kvlp = tp->lp[GETSKINDEX(tp, sk)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQSK(sk, kvp[i].ko))
+ goto found;
+ break;
+ }
+ return NULL;
+
+ found:
+ return kvp[i].vo;
+}
+
+static void delete(Ttable_t * tp, Tobj ko, char *sk)
+{
+ Tkvlist_t *kvlp;
+ Tkv_t *kvp;
+ long ik, i, j;
+ double rk;
+
+ switch (M_TYPEOF(ko)) {
+ case T_INTEGER:
+ ik = ((Tinteger_t *) ko)->i;
+ if ((kvlp = tp->lp[GETIKINDEX(tp, ik)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQIK(ik, kvp[i].ko))
+ goto found;
+ break;
+ case T_REAL:
+ rk = ((Treal_t *) ko)->d;
+ if ((kvlp = tp->lp[GETRKINDEX(tp, rk)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQRK(rk, kvp[i].ko))
+ goto found;
+ break;
+ case T_STRING:
+ if (M_AREAOF(ko) != 0)
+ sk = ((Tstring_t *) ko)->s;
+ if ((kvlp = tp->lp[GETSKINDEX(tp, sk)]))
+ for (i = 0, kvp = &kvlp->kv[0]; i < kvlp->i; i++)
+ if (ISEQSK(sk, kvp[i].ko))
+ goto found;
+ break;
+ }
+ return;
+
+ found:
+ for (j = i, kvp = &kvlp->kv[0]; j < kvlp->i - 1; j++)
+ kvp[j] = kvp[j + 1];
+ kvlp->i--;
+ tp->n--;
+ tp->time = Ttime;
+}
+
+static void copytable(Ttable_t * tp, long ln)
+{
+ Tkvlist_t **olp, **lp;
+ Tkvlist_t *okvlp, *kvlp = NULL, *nkvlp;
+ Tkv_t *kvp;
+ long ik, oln, i, j, k, ind = 0;
+ double rk;
+ char *sk;
+
+ lp = Mallocate((long) (ln * T_KVLISTPTRSIZE));
+ oln = tp->ln, tp->ln = ln;
+ olp = tp->lp, tp->lp = lp;
+ for (i = 0; i < ln; i++)
+ lp[i] = NULL;
+ for (i = 0; i < oln; i++) {
+ if (!(okvlp = olp[i]))
+ continue;
+ for (j = 0; j < okvlp->i; j++) {
+ kvp = &okvlp->kv[j];
+ switch (M_TYPEOF(kvp->ko)) {
+ case T_INTEGER:
+ ik = ((Tinteger_t *) kvp->ko)->i;
+ kvlp = lp[(ind = GETIKINDEX(tp, ik))];
+ break;
+ case T_REAL:
+ rk = ((Treal_t *) kvp->ko)->d;
+ kvlp = lp[(ind = GETRKINDEX(tp, rk))];
+ break;
+ case T_STRING:
+ sk = ((Tstring_t *) kvp->ko)->s;
+ kvlp = lp[(ind = GETSKINDEX(tp, sk))];
+ break;
+ }
+ if (!kvlp) {
+ lp[ind] = kvlp = Mallocate((long) T_KVLISTSIZE(1));
+ kvlp->i = 0, kvlp->n = 1;
+ } else if (kvlp->i == kvlp->n) {
+ lp[ind] = nkvlp =
+ Mallocate((long) T_KVLISTSIZE(kvlp->n * 2));
+ nkvlp->n = kvlp->n * 2;
+ for (k = 0; k < kvlp->i; k++)
+ nkvlp->kv[k] = kvlp->kv[k];
+ nkvlp->i = kvlp->i;
+ Mfree(kvlp, M_BYTE2SIZE(T_KVLISTSIZE(kvlp->n)));
+ kvlp = nkvlp;
+ }
+ kvlp->kv[kvlp->i].ko = kvp->ko, kvlp->kv[kvlp->i++].vo =
+ kvp->vo;
+ }
+ Mfree(okvlp, M_BYTE2SIZE(T_KVLISTSIZE(okvlp->n)));
+ }
+ Mfree(olp, M_BYTE2SIZE(oln * T_KVLISTPTRSIZE));
+}
+
+static void reccopytable(Ttable_t * fmtp, Ttable_t * totp)
+{
+ Tkv_t *fmkvp, *tokvp;
+ long i, j, m;
+
+ totp->lp = Mallocate((long) (fmtp->ln * T_KVLISTPTRSIZE));
+ totp->ln = fmtp->ln;
+ totp->n = fmtp->n;
+ totp->time = Ttime;
+ for (i = 0; i < totp->ln; i++) {
+ if (!fmtp->lp[i]) {
+ totp->lp[i] = NULL;
+ continue;
+ }
+ totp->lp[i] = Mallocate((long) T_KVLISTSIZE(fmtp->lp[i]->n));
+ totp->lp[i]->n = fmtp->lp[i]->n;
+ totp->lp[i]->i = 0;
+ }
+ m = Mpushmark(totp);
+ for (i = 0; i < totp->ln; i++) {
+ if (!totp->lp[i])
+ continue;
+ for (j = 0; j < fmtp->lp[i]->i; j++) {
+ fmkvp = &fmtp->lp[i]->kv[j], tokvp = &totp->lp[i]->kv[j];
+ tokvp->ko = fmkvp->ko;
+ switch (M_TYPEOF(fmkvp->vo)) {
+ case T_INTEGER:
+ case T_REAL:
+ case T_STRING:
+ case T_CODE:
+ tokvp->vo = fmkvp->vo;
+ break;
+ case T_TABLE:
+ if (!(tokvp->vo = mapfind(fmkvp->vo))) {
+ tokvp->vo = Mnew(T_TABLESIZE, T_TABLE);
+ mapinsert(fmkvp->vo, tokvp->vo);
+ reccopytable(fmkvp->vo, tokvp->vo);
+ }
+ break;
+ }
+ totp->lp[i]->i++;
+ }
+ }
+ Mpopmark(m);
+}
+
+static void mapinit(void)
+{
+ long li;
+
+ for (li = 0; li < MAPLISTN; li++)
+ map.list[li] = NULL;
+}
+
+static void mapterm(void)
+{
+ mapentry_t **lp;
+ mapentry_t *cep, *nep;
+ long li;
+
+ for (li = 0; li < MAPLISTN; li++) {
+ lp = &map.list[li];
+ for (cep = *lp; cep; cep = nep) {
+ nep = cep->next;
+ Mfree(cep, mapentrybyte2size);
+ }
+ *lp = NULL;
+ }
+}
+
+static void mapinsert(Tobj fmo, Tobj too)
+{
+ mapentry_t **lp;
+ mapentry_t *cep;
+
+ lp = &map.list[(unsigned long) fmo % MAPLISTN];
+ if (!(cep = Mallocate(MAPENTRYSIZE)))
+ panic(POS, "mapinsert", "cannot allocate mapentry");
+ cep->fmo = fmo, cep->too = too;
+ cep->next = *lp, *lp = cep;
+}
+
+static Tobj mapfind(Tobj fmo)
+{
+ mapentry_t **lp;
+ mapentry_t *cep;
+
+ lp = &map.list[(unsigned long) fmo % MAPLISTN];
+ for (cep = *lp; cep; cep = cep->next)
+ if (cep->fmo == fmo)
+ return cep->too;
+ return NULL;
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#ifndef _TBL_H
+#define _TBL_H
+ typedef enum {
+ T_INTEGER = 1, T_REAL, T_STRING, T_CODE, T_TABLE, T_SIZE
+ } Ttype_t;
+
+ typedef struct Tinteger_t {
+ Mheader_t head;
+ long i;
+ } Tinteger_t;
+#define T_INTEGERSIZE sizeof (Tinteger_t)
+ typedef struct Treal_t {
+ Mheader_t head;
+ double d;
+ } Treal_t;
+#define T_REALSIZE sizeof (Treal_t)
+ typedef struct Tstring_t {
+ Mheader_t head;
+ char s[1];
+ } Tstring_t;
+#define T_STRINGSIZE(l) (l + Tstringoffset)
+ typedef struct Tcode_t {
+ Mheader_t head;
+ Code_t c[1];
+ } Tcode_t;
+#define T_CODESIZE(l) (l * C_CODESIZE + Tcodeoffset)
+ typedef struct Tkv_t {
+ void *ko;
+ void *vo;
+ } Tkv_t;
+#define T_KVSIZE sizeof (Tkv_t)
+ typedef struct Tkvlist_t {
+ long i, n;
+ Tkv_t kv[1];
+ } Tkvlist_t;
+#define T_KVLISTSIZE(l) (l * T_KVSIZE + Tkvoffset)
+#define T_KVLISTPTRSIZE sizeof (Tkvlist_t *)
+ typedef struct Ttable_t {
+ Mheader_t head;
+ long n, ln;
+ long time;
+ Tkvlist_t **lp;
+ } Ttable_t;
+#define T_TABLESIZE sizeof (Ttable_t)
+ typedef struct Tkvindex_t {
+ Ttable_t *tp;
+ Tkv_t *kvp;
+ long i, j;
+ } Tkvindex_t;
+
+ typedef void *Tobj;
+
+ typedef struct Tonm_t { /* Object aNd Mark */
+ Tobj o;
+ long m;
+ } Tonm_t;
+
+#define T_ISSTRING(o) (M_TYPEOF (o) == T_STRING)
+#define T_ISTABLE(o) (M_TYPEOF (o) == T_TABLE)
+#define T_ISINTEGER(o) (M_TYPEOF (o) == T_INTEGER)
+#define T_ISREAL(o) (M_TYPEOF (o) == T_REAL)
+#define T_ISNUMBER(o) (M_TYPEOF (o) == T_REAL || M_TYPEOF (o) == T_INTEGER)
+
+#define Tgettype(p) ((Ttype_t)(((Mheader_t *) p)->type))
+#define Tgettablen(p) (((Ttable_t *) p)->n)
+#define Tgettime(p) (((Ttable_t *) p)->time)
+#define Tgetstring(p) (char *) &(((Tstring_t *) p)->s[0])
+#define Tgetcode(p) (Code_t *) &(((Tcode_t *) p)->c[0])
+#define Tgetinteger(p) (((Tinteger_t *) p)->i)
+#define Tgetreal(p) (((Treal_t *) p)->d)
+#define Tgetnumber(p) (T_ISINTEGER (p) ? Tgetinteger (p) : Tgetreal (p))
+
+#define TCgettype(p, off) ((Tgetcode (p) + off)->ctype)
+#define TCgetfp(p, off) ((Tgetcode (p) + off)->u.fp)
+#define TCgetinteger(p, off) ((Tgetcode (p) + off)->u.i)
+#define TCgetobject(p, off) ((Tgetcode (p) + off)->u.o)
+#define TCgetreal(p, off) ((Tgetcode (p) + off)->u.d)
+#define TCgetstring(p, off) ((char *) &((Tgetcode (p) + off)->u.s))
+#define TCgetnext(p, off) ((Tgetcode (p) + off)->next)
+#define TCgetaddr(p, off) (Tgetcode (p) + off)
+
+ extern long Ttime;
+ extern int Tstringoffset, Tcodeoffset, Tkvoffset;
+ extern Tobj Ttrue, Tfalse;
+
+ void Tinit(void);
+ void Tterm(void);
+ void Tgchelper(void *);
+ void Tfreehelper(void *);
+ Tobj Tinteger(long);
+ Tobj Treal(double);
+ Tobj Tstring(char *);
+ Tobj Tcode(Code_t *, int, int);
+ Tobj Ttable(long);
+ void Tinsi(Tobj, long, Tobj);
+ void Tinsr(Tobj, double, Tobj);
+ void Tinss(Tobj, char *, Tobj);
+ void Tinso(Tobj, Tobj, Tobj);
+ Tobj Tfindi(Tobj, long);
+ Tobj Tfindr(Tobj, double);
+ Tobj Tfinds(Tobj, char *);
+ Tobj Tfindo(Tobj, Tobj);
+ void Tdeli(Tobj, long);
+ void Tdelr(Tobj, double);
+ void Tdels(Tobj, char *);
+ void Tdelo(Tobj, Tobj);
+ Tobj Tcopy(Tobj);
+ void Tgetfirst(Tobj, Tkvindex_t *);
+ void Tgetnext(Tkvindex_t *);
+#endif /* _TBL_H */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#include "common.h"
+#include "g.h"
+#include "mem.h"
+#include "code.h"
+#include "tbl.h"
+#include "parse.h"
+#include "exec.h"
+#include "str.h"
+#include "txtview.h"
+
+typedef enum {
+ TXT_SEEN, TXT_ABSTRACT, TXT_FULL
+} txtmode_t;
+typedef struct txtnode_t {
+ txtmode_t mode;
+ Ttype_t ttype;
+ Tobj ko, vo;
+ long time;
+ char *path;
+ union {
+ struct {
+ struct txtnode_t *txtnode;
+ Tobj ko;
+ char *text;
+ int wi;
+ } s;
+ struct {
+ char *text;
+ int wi;
+ } a;
+ union {
+ struct {
+ char *text;
+ int wi;
+ } s;
+ struct {
+ char *ftext, *ltext;
+ int fwi, mwi, lwi;
+ struct txtnode_t *list;
+ int n;
+ } t;
+ } f;
+ } u;
+} txtnode_t;
+static txtnode_t *txtroot;
+static txtnode_t defnode;
+
+static txtnode_t **seenp;
+static long seeni, seenn;
+#define SEENINCR 100
+#define SEENSIZE sizeof (txtnode_t)
+
+static Tobj txtvo2toggle = NULL;
+
+static Gwattr_t arraydata[2], buttondata[5];
+
+static int txton, txtx, txty, txtwidth, txtheight;
+static int txtwi, queryws[G_QWMODES + 1], listwi, scrollwi, arraywi, cmdwi;
+
+static Psrc_t src;
+
+#define max(a, b) (((a) >= (b)) ? (a) : (b))
+
+static void viewon(void);
+static void viewoff(void);
+static void update(txtnode_t *, long);
+static void buildlist(txtnode_t *);
+static void rebuildlist(txtnode_t *);
+static void fillnode(txtnode_t *, txtnode_t *);
+static void unfillnode(txtnode_t *);
+static int cmp(const void *, const void *);
+static txtnode_t *findseen(txtnode_t *);
+static void add2seen(txtnode_t *);
+static void orderfunc(void *, Gawdata_t *);
+static void coordsfunc(int, Gawdata_t *);
+static void coords2func(int, Gawdata_t *);
+
+void TXTinit(Grect_t r)
+{
+ Gwattr_t data[1];
+ int i;
+
+ txton = TRUE;
+ txtwi = -1;
+ txtx = r.o.x, txty = r.o.y;
+ txtwidth = r.c.x - r.o.x + 1, txtheight = r.c.y - r.o.y + 1;
+
+ buttondata[0].id = G_ATTRBUTTONCB;
+ buttondata[0].u.func = (void *) (TXTtoggle);
+ buttondata[1].id = G_ATTRSIZE;
+ buttondata[1].u.s.x = buttondata[1].u.s.y = 0;
+ buttondata[2].id = G_ATTRBORDERWIDTH;
+ buttondata[2].u.i = 0;
+ buttondata[3].id = G_ATTRTEXT;
+ buttondata[4].id = G_ATTRUSERDATA;
+
+ arraydata[0].id = G_ATTRRESIZECB;
+ arraydata[0].u.func = (void *) (coordsfunc);
+ arraydata[1].id = G_ATTRSIZE;
+ arraydata[1].u.s.x = arraydata[1].u.s.y = 0;
+
+ defnode.mode = TXT_ABSTRACT;
+ defnode.ttype = T_TABLE;
+ defnode.ko = defnode.vo = NULL;
+ defnode.time = -1;
+ defnode.path = NULL;
+ defnode.u.s.txtnode = NULL;
+ defnode.u.s.ko = NULL;
+ defnode.u.s.text = NULL;
+ defnode.u.s.wi = 0;
+ defnode.u.a.text = NULL;
+ defnode.u.a.wi = 0;
+ defnode.u.f.s.text = NULL;
+ defnode.u.f.s.wi = 0;
+ defnode.u.f.t.ftext = defnode.u.f.t.ltext = NULL;
+ defnode.u.f.t.fwi = 0;
+ defnode.u.f.t.mwi = 0;
+ defnode.u.f.t.lwi = 0;
+ defnode.u.f.t.list = NULL;
+ defnode.u.f.t.n = 0;
+
+ for (i = 1; i <= G_QWMODES; i++) {
+ data[0].id = G_ATTRMODE;
+ switch (i) {
+ case G_QWSTRING:
+ data[0].u.t = "string";
+ break;
+ case G_QWFILE:
+ data[0].u.t = "file";
+ break;
+ case G_QWCHOICE:
+ data[0].u.t = "choice";
+ break;
+ }
+ queryws[i] = Gcreatewidget(-1, G_QUERYWIDGET, 1, &data[0]);
+ }
+
+ src.flag = CHARSRC, src.fp = NULL, src.tok = -1, src.lnum = 1;
+}
+
+void TXTterm(void)
+{
+ int i;
+
+ for (i = 1; i <= G_QWMODES; i++)
+ Gdestroywidget(queryws[i]);
+ if (txton)
+ viewoff(), txton = FALSE;
+}
+
+/* LEFTY builtin */
+int TXTmode(int argc, lvar_t * argv)
+{
+ char *s;
+
+ if (!argv[0].o || Tgettype(argv[0].o) != T_STRING)
+ return L_FAILURE;
+ s = Tgetstring(argv[0].o);
+ if (Strcmp(s, "on") == 0) {
+ if (txtwi == -1)
+ viewon();
+ } else if (Strcmp(s, "off") == 0) {
+ if (txtwi != -1)
+ viewoff();
+ else
+ txton = FALSE;
+ }
+ return L_SUCCESS;
+}
+
+static void viewon(void)
+{
+ Gwattr_t data[5];
+
+ data[0].id = G_ATTRNAME;
+ data[0].u.t = "LEFTY text view";
+ data[1].id = G_ATTRORIGIN;
+ data[1].u.p.x = txtx, data[1].u.p.y = txty;
+ data[2].id = G_ATTRSIZE;
+ data[2].u.s.x = txtwidth, data[2].u.s.y = txtheight;
+ txtwi = Gcreatewidget(-1, G_VIEWWIDGET, 3, &data[0]);
+
+ data[0].id = G_ATTRSIZE;
+ data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight;
+ data[1].id = G_ATTRBORDERWIDTH;
+ data[1].u.i = 1;
+ data[2].id = G_ATTRRESIZECB;
+ data[2].u.func = (void *) (coords2func);
+ listwi = Gcreatewidget(txtwi, G_ARRAYWIDGET, 3, &data[0]);
+ Gawsetmode(&Gwidgets[listwi], TRUE);
+
+ data[0].id = G_ATTRSIZE;
+ data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight / 3;
+ data[1].id = G_ATTRBORDERWIDTH;
+ data[1].u.i = 0;
+ data[2].id = G_ATTRTEXT;
+ data[2].u.t = NULL;
+ data[3].id = G_ATTRNEWLINECB;
+ data[3].u.func = (void *) (TXTprocess);
+ data[4].id = G_ATTRMODE;
+ data[4].u.t = "oneline";
+ cmdwi = Gcreatewidget(listwi, G_TEXTWIDGET, 5, &data[0]);
+
+ data[0].id = G_ATTRSIZE;
+ data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight * 2 / 3;
+ data[1].id = G_ATTRMODE;
+ data[1].u.t = "forcebars";
+ scrollwi = Gcreatewidget(listwi, G_SCROLLWIDGET, 2, &data[0]);
+
+ data[0].id = G_ATTRRESIZECB;
+ data[0].u.func = (void *) (coordsfunc);
+ data[1].id = G_ATTRSIZE;
+ data[1].u.s.x = txtwidth, data[1].u.s.y = txtheight;
+ data[2].id = G_ATTRBORDERWIDTH;
+ data[2].u.i = 0;
+ arraywi = Gcreatewidget(scrollwi, G_ARRAYWIDGET, 3, &data[0]);
+
+ Gawsetmode(&Gwidgets[listwi], FALSE);
+
+ if (!(txtroot = malloc(sizeof(txtnode_t))))
+ panic(POS, "TXTinit", "txtroot malloc failed");
+ *txtroot = defnode;
+ txtroot->mode = TXT_FULL;
+ txtroot->vo = root;
+ txtroot->path = NULL;
+ txtroot->u.f.t.mwi = arraywi;
+
+ seenp = Marrayalloc((long) SEENINCR * SEENSIZE);
+ seeni = 0;
+ seenn = SEENINCR;
+ txton = TRUE;
+}
+
+static void viewoff(void)
+{
+ Marrayfree(seenp);
+ seeni = seenn = 0;
+ unfillnode(txtroot);
+ free(txtroot);
+ Gdestroywidget(arraywi);
+ Gdestroywidget(scrollwi);
+ Gdestroywidget(cmdwi);
+ Gdestroywidget(listwi);
+ Gdestroywidget(txtwi);
+ txton = FALSE;
+ txtwi = -1;
+}
+
+/* LEFTY builtin */
+int TXTask(int argc, lvar_t * argv)
+{
+ Tobj so, ao;
+ char buf[1200];
+ char *sp, *ap;
+ int mode = 0;
+ ap = 0;
+
+ if (argc < 2)
+ mode = G_QWSTRING;
+ else {
+ so = argv[1].o;
+ if (T_ISSTRING(so)) {
+ sp = Tgetstring(so);
+ if (Strcmp(sp, "string") == 0)
+ mode = G_QWSTRING;
+ else if (Strcmp(sp, "file") == 0)
+ mode = G_QWFILE;
+ else if (Strcmp(sp, "choice") == 0)
+ mode = G_QWCHOICE;
+ }
+ }
+ if (argc < 3)
+ ap = NULL;
+ else {
+ ao = argv[2].o;
+ if (T_ISSTRING(ao))
+ ap = Tgetstring(ao);
+ }
+ if (Gqueryask(queryws[mode], Tgetstring(argv[0].o), ap, buf, 1200) ==
+ 0)
+ rtno = Tstring(buf);
+ else
+ rtno = NULL;
+#ifndef NOQUERYFIX
+ if (mode == G_QWCHOICE) {
+ Gwattr_t data[1];
+
+ data[0].id = G_ATTRMODE;
+ data[0].u.t = "choice";
+ Gdestroywidget(queryws[mode]);
+ queryws[mode] = Gcreatewidget(-1, G_QUERYWIDGET, 1, &data[0]);
+ }
+#endif
+ return L_SUCCESS;
+}
+
+void TXTprocess(int wi, char *sp)
+{
+ Tobj co;
+
+ src.s = sp;
+ if ((co = Punit(&src)))
+ Eoktorun = TRUE, Eunit(co);
+}
+
+void TXTupdate(void)
+{
+ if (!txton)
+ return;
+ if (txtwi == -1)
+ viewon();
+ seeni = 0;
+ update(txtroot, txtroot->time);
+ txtroot->time = Ttime;
+ Ttime++;
+}
+
+void TXTtoggle(int wi, void *data)
+{
+ txtvo2toggle = data;
+ TXTupdate();
+ txtvo2toggle = NULL;
+}
+
+/* update is called only for TXT_FULL tables */
+static void update(txtnode_t * pnode, long ptim)
+{
+ txtnode_t *cnode, *seennode;
+ long ctim;
+ int i;
+
+ Gawsetmode(&Gwidgets[pnode->u.f.t.mwi], TRUE);
+ if (!pnode->u.f.t.list)
+ buildlist(pnode);
+ else if (ptim < Tgettime(pnode->vo))
+ rebuildlist(pnode);
+ for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n;
+ i++, cnode++) {
+ ctim = cnode->time;
+ if (txtvo2toggle == cnode->vo) {
+ switch (cnode->mode) {
+ case TXT_SEEN:
+ break;
+ case TXT_ABSTRACT:
+ unfillnode(cnode);
+ cnode->mode = TXT_FULL;
+ fillnode(pnode, cnode);
+ break;
+ case TXT_FULL:
+ unfillnode(cnode);
+ cnode->mode = TXT_ABSTRACT;
+ fillnode(pnode, cnode);
+ break;
+ }
+ }
+ if (!(seennode = findseen(cnode)))
+ add2seen(cnode);
+ if (seennode && cnode->mode == TXT_SEEN &&
+ seennode->ko != cnode->u.s.ko) {
+ unfillnode(cnode);
+ cnode->u.s.txtnode = seennode;
+ cnode->u.s.ko = seennode->ko;
+ fillnode(pnode, cnode);
+ } else if (seennode && cnode->mode != TXT_SEEN) {
+ unfillnode(cnode);
+ cnode->mode = TXT_SEEN;
+ cnode->u.s.txtnode = seennode;
+ cnode->u.s.ko = seennode->ko;
+ fillnode(pnode, cnode);
+ } else if (!seennode && cnode->mode == TXT_SEEN) {
+ unfillnode(cnode);
+ cnode->mode = TXT_ABSTRACT;
+ fillnode(pnode, cnode);
+ } else if (cnode->time == -1) {
+ unfillnode(cnode);
+ if (seennode)
+ cnode->u.s.txtnode = seennode;
+ fillnode(pnode, cnode);
+ }
+ if (cnode->ttype == T_TABLE && cnode->mode == TXT_FULL)
+ update(cnode, ctim);
+ }
+ Gaworder(&Gwidgets[pnode->u.f.t.mwi], pnode, orderfunc);
+ Gawsetmode(&Gwidgets[pnode->u.f.t.mwi], FALSE);
+}
+
+static void buildlist(txtnode_t * pnode)
+{
+ Tkvindex_t tkvi;
+ Tobj ko, vo;
+ Ttype_t vtype;
+ txtnode_t *cnode;
+
+ pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
+ if (!(pnode->u.f.t.list =
+ malloc(max(pnode->u.f.t.n, 1) * sizeof(txtnode_t))))
+ panic(POS, "buildlist", "list malloc failed");
+
+ for (cnode = &pnode->u.f.t.list[0], Tgetfirst(pnode->vo, &tkvi);
+ tkvi.kvp; Tgetnext(&tkvi)) {
+ ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
+ vtype = Tgettype(vo);
+ if (vtype == T_CODE && TCgettype(vo, TCgetnext(vo, TCgetnext(vo,
+ TCgetnext
+ (vo,
+ TCgetfp
+ (vo,
+ 0)))))
+ == C_INTERNAL) {
+ pnode->u.f.t.n--;
+ continue;
+ }
+ *cnode = defnode;
+ cnode->vo = vo;
+ cnode->ko = ko;
+ cnode->ttype = vtype;
+ cnode++;
+ }
+ qsort((char *) pnode->u.f.t.list, pnode->u.f.t.n,
+ sizeof(txtnode_t), cmp);
+}
+
+static void rebuildlist(txtnode_t * pnode)
+{
+ Tkvindex_t tkvi;
+ Tobj ko, vo;
+ Ttype_t vtype;
+ txtnode_t *cnode;
+ txtnode_t *olist, *nlist;
+ txtnode_t tmpnode;
+ int on, nn, i, j, cmpval = 0;
+
+ olist = pnode->u.f.t.list;
+ on = pnode->u.f.t.n;
+ pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
+ if (!(pnode->u.f.t.list =
+ malloc(max(pnode->u.f.t.n, 1) * sizeof(txtnode_t))))
+ panic(POS, "rebuildlist", "list malloc failed");
+
+ for (cnode = &pnode->u.f.t.list[0], Tgetfirst(pnode->vo, &tkvi);
+ tkvi.kvp; Tgetnext(&tkvi)) {
+ ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
+ vtype = Tgettype(vo);
+ if (vtype == T_CODE && TCgettype(vo, TCgetnext(vo, TCgetnext(vo,
+ TCgetnext
+ (vo,
+ TCgetfp
+ (vo,
+ 0)))))
+ == C_INTERNAL) {
+ pnode->u.f.t.n--;
+ continue;
+ }
+ *cnode = defnode;
+ cnode->vo = vo;
+ cnode->ko = ko;
+ cnode->ttype = vtype;
+ cnode++;
+ }
+ qsort((char *) pnode->u.f.t.list, pnode->u.f.t.n, sizeof(txtnode_t),
+ cmp);
+ nlist = pnode->u.f.t.list;
+ nn = pnode->u.f.t.n;
+ for (i = 0, j = 0; i < nn; i++) {
+ while (j < on && (cmpval = cmp(&olist[j], &nlist[i])) < 0)
+ j++;
+ if (j < on && cmpval == 0 && nlist[i].vo == olist[j].vo)
+ tmpnode = olist[j], olist[j] = nlist[i], nlist[i] =
+ tmpnode, j++;
+ }
+ for (j = 0; j < on; j++)
+ unfillnode(&olist[j]);
+ free(olist);
+}
+
+static void fillnode(txtnode_t * pnode, txtnode_t * cnode)
+{
+ cnode->time = Ttime;
+ cnode->path = Spath(pnode->path, cnode->ko);
+ switch (cnode->mode) {
+ case TXT_SEEN:
+ cnode->u.s.text = Sseen(cnode->ko, cnode->u.s.txtnode->path);
+ buttondata[3].u.t = cnode->u.s.text;
+ buttondata[4].u.u = (unsigned long) cnode->vo;
+ cnode->u.s.wi = Gcreatewidget(pnode->u.f.t.mwi,
+ G_BUTTONWIDGET, 5, &buttondata[0]);
+ break;
+ case TXT_ABSTRACT:
+ cnode->u.a.text = Sabstract(cnode->ko, cnode->vo);
+ buttondata[3].u.t = cnode->u.a.text;
+ buttondata[4].u.u = (unsigned long) cnode->vo;
+ cnode->u.a.wi = Gcreatewidget(pnode->u.f.t.mwi,
+ G_BUTTONWIDGET, 5, &buttondata[0]);
+ break;
+ case TXT_FULL:
+ if (cnode->ttype == T_TABLE) {
+ cnode->u.f.t.ftext = Stfull(cnode->ko);
+ cnode->u.f.t.ltext = "];";
+ buttondata[3].u.t = cnode->u.f.t.ftext;
+ buttondata[4].u.u = (unsigned long) cnode->vo;
+ cnode->u.f.t.fwi = Gcreatewidget(pnode->u.f.t.mwi,
+ G_BUTTONWIDGET, 5,
+ &buttondata[0]);
+ cnode->u.f.t.mwi =
+ Gcreatewidget(pnode->u.f.t.mwi, G_ARRAYWIDGET, 2,
+ &arraydata[0]);
+ buttondata[3].u.t = cnode->u.f.t.ltext;
+ buttondata[4].u.u = (unsigned long) cnode->vo;
+ cnode->u.f.t.lwi = Gcreatewidget(pnode->u.f.t.mwi,
+ G_BUTTONWIDGET, 5,
+ &buttondata[0]);
+ } else {
+ cnode->u.f.s.text = Ssfull(cnode->ko, cnode->vo);
+ buttondata[3].u.t = cnode->u.f.s.text;
+ buttondata[4].u.u = (unsigned long) cnode->vo;
+ cnode->u.f.s.wi = Gcreatewidget(pnode->u.f.t.mwi,
+ G_BUTTONWIDGET, 5,
+ &buttondata[0]);
+ }
+ break;
+ }
+}
+
+static void unfillnode(txtnode_t * cnode)
+{
+ int i;
+
+ if (cnode->path)
+ free(cnode->path), cnode->path = NULL;
+ switch (cnode->mode) {
+ case TXT_SEEN:
+ if (cnode->u.s.text)
+ free(cnode->u.s.text);
+ if (cnode->u.s.wi)
+ Gdestroywidget(cnode->u.s.wi);
+ break;
+ case TXT_ABSTRACT:
+ if (cnode->u.a.text)
+ free(cnode->u.a.text);
+ if (cnode->u.a.wi)
+ Gdestroywidget(cnode->u.a.wi);
+ break;
+ case TXT_FULL:
+ if (cnode->ttype == T_TABLE) {
+ for (i = 0; i < cnode->u.f.t.n; i++)
+ unfillnode(&cnode->u.f.t.list[i]);
+ if (cnode->u.f.t.list)
+ free(cnode->u.f.t.list);
+ if (cnode->u.f.t.ftext)
+ free(cnode->u.f.t.ftext);
+ if (cnode->u.f.t.fwi) {
+ Gdestroywidget(cnode->u.f.t.fwi);
+ Gdestroywidget(cnode->u.f.t.mwi);
+ Gdestroywidget(cnode->u.f.t.lwi);
+ }
+ } else {
+ if (cnode->u.f.s.text)
+ free(cnode->u.f.s.text);
+ if (cnode->u.f.s.wi)
+ Gdestroywidget(cnode->u.f.s.wi);
+ }
+ break;
+ }
+ cnode->u.s.text = NULL;
+ cnode->u.s.wi = 0;
+ cnode->u.a.text = NULL;
+ cnode->u.a.wi = 0;
+ cnode->u.f.t.list = NULL;
+ cnode->u.f.t.ftext = NULL;
+ cnode->u.f.t.fwi = 0;
+ cnode->u.f.t.mwi = 0;
+ cnode->u.f.t.lwi = 0;
+ cnode->u.f.s.text = NULL;
+ cnode->u.f.s.wi = 0;
+}
+
+static int cmp(const void *a, const void *b)
+{
+ Ttype_t atype, btype;
+ txtnode_t *anode, *bnode;
+ double d1 = 0.0, d2 = 0.0;
+
+ anode = (txtnode_t *) a, bnode = (txtnode_t *) b;
+ atype = Tgettype(anode->ko), btype = Tgettype(bnode->ko);
+ if (atype != btype)
+ return (atype - btype);
+ if (atype == T_STRING)
+ return Strcmp(Tgetstring(anode->ko), Tgetstring(bnode->ko));
+ if (atype == T_INTEGER)
+ d1 = Tgetinteger(anode->ko), d2 = Tgetinteger(bnode->ko);
+ else if (atype == T_REAL)
+ d1 = Tgetreal(anode->ko), d2 = Tgetreal(bnode->ko);
+ if (d1 < d2)
+ return -1;
+ else if (d1 > d2)
+ return 1;
+ else
+ return 0; /* but this should never happen since keys are unique */
+}
+
+static txtnode_t *findseen(txtnode_t * cnode)
+{
+ int i;
+
+ for (i = 0; i < seeni; i++)
+ if (seenp[i]->vo == cnode->vo)
+ return seenp[i];
+ return NULL;
+}
+
+static void add2seen(txtnode_t * cnode)
+{
+ if (seeni >= seenn) {
+ seenp = Marraygrow(seenp, (long) (seenn + SEENINCR) * SEENSIZE);
+ seenn += SEENINCR;
+ }
+ seenp[seeni++] = cnode;
+}
+
+static void orderfunc(void *data, Gawdata_t * dp)
+{
+ txtnode_t *pnode, *cnode;
+ int i;
+
+ pnode = data;
+ dp->cj = 0;
+ for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n;
+ i++, cnode++)
+ switch (cnode->mode) {
+ case TXT_SEEN:
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.s.wi].w;
+ break;
+ case TXT_ABSTRACT:
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.a.wi].w;
+ break;
+ case TXT_FULL:
+ if (cnode->ttype == T_TABLE) {
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.fwi].w;
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.mwi].w;
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.lwi].w;
+ } else
+ dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.s.wi].w;
+ break;
+ }
+}
+
+static void coordsfunc(int wi, Gawdata_t * dp)
+{
+ Gawcarray_t *cp;
+ int cox, coy;
+ int ci;
+
+ cox = coy = 0;
+ for (ci = 0; ci < dp->cj; ci++) {
+ cp = &dp->carray[ci];
+ if (!cp->flag)
+ continue;
+ cp->ox = cox, cp->oy = coy;
+ cp->sx = dp->sx - 2 * cp->bs;
+ coy += cp->sy + 2 * cp->bs;
+ }
+ dp->sy = coy;
+}
+
+static void coords2func(int wi, Gawdata_t * dp)
+{
+ Gawcarray_t *cp;
+ int cox, coy;
+ int ci, cj;
+
+ cox = coy = 0;
+ for (ci = 0, cj = 0; ci < dp->cj; ci++) {
+ cp = &dp->carray[ci];
+ if (!cp->flag)
+ continue;
+ cp->ox = cox, cp->oy = coy;
+ cj++;
+ cp->sx = dp->sx - 2 * cp->bs;
+ if (cj == 2)
+ cp->sy = dp->sy - coy - 2 * cp->bs;
+ coy += cp->sy + 2 * cp->bs;
+ }
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Lefteris Koutsofios - AT&T Bell Laboratories */
+
+#ifndef _TXTVIEW_H
+#define _TXTVIEW_H
+ void TXTinit(Grect_t);
+ void TXTterm(void);
+ int TXTmode(int argc, lvar_t * argv);
+ int TXTask(int argc, lvar_t * argv);
+ void TXTprocess(int, char *);
+ void TXTupdate(void);
+ void TXTtoggle(int, void *);
+#endif /* _TXTVIEW_H */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = x11
+
+EXTRA_DIST = mswin32 none