From: ellson Date: Thu, 6 Jan 2005 15:01:43 +0000 (+0000) Subject: add lefty, dotty, lneato to graphviz2 tree X-Git-Tag: LAST_LIBGRAPH~32^2~8130 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0cbc83c0f22e4ea25fc561cf297b93910d59d6b2;p=graphviz add lefty, dotty, lneato to graphviz2 tree --- diff --git a/cmd/lefty/os/unix/.cvsignore b/cmd/lefty/os/unix/.cvsignore new file mode 100644 index 000000000..9fb985742 --- /dev/null +++ b/cmd/lefty/os/unix/.cvsignore @@ -0,0 +1,6 @@ +*.la +*.lo +.deps +.libs +Makefile +Makefile.in diff --git a/cmd/lefty/os/unix/Makefile.am b/cmd/lefty/os/unix/Makefile.am new file mode 100644 index 000000000..a3b31cce4 --- /dev/null +++ b/cmd/lefty/os/unix/Makefile.am @@ -0,0 +1,11 @@ +## 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) diff --git a/cmd/lefty/os/unix/io.c b/cmd/lefty/os/unix/io.c new file mode 100644 index 000000000..338460e9e --- /dev/null +++ b/cmd/lefty/os/unix/io.c @@ -0,0 +1,439 @@ +/* $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 +#include +#include +#ifndef HAVE_TERMIOS_H +#include +#else +#include +#endif +#include +#include +#include +#ifdef HAVEVFORK +#define FORK vfork +#else +#define FORK fork +#endif +#include + +#ifdef HAVE_UNISTD_H +# include +#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); +} diff --git a/cmd/lefty/parse.c b/cmd/lefty/parse.c new file mode 100644 index 000000000..406066dc3 --- /dev/null +++ b/cmd/lefty/parse.c @@ -0,0 +1,685 @@ +/* $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 + = function () internal ""; +*/ +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 + (); where 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); +} diff --git a/cmd/lefty/parse.h b/cmd/lefty/parse.h new file mode 100644 index 000000000..191fd8609 --- /dev/null +++ b/cmd/lefty/parse.h @@ -0,0 +1,43 @@ +/* $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 diff --git a/cmd/lefty/str.c b/cmd/lefty/str.c new file mode 100644 index 000000000..a3559074e --- /dev/null +++ b/cmd/lefty/str.c @@ -0,0 +1,554 @@ +/* $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(""); + 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; +} diff --git a/cmd/lefty/str.h b/cmd/lefty/str.h new file mode 100644 index 000000000..b2802e522 --- /dev/null +++ b/cmd/lefty/str.h @@ -0,0 +1,38 @@ +/* $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 diff --git a/cmd/lefty/tbl.c b/cmd/lefty/tbl.c new file mode 100644 index 000000000..08e48eb0e --- /dev/null +++ b/cmd/lefty/tbl.c @@ -0,0 +1,730 @@ +/* $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; +} diff --git a/cmd/lefty/tbl.h b/cmd/lefty/tbl.h new file mode 100644 index 000000000..779169361 --- /dev/null +++ b/cmd/lefty/tbl.h @@ -0,0 +1,137 @@ +/* $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 diff --git a/cmd/lefty/txtview.c b/cmd/lefty/txtview.c new file mode 100644 index 000000000..34ad53c70 --- /dev/null +++ b/cmd/lefty/txtview.c @@ -0,0 +1,702 @@ +/* $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; + } +} diff --git a/cmd/lefty/txtview.h b/cmd/lefty/txtview.h new file mode 100644 index 000000000..23dc2c254 --- /dev/null +++ b/cmd/lefty/txtview.h @@ -0,0 +1,37 @@ +/* $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 diff --git a/cmd/lefty/ws/.cvsignore b/cmd/lefty/ws/.cvsignore new file mode 100644 index 000000000..9fb985742 --- /dev/null +++ b/cmd/lefty/ws/.cvsignore @@ -0,0 +1,6 @@ +*.la +*.lo +.deps +.libs +Makefile +Makefile.in diff --git a/cmd/lefty/ws/Makefile.am b/cmd/lefty/ws/Makefile.am new file mode 100644 index 000000000..c58b50e76 --- /dev/null +++ b/cmd/lefty/ws/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = x11 + +EXTRA_DIST = mswin32 none