added mk and troff to 9base (unfinished yet, DO NOT USE) - 9base - revived mini… | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit a08a2a9000cf4cb01ac165f410dbe99a64191edd | |
parent c0a69251c8988bdbabf4f3d3e20f40e363990c6c | |
Author: Anselm R Garbe <[email protected]> | |
Date: Mon, 24 Aug 2009 19:23:45 +0100 | |
added mk and troff to 9base (unfinished yet, DO NOT USE) | |
Diffstat: | |
M Makefile | 8 ++++---- | |
M config.mk | 2 +- | |
A mk/Makefile | 11 +++++++++++ | |
A mk/NOTICE | 27 +++++++++++++++++++++++++++ | |
A mk/README | 7 +++++++ | |
A mk/arc.c | 52 +++++++++++++++++++++++++++++… | |
A mk/archive.c | 253 +++++++++++++++++++++++++++++… | |
A mk/bufblock.c | 88 +++++++++++++++++++++++++++++… | |
A mk/env.c | 149 +++++++++++++++++++++++++++++… | |
A mk/file.c | 90 +++++++++++++++++++++++++++++… | |
A mk/fns.h | 88 +++++++++++++++++++++++++++++… | |
A mk/graph.c | 279 +++++++++++++++++++++++++++++… | |
A mk/job.c | 33 +++++++++++++++++++++++++++++… | |
A mk/lex.c | 146 +++++++++++++++++++++++++++++… | |
A mk/main.c | 287 +++++++++++++++++++++++++++++… | |
A mk/match.c | 49 +++++++++++++++++++++++++++++… | |
A mk/mk.1 | 691 +++++++++++++++++++++++++++++… | |
A mk/mk.c | 234 +++++++++++++++++++++++++++++… | |
A mk/mk.h | 185 ++++++++++++++++++++++++++++++ | |
A mk/mkfile | 37 +++++++++++++++++++++++++++++… | |
A mk/mkfile.test | 12 ++++++++++++ | |
A mk/parse.c | 318 +++++++++++++++++++++++++++++… | |
A mk/rc.c | 194 ++++++++++++++++++++++++++++++ | |
A mk/recipe.c | 117 +++++++++++++++++++++++++++++… | |
A mk/rule.c | 112 +++++++++++++++++++++++++++++… | |
A mk/run.c | 296 +++++++++++++++++++++++++++++… | |
A mk/sh.c | 206 +++++++++++++++++++++++++++++… | |
A mk/shell.c | 80 +++++++++++++++++++++++++++++… | |
A mk/shprint.c | 125 +++++++++++++++++++++++++++++… | |
A mk/symtab.c | 97 ++++++++++++++++++++++++++++++ | |
A mk/sys.h | 5 +++++ | |
A mk/sys.std.h | 27 +++++++++++++++++++++++++++ | |
A mk/unix.c | 341 +++++++++++++++++++++++++++++… | |
A mk/var.c | 41 +++++++++++++++++++++++++++++… | |
A mk/varsub.c | 252 +++++++++++++++++++++++++++++… | |
A mk/word.c | 189 +++++++++++++++++++++++++++++… | |
A troff/FIXES | 821 ++++++++++++++++++++++++++++++ | |
A troff/Makefile | 11 +++++++++++ | |
A troff/README | 31 +++++++++++++++++++++++++++++… | |
A troff/cvt | 45 +++++++++++++++++++++++++++++… | |
A troff/dwbinit.c | 317 +++++++++++++++++++++++++++++… | |
A troff/dwbinit.h | 19 +++++++++++++++++++ | |
A troff/ext.h | 187 +++++++++++++++++++++++++++++… | |
A troff/find | 1 + | |
A troff/fns.h | 389 +++++++++++++++++++++++++++++… | |
A troff/hytab.c | 126 +++++++++++++++++++++++++++++… | |
A troff/mbwc.c | 165 +++++++++++++++++++++++++++++… | |
A troff/mkfile | 57 +++++++++++++++++++++++++++++… | |
A troff/n1.c | 1134 +++++++++++++++++++++++++++++… | |
A troff/n10.c | 549 +++++++++++++++++++++++++++++… | |
A troff/n2.c | 325 +++++++++++++++++++++++++++++… | |
A troff/n3.c | 954 +++++++++++++++++++++++++++++… | |
A troff/n4.c | 828 ++++++++++++++++++++++++++++++ | |
A troff/n5.c | 1150 +++++++++++++++++++++++++++++… | |
A troff/n6.c | 363 +++++++++++++++++++++++++++++… | |
A troff/n7.c | 837 +++++++++++++++++++++++++++++… | |
A troff/n8.c | 545 +++++++++++++++++++++++++++++… | |
A troff/n9.c | 489 +++++++++++++++++++++++++++++… | |
A troff/ni.c | 390 +++++++++++++++++++++++++++++… | |
A troff/suftab.c | 612 +++++++++++++++++++++++++++++… | |
A troff/t10.c | 513 +++++++++++++++++++++++++++++… | |
A troff/t11.c | 260 +++++++++++++++++++++++++++++… | |
A troff/t6.c | 889 ++++++++++++++++++++++++++++++ | |
A troff/tdef.h | 673 +++++++++++++++++++++++++++++… | |
A troff/troff.1 | 199 +++++++++++++++++++++++++++++… | |
A troff/unansi | 49 +++++++++++++++++++++++++++++… | |
66 files changed, 18051 insertions(+), 5 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -1,10 +1,10 @@ | |
-# 9base - awk basename cal cat cleanname du echo grep rc sed seq sleep | |
-# hoc sort tee test touch tr uniq from Plan 9 | |
+# 9base - awk basename bc cal cat cleanname dc du echo grep mk rc sed seq sleep | |
+# troff hoc sort tee test touch tr uniq from Plan 9 | |
include config.mk | |
-SUBDIRS = lib9 yacc awk basename bc dc du cal cat cleanname date echo grep ls… | |
- hoc rc read sed seq sleep sort tee test touch tr uniq | |
+SUBDIRS = lib9 mk yacc awk basename bc dc du cal cat cleanname date echo grep… | |
+ hoc rc read sed seq sleep sort tee test touch tr troff uniq | |
all: | |
@echo 9base build options: | |
diff --git a/config.mk b/config.mk | |
@@ -4,7 +4,7 @@ | |
PREFIX = /usr/local/plan9 | |
MANPREFIX = ${PREFIX}/share/man | |
-VERSION = 3 | |
+VERSION = 4 | |
OBJTYPE = 386 | |
#OBJTYPE = arm | |
#OBJTYPE = x86_64 | |
diff --git a/mk/Makefile b/mk/Makefile | |
@@ -0,0 +1,11 @@ | |
+# mk - mk unix port from plan9 | |
+# Depends on ../lib9 | |
+ | |
+TARG = mk | |
+ | |
+OFILES = arc.o archive.o bufblock.o env.o file.o graph.o job.o lex.o \ | |
+ main.o match.o mk.o parse.o recipe.o rc.o rule.o run.o sh.o \ | |
+ shell.o shprint.o symtab.o var.o varsub.o word.o unix.o | |
+MANFILES = mk.1 | |
+ | |
+include ../std.mk | |
diff --git a/mk/NOTICE b/mk/NOTICE | |
@@ -0,0 +1,27 @@ | |
+Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | |
+Portions Copyright © 1995-1997 C H Forsyth ([email protected]). All … | |
+Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved. | |
+Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com… | |
+ | |
+Under a licence agreement with Lucent Technologies Inc. effective 1st March 20… | |
+Vita Nuova Holdings Limited has the right to determine (within a specified sco… | |
+the form and content of sublicences for this software. | |
+ | |
+Vita Nuova Holdings Limited now makes this software available as Free | |
+Software under the terms of the `GNU General Public LIcense, Version 2' | |
+(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for | |
+the full terms and conditions). One of the conditions of that licence | |
+is that you must keep intact all notices that refer to that licence and to the… | |
+of any warranty: for this software, note that includes this NOTICE file in par… | |
+ | |
+This suite of programs is distributed in the hope that it will be useful, | |
+but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+`GNU General Public License' for more details. | |
+ | |
+This copyright NOTICE applies to all files in this directory and | |
+subdirectories, unless another copyright notice appears in a given | |
+file or subdirectory. If you take code from this software to use in | |
+other programs, you must somehow include with it an appropriate | |
+copyright notice that includes the copyright notice and the other | |
+notices above. | |
diff --git a/mk/README b/mk/README | |
@@ -0,0 +1,7 @@ | |
+This is a Unix port of mk, | |
+originally done for the Inferno operating system. | |
+ | |
+Russ Cox repackaged this to build as a standalone | |
+Unix program. Send comments about packaging to | |
+Russ Cox <[email protected]> | |
+ | |
diff --git a/mk/arc.c b/mk/arc.c | |
@@ -0,0 +1,52 @@ | |
+#include "mk.h" | |
+ | |
+Arc * | |
+newarc(Node *n, Rule *r, char *stem, Resub *match) | |
+{ | |
+ Arc *a; | |
+ | |
+ a = (Arc *)Malloc(sizeof(Arc)); | |
+ a->n = n; | |
+ a->r = r; | |
+ a->stem = strdup(stem); | |
+ rcopy(a->match, match, NREGEXP); | |
+ a->next = 0; | |
+ a->flag = 0; | |
+ a->prog = r->prog; | |
+ return(a); | |
+} | |
+ | |
+void | |
+dumpa(char *s, Arc *a) | |
+{ | |
+ char buf[1024]; | |
+ | |
+ Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'", | |
+ s, a, a->n, a->r, a->flag, a->stem); | |
+ if(a->prog) | |
+ Bprint(&bout, " prog='%s'", a->prog); | |
+ Bprint(&bout, "\n"); | |
+ | |
+ if(a->n){ | |
+ snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:""); | |
+ dumpn(buf, a->n); | |
+ } | |
+} | |
+ | |
+void | |
+nrep(void) | |
+{ | |
+ Symtab *sym; | |
+ Word *w; | |
+ | |
+ sym = symlook("NREP", S_VAR, 0); | |
+ if(sym){ | |
+ w = sym->u.ptr; | |
+ if (w && w->s && *w->s) | |
+ nreps = atoi(w->s); | |
+ } | |
+ if(nreps < 1) | |
+ nreps = 1; | |
+ if(DEBUG(D_GRAPH)) | |
+ Bprint(&bout, "nreps = %d\n", nreps); | |
+} | |
diff --git a/mk/archive.c b/mk/archive.c | |
@@ -0,0 +1,253 @@ | |
+#include "mk.h" | |
+#define ARMAG "!<arch>\n" | |
+#define SARMAG 8 | |
+ | |
+#define ARFMAG "`\n" | |
+#define SARNAME 16 | |
+ | |
+struct ar_hdr | |
+{ | |
+ char name[SARNAME]; | |
+ char date[12]; | |
+ char uid[6]; | |
+ char gid[6]; | |
+ char mode[8]; | |
+ char size[10]; | |
+ char fmag[2]; | |
+}; | |
+#define SAR_HDR (SARNAME+44) | |
+ | |
+static int dolong = 1; | |
+ | |
+static void atimes(char *); | |
+static char *split(char*, char**); | |
+ | |
+long | |
+readn(int f, void *av, long n) | |
+{ | |
+ char *a; | |
+ long m, t; | |
+ | |
+ a = av; | |
+ t = 0; | |
+ while(t < n){ | |
+ m = read(f, a+t, n-t); | |
+ if(m <= 0){ | |
+ if(t == 0) | |
+ return m; | |
+ break; | |
+ } | |
+ t += m; | |
+ } | |
+ return t; | |
+} | |
+long | |
+atimeof(int force, char *name) | |
+{ | |
+ Symtab *sym; | |
+ long t; | |
+ char *archive, *member, buf[512]; | |
+ | |
+ archive = split(name, &member); | |
+ if(archive == 0) | |
+ Exit(); | |
+ | |
+ t = mtime(archive); | |
+ sym = symlook(archive, S_AGG, 0); | |
+ if(sym){ | |
+ if(force || (t > sym->u.value)){ | |
+ atimes(archive); | |
+ sym->u.value = t; | |
+ } | |
+ } | |
+ else{ | |
+ atimes(archive); | |
+ /* mark the aggegate as having been done */ | |
+ symlook(strdup(archive), S_AGG, "")->u.value = t; | |
+ } | |
+ /* truncate long member name to sizeof of name field in archiv… | |
+ if(dolong) | |
+ snprint(buf, sizeof(buf), "%s(%s)", archive, member); | |
+ else | |
+ snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member… | |
+ sym = symlook(buf, S_TIME, 0); | |
+ if (sym) | |
+ return sym->u.value; | |
+ return 0; | |
+} | |
+ | |
+void | |
+atouch(char *name) | |
+{ | |
+ char *archive, *member; | |
+ int fd, i; | |
+ struct ar_hdr h; | |
+ long t; | |
+ | |
+ archive = split(name, &member); | |
+ if(archive == 0) | |
+ Exit(); | |
+ | |
+ fd = open(archive, ORDWR); | |
+ if(fd < 0){ | |
+ fd = create(archive, OWRITE, 0666); | |
+ if(fd < 0){ | |
+ fprint(2, "create %s: %r\n", archive); | |
+ Exit(); | |
+ } | |
+ write(fd, ARMAG, SARMAG); | |
+ } | |
+ if(symlook(name, S_TIME, 0)){ | |
+ /* hoon off and change it in situ */ | |
+ LSEEK(fd, SARMAG, 0); | |
+ while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){ | |
+ for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--) | |
+ ; | |
+ h.name[i+1]=0; | |
+ if(strcmp(member, h.name) == 0){ | |
+ t = SARNAME-sizeof(h); /* ughgghh */ | |
+ LSEEK(fd, t, 1); | |
+ fprint(fd, "%-12ld", time(0)); | |
+ break; | |
+ } | |
+ t = atol(h.size); | |
+ if(t&01) t++; | |
+ LSEEK(fd, t, 1); | |
+ } | |
+ } | |
+ close(fd); | |
+} | |
+ | |
+static void | |
+atimes(char *ar) | |
+{ | |
+ struct ar_hdr h; | |
+ long t; | |
+ int fd, i, namelen; | |
+ char buf[2048], *p, *strings; | |
+ char name[1024]; | |
+ Symtab *sym; | |
+ | |
+ strings = nil; | |
+ fd = open(ar, OREAD); | |
+ if(fd < 0) | |
+ return; | |
+ | |
+ if(read(fd, buf, SARMAG) != SARMAG){ | |
+ close(fd); | |
+ return; | |
+ } | |
+ while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){ | |
+ t = atol(h.date); | |
+ if(t == 0) /* as it sometimes happens; thanks ken */ | |
+ t = 1; | |
+ namelen = 0; | |
+ if(memcmp(h.name, "#1/", 3) == 0){ /* BSD */ | |
+ namelen = atoi(h.name+3); | |
+ if(namelen >= sizeof name){ | |
+ namelen = 0; | |
+ goto skip; | |
+ } | |
+ if(readn(fd, name, namelen) != namelen) | |
+ break; | |
+ name[namelen] = 0; | |
+ }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */ | |
+ /* date, uid, gid, mode all ' ' */ | |
+ for(i=2; i<16+12+6+6+8; i++) | |
+ if(h.name[i] != ' ') | |
+ goto skip; | |
+ t = atol(h.size); | |
+ if(t&01) | |
+ t++; | |
+ free(strings); | |
+ strings = malloc(t+1); | |
+ if(strings){ | |
+ if(readn(fd, strings, t) != t){ | |
+ free(strings); | |
+ strings = nil; | |
+ break; | |
+ } | |
+ strings[t] = 0; | |
+ continue; | |
+ } | |
+ goto skip; | |
+ }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1]… | |
+ i = strtol(h.name+1, &p, 10); | |
+ if(*p != ' ' || i >= strlen(strings)) | |
+ goto skip; | |
+ p = strings+i; | |
+ for(; *p && *p != '/'; p++) | |
+ ; | |
+ namelen = p-(strings+i); | |
+ if(namelen >= sizeof name){ | |
+ namelen = 0; | |
+ goto skip; | |
+ } | |
+ memmove(name, strings+i, namelen); | |
+ name[namelen] = 0; | |
+ namelen = 0; | |
+ }else{ | |
+ strncpy(name, h.name, sizeof(h.name)); | |
+ for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--) | |
+ ; | |
+ if(name[i] == '/') /* system V bug */ | |
+ i--; | |
+ name[i+1]=0; | |
+ } | |
+ snprint(buf, sizeof buf, "%s(%s)", ar, name); | |
+ sym = symlook(strdup(buf), S_TIME, (void *)t); | |
+ sym->u.value = t; | |
+ skip: | |
+ t = atol(h.size); | |
+ if(t&01) t++; | |
+ t -= namelen; | |
+ LSEEK(fd, t, 1); | |
+ } | |
+ close(fd); | |
+ free(strings); | |
+} | |
+ | |
+static int | |
+type(char *file) | |
+{ | |
+ int fd; | |
+ char buf[SARMAG]; | |
+ | |
+ fd = open(file, OREAD); | |
+ if(fd < 0){ | |
+ if(symlook(file, S_BITCH, 0) == 0){ | |
+ if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a… | |
+ Bprint(&bout, "%s doesn't exist: assuming it w… | |
+ symlook(file, S_BITCH, (void *)file); | |
+ } | |
+ return 1; | |
+ } | |
+ if(read(fd, buf, SARMAG) != SARMAG){ | |
+ close(fd); | |
+ return 0; | |
+ } | |
+ close(fd); | |
+ return !strncmp(ARMAG, buf, SARMAG); | |
+} | |
+ | |
+static char* | |
+split(char *name, char **member) | |
+{ | |
+ char *p, *q; | |
+ | |
+ p = strdup(name); | |
+ q = utfrune(p, '('); | |
+ if(q){ | |
+ *q++ = 0; | |
+ if(member) | |
+ *member = q; | |
+ q = utfrune(q, ')'); | |
+ if (q) | |
+ *q = 0; | |
+ if(type(p)) | |
+ return p; | |
+ free(p); | |
+ fprint(2, "mk: '%s' is not an archive\n", name); | |
+ } | |
+ return 0; | |
+} | |
diff --git a/mk/bufblock.c b/mk/bufblock.c | |
@@ -0,0 +1,88 @@ | |
+#include "mk.h" | |
+ | |
+static Bufblock *freelist; | |
+#define QUANTA 4096 | |
+ | |
+Bufblock * | |
+newbuf(void) | |
+{ | |
+ Bufblock *p; | |
+ | |
+ if (freelist) { | |
+ p = freelist; | |
+ freelist = freelist->next; | |
+ } else { | |
+ p = (Bufblock *) Malloc(sizeof(Bufblock)); | |
+ p->start = Malloc(QUANTA*sizeof(*p->start)); | |
+ p->end = p->start+QUANTA; | |
+ } | |
+ p->current = p->start; | |
+ *p->start = 0; | |
+ p->next = 0; | |
+ return p; | |
+} | |
+ | |
+void | |
+freebuf(Bufblock *p) | |
+{ | |
+ p->next = freelist; | |
+ freelist = p; | |
+} | |
+ | |
+void | |
+growbuf(Bufblock *p) | |
+{ | |
+ int n; | |
+ Bufblock *f; | |
+ char *cp; | |
+ | |
+ n = p->end-p->start+QUANTA; | |
+ /* search the free list for a big buffer */ | |
+ for (f = freelist; f; f = f->next) { | |
+ if (f->end-f->start >= n) { | |
+ memcpy(f->start, p->start, p->end-p->start); | |
+ cp = f->start; | |
+ f->start = p->start; | |
+ p->start = cp; | |
+ cp = f->end; | |
+ f->end = p->end; | |
+ p->end = cp; | |
+ f->current = f->start; | |
+ break; | |
+ } | |
+ } | |
+ if (!f) { /* not found - grow it */ | |
+ p->start = Realloc(p->start, n); | |
+ p->end = p->start+n; | |
+ } | |
+ p->current = p->start+n-QUANTA; | |
+} | |
+ | |
+void | |
+bufcpy(Bufblock *buf, char *cp, int n) | |
+{ | |
+ | |
+ while (n--) | |
+ insert(buf, *cp++); | |
+} | |
+ | |
+void | |
+insert(Bufblock *buf, int c) | |
+{ | |
+ | |
+ if (buf->current >= buf->end) | |
+ growbuf(buf); | |
+ *buf->current++ = c; | |
+} | |
+ | |
+void | |
+rinsert(Bufblock *buf, Rune r) | |
+{ | |
+ int n; | |
+ | |
+ n = runelen(r); | |
+ if (buf->current+n > buf->end) | |
+ growbuf(buf); | |
+ runetochar(buf->current, &r); | |
+ buf->current += n; | |
+} | |
diff --git a/mk/env.c b/mk/env.c | |
@@ -0,0 +1,149 @@ | |
+#include "mk.h" | |
+ | |
+enum { | |
+ ENVQUANTA=10 | |
+}; | |
+ | |
+Envy *envy; | |
+static int nextv; | |
+ | |
+static char *myenv[] = | |
+{ | |
+ "target", | |
+ "stem", | |
+ "prereq", | |
+ "pid", | |
+ "nproc", | |
+ "newprereq", | |
+ "alltarget", | |
+ "newmember", | |
+ "stem0", /* must be in order from here */ | |
+ "stem1", | |
+ "stem2", | |
+ "stem3", | |
+ "stem4", | |
+ "stem5", | |
+ "stem6", | |
+ "stem7", | |
+ "stem8", | |
+ "stem9", | |
+ 0 | |
+}; | |
+ | |
+void | |
+initenv(void) | |
+{ | |
+ char **p; | |
+ | |
+ for(p = myenv; *p; p++) | |
+ symlook(*p, S_INTERNAL, (void *)""); | |
+ readenv(); /* o.s. dependent */ | |
+} | |
+ | |
+static void | |
+envinsert(char *name, Word *value) | |
+{ | |
+ static int envsize; | |
+ | |
+ if (nextv >= envsize) { | |
+ envsize += ENVQUANTA; | |
+ envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy)); | |
+ } | |
+ envy[nextv].name = name; | |
+ envy[nextv++].values = value; | |
+} | |
+ | |
+static void | |
+envupd(char *name, Word *value) | |
+{ | |
+ Envy *e; | |
+ | |
+ for(e = envy; e->name; e++) | |
+ if(strcmp(name, e->name) == 0){ | |
+ delword(e->values); | |
+ e->values = value; | |
+ return; | |
+ } | |
+ e->name = name; | |
+ e->values = value; | |
+ envinsert(0,0); | |
+} | |
+ | |
+static void | |
+ecopy(Symtab *s) | |
+{ | |
+ char **p; | |
+ | |
+ if(symlook(s->name, S_NOEXPORT, 0)) | |
+ return; | |
+ for(p = myenv; *p; p++) | |
+ if(strcmp(*p, s->name) == 0) | |
+ return; | |
+ envinsert(s->name, s->u.ptr); | |
+} | |
+ | |
+void | |
+execinit(void) | |
+{ | |
+ char **p; | |
+ | |
+ nextv = 0; | |
+ for(p = myenv; *p; p++) | |
+ envinsert(*p, stow("")); | |
+ | |
+ symtraverse(S_VAR, ecopy); | |
+ envinsert(0, 0); | |
+} | |
+ | |
+Envy* | |
+buildenv(Job *j, int slot) | |
+{ | |
+ char **p, *cp, *qp; | |
+ Word *w, *v, **l; | |
+ int i; | |
+ char buf[256]; | |
+ | |
+ envupd("target", wdup(j->t)); | |
+ if(j->r->attr®EXP) | |
+ envupd("stem",newword("")); | |
+ else | |
+ envupd("stem", newword(j->stem)); | |
+ envupd("prereq", wdup(j->p)); | |
+ sprint(buf, "%d", getpid()); | |
+ envupd("pid", newword(buf)); | |
+ sprint(buf, "%d", slot); | |
+ envupd("nproc", newword(buf)); | |
+ envupd("newprereq", wdup(j->np)); | |
+ envupd("alltarget", wdup(j->at)); | |
+ l = &v; | |
+ v = w = wdup(j->np); | |
+ while(w){ | |
+ cp = strchr(w->s, '('); | |
+ if(cp){ | |
+ qp = strchr(cp+1, ')'); | |
+ if(qp){ | |
+ *qp = 0; | |
+ strcpy(w->s, cp+1); | |
+ l = &w->next; | |
+ w = w->next; | |
+ continue; | |
+ } | |
+ } | |
+ *l = w->next; | |
+ free(w->s); | |
+ free(w); | |
+ w = *l; | |
+ } | |
+ envupd("newmember", v); | |
+ /* update stem0 -> stem9 */ | |
+ for(p = myenv; *p; p++) | |
+ if(strcmp(*p, "stem0") == 0) | |
+ break; | |
+ for(i = 0; *p; i++, p++){ | |
+ if((j->r->attr®EXP) && j->match[i]) | |
+ envupd(*p, newword(j->match[i])); | |
+ else | |
+ envupd(*p, newword("")); | |
+ } | |
+ return envy; | |
+} | |
diff --git a/mk/file.c b/mk/file.c | |
@@ -0,0 +1,90 @@ | |
+#include "mk.h" | |
+ | |
+/* table-driven version in bootes dump of 12/31/96 */ | |
+ | |
+long | |
+mtime(char *name) | |
+{ | |
+ return mkmtime(name); | |
+} | |
+ | |
+long | |
+timeof(char *name, int force) | |
+{ | |
+ Symtab *sym; | |
+ long t; | |
+ | |
+ if(utfrune(name, '(')) | |
+ return atimeof(force, name); /* archive */ | |
+ | |
+ if(force) | |
+ return mtime(name); | |
+ | |
+ | |
+ sym = symlook(name, S_TIME, 0); | |
+ if (sym) | |
+ return sym->u.value; | |
+ | |
+ t = mtime(name); | |
+ if(t == 0) | |
+ return 0; | |
+ | |
+ symlook(name, S_TIME, (void*)t); /* install time in cac… | |
+ return t; | |
+} | |
+ | |
+void | |
+touch(char *name) | |
+{ | |
+ Bprint(&bout, "touch(%s)\n", name); | |
+ if(nflag) | |
+ return; | |
+ | |
+ if(utfrune(name, '(')) | |
+ atouch(name); /* archive */ | |
+ else if(chgtime(name) < 0) { | |
+ fprint(2, "%s: %r\n", name); | |
+ Exit(); | |
+ } | |
+} | |
+ | |
+void | |
+delete(char *name) | |
+{ | |
+ if(utfrune(name, '(') == 0) { /* file */ | |
+ if(remove(name) < 0) | |
+ fprint(2, "remove %s: %r\n", name); | |
+ } else | |
+ fprint(2, "hoon off; mk can'tdelete archive members\n"); | |
+} | |
+ | |
+void | |
+timeinit(char *s) | |
+{ | |
+ long t; | |
+ char *cp; | |
+ Rune r; | |
+ int c, n; | |
+ | |
+ t = time(0); | |
+ while (*s) { | |
+ cp = s; | |
+ do{ | |
+ n = chartorune(&r, s); | |
+ if (r == ' ' || r == ',' || r == '\n') | |
+ break; | |
+ s += n; | |
+ } while(*s); | |
+ c = *s; | |
+ *s = 0; | |
+ symlook(strdup(cp), S_TIME, (void *)t)->u.value = t; | |
+ if (c) | |
+ *s++ = c; | |
+ while(*s){ | |
+ n = chartorune(&r, s); | |
+ if(r != ' ' && r != ',' && r != '\n') | |
+ break; | |
+ s += n; | |
+ } | |
+ } | |
+} | |
diff --git a/mk/fns.h b/mk/fns.h | |
@@ -0,0 +1,88 @@ | |
+#undef waitfor | |
+#define waitfor mkwaitfor | |
+ | |
+void addrule(char*, Word*, char*, Word*, int, int, char*); | |
+void addrules(Word*, Word*, char*, int, int, char*); | |
+void addw(Word*, char*); | |
+void assert(char*, int); | |
+int assline(Biobuf *, Bufblock *); | |
+long atimeof(int,char*); | |
+void atouch(char*); | |
+void bufcpy(Bufblock *, char *, int); | |
+Envy *buildenv(Job*, int); | |
+void catchnotes(void); | |
+int chgtime(char*); | |
+void clrmade(Node*); | |
+void delete(char*); | |
+void delword(Word*); | |
+int dorecipe(Node*); | |
+void dumpa(char*, Arc*); | |
+void dumpj(char*, Job*, int); | |
+void dumpn(char*, Node*); | |
+void dumpr(char*, Rule*); | |
+void dumpv(char*); | |
+void dumpw(char*, Word*); | |
+void execinit(void); | |
+int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*); | |
+void Exit(void); | |
+void expunge(int, char*); | |
+void freebuf(Bufblock*); | |
+void front(char*); | |
+Node *graph(char*); | |
+void growbuf(Bufblock *); | |
+void initenv(void); | |
+void initshell(void); | |
+void insert(Bufblock *, int); | |
+void ipop(void); | |
+void ipush(void); | |
+void killchildren(char*); | |
+void *Malloc(int); | |
+char *maketmp(int*); | |
+int match(char*, char*, char*, Shell*); | |
+char *membername(char*, int, char*); | |
+void mk(char*); | |
+unsigned long mkmtime(char*); | |
+long mtime(char*); | |
+Arc *newarc(Node*, Rule*, char*, Resub*); | |
+Bufblock *newbuf(void); | |
+Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*); | |
+Word *newword(char*); | |
+int nextrune(Biobuf*, int); | |
+int nextslot(void); | |
+void nproc(void); | |
+void nrep(void); | |
+int outofdate(Node*, Arc*, int); | |
+void parse(char*, int, int); | |
+int pipecmd(char*, Envy*, int*, Shell*, Word*); | |
+void popshell(void); | |
+void prusage(void); | |
+void pushshell(void); | |
+void rcopy(char**, Resub*, int); | |
+void readenv(void); | |
+void *Realloc(void*, int); | |
+void rinsert(Bufblock *, Rune); | |
+char *rulecnt(void); | |
+void run(Job*); | |
+char *setshell(Word*); | |
+void setvar(char*, void*); | |
+int shargv(Word*, int, char***); | |
+char *shname(char*); | |
+void shprint(char*, Envy*, Bufblock*, Shell*); | |
+Word *stow(char*); | |
+void subst(char*, char*, char*); | |
+void symdel(char*, int); | |
+void syminit(void); | |
+Symtab *symlook(char*, int, void*); | |
+void symstat(void); | |
+void symtraverse(int, void(*)(Symtab*)); | |
+void timeinit(char*); | |
+long timeof(char*, int); | |
+void touch(char*); | |
+void update(int, Node*); | |
+void usage(void); | |
+Word *varsub(char**); | |
+int waitfor(char*); | |
+int waitup(int, int*); | |
+Word *wdup(Word*); | |
+int work(Node*, Node*, Arc*); | |
+char *wtos(Word*, int); | |
diff --git a/mk/graph.c b/mk/graph.c | |
@@ -0,0 +1,279 @@ | |
+#include "mk.h" | |
+ | |
+static Node *applyrules(char *, char *); | |
+static void togo(Node *); | |
+static int vacuous(Node *); | |
+static Node *newnode(char *); | |
+static void trace(char *, Arc *); | |
+static void cyclechk(Node *); | |
+static void ambiguous(Node *); | |
+static void attribute(Node *); | |
+ | |
+Node * | |
+graph(char *target) | |
+{ | |
+ Node *node; | |
+ char *cnt; | |
+ | |
+ cnt = rulecnt(); | |
+ node = applyrules(target, cnt); | |
+ free(cnt); | |
+ cyclechk(node); | |
+ node->flags |= PROBABLE; /* make sure it doesn't get deleted */ | |
+ vacuous(node); | |
+ ambiguous(node); | |
+ attribute(node); | |
+ return(node); | |
+} | |
+ | |
+static Node * | |
+applyrules(char *target, char *cnt) | |
+{ | |
+ Symtab *sym; | |
+ Node *node; | |
+ Rule *r; | |
+ Arc head, *a = &head; | |
+ Word *w; | |
+ char stem[NAMEBLOCK], buf[NAMEBLOCK]; | |
+ Resub rmatch[NREGEXP]; | |
+ | |
+/* print("applyrules(%lux='%s')\n", target, target); */ | |
+ sym = symlook(target, S_NODE, 0); | |
+ if(sym) | |
+ return sym->u.ptr; | |
+ target = strdup(target); | |
+ node = newnode(target); | |
+ head.n = 0; | |
+ head.next = 0; | |
+ sym = symlook(target, S_TARGET, 0); | |
+ memset((char*)rmatch, 0, sizeof(rmatch)); | |
+ for(r = sym? sym->u.ptr:0; r; r = r->chain){ | |
+ if(r->attr&META) continue; | |
+ if(strcmp(target, r->target)) continue; | |
+ if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || … | |
+ if(cnt[r->rule] >= nreps) continue; | |
+ cnt[r->rule]++; | |
+ node->flags |= PROBABLE; | |
+ | |
+/* if(r->attr&VIR) | |
+ * node->flags |= VIRTUAL; | |
+ * if(r->attr&NOREC) | |
+ * node->flags |= NORECIPE; | |
+ * if(r->attr&DEL) | |
+ * node->flags |= DELETE; | |
+ */ | |
+ if(!r->tail || !r->tail->s || !*r->tail->s) { | |
+ a->next = newarc((Node *)0, r, "", rmatch); | |
+ a = a->next; | |
+ } else | |
+ for(w = r->tail; w; w = w->next){ | |
+ a->next = newarc(applyrules(w->s, cnt), r, "",… | |
+ a = a->next; | |
+ } | |
+ cnt[r->rule]--; | |
+ head.n = node; | |
+ } | |
+ for(r = metarules; r; r = r->next){ | |
+ if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || … | |
+ if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) | |
+ continue; | |
+ if(r->attr®EXP){ | |
+ stem[0] = 0; | |
+ patrule = r; | |
+ memset((char*)rmatch, 0, sizeof(rmatch)); | |
+ if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0) | |
+ continue; | |
+ } else { | |
+ if(!match(node->name, r->target, stem, r->shellt)) con… | |
+ } | |
+ if(cnt[r->rule] >= nreps) continue; | |
+ cnt[r->rule]++; | |
+ | |
+/* if(r->attr&VIR) | |
+ * node->flags |= VIRTUAL; | |
+ * if(r->attr&NOREC) | |
+ * node->flags |= NORECIPE; | |
+ * if(r->attr&DEL) | |
+ * node->flags |= DELETE; | |
+ */ | |
+ | |
+ if(!r->tail || !r->tail->s || !*r->tail->s) { | |
+ a->next = newarc((Node *)0, r, stem, rmatch); | |
+ a = a->next; | |
+ } else | |
+ for(w = r->tail; w; w = w->next){ | |
+ if(r->attr®EXP) | |
+ regsub(w->s, buf, sizeof buf, rmatch, … | |
+ else | |
+ subst(stem, w->s, buf); | |
+ a->next = newarc(applyrules(buf, cnt), r, stem… | |
+ a = a->next; | |
+ } | |
+ cnt[r->rule]--; | |
+ } | |
+ a->next = node->prereqs; | |
+ node->prereqs = head.next; | |
+ return(node); | |
+} | |
+ | |
+static void | |
+togo(Node *node) | |
+{ | |
+ Arc *la, *a; | |
+ | |
+ /* delete them now */ | |
+ la = 0; | |
+ for(a = node->prereqs; a; la = a, a = a->next) | |
+ if(a->flag&TOGO){ | |
+ if(a == node->prereqs) | |
+ node->prereqs = a->next; | |
+ else | |
+ la->next = a->next, a = la; | |
+ } | |
+} | |
+ | |
+static int | |
+vacuous(Node *node) | |
+{ | |
+ Arc *la, *a; | |
+ int vac = !(node->flags&PROBABLE); | |
+ | |
+ if(node->flags&READY) | |
+ return(node->flags&VACUOUS); | |
+ node->flags |= READY; | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(a->n && vacuous(a->n) && (a->r->attr&META)) | |
+ a->flag |= TOGO; | |
+ else | |
+ vac = 0; | |
+ /* if a rule generated arcs that DON'T go; no others from that rule go… | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if((a->flag&TOGO) == 0) | |
+ for(la = node->prereqs; la; la = la->next) | |
+ if((la->flag&TOGO) && (la->r == a->r)){ | |
+ la->flag &= ~TOGO; | |
+ } | |
+ togo(node); | |
+ if(vac) | |
+ node->flags |= VACUOUS; | |
+ return(vac); | |
+} | |
+ | |
+static Node * | |
+newnode(char *name) | |
+{ | |
+ register Node *node; | |
+ | |
+ node = (Node *)Malloc(sizeof(Node)); | |
+ symlook(name, S_NODE, (void *)node); | |
+ node->name = name; | |
+ node->time = timeof(name, 0); | |
+ node->prereqs = 0; | |
+ node->flags = node->time? PROBABLE : 0; | |
+ node->next = 0; | |
+ return(node); | |
+} | |
+ | |
+void | |
+dumpn(char *s, Node *n) | |
+{ | |
+ char buf[1024]; | |
+ Arc *a; | |
+ | |
+ snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:""); | |
+ Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n", | |
+ s, n->name, n, n->time, n->flags, n->next); | |
+ for(a = n->prereqs; a; a = a->next) | |
+ dumpa(buf, a); | |
+} | |
+ | |
+static void | |
+trace(char *s, Arc *a) | |
+{ | |
+ fprint(2, "\t%s", s); | |
+ while(a){ | |
+ fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line, | |
+ a->n? a->n->name:""); | |
+ if(a->n){ | |
+ for(a = a->n->prereqs; a; a = a->next) | |
+ if(*a->r->recipe) break; | |
+ } else | |
+ a = 0; | |
+ } | |
+ fprint(2, "\n"); | |
+} | |
+ | |
+static void | |
+cyclechk(Node *n) | |
+{ | |
+ Arc *a; | |
+ | |
+ if((n->flags&CYCLE) && n->prereqs){ | |
+ fprint(2, "mk: cycle in graph detected at target %s\n", n->nam… | |
+ Exit(); | |
+ } | |
+ n->flags |= CYCLE; | |
+ for(a = n->prereqs; a; a = a->next) | |
+ if(a->n) | |
+ cyclechk(a->n); | |
+ n->flags &= ~CYCLE; | |
+} | |
+ | |
+static void | |
+ambiguous(Node *n) | |
+{ | |
+ Arc *a; | |
+ Rule *r = 0; | |
+ Arc *la; | |
+ int bad = 0; | |
+ | |
+ la = 0; | |
+ for(a = n->prereqs; a; a = a->next){ | |
+ if(a->n) | |
+ ambiguous(a->n); | |
+ if(*a->r->recipe == 0) continue; | |
+ if(r == 0) | |
+ r = a->r, la = a; | |
+ else{ | |
+ if(r->recipe != a->r->recipe){ | |
+ if((r->attr&META) && !(a->r->attr&META)){ | |
+ la->flag |= TOGO; | |
+ r = a->r, la = a; | |
+ } else if(!(r->attr&META) && (a->r->attr&META)… | |
+ a->flag |= TOGO; | |
+ continue; | |
+ } | |
+ } | |
+ if(r->recipe != a->r->recipe){ | |
+ if(bad == 0){ | |
+ fprint(2, "mk: ambiguous recipes for %… | |
+ bad = 1; | |
+ trace(n->name, la); | |
+ } | |
+ trace(n->name, a); | |
+ } | |
+ } | |
+ } | |
+ if(bad) | |
+ Exit(); | |
+ togo(n); | |
+} | |
+ | |
+static void | |
+attribute(Node *n) | |
+{ | |
+ register Arc *a; | |
+ | |
+ for(a = n->prereqs; a; a = a->next){ | |
+ if(a->r->attr&VIR) | |
+ n->flags |= VIRTUAL; | |
+ if(a->r->attr&NOREC) | |
+ n->flags |= NORECIPE; | |
+ if(a->r->attr&DEL) | |
+ n->flags |= DELETE; | |
+ if(a->n) | |
+ attribute(a->n); | |
+ } | |
+ if(n->flags&VIRTUAL) | |
+ n->time = 0; | |
+} | |
diff --git a/mk/job.c b/mk/job.c | |
@@ -0,0 +1,33 @@ | |
+#include "mk.h" | |
+ | |
+Job * | |
+newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, … | |
+{ | |
+ register Job *j; | |
+ | |
+ j = (Job *)Malloc(sizeof(Job)); | |
+ j->r = r; | |
+ j->n = nlist; | |
+ j->stem = stem; | |
+ j->match = match; | |
+ j->p = pre; | |
+ j->np = npre; | |
+ j->t = tar; | |
+ j->at = atar; | |
+ j->nproc = -1; | |
+ j->next = 0; | |
+ return(j); | |
+} | |
+ | |
+void | |
+dumpj(char *s, Job *j, int all) | |
+{ | |
+ Bprint(&bout, "%s\n", s); | |
+ while(j){ | |
+ Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n", | |
+ j, j->r, j->n, j->stem, j->nproc); | |
+ Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprere… | |
+ wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wt… | |
+ j = all? j->next : 0; | |
+ } | |
+} | |
diff --git a/mk/lex.c b/mk/lex.c | |
@@ -0,0 +1,146 @@ | |
+#include "mk.h" | |
+ | |
+static int bquote(Biobuf*, Bufblock*); | |
+ | |
+/* | |
+ * Assemble a line skipping blank lines, comments, and eliding | |
+ * escaped newlines | |
+ */ | |
+int | |
+assline(Biobuf *bp, Bufblock *buf) | |
+{ | |
+ int c; | |
+ int lastc; | |
+ | |
+ buf->current=buf->start; | |
+ while ((c = nextrune(bp, 1)) >= 0){ | |
+ switch(c) | |
+ { | |
+ case '\r': /* consumes CRs for Win95 */ | |
+ continue; | |
+ case '\n': | |
+ if (buf->current != buf->start) { | |
+ insert(buf, 0); | |
+ return 1; | |
+ } | |
+ break; /* skip empty lines */ | |
+ case '\\': | |
+ case '\'': | |
+ case '"': | |
+ rinsert(buf, c); | |
+ if (shellt->escapetoken(bp, buf, 1, c) == 0) | |
+ Exit(); | |
+ break; | |
+ case '`': | |
+ if (bquote(bp, buf) == 0) | |
+ Exit(); | |
+ break; | |
+ case '#': | |
+ lastc = '#'; | |
+ while ((c = Bgetc(bp)) != '\n') { | |
+ if (c < 0) | |
+ goto eof; | |
+ if(c != '\r') | |
+ lastc = c; | |
+ } | |
+ mkinline++; | |
+ if (lastc == '\\') | |
+ break; /* propagate escaped new… | |
+ if (buf->current != buf->start) { | |
+ insert(buf, 0); | |
+ return 1; | |
+ } | |
+ break; | |
+ default: | |
+ rinsert(buf, c); | |
+ break; | |
+ } | |
+ } | |
+eof: | |
+ insert(buf, 0); | |
+ return *buf->start != 0; | |
+} | |
+ | |
+/* | |
+ * assemble a back-quoted shell command into a buffer | |
+ */ | |
+static int | |
+bquote(Biobuf *bp, Bufblock *buf) | |
+{ | |
+ int c, line, term; | |
+ int start; | |
+ | |
+ line = mkinline; | |
+ while((c = Bgetrune(bp)) == ' ' || c == '\t') | |
+ ; | |
+ if(c == '{'){ | |
+ term = '}'; /* rc style */ | |
+ while((c = Bgetrune(bp)) == ' ' || c == '\t') | |
+ ; | |
+ } else | |
+ term = '`'; /* sh style */ | |
+ | |
+ start = buf->current-buf->start; | |
+ for(;c > 0; c = nextrune(bp, 0)){ | |
+ if(c == term){ | |
+ insert(buf, '\n'); | |
+ insert(buf,0); | |
+ buf->current = buf->start+start; | |
+ execinit(); | |
+ execsh(0, buf->current, buf, envy, shellt, shellcmd); | |
+ return 1; | |
+ } | |
+ if(c == '\n') | |
+ break; | |
+ if(c == '\'' || c == '"' || c == '\\'){ | |
+ insert(buf, c); | |
+ if(!shellt->escapetoken(bp, buf, 1, c)) | |
+ return 0; | |
+ continue; | |
+ } | |
+ rinsert(buf, c); | |
+ } | |
+ SYNERR(line); | |
+ fprint(2, "missing closing %c after `\n", term); | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * get next character stripping escaped newlines | |
+ * the flag specifies whether escaped newlines are to be elided or | |
+ * replaced with a blank. | |
+ */ | |
+int | |
+nextrune(Biobuf *bp, int elide) | |
+{ | |
+ int c, c2; | |
+ static int savec; | |
+ | |
+ if(savec){ | |
+ c = savec; | |
+ savec = 0; | |
+ return c; | |
+ } | |
+ | |
+ for (;;) { | |
+ c = Bgetrune(bp); | |
+ if (c == '\\') { | |
+ c2 = Bgetrune(bp); | |
+ if(c2 == '\r'){ | |
+ savec = c2; | |
+ c2 = Bgetrune(bp); | |
+ } | |
+ if (c2 == '\n') { | |
+ savec = 0; | |
+ mkinline++; | |
+ if (elide) | |
+ continue; | |
+ return ' '; | |
+ } | |
+ Bungetrune(bp); | |
+ } | |
+ if (c == '\n') | |
+ mkinline++; | |
+ return c; | |
+ } | |
+} | |
diff --git a/mk/main.c b/mk/main.c | |
@@ -0,0 +1,287 @@ | |
+#include "mk.h" | |
+ | |
+#define MKFILE "mkfile" | |
+ | |
+int debug; | |
+Rule *rules, *metarules; | |
+int nflag = 0; | |
+int tflag = 0; | |
+int iflag = 0; | |
+int kflag = 0; | |
+int aflag = 0; | |
+int uflag = 0; | |
+char *explain = 0; | |
+Word *target1; | |
+int nreps = 1; | |
+Job *jobs; | |
+Biobuf bout; | |
+Rule *patrule; | |
+void badusage(void); | |
+#ifdef PROF | |
+short buf[10000]; | |
+#endif | |
+ | |
+int | |
+main(int argc, char **argv) | |
+{ | |
+ Word *w; | |
+ char *s, *temp; | |
+ char *files[256], **f = files, **ff; | |
+ int sflag = 0; | |
+ int i; | |
+ int tfd = -1; | |
+ Biobuf tb; | |
+ Bufblock *buf; | |
+ Bufblock *whatif; | |
+ | |
+ /* | |
+ * start with a copy of the current environment variables | |
+ * instead of sharing them | |
+ */ | |
+ | |
+ Binit(&bout, 1, OWRITE); | |
+ buf = newbuf(); | |
+ whatif = 0; | |
+ USED(argc); | |
+ for(argv++; *argv && (**argv == '-'); argv++) | |
+ { | |
+ bufcpy(buf, argv[0], strlen(argv[0])); | |
+ insert(buf, ' '); | |
+ switch(argv[0][1]) | |
+ { | |
+ case 'a': | |
+ aflag = 1; | |
+ break; | |
+ case 'd': | |
+ if(*(s = &argv[0][2])) | |
+ while(*s) switch(*s++) | |
+ { | |
+ case 'p': debug |= D_PARSE; break; | |
+ case 'g': debug |= D_GRAPH; break; | |
+ case 'e': debug |= D_EXEC; break; | |
+ } | |
+ else | |
+ debug = 0xFFFF; | |
+ break; | |
+ case 'e': | |
+ explain = &argv[0][2]; | |
+ break; | |
+ case 'f': | |
+ if(*++argv == 0) | |
+ badusage(); | |
+ *f++ = *argv; | |
+ bufcpy(buf, argv[0], strlen(argv[0])); | |
+ insert(buf, ' '); | |
+ break; | |
+ case 'i': | |
+ iflag = 1; | |
+ break; | |
+ case 'k': | |
+ kflag = 1; | |
+ break; | |
+ case 'n': | |
+ nflag = 1; | |
+ break; | |
+ case 's': | |
+ sflag = 1; | |
+ break; | |
+ case 't': | |
+ tflag = 1; | |
+ break; | |
+ case 'u': | |
+ uflag = 1; | |
+ break; | |
+ case 'w': | |
+ if(whatif == 0) | |
+ whatif = newbuf(); | |
+ else | |
+ insert(whatif, ' '); | |
+ if(argv[0][2]) | |
+ bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]… | |
+ else { | |
+ if(*++argv == 0) | |
+ badusage(); | |
+ bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]… | |
+ } | |
+ break; | |
+ default: | |
+ badusage(); | |
+ } | |
+ } | |
+#ifdef PROF | |
+ { | |
+ extern etext(); | |
+ monitor(main, etext, buf, sizeof buf, 300); | |
+ } | |
+#endif | |
+ | |
+ if(aflag) | |
+ iflag = 1; | |
+ usage(); | |
+ syminit(); | |
+ initshell(); | |
+ initenv(); | |
+ usage(); | |
+ | |
+ /* | |
+ assignment args become null strings | |
+ */ | |
+ temp = 0; | |
+ for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){ | |
+ bufcpy(buf, argv[i], strlen(argv[i])); | |
+ insert(buf, ' '); | |
+ if(tfd < 0){ | |
+ temp = maketmp(&tfd); | |
+ if(temp == 0) { | |
+ fprint(2, "temp file: %r\n"); | |
+ Exit(); | |
+ } | |
+ Binit(&tb, tfd, OWRITE); | |
+ } | |
+ Bprint(&tb, "%s\n", argv[i]); | |
+ *argv[i] = 0; | |
+ } | |
+ if(tfd >= 0){ | |
+ Bflush(&tb); | |
+ LSEEK(tfd, 0L, 0); | |
+ parse("command line args", tfd, 1); | |
+ remove(temp); | |
+ } | |
+ | |
+ if (buf->current != buf->start) { | |
+ buf->current--; | |
+ insert(buf, 0); | |
+ } | |
+ symlook("MKFLAGS", S_VAR, (void *) stow(buf->start)); | |
+ buf->current = buf->start; | |
+ for(i = 0; argv[i]; i++){ | |
+ if(*argv[i] == 0) continue; | |
+ if(i) | |
+ insert(buf, ' '); | |
+ bufcpy(buf, argv[i], strlen(argv[i])); | |
+ } | |
+ insert(buf, 0); | |
+ symlook("MKARGS", S_VAR, (void *) stow(buf->start)); | |
+ freebuf(buf); | |
+ | |
+ if(f == files){ | |
+ if(access(MKFILE, 4) == 0) | |
+ parse(MKFILE, open(MKFILE, 0), 0); | |
+ } else | |
+ for(ff = files; ff < f; ff++) | |
+ parse(*ff, open(*ff, 0), 0); | |
+ if(DEBUG(D_PARSE)){ | |
+ dumpw("default targets", target1); | |
+ dumpr("rules", rules); | |
+ dumpr("metarules", metarules); | |
+ dumpv("variables"); | |
+ } | |
+ if(whatif){ | |
+ insert(whatif, 0); | |
+ timeinit(whatif->start); | |
+ freebuf(whatif); | |
+ } | |
+ execinit(); | |
+ /* skip assignment args */ | |
+ while(*argv && (**argv == 0)) | |
+ argv++; | |
+ | |
+ catchnotes(); | |
+ if(*argv == 0){ | |
+ if(target1) | |
+ for(w = target1; w; w = w->next) | |
+ mk(w->s); | |
+ else { | |
+ fprint(2, "mk: nothing to mk\n"); | |
+ Exit(); | |
+ } | |
+ } else { | |
+ if(sflag){ | |
+ for(; *argv; argv++) | |
+ if(**argv) | |
+ mk(*argv); | |
+ } else { | |
+ Word *head, *tail, *t; | |
+ | |
+ /* fake a new rule with all the args as prereqs */ | |
+ tail = 0; | |
+ t = 0; | |
+ for(; *argv; argv++) | |
+ if(**argv){ | |
+ if(tail == 0) | |
+ tail = t = newword(*argv); | |
+ else { | |
+ t->next = newword(*argv); | |
+ t = t->next; | |
+ } | |
+ } | |
+ if(tail->next == 0) | |
+ mk(tail->s); | |
+ else { | |
+ head = newword("command line arguments"); | |
+ addrules(head, tail, strdup(""), VIR, mkinline… | |
+ mk(head->s); | |
+ } | |
+ } | |
+ } | |
+ if(uflag) | |
+ prusage(); | |
+ exits(0); | |
+ return 0; | |
+} | |
+ | |
+void | |
+badusage(void) | |
+{ | |
+ | |
+ fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]]… | |
+ Exit(); | |
+} | |
+ | |
+void * | |
+Malloc(int n) | |
+{ | |
+ register void *s; | |
+ | |
+ s = malloc(n); | |
+ if(!s) { | |
+ fprint(2, "mk: cannot alloc %d bytes\n", n); | |
+ Exit(); | |
+ } | |
+ return(s); | |
+} | |
+ | |
+void * | |
+Realloc(void *s, int n) | |
+{ | |
+ if(s) | |
+ s = realloc(s, n); | |
+ else | |
+ s = malloc(n); | |
+ if(!s) { | |
+ fprint(2, "mk: cannot alloc %d bytes\n", n); | |
+ Exit(); | |
+ } | |
+ return(s); | |
+} | |
+ | |
+void | |
+assert(char *s, int n) | |
+{ | |
+ if(!n){ | |
+ fprint(2, "mk: Assertion ``%s'' failed.\n", s); | |
+ Exit(); | |
+ } | |
+} | |
+ | |
+void | |
+regerror(char *s) | |
+{ | |
+ if(patrule) | |
+ fprint(2, "mk: %s:%d: regular expression error; %s\n", | |
+ patrule->file, patrule->line, s); | |
+ else | |
+ fprint(2, "mk: %s:%d: regular expression error; %s\n", | |
+ infile, mkinline, s); | |
+ Exit(); | |
+} | |
diff --git a/mk/match.c b/mk/match.c | |
@@ -0,0 +1,49 @@ | |
+#include "mk.h" | |
+ | |
+int | |
+match(char *name, char *template, char *stem, Shell *sh) | |
+{ | |
+ Rune r; | |
+ int n; | |
+ | |
+ while(*name && *template){ | |
+ n = chartorune(&r, template); | |
+ if (PERCENT(r)) | |
+ break; | |
+ while (n--) | |
+ if(*name++ != *template++) | |
+ return 0; | |
+ } | |
+ if(!PERCENT(*template)) | |
+ return 0; | |
+ n = strlen(name)-strlen(template+1); | |
+ if (n < 0) | |
+ return 0; | |
+ if (strcmp(template+1, name+n)) | |
+ return 0; | |
+ strncpy(stem, name, n); | |
+ stem[n] = 0; | |
+ if(*template == '&') | |
+ return !sh->charin(stem, "./"); | |
+ return 1; | |
+} | |
+ | |
+void | |
+subst(char *stem, char *template, char *dest) | |
+{ | |
+ Rune r; | |
+ char *s; | |
+ int n; | |
+ | |
+ while(*template){ | |
+ n = chartorune(&r, template); | |
+ if (PERCENT(r)) { | |
+ template += n; | |
+ for (s = stem; *s; s++) | |
+ *dest++ = *s; | |
+ } else | |
+ while (n--) | |
+ *dest++ = *template++; | |
+ } | |
+ *dest = 0; | |
+} | |
diff --git a/mk/mk.1 b/mk/mk.1 | |
@@ -0,0 +1,691 @@ | |
+.TH MK 1 | |
+.SH NAME | |
+mk \- maintain (make) related files | |
+.SH SYNOPSIS | |
+.B mk | |
+[ | |
+.B -f | |
+.I mkfile | |
+] ... | |
+[ | |
+.I option ... | |
+] | |
+[ | |
+.I target ... | |
+] | |
+.SH DESCRIPTION | |
+.I Mk | |
+uses the dependency rules specified in | |
+.I mkfile | |
+to control the update (usually by compilation) of | |
+.I targets | |
+(usually files) | |
+from the source files upon which they depend. | |
+The | |
+.I mkfile | |
+(default | |
+.LR mkfile ) | |
+contains a | |
+.I rule | |
+for each target that identifies the files and other | |
+targets upon which it depends and an | |
+.IR sh (1) | |
+script, a | |
+.IR recipe , | |
+to update the target. | |
+The script is run if the target does not exist | |
+or if it is older than any of the files it depends on. | |
+.I Mkfile | |
+may also contain | |
+.I meta-rules | |
+that define actions for updating implicit targets. | |
+If no | |
+.I target | |
+is specified, the target of the first rule (not meta-rule) in | |
+.I mkfile | |
+is updated. | |
+.PP | |
+The environment variable | |
+.B $NPROC | |
+determines how many targets may be updated simultaneously; | |
+Some operating systems, e.g., Plan 9, set | |
+.B $NPROC | |
+automatically to the number of CPUs on the current machine. | |
+.PP | |
+Options are: | |
+.TP \w'\fL-d[egp]\ 'u | |
+.B -a | |
+Assume all targets to be out of date. | |
+Thus, everything is updated. | |
+.PD 0 | |
+.TP | |
+.BR -d [ egp ] | |
+Produce debugging output | |
+.RB ( p | |
+is for parsing, | |
+.B g | |
+for graph building, | |
+.B e | |
+for execution). | |
+.TP | |
+.B -e | |
+Explain why each target is made. | |
+.TP | |
+.B -i | |
+Force any missing intermediate targets to be made. | |
+.TP | |
+.B -k | |
+Do as much work as possible in the face of errors. | |
+.TP | |
+.B -n | |
+Print, but do not execute, the commands | |
+needed to update the targets. | |
+.TP | |
+.B -s | |
+Make the command line arguments sequentially rather than in parallel. | |
+.TP | |
+.B -t | |
+Touch (update the modified date of) file targets, without | |
+executing any recipes. | |
+.TP | |
+.BI -w target1 , target2,... | |
+Pretend the modify time for each | |
+.I target | |
+is the current time; useful in conjunction with | |
+.B -n | |
+to learn what updates would be triggered by | |
+modifying the | |
+.IR targets . | |
+.PD | |
+.SS The \fLmkfile\fP | |
+A | |
+.I mkfile | |
+consists of | |
+.I assignments | |
+(described under `Environment') and | |
+.IR rules . | |
+A rule contains | |
+.I targets | |
+and a | |
+.IR tail . | |
+A target is a literal string | |
+and is normally a file name. | |
+The tail contains zero or more | |
+.I prerequisites | |
+and an optional | |
+.IR recipe , | |
+which is an | |
+.B shell | |
+script. | |
+Each line of the recipe must begin with white space. | |
+A rule takes the form | |
+.IP | |
+.EX | |
+target: prereq1 prereq2 | |
+ \f2recipe using\fP prereq1, prereq2 \f2to build\fP target | |
+.EE | |
+.PP | |
+When the recipe is executed, | |
+the first character on every line is elided. | |
+.PP | |
+After the colon on the target line, a rule may specify | |
+.IR attributes , | |
+described below. | |
+.PP | |
+A | |
+.I meta-rule | |
+has a target of the form | |
+.IB A % B | |
+where | |
+.I A | |
+and | |
+.I B | |
+are (possibly empty) strings. | |
+A meta-rule acts as a rule for any potential target whose | |
+name matches | |
+.IB A % B | |
+with | |
+.B % | |
+replaced by an arbitrary string, called the | |
+.IR stem . | |
+In interpreting a meta-rule, | |
+the stem is substituted for all occurrences of | |
+.B % | |
+in the prerequisite names. | |
+In the recipe of a meta-rule, the environment variable | |
+.B $stem | |
+contains the string matched by the | |
+.BR % . | |
+For example, a meta-rule to compile a C program using | |
+.IR 9c (1) | |
+might be: | |
+.IP | |
+.EX | |
+%: %.c | |
+ 9c -c $stem.c | |
+ 9l -o $stem $stem.o | |
+.EE | |
+.PP | |
+Meta-rules may contain an ampersand | |
+.B & | |
+rather than a percent sign | |
+.BR % . | |
+A | |
+.B % | |
+matches a maximal length string of any characters; | |
+an | |
+.B & | |
+matches a maximal length string of any characters except period | |
+or slash. | |
+.PP | |
+The text of the | |
+.I mkfile | |
+is processed as follows. | |
+Lines beginning with | |
+.B < | |
+followed by a file name are replaced by the contents of the named | |
+file. | |
+Lines beginning with | |
+.B "<|" | |
+followed by a file name are replaced by the output | |
+of the execution of the named | |
+file. | |
+Blank lines and comments, which run from unquoted | |
+.B # | |
+characters to the following newline, are deleted. | |
+The character sequence backslash-newline is deleted, | |
+so long lines in | |
+.I mkfile | |
+may be folded. | |
+Non-recipe lines are processed by substituting for | |
+.BI `{ command } | |
+the output of the | |
+.I command | |
+when run by | |
+.IR sh . | |
+References to variables are replaced by the variables' values. | |
+Special characters may be quoted using single quotes | |
+.BR \&'' | |
+as in | |
+.IR sh (1). | |
+.PP | |
+Assignments and rules are distinguished by | |
+the first unquoted occurrence of | |
+.B : | |
+(rule) | |
+or | |
+.B = | |
+(assignment). | |
+.PP | |
+A later rule may modify or override an existing rule under the | |
+following conditions: | |
+.TP | |
+\- | |
+If the targets of the rules exactly match and one rule | |
+contains only a prerequisite clause and no recipe, the | |
+clause is added to the prerequisites of the other rule. | |
+If either or both targets are virtual, the recipe is | |
+always executed. | |
+.TP | |
+\- | |
+If the targets of the rules match exactly and the | |
+prerequisites do not match and both rules | |
+contain recipes, | |
+.I mk | |
+reports an ``ambiguous recipe'' error. | |
+.TP | |
+\- | |
+If the target and prerequisites of both rules match exactly, | |
+the second rule overrides the first. | |
+.SS Environment | |
+Rules may make use of | |
+shell | |
+environment variables. | |
+A legal reference of the form | |
+.B $OBJ | |
+or | |
+.B ${name} | |
+is expanded as in | |
+.IR sh (1). | |
+A reference of the form | |
+.BI ${name: A % B = C\fL%\fID\fL}\fR, | |
+where | |
+.I A, B, C, D | |
+are (possibly empty) strings, | |
+has the value formed by expanding | |
+.B $name | |
+and substituting | |
+.I C | |
+for | |
+.I A | |
+and | |
+.I D | |
+for | |
+.I B | |
+in each word in | |
+.B $name | |
+that matches pattern | |
+.IB A % B\f1. | |
+.PP | |
+Variables can be set by | |
+assignments of the form | |
+.I | |
+ var\fL=\fR[\fIattr\fL=\fR]\fIvalue\fR | |
+.br | |
+Blanks in the | |
+.I value | |
+break it into words. | |
+Such variables are exported | |
+to the environment of | |
+recipes as they are executed, unless | |
+.BR U , | |
+the only legal attribute | |
+.IR attr , | |
+is present. | |
+The initial value of a variable is | |
+taken from (in increasing order of precedence) | |
+the default values below, | |
+.I mk's | |
+environment, the | |
+.IR mkfiles , | |
+and any command line assignment as an argument to | |
+.IR mk . | |
+A variable assignment argument overrides the first (but not any subsequent) | |
+assignment to that variable. | |
+.PP | |
+The variable | |
+.B MKFLAGS | |
+contains all the option arguments (arguments starting with | |
+.L - | |
+or containing | |
+.LR = ) | |
+and | |
+.B MKARGS | |
+contains all the targets in the call to | |
+.IR mk . | |
+.PP | |
+The variable | |
+.B MKSHELL | |
+contains the shell command line | |
+.I mk | |
+uses to run recipes. | |
+If the first word of the command ends in | |
+.B rc | |
+or | |
+.BR rcsh , | |
+.I mk | |
+uses | |
+.IR rc (1)'s | |
+quoting rules; otherwise it uses | |
+.IR sh (1)'s. | |
+The | |
+.B MKSHELL | |
+variable is consulted when the mkfile is read, not when it is executed, | |
+so that different shells can be used within a single mkfile: | |
+.IP | |
+.EX | |
+MKSHELL=$PLAN9/bin/rc | |
+use-rc:V: | |
+ for(i in a b c) echo $i | |
+ | |
+MKSHELL=sh | |
+use-sh:V: | |
+ for i in a b c; do echo $i; done | |
+.EE | |
+.LP | |
+Mkfiles included via | |
+.B < | |
+or | |
+.B <| | |
+.RI ( q.v. ) | |
+see their own private copy of | |
+.BR MKSHELL , | |
+which always starts set to | |
+.B sh . | |
+.PP | |
+Dynamic information may be included in the mkfile by using a line of the form | |
+.IP | |
+\fR<|\fIcommand\fR \fIargs\fR | |
+.LP | |
+This runs the command | |
+.I command | |
+with the given arguments | |
+.I args | |
+and pipes its standard output to | |
+.I mk | |
+to be included as part of the mkfile. For instance, the Inferno kernels | |
+use this technique | |
+to run a shell command with an awk script and a configuration | |
+file as arguments in order for | |
+the | |
+.I awk | |
+script to process the file and output a set of variables and their values. | |
+.SS Execution | |
+.PP | |
+During execution, | |
+.I mk | |
+determines which targets must be updated, and in what order, | |
+to build the | |
+.I names | |
+specified on the command line. | |
+It then runs the associated recipes. | |
+.PP | |
+A target is considered up to date if it has no prerequisites or | |
+if all its prerequisites are up to date and it is newer | |
+than all its prerequisites. | |
+Once the recipe for a target has executed, the target is | |
+considered up to date. | |
+.PP | |
+The date stamp | |
+used to determine if a target is up to date is computed | |
+differently for different types of targets. | |
+If a target is | |
+.I virtual | |
+(the target of a rule with the | |
+.B V | |
+attribute), | |
+its date stamp is initially zero; when the target is | |
+updated the date stamp is set to | |
+the most recent date stamp of its prerequisites. | |
+Otherwise, if a target does not exist as a file, | |
+its date stamp is set to the most recent date stamp of its prerequisites, | |
+or zero if it has no prerequisites. | |
+Otherwise, the target is the name of a file and | |
+the target's date stamp is always that file's modification date. | |
+The date stamp is computed when the target is needed in | |
+the execution of a rule; it is not a static value. | |
+.PP | |
+Nonexistent targets that have prerequisites | |
+and are themselves prerequisites are treated specially. | |
+Such a target | |
+.I t | |
+is given the date stamp of its most recent prerequisite | |
+and if this causes all the targets which have | |
+.I t | |
+as a prerequisite to be up to date, | |
+.I t | |
+is considered up to date. | |
+Otherwise, | |
+.I t | |
+is made in the normal fashion. | |
+The | |
+.B -i | |
+flag overrides this special treatment. | |
+.PP | |
+Files may be made in any order that respects | |
+the preceding restrictions. | |
+.PP | |
+A recipe is executed by supplying the recipe as standard input to | |
+the command | |
+.BR /bin/sh . | |
+(Note that unlike | |
+.IR make , | |
+.I mk | |
+feeds the entire recipe to the shell rather than running each line | |
+of the recipe separately.) | |
+The environment is augmented by the following variables: | |
+.TP 14 | |
+.B $alltarget | |
+all the targets of this rule. | |
+.TP | |
+.B $newprereq | |
+the prerequisites that caused this rule to execute. | |
+.TP | |
+.B $newmember | |
+the prerequisites that are members of an aggregate | |
+that caused this rule to execute. | |
+When the prerequisites of a rule are members of an | |
+aggregate, | |
+.B $newprereq | |
+contains the name of the aggregate and out of date | |
+members, while | |
+.B $newmember | |
+contains only the name of the members. | |
+.TP | |
+.B $nproc | |
+the process slot for this recipe. | |
+It satisfies | |
+.RB 0≤ $nproc < $NPROC . | |
+.TP | |
+.B $pid | |
+the process id for the | |
+.I mk | |
+executing the recipe. | |
+.TP | |
+.B $prereq | |
+all the prerequisites for this rule. | |
+.TP | |
+.B $stem | |
+if this is a meta-rule, | |
+.B $stem | |
+is the string that matched | |
+.B % | |
+or | |
+.BR & . | |
+Otherwise, it is empty. | |
+For regular expression meta-rules (see below), the variables | |
+.LR stem0 ", ...," | |
+.L stem9 | |
+are set to the corresponding subexpressions. | |
+.TP | |
+.B $target | |
+the targets for this rule that need to be remade. | |
+.PP | |
+These variables are available only during the execution of a recipe, | |
+not while evaluating the | |
+.IR mkfile . | |
+.PP | |
+Unless the rule has the | |
+.B Q | |
+attribute, | |
+the recipe is printed prior to execution | |
+with recognizable environment variables expanded. | |
+Commands returning error status | |
+cause | |
+.I mk | |
+to terminate. | |
+.PP | |
+Recipes and backquoted | |
+.B rc | |
+commands in places such as assignments | |
+execute in a copy of | |
+.I mk's | |
+environment; changes they make to | |
+environment variables are not visible from | |
+.IR mk . | |
+.PP | |
+Variable substitution in a rule is done when | |
+the rule is read; variable substitution in the recipe is done | |
+when the recipe is executed. For example: | |
+.IP | |
+.EX | |
+bar=a.c | |
+foo: $bar | |
+ $CC -o foo $bar | |
+bar=b.c | |
+.EE | |
+.PP | |
+will compile | |
+.B b.c | |
+into | |
+.BR foo , | |
+if | |
+.B a.c | |
+is newer than | |
+.BR foo . | |
+.SS Aggregates | |
+Names of the form | |
+.IR a ( b ) | |
+refer to member | |
+.I b | |
+of the aggregate | |
+.IR a . | |
+Currently, the only aggregates supported are | |
+.I 9ar | |
+(see | |
+.IR 9c (1)) | |
+archives. | |
+.SS Attributes | |
+The colon separating the target from the prerequisites | |
+may be | |
+immediately followed by | |
+.I attributes | |
+and another colon. | |
+The attributes are: | |
+.TP | |
+.B D | |
+If the recipe exits with a non-null status, the target is deleted. | |
+.TP | |
+.B E | |
+Continue execution if the recipe draws errors. | |
+.TP | |
+.B N | |
+If there is no recipe, the target has its time updated. | |
+.TP | |
+.B n | |
+The rule is a meta-rule that cannot be a target of a virtual rule. | |
+Only files match the pattern in the target. | |
+.TP | |
+.B P | |
+The characters after the | |
+.B P | |
+until the terminating | |
+.B : | |
+are taken as a program name. | |
+It will be invoked as | |
+.B "sh -c prog 'arg1' 'arg2'" | |
+and should return a zero exit status | |
+if and only if arg1 is up to date with respect to arg2. | |
+Date stamps are still propagated in the normal way. | |
+.TP | |
+.B Q | |
+The recipe is not printed prior to execution. | |
+.TP | |
+.B R | |
+The rule is a meta-rule using regular expressions. | |
+In the rule, | |
+.B % | |
+has no special meaning. | |
+The target is interpreted as a regular expression as defined in | |
+.IR regexp (7). | |
+The prerequisites may contain references | |
+to subexpressions in form | |
+.BI \e n\f1, | |
+as in the substitute command of | |
+.IR sed (1). | |
+.TP | |
+.B U | |
+The targets are considered to have been updated | |
+even if the recipe did not do so. | |
+.TP | |
+.B V | |
+The targets of this rule are marked as virtual. | |
+They are distinct from files of the same name. | |
+.PD | |
+.SH EXAMPLES | |
+A simple mkfile to compile a program: | |
+.IP | |
+.EX | |
+.ta 8n +8n +8n +8n +8n +8n +8n | |
+</$objtype/mkfile | |
+ | |
+prog: a.$O b.$O c.$O | |
+ $LD $LDFLAGS -o $target $prereq | |
+ | |
+%.$O: %.c | |
+ $CC $CFLAGS $stem.c | |
+.EE | |
+.PP | |
+Override flag settings in the mkfile: | |
+.IP | |
+.EX | |
+% mk target 'CFLAGS=-S -w' | |
+.EE | |
+.PP | |
+Maintain a library: | |
+.IP | |
+.EX | |
+libc.a(%.$O):N: %.$O | |
+libc.a: libc.a(abs.$O) libc.a(access.$O) libc.a(alarm.$O) ... | |
+ ar r libc.a $newmember | |
+.EE | |
+.PP | |
+String expression variables to derive names from a master list: | |
+.IP | |
+.EX | |
+NAMES=alloc arc bquote builtins expand main match mk var word | |
+OBJ=${NAMES:%=%.$O} | |
+.EE | |
+.PP | |
+Regular expression meta-rules: | |
+.IP | |
+.EX | |
+([^/]*)/(.*)\e.$O:R: \e1/\e2.c | |
+ cd $stem1; $CC $CFLAGS $stem2.c | |
+.EE | |
+.PP | |
+A correct way to deal with | |
+.IR yacc (1) | |
+grammars. | |
+The file | |
+.B lex.c | |
+includes the file | |
+.B x.tab.h | |
+rather than | |
+.B y.tab.h | |
+in order to reflect changes in content, not just modification time. | |
+.IP | |
+.EX | |
+lex.$O: x.tab.h | |
+x.tab.h: y.tab.h | |
+ cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h | |
+y.tab.c y.tab.h: gram.y | |
+ $YACC -d gram.y | |
+.EE | |
+.PP | |
+The above example could also use the | |
+.B P | |
+attribute for the | |
+.B x.tab.h | |
+rule: | |
+.IP | |
+.EX | |
+x.tab.h:Pcmp -s: y.tab.h | |
+ cp y.tab.h x.tab.h | |
+.EE | |
+.SH SOURCE | |
+.B \*9/src/cmd/mk | |
+.SH SEE ALSO | |
+.IR sh (1), | |
+.IR regexp (7) | |
+.PP | |
+A. Hume, | |
+``Mk: a Successor to Make'' | |
+(Tenth Edition Research Unix Manuals). | |
+.PP | |
+Andrew G. Hume and Bob Flandrena, | |
+``Maintaining Files on Plan 9 with Mk''. | |
+DOCPREFIX/doc/mk.pdf | |
+.SH HISTORY | |
+Andrew Hume wrote | |
+.I mk | |
+for Tenth Edition Research Unix. | |
+It was later ported to Plan 9. | |
+This software is a port of the Plan 9 version back to Unix. | |
+.SH BUGS | |
+Identical recipes for regular expression meta-rules only have one target. | |
+.PP | |
+Seemingly appropriate input like | |
+.B CFLAGS=-DHZ=60 | |
+is parsed as an erroneous attribute; correct it by inserting | |
+a space after the first | |
+.LR = . | |
+.PP | |
+The recipes printed by | |
+.I mk | |
+before being passed to | |
+the shell | |
+for execution are sometimes erroneously expanded | |
+for printing. Don't trust what's printed; rely | |
+on what the shell | |
+does. | |
diff --git a/mk/mk.c b/mk/mk.c | |
@@ -0,0 +1,234 @@ | |
+#include "mk.h" | |
+ | |
+int runerrs; | |
+ | |
+void | |
+mk(char *target) | |
+{ | |
+ Node *node; | |
+ int did = 0; | |
+ | |
+ nproc(); /* it can be updated dynamically */ | |
+ nrep(); /* it can be updated dynamically */ | |
+ runerrs = 0; | |
+ node = graph(target); | |
+ if(DEBUG(D_GRAPH)){ | |
+ dumpn("new target\n", node); | |
+ Bflush(&bout); | |
+ } | |
+ clrmade(node); | |
+ while(node->flags&NOTMADE){ | |
+ if(work(node, (Node *)0, (Arc *)0)) | |
+ did = 1; /* found something to do */ | |
+ else { | |
+ if(waitup(1, (int *)0) > 0){ | |
+ if(node->flags&(NOTMADE|BEINGMADE)){ | |
+ assert("must be run errors", runerrs); | |
+ break; /* nothing more waiting … | |
+ } | |
+ } | |
+ } | |
+ } | |
+ if(node->flags&BEINGMADE) | |
+ waitup(-1, (int *)0); | |
+ while(jobs) | |
+ waitup(-2, (int *)0); | |
+ assert("target didn't get done", runerrs || (node->flags&MADE)); | |
+ if(did == 0) | |
+ Bprint(&bout, "mk: '%s' is up to date\n", node->name); | |
+} | |
+ | |
+void | |
+clrmade(Node *n) | |
+{ | |
+ Arc *a; | |
+ | |
+ n->flags &= ~(CANPRETEND|PRETENDING); | |
+ if(strchr(n->name, '(') ==0 || n->time) | |
+ n->flags |= CANPRETEND; | |
+ MADESET(n, NOTMADE); | |
+ for(a = n->prereqs; a; a = a->next) | |
+ if(a->n) | |
+ clrmade(a->n); | |
+} | |
+ | |
+static void | |
+unpretend(Node *n) | |
+{ | |
+ MADESET(n, NOTMADE); | |
+ n->flags &= ~(CANPRETEND|PRETENDING); | |
+ n->time = 0; | |
+} | |
+ | |
+static char* | |
+dir(void) | |
+{ | |
+ static char buf[1024]; | |
+ | |
+ return getcwd(buf, sizeof buf); | |
+} | |
+ | |
+int | |
+work(Node *node, Node *p, Arc *parc) | |
+{ | |
+ Arc *a, *ra; | |
+ int weoutofdate; | |
+ int ready; | |
+ int did = 0; | |
+ | |
+ /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, nod… | |
+ if(node->flags&BEINGMADE) | |
+ return(did); | |
+ if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p,… | |
+ if(explain) | |
+ fprint(1, "unpretending %s(%ld) because %s is out of d… | |
+ node->name, node->time, p->name, p->time); | |
+ unpretend(node); | |
+ } | |
+ /* | |
+ have a look if we are pretending in case | |
+ someone has been unpretended out from underneath us | |
+ */ | |
+ if(node->flags&MADE){ | |
+ if(node->flags&PRETENDING){ | |
+ node->time = 0; | |
+ }else | |
+ return(did); | |
+ } | |
+ /* consider no prerequsite case */ | |
+ if(node->prereqs == 0){ | |
+ if(node->time == 0){ | |
+ fprint(2, "mk: don't know how to make '%s' in %s\n", n… | |
+ if(kflag){ | |
+ node->flags |= BEINGMADE; | |
+ runerrs++; | |
+ } else | |
+ Exit(); | |
+ } else | |
+ MADESET(node, MADE); | |
+ return(did); | |
+ } | |
+ /* | |
+ now see if we are out of date or what | |
+ */ | |
+ ready = 1; | |
+ weoutofdate = aflag; | |
+ ra = 0; | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(a->n){ | |
+ did = work(a->n, node, a) || did; | |
+ if(a->n->flags&(NOTMADE|BEINGMADE)) | |
+ ready = 0; | |
+ if(outofdate(node, a, 0)){ | |
+ weoutofdate = 1; | |
+ if((ra == 0) || (ra->n == 0) | |
+ || (ra->n->time < a->n->time)) | |
+ ra = a; | |
+ } | |
+ } else { | |
+ if(node->time == 0){ | |
+ if(ra == 0) | |
+ ra = a; | |
+ weoutofdate = 1; | |
+ } | |
+ } | |
+ if(ready == 0) /* can't do anything now */ | |
+ return(did); | |
+ if(weoutofdate == 0){ | |
+ MADESET(node, MADE); | |
+ return(did); | |
+ } | |
+ /* | |
+ can we pretend to be made? | |
+ */ | |
+ if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPR… | |
+ && p && ra->n && !outofdate(p, ra, 0)){ | |
+ node->flags &= ~CANPRETEND; | |
+ MADESET(node, MADE); | |
+ if(explain && ((node->flags&PRETENDING) == 0)) | |
+ fprint(1, "pretending %s has time %ld\n", node->name, … | |
+ node->flags |= PRETENDING; | |
+ return(did); | |
+ } | |
+ /* | |
+ node is out of date and we REALLY do have to do something. | |
+ quickly rescan for pretenders | |
+ */ | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(a->n && (a->n->flags&PRETENDING)){ | |
+ if(explain) | |
+ Bprint(&bout, "unpretending %s because of %s b… | |
+ a->n->name, node->name, ra->n? ra->n->name : "… | |
+ | |
+ unpretend(a->n); | |
+ did = work(a->n, node, a) || did; | |
+ ready = 0; | |
+ } | |
+ if(ready == 0) /* try later unless nothing has happened for -k'… | |
+ return(did || work(node, p, parc)); | |
+ did = dorecipe(node) || did; | |
+ return(did); | |
+} | |
+ | |
+void | |
+update(int fake, Node *node) | |
+{ | |
+ Arc *a; | |
+ | |
+ MADESET(node, fake? BEINGMADE : MADE); | |
+ if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){ | |
+ node->time = timeof(node->name, 1); | |
+ node->flags &= ~(CANPRETEND|PRETENDING); | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(a->prog) | |
+ outofdate(node, a, 1); | |
+ } else { | |
+ node->time = 1; | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(a->n && outofdate(node, a, 1)) | |
+ node->time = a->n->time; | |
+ } | |
+/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, n… | |
+} | |
+ | |
+static int | |
+pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd) | |
+{ | |
+ char buf[3*NAMEBLOCK]; | |
+ int pid; | |
+ | |
+ Bflush(&bout); | |
+ snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q); | |
+ pid = pipecmd(buf, 0, 0, sh, shcmd); | |
+ while(waitup(-3, &pid) >= 0) | |
+ ; | |
+ return(pid? 2:1); | |
+} | |
+ | |
+int | |
+outofdate(Node *node, Arc *arc, int eval) | |
+{ | |
+ char buf[3*NAMEBLOCK], *str; | |
+ Symtab *sym; | |
+ int ret; | |
+ | |
+ str = 0; | |
+ if(arc->prog){ | |
+ snprint(buf, sizeof buf, "%s%c%s", node->name, 0377, arc->n->n… | |
+ sym = symlook(buf, S_OUTOFDATE, 0); | |
+ if(sym == 0 || eval){ | |
+ if(sym == 0) | |
+ str = strdup(buf); | |
+ ret = pcmp(arc->prog, node->name, arc->n->name, arc->r… | |
+ if(sym) | |
+ sym->u.value = ret; | |
+ else | |
+ symlook(str, S_OUTOFDATE, (void *)(uintptr)ret… | |
+ } else | |
+ ret = sym->u.value; | |
+ return(ret-1); | |
+ } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing … | |
+ return 1; | |
+ else | |
+ return node->time <= arc->n->time; | |
+} | |
diff --git a/mk/mk.h b/mk/mk.h | |
@@ -0,0 +1,185 @@ | |
+#include "sys.h" | |
+ | |
+#undef assert | |
+#define assert mkassert | |
+extern Biobuf bout; | |
+ | |
+typedef struct Bufblock | |
+{ | |
+ struct Bufblock *next; | |
+ char *start; | |
+ char *end; | |
+ char *current; | |
+} Bufblock; | |
+ | |
+typedef struct Word | |
+{ | |
+ char *s; | |
+ struct Word *next; | |
+} Word; | |
+ | |
+typedef struct Envy | |
+{ | |
+ char *name; | |
+ Word *values; | |
+} Envy; | |
+ | |
+extern Envy *envy; | |
+ | |
+typedef struct Shell | |
+{ | |
+ char *name; | |
+ char *termchars; /* used in parse.c to isolate assignmen… | |
+ int iws; /* inter-word separator in envi… | |
+ char *(*charin)(char*, char*); /* search for unescaped c… | |
+ char *(*expandquote)(char*, Rune, Bufblock*); /* extract… | |
+ int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* inp… | |
+ char *(*copyq)(char*, Rune, Bufblock*); /* check for quo… | |
+ int (*matchname)(char*); /* does name match */ | |
+} Shell; | |
+ | |
+typedef struct Rule | |
+{ | |
+ char *target; /* one target */ | |
+ Word *tail; /* constituents of targets … | |
+ char *recipe; /* do it ! */ | |
+ short attr; /* attributes */ | |
+ short line; /* source line */ | |
+ char *file; /* source file */ | |
+ Word *alltargets; /* all the targets */ | |
+ int rule; /* rule number */ | |
+ Reprog *pat; /* reg exp goo */ | |
+ char *prog; /* to use in out of date */ | |
+ struct Rule *chain; /* hashed per target */ | |
+ struct Rule *next; | |
+ Shell *shellt; /* shell to use with this rule */ | |
+ Word *shellcmd; | |
+} Rule; | |
+ | |
+extern Rule *rules, *metarules, *patrule; | |
+ | |
+/* Rule.attr */ | |
+#define META 0x0001 | |
+#define UNUSED 0x0002 | |
+#define UPD 0x0004 | |
+#define QUIET 0x0008 | |
+#define VIR 0x0010 | |
+#define REGEXP 0x0020 | |
+#define NOREC 0x0040 | |
+#define DEL 0x0080 | |
+#define NOVIRT 0x0100 | |
+ | |
+#define NREGEXP 10 | |
+ | |
+typedef struct Arc | |
+{ | |
+ short flag; | |
+ struct Node *n; | |
+ Rule *r; | |
+ char *stem; | |
+ char *prog; | |
+ char *match[NREGEXP]; | |
+ struct Arc *next; | |
+} Arc; | |
+ | |
+ /* Arc.flag */ | |
+#define TOGO 1 | |
+ | |
+typedef struct Node | |
+{ | |
+ char *name; | |
+ long time; | |
+ unsigned short flags; | |
+ Arc *prereqs; | |
+ struct Node *next; /* list for a rule */ | |
+} Node; | |
+ | |
+ /* Node.flags */ | |
+#define VIRTUAL 0x0001 | |
+#define CYCLE 0x0002 | |
+#define READY 0x0004 | |
+#define CANPRETEND 0x0008 | |
+#define PRETENDING 0x0010 | |
+#define NOTMADE 0x0020 | |
+#define BEINGMADE 0x0040 | |
+#define MADE 0x0080 | |
+#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEIN… | |
+#define PROBABLE 0x0100 | |
+#define VACUOUS 0x0200 | |
+#define NORECIPE 0x0400 | |
+#define DELETE 0x0800 | |
+#define NOMINUSE 0x1000 | |
+ | |
+typedef struct Job | |
+{ | |
+ Rule *r; /* master rule for job */ | |
+ Node *n; /* list of node targets */ | |
+ char *stem; | |
+ char **match; | |
+ Word *p; /* prerequistes */ | |
+ Word *np; /* new prerequistes */ | |
+ Word *t; /* targets */ | |
+ Word *at; /* all targets */ | |
+ int nproc; /* slot number */ | |
+ struct Job *next; | |
+} Job; | |
+extern Job *jobs; | |
+ | |
+typedef struct Symtab | |
+{ | |
+ short space; | |
+ char *name; | |
+ union { | |
+ void *ptr; | |
+ uintptr value; | |
+ } u; | |
+ struct Symtab *next; | |
+} Symtab; | |
+ | |
+enum { | |
+ S_VAR, /* variable -> value */ | |
+ S_TARGET, /* target -> rule */ | |
+ S_TIME, /* file -> time */ | |
+ S_PID, /* pid -> products */ | |
+ S_NODE, /* target name -> node */ | |
+ S_AGG, /* aggregate -> time */ | |
+ S_BITCH, /* bitched about aggregate not there */ | |
+ S_NOEXPORT, /* var -> noexport */ | |
+ S_OVERRIDE, /* can't override */ | |
+ S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */ | |
+ S_MAKEFILE, /* target -> node */ | |
+ S_MAKEVAR, /* dumpable mk variable */ | |
+ S_EXPORTED, /* var -> current exported value */ | |
+ S_WESET, /* variable; we set in the mkfile */ | |
+ S_INTERNAL /* an internal mk variable (e.g., stem, target) */ | |
+}; | |
+ | |
+extern int debug; | |
+extern int nflag, tflag, iflag, kflag, aflag, mflag; | |
+extern int mkinline; | |
+extern char *infile; | |
+extern int nreps; | |
+extern char *explain; | |
+extern Shell *shellt; | |
+extern Word *shellcmd; | |
+ | |
+extern Shell shshell, rcshell; | |
+ | |
+#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile… | |
+#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r… | |
+#define NAMEBLOCK 1000 | |
+#define BIGBLOCK 20000 | |
+ | |
+#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n')) | |
+#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^… | |
+ | |
+#define DEBUG(x) (debug&(x)) | |
+#define D_PARSE 0x01 | |
+#define D_GRAPH 0x02 | |
+#define D_EXEC 0x04 | |
+ | |
+#define LSEEK(f,o,p) seek(f,o,p) | |
+ | |
+#define PERCENT(ch) (((ch) == '%') || ((ch) == '&')) | |
+ | |
+#include "fns.h" | |
diff --git a/mk/mkfile b/mk/mkfile | |
@@ -0,0 +1,37 @@ | |
+<$PLAN9/src/mkhdr | |
+ | |
+TARG=mk | |
+ | |
+OFILES=\ | |
+ arc.$O\ | |
+ archive.$O\ | |
+ bufblock.$O\ | |
+ env.$O\ | |
+ file.$O\ | |
+ graph.$O\ | |
+ job.$O\ | |
+ lex.$O\ | |
+ main.$O\ | |
+ match.$O\ | |
+ mk.$O\ | |
+ parse.$O\ | |
+ recipe.$O\ | |
+ rc.$O\ | |
+ rule.$O\ | |
+ run.$O\ | |
+ sh.$O\ | |
+ shell.$O\ | |
+ shprint.$O\ | |
+ symtab.$O\ | |
+ var.$O\ | |
+ varsub.$O\ | |
+ word.$O\ | |
+ unix.$O\ | |
+ | |
+HFILES=\ | |
+ mk.h\ | |
+ fns.h\ | |
+ | |
+ | |
+<$PLAN9/src/mkone | |
+ | |
diff --git a/mk/mkfile.test b/mk/mkfile.test | |
@@ -0,0 +1,12 @@ | |
+MKSHELL=$PLAN9/bin/rc | |
+use-rc:V: | |
+ for(i in a b c) | |
+ echo $i | |
+ | |
+MKSHELL=/bin/sh | |
+use-sh:V: | |
+ for i in a b c | |
+ do | |
+ echo $i | |
+ done | |
+ | |
diff --git a/mk/parse.c b/mk/parse.c | |
@@ -0,0 +1,318 @@ | |
+#include "mk.h" | |
+ | |
+char *infile; | |
+int mkinline; | |
+static int rhead(char *, Word **, Word **, int *, char **); | |
+static char *rbody(Biobuf*); | |
+extern Word *target1; | |
+ | |
+void | |
+parse(char *f, int fd, int varoverride) | |
+{ | |
+ int hline; | |
+ char *body; | |
+ Word *head, *tail; | |
+ int attr, set, pid; | |
+ char *prog, *p; | |
+ int newfd; | |
+ Biobuf in; | |
+ Bufblock *buf; | |
+ char *err; | |
+ | |
+ if(fd < 0){ | |
+ fprint(2, "open %s: %r\n", f); | |
+ Exit(); | |
+ } | |
+ pushshell(); | |
+ ipush(); | |
+ infile = strdup(f); | |
+ mkinline = 1; | |
+ Binit(&in, fd, OREAD); | |
+ buf = newbuf(); | |
+ while(assline(&in, buf)){ | |
+ hline = mkinline; | |
+ switch(rhead(buf->start, &head, &tail, &attr, &prog)) | |
+ { | |
+ case '<': | |
+ p = wtos(tail, ' '); | |
+ if(*p == 0){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing include file name\n"); | |
+ Exit(); | |
+ } | |
+ newfd = open(p, OREAD); | |
+ if(newfd < 0){ | |
+ fprint(2, "warning: skipping missing include f… | |
+ } else | |
+ parse(p, newfd, 0); | |
+ break; | |
+ case '|': | |
+ p = wtos(tail, ' '); | |
+ if(*p == 0){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing include program name\n"); | |
+ Exit(); | |
+ } | |
+ execinit(); | |
+ pid=pipecmd(p, envy, &newfd, shellt, shellcmd); | |
+ if(newfd < 0){ | |
+ fprint(2, "warning: skipping missing program f… | |
+ } else | |
+ parse(p, newfd, 0); | |
+ while(waitup(-3, &pid) >= 0) | |
+ ; | |
+ if(pid != 0){ | |
+ fprint(2, "bad include program status\n"); | |
+ Exit(); | |
+ } | |
+ break; | |
+ case ':': | |
+ body = rbody(&in); | |
+ addrules(head, tail, body, attr, hline, prog); | |
+ break; | |
+ case '=': | |
+ if(head->next){ | |
+ SYNERR(-1); | |
+ fprint(2, "multiple vars on left side of assig… | |
+ Exit(); | |
+ } | |
+ if(symlook(head->s, S_OVERRIDE, 0)){ | |
+ set = varoverride; | |
+ } else { | |
+ set = 1; | |
+ if(varoverride) | |
+ symlook(head->s, S_OVERRIDE, (void *)"… | |
+ } | |
+ if(set){ | |
+/* | |
+char *cp; | |
+dumpw("tail", tail); | |
+cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp); | |
+*/ | |
+ setvar(head->s, (void *) tail); | |
+ symlook(head->s, S_WESET, (void *)""); | |
+ if(strcmp(head->s, "MKSHELL") == 0){ | |
+ if((err = setshell(tail)) != nil){ | |
+ SYNERR(hline); | |
+ fprint(2, "%s\n", err); | |
+ Exit(); | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ if(attr) | |
+ symlook(head->s, S_NOEXPORT, (void *)""); | |
+ break; | |
+ default: | |
+ SYNERR(hline); | |
+ fprint(2, "expected one of :<=\n"); | |
+ Exit(); | |
+ break; | |
+ } | |
+ } | |
+ close(fd); | |
+ freebuf(buf); | |
+ ipop(); | |
+ popshell(); | |
+} | |
+ | |
+void | |
+addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog) | |
+{ | |
+ Word *w; | |
+ | |
+ assert("addrules args", head && body); | |
+ /* tuck away first non-meta rule as default target*/ | |
+ if(target1 == 0 && !(attr®EXP)){ | |
+ for(w = head; w; w = w->next) | |
+ if(shellt->charin(w->s, "%&")) | |
+ break; | |
+ if(w == 0) | |
+ target1 = wdup(head); | |
+ } | |
+ for(w = head; w; w = w->next) | |
+ addrule(w->s, tail, body, head, attr, hline, prog); | |
+} | |
+ | |
+static int | |
+rhead(char *line, Word **h, Word **t, int *attr, char **prog) | |
+{ | |
+ char *p; | |
+ char *pp; | |
+ int sep; | |
+ Rune r; | |
+ int n; | |
+ Word *w; | |
+ | |
+ p = shellt->charin(line,":=<"); | |
+ if(p == 0) | |
+ return('?'); | |
+ sep = *p; | |
+ *p++ = 0; | |
+ if(sep == '<' && *p == '|'){ | |
+ sep = '|'; | |
+ p++; | |
+ } | |
+ *attr = 0; | |
+ *prog = 0; | |
+ if(sep == '='){ | |
+ pp = shellt->charin(p, shellt->termchars); /* termchars… | |
+ if (pp && *pp == '=') { | |
+ while (p != pp) { | |
+ n = chartorune(&r, p); | |
+ switch(r) | |
+ { | |
+ default: | |
+ SYNERR(-1); | |
+ fprint(2, "unknown attribute '%c'\n",*… | |
+ Exit(); | |
+ case 'U': | |
+ *attr = 1; | |
+ break; | |
+ } | |
+ p += n; | |
+ } | |
+ p++; /* skip trailing '=' */ | |
+ } | |
+ } | |
+ if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){ | |
+ while (*p) { | |
+ n = chartorune(&r, p); | |
+ if (r == ':') | |
+ break; | |
+ p += n; | |
+ switch(r) | |
+ { | |
+ default: | |
+ SYNERR(-1); | |
+ fprint(2, "unknown attribute '%c'\n", p[-1]); | |
+ Exit(); | |
+ case 'D': | |
+ *attr |= DEL; | |
+ break; | |
+ case 'E': | |
+ *attr |= NOMINUSE; | |
+ break; | |
+ case 'n': | |
+ *attr |= NOVIRT; | |
+ break; | |
+ case 'N': | |
+ *attr |= NOREC; | |
+ break; | |
+ case 'P': | |
+ pp = utfrune(p, ':'); | |
+ if (pp == 0 || *pp == 0) | |
+ goto eos; | |
+ *pp = 0; | |
+ *prog = strdup(p); | |
+ *pp = ':'; | |
+ p = pp; | |
+ break; | |
+ case 'Q': | |
+ *attr |= QUIET; | |
+ break; | |
+ case 'R': | |
+ *attr |= REGEXP; | |
+ break; | |
+ case 'U': | |
+ *attr |= UPD; | |
+ break; | |
+ case 'V': | |
+ *attr |= VIR; | |
+ break; | |
+ } | |
+ } | |
+ if (*p++ != ':') { | |
+ eos: | |
+ SYNERR(-1); | |
+ fprint(2, "missing trailing :\n"); | |
+ Exit(); | |
+ } | |
+ } | |
+ *h = w = stow(line); | |
+ if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') { | |
+ SYNERR(mkinline-1); | |
+ fprint(2, "no var on left side of assignment/rule\n"); | |
+ Exit(); | |
+ } | |
+ *t = stow(p); | |
+ return(sep); | |
+} | |
+ | |
+static char * | |
+rbody(Biobuf *in) | |
+{ | |
+ Bufblock *buf; | |
+ int r, lastr; | |
+ char *p; | |
+ | |
+ lastr = '\n'; | |
+ buf = newbuf(); | |
+ for(;;){ | |
+ r = Bgetrune(in); | |
+ if (r < 0) | |
+ break; | |
+ if (lastr == '\n') { | |
+ if (r == '#') | |
+ rinsert(buf, r); | |
+ else if (r != ' ' && r != '\t') { | |
+ Bungetrune(in); | |
+ break; | |
+ } | |
+ } else | |
+ rinsert(buf, r); | |
+ lastr = r; | |
+ if (r == '\n') | |
+ mkinline++; | |
+ } | |
+ insert(buf, 0); | |
+ p = strdup(buf->start); | |
+ freebuf(buf); | |
+ return p; | |
+} | |
+ | |
+struct input | |
+{ | |
+ char *file; | |
+ int line; | |
+ struct input *next; | |
+}; | |
+static struct input *inputs = 0; | |
+ | |
+void | |
+ipush(void) | |
+{ | |
+ struct input *in, *me; | |
+ | |
+ me = (struct input *)Malloc(sizeof(*me)); | |
+ me->file = infile; | |
+ me->line = mkinline; | |
+ me->next = 0; | |
+ if(inputs == 0) | |
+ inputs = me; | |
+ else { | |
+ for(in = inputs; in->next; ) | |
+ in = in->next; | |
+ in->next = me; | |
+ } | |
+} | |
+ | |
+void | |
+ipop(void) | |
+{ | |
+ struct input *in, *me; | |
+ | |
+ assert("pop input list", inputs != 0); | |
+ if(inputs->next == 0){ | |
+ me = inputs; | |
+ inputs = 0; | |
+ } else { | |
+ for(in = inputs; in->next->next; ) | |
+ in = in->next; | |
+ me = in->next; | |
+ in->next = 0; | |
+ } | |
+ infile = me->file; | |
+ mkinline = me->line; | |
+ free((char *)me); | |
+} | |
diff --git a/mk/rc.c b/mk/rc.c | |
@@ -0,0 +1,194 @@ | |
+#include "mk.h" | |
+ | |
+/* | |
+ * This file contains functions that depend on rc's syntax. Most | |
+ * of the routines extract strings observing rc's escape conventions | |
+ */ | |
+ | |
+ | |
+/* | |
+ * skip a token in single quotes. | |
+ */ | |
+static char * | |
+squote(char *cp) | |
+{ | |
+ Rune r; | |
+ int n; | |
+ | |
+ while(*cp){ | |
+ n = chartorune(&r, cp); | |
+ if(r == '\'') { | |
+ n += chartorune(&r, cp+n); | |
+ if(r != '\'') | |
+ return(cp); | |
+ } | |
+ cp += n; | |
+ } | |
+ SYNERR(-1); /* should never occur */ | |
+ fprint(2, "missing closing '\n"); | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * search a string for characters in a pattern set | |
+ * characters in quotes and variable generators are escaped | |
+ */ | |
+char * | |
+rccharin(char *cp, char *pat) | |
+{ | |
+ Rune r; | |
+ int n, vargen; | |
+ | |
+ vargen = 0; | |
+ while(*cp){ | |
+ n = chartorune(&r, cp); | |
+ switch(r){ | |
+ case '\'': /* skip quoted string */ | |
+ cp = squote(cp+1); /* n must = 1 */ | |
+ if(!cp) | |
+ return 0; | |
+ break; | |
+ case '$': | |
+ if(*(cp+1) == '{') | |
+ vargen = 1; | |
+ break; | |
+ case '}': | |
+ if(vargen) | |
+ vargen = 0; | |
+ else if(utfrune(pat, r)) | |
+ return cp; | |
+ break; | |
+ default: | |
+ if(vargen == 0 && utfrune(pat, r)) | |
+ return cp; | |
+ break; | |
+ } | |
+ cp += n; | |
+ } | |
+ if(vargen){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing closing } in pattern generator\n"); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * extract an escaped token. Possible escape chars are single-quote, | |
+ * double-quote,and backslash. Only the first is valid for rc. the | |
+ * others are just inserted into the receiving buffer. | |
+ */ | |
+char* | |
+rcexpandquote(char *s, Rune r, Bufblock *b) | |
+{ | |
+ if (r != '\'') { | |
+ rinsert(b, r); | |
+ return s; | |
+ } | |
+ | |
+ while(*s){ | |
+ s += chartorune(&r, s); | |
+ if(r == '\'') { | |
+ if(*s == '\'') | |
+ s++; | |
+ else | |
+ return s; | |
+ } | |
+ rinsert(b, r); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * Input an escaped token. Possible escape chars are single-quote, | |
+ * double-quote and backslash. Only the first is a valid escape for | |
+ * rc; the others are just inserted into the receiving buffer. | |
+ */ | |
+int | |
+rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) | |
+{ | |
+ int c, line; | |
+ | |
+ if(esc != '\'') | |
+ return 1; | |
+ | |
+ line = mkinline; | |
+ while((c = nextrune(bp, 0)) > 0){ | |
+ if(c == '\''){ | |
+ if(preserve) | |
+ rinsert(buf, c); | |
+ c = Bgetrune(bp); | |
+ if (c < 0) | |
+ break; | |
+ if(c != '\''){ | |
+ Bungetrune(bp); | |
+ return 1; | |
+ } | |
+ } | |
+ rinsert(buf, c); | |
+ } | |
+ SYNERR(line); fprint(2, "missing closing %c\n", esc); | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * copy a single-quoted string; s points to char after opening quote | |
+ */ | |
+static char * | |
+copysingle(char *s, Bufblock *buf) | |
+{ | |
+ Rune r; | |
+ | |
+ while(*s){ | |
+ s += chartorune(&r, s); | |
+ rinsert(buf, r); | |
+ if(r == '\'') | |
+ break; | |
+ } | |
+ return s; | |
+} | |
+/* | |
+ * check for quoted strings. backquotes are handled here; single quote… | |
+ * s points to char after opening quote, q. | |
+ */ | |
+char * | |
+rccopyq(char *s, Rune q, Bufblock *buf) | |
+{ | |
+ if(q == '\'') /* copy quoted string */ | |
+ return copysingle(s, buf); | |
+ | |
+ if(q != '`') /* not quoted */ | |
+ return s; | |
+ | |
+ while(*s){ /* copy backquoted string */ | |
+ s += chartorune(&q, s); | |
+ rinsert(buf, q); | |
+ if(q == '}') | |
+ break; | |
+ if(q == '\'') | |
+ s = copysingle(s, buf); /* copy quoted string */ | |
+ } | |
+ return s; | |
+} | |
+ | |
+static int | |
+rcmatchname(char *name) | |
+{ | |
+ char *p; | |
+ | |
+ if((p = strrchr(name, '/')) != nil) | |
+ name = p+1; | |
+ if(name[0] == 'r' && name[1] == 'c') | |
+ return 1; | |
+ return 0; | |
+} | |
+ | |
+Shell rcshell = { | |
+ "rc", | |
+ "'= \t", | |
+ '\1', | |
+ rccharin, | |
+ rcexpandquote, | |
+ rcescapetoken, | |
+ rccopyq, | |
+ rcmatchname | |
+}; | |
diff --git a/mk/recipe.c b/mk/recipe.c | |
@@ -0,0 +1,117 @@ | |
+#include "mk.h" | |
+ | |
+int | |
+dorecipe(Node *node) | |
+{ | |
+ char buf[BIGBLOCK]; | |
+ register Node *n; | |
+ Rule *r = 0; | |
+ Arc *a, *aa; | |
+ Word head, ahead, lp, ln, *w, *ww, *aw; | |
+ Symtab *s; | |
+ int did = 0; | |
+ | |
+ aa = 0; | |
+ /* | |
+ pick up the rule | |
+ */ | |
+ for(a = node->prereqs; a; a = a->next) | |
+ if(*a->r->recipe) | |
+ r = (aa = a)->r; | |
+ /* | |
+ no recipe? go to buggery! | |
+ */ | |
+ if(r == 0){ | |
+ if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){ | |
+ fprint(2, "mk: no recipe to make '%s'\n", node->name); | |
+ Exit(); | |
+ } | |
+ if(strchr(node->name, '(') && node->time == 0) | |
+ MADESET(node, MADE); | |
+ else | |
+ update(0, node); | |
+ if(tflag){ | |
+ if(!(node->flags&VIRTUAL)) | |
+ touch(node->name); | |
+ else if(explain) | |
+ Bprint(&bout, "no touch of virtual '%s'\n", no… | |
+ } | |
+ return(did); | |
+ } | |
+ /* | |
+ build the node list | |
+ */ | |
+ node->next = 0; | |
+ head.next = 0; | |
+ ww = &head; | |
+ ahead.next = 0; | |
+ aw = &ahead; | |
+ if(r->attr®EXP){ | |
+ ww->next = newword(node->name); | |
+ aw->next = newword(node->name); | |
+ } else { | |
+ for(w = r->alltargets; w; w = w->next){ | |
+ if(r->attr&META) | |
+ subst(aa->stem, w->s, buf); | |
+ else | |
+ strcpy(buf, w->s); | |
+ aw->next = newword(buf); | |
+ aw = aw->next; | |
+ if((s = symlook(buf, S_NODE, 0)) == 0) | |
+ continue; /* not a node we are interest… | |
+ n = s->u.ptr; | |
+ if(aflag == 0 && n->time) { | |
+ for(a = n->prereqs; a; a = a->next) | |
+ if(a->n && outofdate(n, a, 0)) | |
+ break; | |
+ if(a == 0) | |
+ continue; | |
+ } | |
+ ww->next = newword(buf); | |
+ ww = ww->next; | |
+ if(n == node) continue; | |
+ n->next = node->next; | |
+ node->next = n; | |
+ } | |
+ } | |
+ for(n = node; n; n = n->next) | |
+ if((n->flags&READY) == 0) | |
+ return(did); | |
+ /* | |
+ gather the params for the job | |
+ */ | |
+ lp.next = ln.next = 0; | |
+ for(n = node; n; n = n->next){ | |
+ for(a = n->prereqs; a; a = a->next){ | |
+ if(a->n){ | |
+ addw(&lp, a->n->name); | |
+ if(outofdate(n, a, 0)){ | |
+ addw(&ln, a->n->name); | |
+ if(explain) | |
+ fprint(1, "%s(%ld) < %s(%ld)\n… | |
+ n->name, n->time, a->n… | |
+ } | |
+ } else { | |
+ if(explain) | |
+ fprint(1, "%s has no prerequisites\n", | |
+ n->name); | |
+ } | |
+ } | |
+ MADESET(n, BEINGMADE); | |
+ } | |
+ /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),… | |
+ run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, … | |
+ return(1); | |
+} | |
+ | |
+void | |
+addw(Word *w, char *s) | |
+{ | |
+ Word *lw; | |
+ | |
+ for(lw = w; w = w->next; lw = w){ | |
+ if(strcmp(s, w->s) == 0) | |
+ return; | |
+ } | |
+ lw->next = newword(s); | |
+} | |
diff --git a/mk/rule.c b/mk/rule.c | |
@@ -0,0 +1,112 @@ | |
+#include "mk.h" | |
+ | |
+static Rule *lr, *lmr; | |
+static int rcmp(Rule *r, char *target, Word *tail); | |
+static int nrules = 0; | |
+ | |
+void | |
+addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, … | |
+{ | |
+ Rule *r; | |
+ Rule *rr; | |
+ Symtab *sym; | |
+ int reuse; | |
+ | |
+ r = 0; | |
+ reuse = 0; | |
+ if(sym = symlook(head, S_TARGET, 0)){ | |
+ for(r = sym->u.ptr; r; r = r->chain) | |
+ if(rcmp(r, head, tail) == 0){ | |
+ reuse = 1; | |
+ break; | |
+ } | |
+ } | |
+ if(r == 0) | |
+ r = (Rule *)Malloc(sizeof(Rule)); | |
+ r->shellt = shellt; | |
+ r->shellcmd = shellcmd; | |
+ r->target = head; | |
+ r->tail = tail; | |
+ r->recipe = body; | |
+ r->line = hline; | |
+ r->file = infile; | |
+ r->attr = attr; | |
+ r->alltargets = ahead; | |
+ r->prog = prog; | |
+ r->rule = nrules++; | |
+ if(!reuse){ | |
+ rr = symlook(head, S_TARGET, (void *)r)->u.ptr; | |
+ if(rr != r){ | |
+ r->chain = rr->chain; | |
+ rr->chain = r; | |
+ } else | |
+ r->chain = 0; | |
+ } | |
+ if(!reuse) | |
+ r->next = 0; | |
+ if((attr®EXP) || shellt->charin(head, "%&")){ | |
+ r->attr |= META; | |
+ if(reuse) | |
+ return; | |
+ if(attr®EXP){ | |
+ patrule = r; | |
+ r->pat = regcomp(head); | |
+ } | |
+ if(metarules == 0) | |
+ metarules = lmr = r; | |
+ else { | |
+ lmr->next = r; | |
+ lmr = r; | |
+ } | |
+ } else { | |
+ if(reuse) | |
+ return; | |
+ r->pat = 0; | |
+ if(rules == 0) | |
+ rules = lr = r; | |
+ else { | |
+ lr->next = r; | |
+ lr = r; | |
+ } | |
+ } | |
+} | |
+ | |
+void | |
+dumpr(char *s, Rule *r) | |
+{ | |
+ if(r == nil) | |
+ return; | |
+ Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n", | |
+ s, r, r->shellt->name, wtos(r->shellcmd, ' ')); | |
+ for(; r; r = r->next){ | |
+ Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld a… | |
+ r, r->file, r->line, r->attr, r->next, r->chain, wtos(… | |
+ if(r->prog) | |
+ Bprint(&bout, " prog='%s'", r->prog); | |
+ Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, … | |
+ Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe); | |
+ } | |
+} | |
+ | |
+static int | |
+rcmp(Rule *r, char *target, Word *tail) | |
+{ | |
+ Word *w; | |
+ | |
+ if(strcmp(r->target, target)) | |
+ return 1; | |
+ for(w = r->tail; w && tail; w = w->next, tail = tail->next) | |
+ if(strcmp(w->s, tail->s)) | |
+ return 1; | |
+ return(w || tail); | |
+} | |
+ | |
+char * | |
+rulecnt(void) | |
+{ | |
+ char *s; | |
+ | |
+ s = Malloc(nrules); | |
+ memset(s, 0, nrules); | |
+ return(s); | |
+} | |
diff --git a/mk/run.c b/mk/run.c | |
@@ -0,0 +1,296 @@ | |
+#include "mk.h" | |
+ | |
+typedef struct Event | |
+{ | |
+ int pid; | |
+ Job *job; | |
+} Event; | |
+static Event *events; | |
+static int nevents, nrunning, nproclimit; | |
+ | |
+typedef struct Process | |
+{ | |
+ int pid; | |
+ int status; | |
+ struct Process *b, *f; | |
+} Process; | |
+static Process *phead, *pfree; | |
+static void sched(void); | |
+static void pnew(int, int), pdelete(Process *); | |
+ | |
+int pidslot(int); | |
+ | |
+void | |
+run(Job *j) | |
+{ | |
+ Job *jj; | |
+ | |
+ if(jobs){ | |
+ for(jj = jobs; jj->next; jj = jj->next) | |
+ ; | |
+ jj->next = j; | |
+ } else | |
+ jobs = j; | |
+ j->next = 0; | |
+ /* this code also in waitup after parse redirect */ | |
+ if(nrunning < nproclimit) | |
+ sched(); | |
+} | |
+ | |
+static void | |
+sched(void) | |
+{ | |
+ char *flags; | |
+ Job *j; | |
+ Bufblock *buf; | |
+ int slot; | |
+ Node *n; | |
+ Envy *e; | |
+ | |
+ if(jobs == 0){ | |
+ usage(); | |
+ return; | |
+ } | |
+ j = jobs; | |
+ jobs = j->next; | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "firing up job for target %s\n", wtos(j->t, ' ')); | |
+ slot = nextslot(); | |
+ events[slot].job = j; | |
+ buf = newbuf(); | |
+ e = buildenv(j, slot); | |
+ shprint(j->r->recipe, e, buf, j->r->shellt); | |
+ if(!tflag && (nflag || !(j->r->attr&QUIET))) | |
+ Bwrite(&bout, buf->start, (long)strlen(buf->start)); | |
+ freebuf(buf); | |
+ if(nflag||tflag){ | |
+ for(n = j->n; n; n = n->next){ | |
+ if(tflag){ | |
+ if(!(n->flags&VIRTUAL)) | |
+ touch(n->name); | |
+ else if(explain) | |
+ Bprint(&bout, "no touch of virtual '%s… | |
+ } | |
+ n->time = time((long *)0); | |
+ MADESET(n, MADE); | |
+ } | |
+ } else { | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "recipe='%s'", j->r->recipe);/**/ | |
+ Bflush(&bout); | |
+ if(j->r->attr&NOMINUSE) | |
+ flags = 0; | |
+ else | |
+ flags = "-e"; | |
+ events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->she… | |
+ usage(); | |
+ nrunning++; | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '),… | |
+ } | |
+} | |
+ | |
+int | |
+waitup(int echildok, int *retstatus) | |
+{ | |
+ Envy *e; | |
+ int pid; | |
+ int slot; | |
+ Symtab *s; | |
+ Word *w; | |
+ Job *j; | |
+ char buf[ERRMAX]; | |
+ Bufblock *bp; | |
+ int uarg = 0; | |
+ int done; | |
+ Node *n; | |
+ Process *p; | |
+ extern int runerrs; | |
+ | |
+ /* first check against the proces slist */ | |
+ if(retstatus) | |
+ for(p = phead; p; p = p->f) | |
+ if(p->pid == *retstatus){ | |
+ *retstatus = p->status; | |
+ pdelete(p); | |
+ return(-1); | |
+ } | |
+again: /* rogue processes */ | |
+ pid = waitfor(buf); | |
+ if(pid == -1){ | |
+ if(echildok > 0) | |
+ return(1); | |
+ else { | |
+ fprint(2, "mk: (waitup %d): %r\n", echildok); | |
+ Exit(); | |
+ } | |
+ } | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); | |
+ if(retstatus && pid == *retstatus){ | |
+ *retstatus = buf[0]? 1:0; | |
+ return(-1); | |
+ } | |
+ slot = pidslot(pid); | |
+ if(slot < 0){ | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(2, "mk: wait returned unexpected process %d\n",… | |
+ pnew(pid, buf[0]? 1:0); | |
+ goto again; | |
+ } | |
+ j = events[slot].job; | |
+ usage(); | |
+ nrunning--; | |
+ events[slot].pid = -1; | |
+ if(buf[0]){ | |
+ e = buildenv(j, slot); | |
+ bp = newbuf(); | |
+ shprint(j->r->recipe, e, bp, j->r->shellt); | |
+ front(bp->start); | |
+ fprint(2, "mk: %s: exit status=%s", bp->start, buf); | |
+ freebuf(bp); | |
+ for(n = j->n, done = 0; n; n = n->next) | |
+ if(n->flags&DELETE){ | |
+ if(done++ == 0) | |
+ fprint(2, ", deleting"); | |
+ fprint(2, " '%s'", n->name); | |
+ delete(n->name); | |
+ } | |
+ fprint(2, "\n"); | |
+ if(kflag){ | |
+ runerrs++; | |
+ uarg = 1; | |
+ } else { | |
+ jobs = 0; | |
+ Exit(); | |
+ } | |
+ } | |
+ for(w = j->t; w; w = w->next){ | |
+ if((s = symlook(w->s, S_NODE, 0)) == 0) | |
+ continue; /* not interested in this node */ | |
+ update(uarg, s->u.ptr); | |
+ } | |
+ if(nrunning < nproclimit) | |
+ sched(); | |
+ return(0); | |
+} | |
+ | |
+void | |
+nproc(void) | |
+{ | |
+ Symtab *sym; | |
+ Word *w; | |
+ | |
+ if(sym = symlook("NPROC", S_VAR, 0)) { | |
+ w = sym->u.ptr; | |
+ if (w && w->s && w->s[0]) | |
+ nproclimit = atoi(w->s); | |
+ } | |
+ if(nproclimit < 1) | |
+ nproclimit = 1; | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "nprocs = %d\n", nproclimit); | |
+ if(nproclimit > nevents){ | |
+ if(nevents) | |
+ events = (Event *)Realloc((char *)events, nproclimit*s… | |
+ else | |
+ events = (Event *)Malloc(nproclimit*sizeof(Event)); | |
+ while(nevents < nproclimit) | |
+ events[nevents++].pid = 0; | |
+ } | |
+} | |
+ | |
+int | |
+nextslot(void) | |
+{ | |
+ int i; | |
+ | |
+ for(i = 0; i < nproclimit; i++) | |
+ if(events[i].pid <= 0) return i; | |
+ assert("out of slots!!", 0); | |
+ return 0; /* cyntax */ | |
+} | |
+ | |
+int | |
+pidslot(int pid) | |
+{ | |
+ int i; | |
+ | |
+ for(i = 0; i < nevents; i++) | |
+ if(events[i].pid == pid) return(i); | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(2, "mk: wait returned unexpected process %d\n", pid); | |
+ return(-1); | |
+} | |
+ | |
+ | |
+static void | |
+pnew(int pid, int status) | |
+{ | |
+ Process *p; | |
+ | |
+ if(pfree){ | |
+ p = pfree; | |
+ pfree = p->f; | |
+ } else | |
+ p = (Process *)Malloc(sizeof(Process)); | |
+ p->pid = pid; | |
+ p->status = status; | |
+ p->f = phead; | |
+ phead = p; | |
+ if(p->f) | |
+ p->f->b = p; | |
+ p->b = 0; | |
+} | |
+ | |
+static void | |
+pdelete(Process *p) | |
+{ | |
+ if(p->f) | |
+ p->f->b = p->b; | |
+ if(p->b) | |
+ p->b->f = p->f; | |
+ else | |
+ phead = p->f; | |
+ p->f = pfree; | |
+ pfree = p; | |
+} | |
+ | |
+void | |
+killchildren(char *msg) | |
+{ | |
+ Process *p; | |
+ | |
+ kflag = 1; /* to make sure waitup doesn't exit */ | |
+ jobs = 0; /* make sure no more get scheduled */ | |
+ for(p = phead; p; p = p->f) | |
+ expunge(p->pid, msg); | |
+ while(waitup(1, (int *)0) == 0) | |
+ ; | |
+ Bprint(&bout, "mk: %s\n", msg); | |
+ Exit(); | |
+} | |
+ | |
+static long tslot[1000]; | |
+static long tick; | |
+ | |
+void | |
+usage(void) | |
+{ | |
+ long t; | |
+ | |
+ time(&t); | |
+ if(tick) | |
+ tslot[nrunning] += (t-tick); | |
+ tick = t; | |
+} | |
+ | |
+void | |
+prusage(void) | |
+{ | |
+ int i; | |
+ | |
+ usage(); | |
+ for(i = 0; i <= nevents; i++) | |
+ fprint(1, "%d: %ld\n", i, tslot[i]); | |
+} | |
diff --git a/mk/sh.c b/mk/sh.c | |
@@ -0,0 +1,206 @@ | |
+#include "mk.h" | |
+ | |
+/* | |
+ * This file contains functions that depend on the shell's syntax. Most | |
+ * of the routines extract strings observing the shell's escape convent… | |
+ */ | |
+ | |
+ | |
+/* | |
+ * skip a token in quotes. | |
+ */ | |
+static char * | |
+squote(char *cp, int c) | |
+{ | |
+ Rune r; | |
+ int n; | |
+ | |
+ while(*cp){ | |
+ n = chartorune(&r, cp); | |
+ if(r == c) | |
+ return cp; | |
+ if(r == '\\') | |
+ n += chartorune(&r, cp+n); | |
+ cp += n; | |
+ } | |
+ SYNERR(-1); /* should never occur */ | |
+ fprint(2, "missing closing '\n"); | |
+ return 0; | |
+} | |
+/* | |
+ * search a string for unescaped characters in a pattern set | |
+ */ | |
+static char * | |
+shcharin(char *cp, char *pat) | |
+{ | |
+ Rune r; | |
+ int n, vargen; | |
+ | |
+ vargen = 0; | |
+ while(*cp){ | |
+ n = chartorune(&r, cp); | |
+ switch(r){ | |
+ case '\\': /* skip escaped char */ | |
+ cp += n; | |
+ n = chartorune(&r, cp); | |
+ break; | |
+ case '\'': /* skip quoted string */ | |
+ case '"': | |
+ cp = squote(cp+1, r); /* n must = 1 */ | |
+ if(!cp) | |
+ return 0; | |
+ break; | |
+ case '$': | |
+ if(*(cp+1) == '{') | |
+ vargen = 1; | |
+ break; | |
+ case '}': | |
+ if(vargen) | |
+ vargen = 0; | |
+ else if(utfrune(pat, r)) | |
+ return cp; | |
+ break; | |
+ default: | |
+ if(vargen == 0 && utfrune(pat, r)) | |
+ return cp; | |
+ break; | |
+ } | |
+ cp += n; | |
+ } | |
+ if(vargen){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing closing } in pattern generator\n"); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * extract an escaped token. Possible escape chars are single-quote, | |
+ * double-quote,and backslash. | |
+ */ | |
+static char* | |
+shexpandquote(char *s, Rune esc, Bufblock *b) | |
+{ | |
+ Rune r; | |
+ | |
+ if (esc == '\\') { | |
+ s += chartorune(&r, s); | |
+ rinsert(b, r); | |
+ return s; | |
+ } | |
+ | |
+ while(*s){ | |
+ s += chartorune(&r, s); | |
+ if(r == esc) | |
+ return s; | |
+ if (r == '\\') { | |
+ rinsert(b, r); | |
+ s += chartorune(&r, s); | |
+ } | |
+ rinsert(b, r); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * Input an escaped token. Possible escape chars are single-quote, | |
+ * double-quote and backslash. | |
+ */ | |
+static int | |
+shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) | |
+{ | |
+ int c, line; | |
+ | |
+ if(esc == '\\') { | |
+ c = Bgetrune(bp); | |
+ if(c == '\r') | |
+ c = Bgetrune(bp); | |
+ if (c == '\n') | |
+ mkinline++; | |
+ rinsert(buf, c); | |
+ return 1; | |
+ } | |
+ | |
+ line = mkinline; | |
+ while((c = nextrune(bp, 0)) >= 0){ | |
+ if(c == esc){ | |
+ if(preserve) | |
+ rinsert(buf, c); | |
+ return 1; | |
+ } | |
+ if(c == '\\') { | |
+ rinsert(buf, c); | |
+ c = Bgetrune(bp); | |
+ if(c == '\r') | |
+ c = Bgetrune(bp); | |
+ if (c < 0) | |
+ break; | |
+ if (c == '\n') | |
+ mkinline++; | |
+ } | |
+ rinsert(buf, c); | |
+ } | |
+ SYNERR(line); fprint(2, "missing closing %c\n", esc); | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * copy a quoted string; s points to char after opening quote | |
+ */ | |
+static char * | |
+copysingle(char *s, Rune q, Bufblock *buf) | |
+{ | |
+ Rune r; | |
+ | |
+ while(*s){ | |
+ s += chartorune(&r, s); | |
+ rinsert(buf, r); | |
+ if(r == q) | |
+ break; | |
+ } | |
+ return s; | |
+} | |
+/* | |
+ * check for quoted strings. backquotes are handled here; single quote… | |
+ * s points to char after opening quote, q. | |
+ */ | |
+static char * | |
+shcopyq(char *s, Rune q, Bufblock *buf) | |
+{ | |
+ if(q == '\'' || q == '"') /* copy quoted string */ | |
+ return copysingle(s, q, buf); | |
+ | |
+ if(q != '`') /* not quoted */ | |
+ return s; | |
+ | |
+ while(*s){ /* copy backquoted string */ | |
+ s += chartorune(&q, s); | |
+ rinsert(buf, q); | |
+ if(q == '`') | |
+ break; | |
+ if(q == '\'' || q == '"') | |
+ s = copysingle(s, q, buf); /* copy quoted strin… | |
+ } | |
+ return s; | |
+} | |
+ | |
+static int | |
+shmatchname(char *name) | |
+{ | |
+ USED(name); | |
+ | |
+ return 1; | |
+} | |
+ | |
+ | |
+Shell shshell = { | |
+ "sh", | |
+ "\"'= \t", /*used in parse.c to isolate assignment attribute*/ | |
+ ' ', /* inter-word separator in env */ | |
+ shcharin, | |
+ shexpandquote, | |
+ shescapetoken, | |
+ shcopyq, | |
+ shmatchname | |
+}; | |
+ | |
diff --git a/mk/shell.c b/mk/shell.c | |
@@ -0,0 +1,80 @@ | |
+#include "mk.h" | |
+ | |
+static Shell *shells[] = { | |
+ &rcshell, | |
+ &shshell | |
+}; | |
+ | |
+Shell *shelldefault = &shshell; | |
+ | |
+Shell *shellt; | |
+Word *shellcmd; | |
+ | |
+typedef struct Shellstack Shellstack; | |
+struct Shellstack | |
+{ | |
+ Shell *t; | |
+ Word *w; | |
+ Shellstack *next; | |
+}; | |
+ | |
+Shellstack *shellstack; | |
+ | |
+char* | |
+setshell(Word *w) | |
+{ | |
+ int i; | |
+ | |
+ if(w->s == nil) | |
+ return "shell name not found on line"; | |
+ | |
+ for(i=0; i<nelem(shells); i++) | |
+ if(shells[i]->matchname(w->s)) | |
+ break; | |
+ if(i == nelem(shells)) | |
+ return "cannot determine shell type"; | |
+ shellt = shells[i]; | |
+ shellcmd = w; | |
+ return nil; | |
+} | |
+ | |
+void | |
+initshell(void) | |
+{ | |
+ shellcmd = stow(shelldefault->name); | |
+ shellt = shelldefault; | |
+ setvar("MKSHELL", shellcmd); | |
+} | |
+ | |
+void | |
+pushshell(void) | |
+{ | |
+ Shellstack *s; | |
+ | |
+ /* save */ | |
+ s = Malloc(sizeof *s); | |
+ s->t = shellt; | |
+ s->w = shellcmd; | |
+ s->next = shellstack; | |
+ shellstack = s; | |
+ | |
+ initshell(); /* reset to defaults */ | |
+} | |
+ | |
+void | |
+popshell(void) | |
+{ | |
+ Shellstack *s; | |
+ | |
+ if(shellstack == nil){ | |
+ fprint(2, "internal shellstack error\n"); | |
+ Exit(); | |
+ } | |
+ | |
+ s = shellstack; | |
+ shellstack = s->next; | |
+ shellt = s->t; | |
+ shellcmd = s->w; | |
+ setvar("MKSHELL", shellcmd); | |
+ free(s); | |
+} | |
diff --git a/mk/shprint.c b/mk/shprint.c | |
@@ -0,0 +1,125 @@ | |
+#include "mk.h" | |
+ | |
+static char *vexpand(char*, Envy*, Bufblock*); | |
+ | |
+#define getfields mkgetfields | |
+ | |
+static int | |
+getfields(char *str, char **args, int max, int mflag, char *set) | |
+{ | |
+ Rune r; | |
+ int nr, intok, narg; | |
+ | |
+ if(max <= 0) | |
+ return 0; | |
+ | |
+ narg = 0; | |
+ args[narg] = str; | |
+ if(!mflag) | |
+ narg++; | |
+ intok = 0; | |
+ for(;; str += nr) { | |
+ nr = chartorune(&r, str); | |
+ if(r == 0) | |
+ break; | |
+ if(utfrune(set, r)) { | |
+ if(narg >= max) | |
+ break; | |
+ *str = 0; | |
+ intok = 0; | |
+ args[narg] = str + nr; | |
+ if(!mflag) | |
+ narg++; | |
+ } else { | |
+ if(!intok && mflag) | |
+ narg++; | |
+ intok = 1; | |
+ } | |
+ } | |
+ return narg; | |
+} | |
+ | |
+void | |
+shprint(char *s, Envy *env, Bufblock *buf, Shell *sh) | |
+{ | |
+ int n; | |
+ Rune r; | |
+ | |
+ while(*s) { | |
+ n = chartorune(&r, s); | |
+ if (r == '$') | |
+ s = vexpand(s, env, buf); | |
+ else { | |
+ rinsert(buf, r); | |
+ s += n; | |
+ s = sh->copyq(s, r, buf); /*handle quoted strin… | |
+ } | |
+ } | |
+ insert(buf, 0); | |
+} | |
+ | |
+static char * | |
+mygetenv(char *name, Envy *env) | |
+{ | |
+ if (!env) | |
+ return 0; | |
+ if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == … | |
+ return 0; | |
+ /* only resolve internal variables and variables we've set */ | |
+ for(; env->name; env++){ | |
+ if (strcmp(env->name, name) == 0) | |
+ return wtos(env->values, ' '); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static char * | |
+vexpand(char *w, Envy *env, Bufblock *buf) | |
+{ | |
+ char *s, carry, *p, *q; | |
+ | |
+ assert("vexpand no $", *w == '$'); | |
+ p = w+1; /* skip dollar sign */ | |
+ if(*p == '{') { | |
+ p++; | |
+ q = utfrune(p, '}'); | |
+ if (!q) | |
+ q = strchr(p, 0); | |
+ } else | |
+ q = shname(p); | |
+ carry = *q; | |
+ *q = 0; | |
+ s = mygetenv(p, env); | |
+ *q = carry; | |
+ if (carry == '}') | |
+ q++; | |
+ if (s) { | |
+ bufcpy(buf, s, strlen(s)); | |
+ free(s); | |
+ } else /* copy name intact*/ | |
+ bufcpy(buf, w, q-w); | |
+ return(q); | |
+} | |
+ | |
+void | |
+front(char *s) | |
+{ | |
+ char *t, *q; | |
+ int i, j; | |
+ char *flds[512]; | |
+ | |
+ q = strdup(s); | |
+ i = getfields(q, flds, 512, 0, " \t\n"); | |
+ if(i > 5){ | |
+ flds[4] = flds[i-1]; | |
+ flds[3] = "..."; | |
+ i = 5; | |
+ } | |
+ t = s; | |
+ for(j = 0; j < i; j++){ | |
+ for(s = flds[j]; *s; *t++ = *s++); | |
+ *t++ = ' '; | |
+ } | |
+ *t = 0; | |
+ free(q); | |
+} | |
diff --git a/mk/symtab.c b/mk/symtab.c | |
@@ -0,0 +1,97 @@ | |
+#include "mk.h" | |
+ | |
+#define NHASH 4099 | |
+#define HASHMUL 79L /* this is a good value */ | |
+static Symtab *hash[NHASH]; | |
+ | |
+void | |
+syminit(void) | |
+{ | |
+ Symtab **s, *ss, *next; | |
+ | |
+ for(s = hash; s < &hash[NHASH]; s++){ | |
+ for(ss = *s; ss; ss = next){ | |
+ next = ss->next; | |
+ free((char *)ss); | |
+ } | |
+ *s = 0; | |
+ } | |
+} | |
+ | |
+Symtab * | |
+symlook(char *sym, int space, void *install) | |
+{ | |
+ long h; | |
+ char *p; | |
+ Symtab *s; | |
+ | |
+ for(p = sym, h = space; *p; h += *p++) | |
+ h *= HASHMUL; | |
+ if(h < 0) | |
+ h = ~h; | |
+ h %= NHASH; | |
+ for(s = hash[h]; s; s = s->next) | |
+ if((s->space == space) && (strcmp(s->name, sym) == 0)) | |
+ return(s); | |
+ if(install == 0) | |
+ return(0); | |
+ s = (Symtab *)Malloc(sizeof(Symtab)); | |
+ s->space = space; | |
+ s->name = sym; | |
+ s->u.ptr = install; | |
+ s->next = hash[h]; | |
+ hash[h] = s; | |
+ return(s); | |
+} | |
+ | |
+void | |
+symdel(char *sym, int space) | |
+{ | |
+ long h; | |
+ char *p; | |
+ Symtab *s, *ls; | |
+ | |
+ /* multiple memory leaks */ | |
+ | |
+ for(p = sym, h = space; *p; h += *p++) | |
+ h *= HASHMUL; | |
+ if(h < 0) | |
+ h = ~h; | |
+ h %= NHASH; | |
+ for(s = hash[h], ls = 0; s; ls = s, s = s->next) | |
+ if((s->space == space) && (strcmp(s->name, sym) == 0)){ | |
+ if(ls) | |
+ ls->next = s->next; | |
+ else | |
+ hash[h] = s->next; | |
+ free((char *)s); | |
+ } | |
+} | |
+ | |
+void | |
+symtraverse(int space, void (*fn)(Symtab*)) | |
+{ | |
+ Symtab **s, *ss; | |
+ | |
+ for(s = hash; s < &hash[NHASH]; s++) | |
+ for(ss = *s; ss; ss = ss->next) | |
+ if(ss->space == space) | |
+ (*fn)(ss); | |
+} | |
+ | |
+void | |
+symstat(void) | |
+{ | |
+ Symtab **s, *ss; | |
+ int n; | |
+ int l[1000]; | |
+ | |
+ memset((char *)l, 0, sizeof(l)); | |
+ for(s = hash; s < &hash[NHASH]; s++){ | |
+ for(ss = *s, n = 0; ss; ss = ss->next) | |
+ n++; | |
+ l[n]++; | |
+ } | |
+ for(n = 0; n < 1000; n++) | |
+ if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n); | |
+} | |
diff --git a/mk/sys.h b/mk/sys.h | |
@@ -0,0 +1,5 @@ | |
+#include <u.h> | |
+#include <libc.h> | |
+#include <bio.h> | |
+#include <regexp.h> | |
+ | |
diff --git a/mk/sys.std.h b/mk/sys.std.h | |
@@ -0,0 +1,27 @@ | |
+#include <utf.h> | |
+#include <fmt.h> | |
+#include <bio.h> | |
+#include <regexp9.h> | |
+#include <stdlib.h> | |
+#include <unistd.h> | |
+#include <fcntl.h> | |
+#include <string.h> | |
+#include <ctype.h> | |
+#include <time.h> | |
+#include <stdint.h> | |
+ | |
+#define OREAD O_RDONLY | |
+#define OWRITE O_WRONLY | |
+#define ORDWR O_RDWR | |
+#define nil 0 | |
+#define nelem(x) (sizeof(x)/sizeof((x)[0])) | |
+#define seek lseek | |
+#define remove unlink | |
+#define exits(x) exit(x && *(char*)x ? 1 : 0) | |
+#define USED(x) if(x){}else | |
+#define create(name, mode, perm) open(name, mode|O_CREAT, perm) | |
+#define ERRMAX 256 | |
+ | |
+typedef uintptr_t uintptr; | |
+#define uchar mk_uchar | |
+typedef unsigned char uchar; | |
diff --git a/mk/unix.c b/mk/unix.c | |
@@ -0,0 +1,341 @@ | |
+#define NOPLAN9DEFINES | |
+#include "mk.h" | |
+#include <sys/wait.h> | |
+#include <signal.h> | |
+#include <sys/stat.h> | |
+#include <sys/time.h> | |
+ | |
+char *shell = "/bin/sh"; | |
+char *shellname = "sh"; | |
+ | |
+extern char **environ; | |
+ | |
+static void | |
+mkperror(char *s) | |
+{ | |
+ fprint(2, "%s: %r\n", s); | |
+} | |
+ | |
+void | |
+readenv(void) | |
+{ | |
+ char **p, *s; | |
+ Word *w; | |
+ | |
+ for(p = environ; *p; p++){ | |
+/* rsc 5/5/2004 -- This misparses fn#cd={whatever} | |
+ s = shname(*p); | |
+ if(*s == '=') { | |
+ *s = 0; | |
+ w = newword(s+1); | |
+ } else | |
+ w = newword(""); | |
+*/ | |
+ s = strchr(*p, '='); | |
+ if(s){ | |
+ *s = 0; | |
+ w = newword(s+1); | |
+ } else | |
+ w = newword(""); | |
+ if (symlook(*p, S_INTERNAL, 0)) | |
+ continue; | |
+ s = strdup(*p); | |
+ setvar(s, (void *)w); | |
+ symlook(s, S_EXPORTED, (void*)"")->u.ptr = ""; | |
+ } | |
+} | |
+ | |
+/* | |
+ * done on child side of fork, so parent's env is not affected | |
+ * and we don't care about freeing memory because we're going | |
+ * to exec immediately after this. | |
+ */ | |
+void | |
+exportenv(Envy *e, Shell *sh) | |
+{ | |
+ int i; | |
+ char **p; | |
+ static char buf[16384]; | |
+ | |
+ p = 0; | |
+ for(i = 0; e->name; e++, i++) { | |
+ p = (char**) Realloc(p, (i+2)*sizeof(char*)); | |
+ if(e->values) | |
+ snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->va… | |
+ else | |
+ snprint(buf, sizeof buf, "%s=", e->name); | |
+ p[i] = strdup(buf); | |
+ } | |
+ p[i] = 0; | |
+ environ = p; | |
+} | |
+ | |
+int | |
+waitfor(char *msg) | |
+{ | |
+ int status; | |
+ int pid; | |
+ | |
+ *msg = 0; | |
+ pid = wait(&status); | |
+ if(pid > 0) { | |
+ if(status&0x7f) { | |
+ if(status&0x80) | |
+ snprint(msg, ERRMAX, "signal %d, core dumped",… | |
+ else | |
+ snprint(msg, ERRMAX, "signal %d", status&0x7f); | |
+ } else if(status&0xff00) | |
+ snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff); | |
+ } | |
+ return pid; | |
+} | |
+ | |
+void | |
+expunge(int pid, char *msg) | |
+{ | |
+ if(strcmp(msg, "interrupt")) | |
+ kill(pid, SIGINT); | |
+ else | |
+ kill(pid, SIGHUP); | |
+} | |
+ | |
+int mypid; | |
+ | |
+int | |
+shargv(Word *cmd, int extra, char ***pargv) | |
+{ | |
+ char **argv; | |
+ int i, n; | |
+ Word *w; | |
+ | |
+ n = 0; | |
+ for(w=cmd; w; w=w->next) | |
+ n++; | |
+ | |
+ argv = Malloc((n+extra+1)*sizeof(argv[0])); | |
+ i = 0; | |
+ for(w=cmd; w; w=w->next) | |
+ argv[i++] = w->s; | |
+ argv[n] = 0; | |
+ *pargv = argv; | |
+ return n; | |
+} | |
+ | |
+int | |
+execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcm… | |
+{ | |
+ char *p, **argv; | |
+ int tot, n, pid, in[2], out[2]; | |
+ | |
+ if(buf && pipe(out) < 0){ | |
+ mkperror("pipe"); | |
+ Exit(); | |
+ } | |
+ pid = fork(); | |
+ mypid = getpid(); | |
+ if(pid < 0){ | |
+ mkperror("mk fork"); | |
+ Exit(); | |
+ } | |
+ if(pid == 0){ | |
+ if(buf) | |
+ close(out[0]); | |
+ if(pipe(in) < 0){ | |
+ mkperror("pipe"); | |
+ Exit(); | |
+ } | |
+ pid = fork(); | |
+ if(pid < 0){ | |
+ mkperror("mk fork"); | |
+ Exit(); | |
+ } | |
+ if(pid != 0){ | |
+ dup2(in[0], 0); | |
+ if(buf){ | |
+ dup2(out[1], 1); | |
+ close(out[1]); | |
+ } | |
+ close(in[0]); | |
+ close(in[1]); | |
+ if (e) | |
+ exportenv(e, sh); | |
+ n = shargv(shellcmd, 1, &argv); | |
+ argv[n++] = args; | |
+ argv[n] = 0; | |
+ execvp(argv[0], argv); | |
+ mkperror(shell); | |
+ _exit(1); | |
+ } | |
+ close(out[1]); | |
+ close(in[0]); | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "starting: %s\n", cmd); | |
+ p = cmd+strlen(cmd); | |
+ while(cmd < p){ | |
+ n = write(in[1], cmd, p-cmd); | |
+ if(n < 0) | |
+ break; | |
+ cmd += n; | |
+ } | |
+ close(in[1]); | |
+ _exit(0); | |
+ } | |
+ if(buf){ | |
+ close(out[1]); | |
+ tot = 0; | |
+ for(;;){ | |
+ if (buf->current >= buf->end) | |
+ growbuf(buf); | |
+ n = read(out[0], buf->current, buf->end-buf->current); | |
+ if(n <= 0) | |
+ break; | |
+ buf->current += n; | |
+ tot += n; | |
+ } | |
+ if (tot && buf->current[-1] == '\n') | |
+ buf->current--; | |
+ close(out[0]); | |
+ } | |
+ return pid; | |
+} | |
+ | |
+int | |
+pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd) | |
+{ | |
+ int pid, pfd[2]; | |
+ int n; | |
+ char **argv; | |
+ | |
+ if(DEBUG(D_EXEC)) | |
+ fprint(1, "pipecmd='%s'\n", cmd);/**/ | |
+ | |
+ if(fd && pipe(pfd) < 0){ | |
+ mkperror("pipe"); | |
+ Exit(); | |
+ } | |
+ pid = fork(); | |
+ if(pid < 0){ | |
+ mkperror("mk fork"); | |
+ Exit(); | |
+ } | |
+ if(pid == 0){ | |
+ if(fd){ | |
+ close(pfd[0]); | |
+ dup2(pfd[1], 1); | |
+ close(pfd[1]); | |
+ } | |
+ if(e) | |
+ exportenv(e, sh); | |
+ n = shargv(shellcmd, 2, &argv); | |
+ argv[n++] = "-c"; | |
+ argv[n++] = cmd; | |
+ argv[n] = 0; | |
+ execvp(argv[0], argv); | |
+ mkperror(shell); | |
+ _exit(1); | |
+ } | |
+ if(fd){ | |
+ close(pfd[1]); | |
+ *fd = pfd[0]; | |
+ } | |
+ return pid; | |
+} | |
+ | |
+void | |
+Exit(void) | |
+{ | |
+ while(wait(0) >= 0) | |
+ ; | |
+ exits("error"); | |
+} | |
+ | |
+static struct | |
+{ | |
+ int sig; | |
+ char *msg; | |
+} sigmsgs[] = | |
+{ | |
+ SIGALRM, "alarm", | |
+ SIGFPE, "sys: fp: fptrap", | |
+ SIGPIPE, "sys: write on closed pipe", | |
+ SIGILL, "sys: trap: illegal instruction", | |
+/* SIGSEGV, "sys: segmentation violation", */ | |
+ 0, 0 | |
+}; | |
+ | |
+static void | |
+notifyf(int sig) | |
+{ | |
+ int i; | |
+ | |
+ for(i = 0; sigmsgs[i].msg; i++) | |
+ if(sigmsgs[i].sig == sig) | |
+ killchildren(sigmsgs[i].msg); | |
+ | |
+ /* should never happen */ | |
+ signal(sig, SIG_DFL); | |
+ kill(getpid(), sig); | |
+} | |
+ | |
+void | |
+catchnotes(void) | |
+{ | |
+ int i; | |
+ | |
+ for(i = 0; sigmsgs[i].msg; i++) | |
+ signal(sigmsgs[i].sig, notifyf); | |
+} | |
+ | |
+char* | |
+maketmp(int *pfd) | |
+{ | |
+ static char temp[] = "/tmp/mkargXXXXXX"; | |
+ static char buf[100]; | |
+ int fd; | |
+ | |
+ strcpy(buf, temp); | |
+ fd = mkstemp(buf); | |
+ if(fd < 0) | |
+ return 0; | |
+ *pfd = fd; | |
+ return buf; | |
+} | |
+ | |
+int | |
+chgtime(char *name) | |
+{ | |
+ if(access(name, 0) >= 0) | |
+ return utimes(name, 0); | |
+ return close(creat(name, 0666)); | |
+} | |
+ | |
+void | |
+rcopy(char **to, Resub *match, int n) | |
+{ | |
+ int c; | |
+ char *p; | |
+ | |
+ *to = match->s.sp; /* stem0 matches complete target */ | |
+ for(to++, match++; --n > 0; to++, match++){ | |
+ if(match->s.sp && match->e.ep){ | |
+ p = match->e.ep; | |
+ c = *p; | |
+ *p = 0; | |
+ *to = strdup(match->s.sp); | |
+ *p = c; | |
+ } | |
+ else | |
+ *to = 0; | |
+ } | |
+} | |
+ | |
+unsigned long | |
+mkmtime(char *name) | |
+{ | |
+ struct stat st; | |
+ | |
+ if(stat(name, &st) < 0) | |
+ return 0; | |
+ | |
+ return st.st_mtime; | |
+} | |
diff --git a/mk/var.c b/mk/var.c | |
@@ -0,0 +1,41 @@ | |
+#include "mk.h" | |
+ | |
+void | |
+setvar(char *name, void *ptr) | |
+{ | |
+ symlook(name, S_VAR, ptr)->u.ptr = ptr; | |
+ symlook(name, S_MAKEVAR, (void*)""); | |
+} | |
+ | |
+static void | |
+print1(Symtab *s) | |
+{ | |
+ Word *w; | |
+ | |
+ Bprint(&bout, "\t%s=", s->name); | |
+ for (w = s->u.ptr; w; w = w->next) | |
+ Bprint(&bout, "'%s'", w->s); | |
+ Bprint(&bout, "\n"); | |
+} | |
+ | |
+void | |
+dumpv(char *s) | |
+{ | |
+ Bprint(&bout, "%s:\n", s); | |
+ symtraverse(S_VAR, print1); | |
+} | |
+ | |
+char * | |
+shname(char *a) | |
+{ | |
+ Rune r; | |
+ int n; | |
+ | |
+ while (*a) { | |
+ n = chartorune(&r, a); | |
+ if (!WORDCHR(r)) | |
+ break; | |
+ a += n; | |
+ } | |
+ return a; | |
+} | |
diff --git a/mk/varsub.c b/mk/varsub.c | |
@@ -0,0 +1,252 @@ | |
+#include "mk.h" | |
+ | |
+static Word *subsub(Word*, char*, char*); | |
+static Word *expandvar(char**); | |
+static Bufblock *varname(char**); | |
+static Word *extractpat(char*, char**, char*, char*); | |
+static int submatch(char*, Word*, Word*, int*, char**); | |
+static Word *varmatch(char *); | |
+ | |
+Word * | |
+varsub(char **s) | |
+{ | |
+ Bufblock *b; | |
+ Word *w; | |
+ | |
+ if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/ | |
+ return expandvar(s); | |
+ | |
+ b = varname(s); | |
+ if(b == 0) | |
+ return 0; | |
+ | |
+ w = varmatch(b->start); | |
+ freebuf(b); | |
+ return w; | |
+} | |
+ | |
+/* | |
+ * extract a variable name | |
+ */ | |
+static Bufblock* | |
+varname(char **s) | |
+{ | |
+ Bufblock *b; | |
+ char *cp; | |
+ Rune r; | |
+ int n; | |
+ | |
+ b = newbuf(); | |
+ cp = *s; | |
+ for(;;){ | |
+ n = chartorune(&r, cp); | |
+ if (!WORDCHR(r)) | |
+ break; | |
+ rinsert(b, r); | |
+ cp += n; | |
+ } | |
+ if (b->current == b->start){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing variable name <%s>\n", *s); | |
+ freebuf(b); | |
+ return 0; | |
+ } | |
+ *s = cp; | |
+ insert(b, 0); | |
+ return b; | |
+} | |
+ | |
+static Word* | |
+varmatch(char *name) | |
+{ | |
+ Word *w; | |
+ Symtab *sym; | |
+ | |
+ sym = symlook(name, S_VAR, 0); | |
+ if(sym){ | |
+ /* check for at least one non-NULL value */ | |
+ for (w = sym->u.ptr; w; w = w->next) | |
+ if(w->s && *w->s) | |
+ return wdup(w); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static Word* | |
+expandvar(char **s) | |
+{ | |
+ Word *w; | |
+ Bufblock *buf; | |
+ Symtab *sym; | |
+ char *cp, *begin, *end; | |
+ | |
+ begin = *s; | |
+ (*s)++; /* skip the '{'… | |
+ buf = varname(s); | |
+ if (buf == 0) | |
+ return 0; | |
+ cp = *s; | |
+ if (*cp == '}') { /* ${name} variant*/ | |
+ (*s)++; /* skip the '}'… | |
+ w = varmatch(buf->start); | |
+ freebuf(buf); | |
+ return w; | |
+ } | |
+ if (*cp != ':') { | |
+ SYNERR(-1); | |
+ fprint(2, "bad variable name <%s>\n", buf->start); | |
+ freebuf(buf); | |
+ return 0; | |
+ } | |
+ cp++; | |
+ end = shellt->charin(cp , "}"); | |
+ if(end == 0){ | |
+ SYNERR(-1); | |
+ fprint(2, "missing '}': %s\n", begin); | |
+ Exit(); | |
+ } | |
+ *end = 0; | |
+ *s = end+1; | |
+ | |
+ sym = symlook(buf->start, S_VAR, 0); | |
+ if(sym == 0 || sym->u.ptr == 0) | |
+ w = newword(buf->start); | |
+ else | |
+ w = subsub(sym->u.ptr, cp, end); | |
+ freebuf(buf); | |
+ return w; | |
+} | |
+ | |
+static Word* | |
+extractpat(char *s, char **r, char *term, char *end) | |
+{ | |
+ int save; | |
+ char *cp; | |
+ Word *w; | |
+ | |
+ cp = shellt->charin(s, term); | |
+ if(cp){ | |
+ *r = cp; | |
+ if(cp == s) | |
+ return 0; | |
+ save = *cp; | |
+ *cp = 0; | |
+ w = stow(s); | |
+ *cp = save; | |
+ } else { | |
+ *r = end; | |
+ w = stow(s); | |
+ } | |
+ return w; | |
+} | |
+ | |
+static Word* | |
+subsub(Word *v, char *s, char *end) | |
+{ | |
+ int nmid; | |
+ Word *head, *tail, *w, *h; | |
+ Word *a, *b, *c, *d; | |
+ Bufblock *buf; | |
+ char *cp, *enda; | |
+ | |
+ a = extractpat(s, &cp, "=%&", end); | |
+ b = c = d = 0; | |
+ if(PERCENT(*cp)) | |
+ b = extractpat(cp+1, &cp, "=", end); | |
+ if(*cp == '=') | |
+ c = extractpat(cp+1, &cp, "&%", end); | |
+ if(PERCENT(*cp)) | |
+ d = stow(cp+1); | |
+ else if(*cp) | |
+ d = stow(cp); | |
+ | |
+ head = tail = 0; | |
+ buf = newbuf(); | |
+ for(; v; v = v->next){ | |
+ h = w = 0; | |
+ if(submatch(v->s, a, b, &nmid, &enda)){ | |
+ /* enda points to end of A match in source; | |
+ * nmid = number of chars between end of A and start o… | |
+ */ | |
+ if(c){ | |
+ h = w = wdup(c); | |
+ while(w->next) | |
+ w = w->next; | |
+ } | |
+ if(PERCENT(*cp) && nmid > 0){ | |
+ if(w){ | |
+ bufcpy(buf, w->s, strlen(w->s)); | |
+ bufcpy(buf, enda, nmid); | |
+ insert(buf, 0); | |
+ free(w->s); | |
+ w->s = strdup(buf->start); | |
+ } else { | |
+ bufcpy(buf, enda, nmid); | |
+ insert(buf, 0); | |
+ h = w = newword(buf->start); | |
+ } | |
+ buf->current = buf->start; | |
+ } | |
+ if(d && *d->s){ | |
+ if(w){ | |
+ | |
+ bufcpy(buf, w->s, strlen(w->s)); | |
+ bufcpy(buf, d->s, strlen(d->s)); | |
+ insert(buf, 0); | |
+ free(w->s); | |
+ w->s = strdup(buf->start); | |
+ w->next = wdup(d->next); | |
+ while(w->next) | |
+ w = w->next; | |
+ buf->current = buf->start; | |
+ } else | |
+ h = w = wdup(d); | |
+ } | |
+ } | |
+ if(w == 0) | |
+ h = w = newword(v->s); | |
+ | |
+ if(head == 0) | |
+ head = h; | |
+ else | |
+ tail->next = h; | |
+ tail = w; | |
+ } | |
+ freebuf(buf); | |
+ delword(a); | |
+ delword(b); | |
+ delword(c); | |
+ delword(d); | |
+ return head; | |
+} | |
+ | |
+static int | |
+submatch(char *s, Word *a, Word *b, int *nmid, char **enda) | |
+{ | |
+ Word *w; | |
+ int n; | |
+ char *end; | |
+ | |
+ n = 0; | |
+ for(w = a; w; w = w->next){ | |
+ n = strlen(w->s); | |
+ if(strncmp(s, w->s, n) == 0) | |
+ break; | |
+ } | |
+ if(a && w == 0) /* a == NULL matches everything*/ | |
+ return 0; | |
+ | |
+ *enda = s+n; /* pointer to end a A part match */ | |
+ *nmid = strlen(s)-n; /* size of remainder of source */ | |
+ end = *enda+*nmid; | |
+ for(w = b; w; w = w->next){ | |
+ n = strlen(w->s); | |
+ if(strcmp(w->s, end-n) == 0){ | |
+ *nmid -= n; | |
+ break; | |
+ } | |
+ } | |
+ if(b && w == 0) /* b == NULL matches everything */ | |
+ return 0; | |
+ return 1; | |
+} | |
diff --git a/mk/word.c b/mk/word.c | |
@@ -0,0 +1,189 @@ | |
+#include "mk.h" | |
+ | |
+static Word *nextword(char**); | |
+ | |
+Word* | |
+newword(char *s) | |
+{ | |
+ Word *w; | |
+ | |
+ w = (Word *)Malloc(sizeof(Word)); | |
+ w->s = strdup(s); | |
+ w->next = 0; | |
+ return(w); | |
+} | |
+ | |
+Word * | |
+stow(char *s) | |
+{ | |
+ Word *head, *w, *new; | |
+ | |
+ w = head = 0; | |
+ while(*s){ | |
+ new = nextword(&s); | |
+ if(new == 0) | |
+ break; | |
+ if (w) | |
+ w->next = new; | |
+ else | |
+ head = w = new; | |
+ while(w->next) | |
+ w = w->next; | |
+ | |
+ } | |
+ if (!head) | |
+ head = newword(""); | |
+ return(head); | |
+} | |
+ | |
+char * | |
+wtos(Word *w, int sep) | |
+{ | |
+ Bufblock *buf; | |
+ char *cp; | |
+ | |
+ buf = newbuf(); | |
+ for(; w; w = w->next){ | |
+ for(cp = w->s; *cp; cp++) | |
+ insert(buf, *cp); | |
+ if(w->next) | |
+ insert(buf, sep); | |
+ } | |
+ insert(buf, 0); | |
+ cp = strdup(buf->start); | |
+ freebuf(buf); | |
+ return(cp); | |
+} | |
+ | |
+Word* | |
+wdup(Word *w) | |
+{ | |
+ Word *v, *new, *base; | |
+ | |
+ v = base = 0; | |
+ while(w){ | |
+ new = newword(w->s); | |
+ if(v) | |
+ v->next = new; | |
+ else | |
+ base = new; | |
+ v = new; | |
+ w = w->next; | |
+ } | |
+ return base; | |
+} | |
+ | |
+void | |
+delword(Word *w) | |
+{ | |
+ Word *v; | |
+ | |
+ while(v = w){ | |
+ w = w->next; | |
+ if(v->s) | |
+ free(v->s); | |
+ free(v); | |
+ } | |
+} | |
+ | |
+/* | |
+ * break out a word from a string handling quotes, executions, | |
+ * and variable expansions. | |
+ */ | |
+static Word* | |
+nextword(char **s) | |
+{ | |
+ Bufblock *b; | |
+ Word *head, *tail, *w; | |
+ Rune r; | |
+ char *cp; | |
+ int empty; | |
+ | |
+ cp = *s; | |
+ b = newbuf(); | |
+restart: | |
+ head = tail = 0; | |
+ while(*cp == ' ' || *cp == '\t') /* leading white space… | |
+ cp++; | |
+ empty = 1; | |
+ while(*cp){ | |
+ cp += chartorune(&r, cp); | |
+ switch(r) | |
+ { | |
+ case ' ': | |
+ case '\t': | |
+ case '\n': | |
+ goto out; | |
+ case '\\': | |
+ case '\'': | |
+ case '"': | |
+ empty = 0; | |
+ cp = shellt->expandquote(cp, r, b); | |
+ if(cp == 0){ | |
+ fprint(2, "missing closing quote: %s\n", *s); | |
+ Exit(); | |
+ } | |
+ break; | |
+ case '$': | |
+ w = varsub(&cp); | |
+ if(w == 0){ | |
+ if(empty) | |
+ goto restart; | |
+ break; | |
+ } | |
+ empty = 0; | |
+ if(b->current != b->start){ | |
+ bufcpy(b, w->s, strlen(w->s)); | |
+ insert(b, 0); | |
+ free(w->s); | |
+ w->s = strdup(b->start); | |
+ b->current = b->start; | |
+ } | |
+ if(head){ | |
+ bufcpy(b, tail->s, strlen(tail->s)); | |
+ bufcpy(b, w->s, strlen(w->s)); | |
+ insert(b, 0); | |
+ free(tail->s); | |
+ tail->s = strdup(b->start); | |
+ tail->next = w->next; | |
+ free(w->s); | |
+ free(w); | |
+ b->current = b->start; | |
+ } else | |
+ tail = head = w; | |
+ while(tail->next) | |
+ tail = tail->next; | |
+ break; | |
+ default: | |
+ empty = 0; | |
+ rinsert(b, r); | |
+ break; | |
+ } | |
+ } | |
+out: | |
+ *s = cp; | |
+ if(b->current != b->start){ | |
+ if(head){ | |
+ cp = b->current; | |
+ bufcpy(b, tail->s, strlen(tail->s)); | |
+ bufcpy(b, b->start, cp-b->start); | |
+ insert(b, 0); | |
+ free(tail->s); | |
+ tail->s = strdup(cp); | |
+ } else { | |
+ insert(b, 0); | |
+ head = newword(b->start); | |
+ } | |
+ } | |
+ freebuf(b); | |
+ return head; | |
+} | |
+ | |
+void | |
+dumpw(char *s, Word *w) | |
+{ | |
+ Bprint(&bout, "%s", s); | |
+ for(; w; w = w->next) | |
+ Bprint(&bout, " '%s'", w->s); | |
+ Bputc(&bout, '\n'); | |
+} | |
diff --git a/troff/FIXES b/troff/FIXES | |
@@ -0,0 +1,821 @@ | |
+March 11, 1994 | |
+ | |
+ If we are just plain old nroff (and not doing UNICODE) we should | |
+ only Lookup characters, not Install when we don't know them. | |
+ If we are troff, we Install them anyway | |
+ | |
+March 8, 1994 | |
+ | |
+ Nroff had problems with parsing quoted white space as options or | |
+ character code in some terminals tables. Changed by having scanf | |
+ include white space when necessary as suggested by Rich. | |
+ | |
+March 1, 1994 | |
+ | |
+ Made sanity check for terminal type depending on the trace level; | |
+ trace level set with -tn flag at start up | |
+ | |
+22 Feb, 1994 | |
+ | |
+ More pointer shuffling fixes. | |
+ | |
+18 Feb, 1994 | |
+ | |
+ More disabling of multibyte stuff. Fixed bug in n5.c: casetm didn' | |
+ know about the new format in the fontables. | |
+ | |
+Feb 17, 1994 | |
+ | |
+ Removed extra include <setlocale> from n1.c | |
+ | |
+ Fixed dubious pointer shuffling in n7.c, t10.c & n8.c. Thanks Rich! | |
+ | |
+Feb 10, 1994 | |
+ | |
+ Disabled the multybyte stuff; only plan 9 will get it. | |
+ | |
+Jan 24, 1994 | |
+ | |
+ Fixed nasty bug discovered by td, which caused core dumps on | |
+ \D'l-0.002775i 0i' and apparently all numbers closer to 0 | |
+ than -.002775. Fixed in storeline() and storeword() (n7.c). | |
+ | |
+Dec 16, 1993 | |
+ | |
+ nroff & troff -N were looking for the TYPESETTER variable, causing | |
+ | |
+ troff: cannot open /sys/lib/troff/term/tab.202; line 1, file stdin | |
+ | |
+ fixed my moving getenv("TYPESETTER") to t10.c in t_ptinit(void). | |
+ | |
+Dec 3, 1993: | |
+ | |
+ The sequence \s+2\H'+10' came sometimes out in the wrong order | |
+ (x H before s), so there wasn't a difference bewteen \s+2\H'+10' | |
+ and \H'+10'\s+2. Now the fonts bits of the CHARHT are used to | |
+ register the current pontsize, so we can issue a s10 in t10.c | |
+ if needed. A bit sneaky. | |
+ | |
+ Try to prevent double slashes in path names. Especially under | |
+ plan9 things started to look ugly. | |
+ | |
+ Exception word list now grows dynamic. | |
+ | |
+Nov 30, 1993: | |
+ | |
+ Allow multiple calls to .pi, requested by Rob. | |
+ .pi cat | |
+ .pi dogs | |
+ is now equivalent with | |
+ .pi cat | dogs | |
+ | |
+ | |
+ .ab now takes also optional error code: | |
+ .ab [n] [string] | |
+ If n and string, n is exit code, string is message | |
+ If n, n is exit code, ``User Abort, exit code n" is message | |
+ If !n and string, standard exit code, string is message | |
+ If !n and ! string, standard exit code, "User Abort" is message | |
+ | |
+Nov 24, 1993: | |
+ | |
+ Reordered code to keep the UNASNI scripts happy. | |
+ | |
+ Nroff dumped core reading terminal tables: apparenty under plan 9, | |
+ scanf includes the '\n'; added test for '\0' in parse in n10.c. | |
+ | |
+ Relative tab settings (.ta +1C +2C) didn't work; anding the | |
+ previous value with TABMASK fixes this (caseta). | |
+ | |
+Nov 23, 1993: | |
+ | |
+ Included code, originally done by bwk for plan 9, to handle | |
+ multi-byte characters. | |
+ | |
+Nov 3, 1993: | |
+ | |
+ ``pair internal'' two char names by shifting 16 bits. Will allow | |
+ the use of 16 bit characters sets (Unicode in plan9 etc.) for | |
+ macro's etc. | |
+ | |
+Oct 20, 1993: | |
+ | |
+ Word & line buffers are now dynamic: No more word or line overflow | |
+ unless when we run out of memory. | |
+ | |
+Oct 11, 1993: | |
+ | |
+ lost diversion warning pops up regularly with man macro's. Due | |
+ to a possible macro coding problem. Triggered by something like | |
+ troff -man: | |
+ .TP | |
+ .TP | |
+ foo | |
+ .ex | |
+ Minimal code: | |
+ .di aa | |
+ throw away this diversion (aa) while being defined. | |
+ .rm aa | |
+ .br | |
+ .di | |
+ | |
+ Fixed by disallowing .rm to throw away current diversion. The | |
+ rn request will complain with: | |
+ | |
+ cannot remove diversion aa during definition; etc. | |
+ | |
+Sep 29, 1993: | |
+ | |
+ Some long standing fixes which never went back in the source. | |
+ Thanks to Janet & Rich. | |
+ | |
+Sep 28, 1993: | |
+ | |
+ Changed getach() (n1.c), so it does't consider truncated | |
+ special characters as (8-bit) ascii. STX ETX ENQ ACK and BELL | |
+ are still allowed for the ultimate backwards compatibility. | |
+ | |
+ Some code changes, so real ANSI compilers like the SGI version | |
+ (acc from Sun is a poor excuse for an ANSI compiler) don't | |
+ barf. Some compromises (static Tchar wbuf in n9.c) allowed so | |
+ the unansified stuff for non-ansi compilers (cc on Sun's) will | |
+ work as well. | |
+ | |
+Sep 9, 1993: | |
+ | |
+ Be nice to Gerard. Now also word spaces in .tl and after | |
+ tabs/fleids etc. | |
+ | |
+Aug 12, 1993: | |
+ | |
+ Tabs setting can now be humongous. We also allow 99 tabs to | |
+ accomodate tbl. As a side effect, NTM buffers are now 1K | |
+ | |
+Aug 11, 1993: | |
+ | |
+ .R register, now contains maximum number of addessable | |
+ registers minus the number actually used. | |
+ | |
+ Small esthetic changes in error messages; removed a statement | |
+ which wasn't reached anyway. | |
+ | |
+Aug 10, 1993: | |
+ | |
+ Some more speed hacks: be smarter doing the linear table | |
+ lookups in alloc() and finds(). | |
+ | |
+ The real name of the det diversion size macro is now gd. | |
+ | |
+Aug 9, 1993: | |
+ | |
+ A much faster way to find the end of a string/macro, by | |
+ remembering that when defined. | |
+ | |
+Aug 6, 1993: | |
+ | |
+ Slightly more eficient way of skipping to the end of a | |
+ string/macro | |
+ | |
+Aug 5, 1993: | |
+ | |
+ Prevent character sign extension for 8-bit charnames diversions | |
+ etc. by unpair | |
+ | |
+Aug 4, 1993: | |
+ | |
+ Growing the dynamical macro/strings name space and registers | |
+ space (See the experiment of 21 July) now with bigger | |
+ increments. Casts added to satisfy non-ANSI compilers. | |
+ | |
+Aug 3, 1993: | |
+ | |
+ Should check return value in alloc (n3.c), to prevent core dump | |
+ when memory gets tight. | |
+ | |
+July 28, 1993: | |
+ | |
+ New request: .sg <div> sets the dn and dl registers to the size | |
+ of the diversion named in the argument. Doesn't do anything | |
+ when the named diversion doesn't exist. The name sg is | |
+ temporary until we find a better one. | |
+ | |
+July 21, 1993: | |
+ | |
+ Experiment: Macro space & registers name allocated | |
+ dynamically. Note that current reallocation occurs in | |
+ increments of 1, to force the code to be executed a lot; a kind | |
+ of stress testing. Also, eight bit characters allowed in | |
+ macro/string names. | |
+ | |
+July 21, 1993: | |
+ | |
+ Turn on the escape mode if the end macro is called. | |
+ | |
+July 20, 1993: | |
+ | |
+ Tracing mode now default off | |
+ | |
+ Don't print s stackdump either when a file specfied on the | |
+ command line argument cannot be opened | |
+ | |
+July 15, 1993: | |
+ | |
+ Don't print useless line & current file informations when a | |
+ file specfied on the command line argument cannot be opened. | |
+ | |
+ Sun ansi compiler doesn't default adhere to standards. Undid | |
+ the kludge in tdef.h | |
+ | |
+July 14, 1993: | |
+ | |
+ Coding error made the tab type R not function properly | |
+ | |
+July 12, 1993: | |
+ | |
+ Fixed a typo in the version stuff, noticed by Rich | |
+ | |
+July 9, 1993: | |
+ | |
+ Added the dwb home configuration stuff, thanks RIch. Also, | |
+ NCHARS is big enough. Added a fflush to casetm, so .fm <file> | |
+ will be up to date. | |
+ | |
+June 25, 1993 (Rich): | |
+ | |
+ -t option | |
+ | |
+ reinstated for the sake of compatibility. Some old | |
+ shells scripts and man(1) from SunOs want this, sigh | |
+ | |
+ Compiler and system dependencies | |
+ | |
+ Some systems pull in sys/types.h via #include <time.h> and then | |
+ the compiler complains about two ushort typedefs. Therefore, | |
+ ushort is now Ushort (and uchar Uchar). | |
+ | |
+ The SVID specifies a strdup, POSIX doesn't, anyway, troff | |
+ provides its own version, slightly different then the standard | |
+ one. A To prevent name clashes with that definion, renamed to | |
+ strdupl. | |
+ | |
+June 24, 1993 (Rich): | |
+ | |
+ -V option added for DWB3.4 (rich) | |
+ | |
+May 18, 1993: | |
+ | |
+ Trivial fix (.cf) request for troff -a | |
+ | |
+ issuing | |
+ | |
+ .cf /dev/null | |
+ | |
+ with troff -a gives some spurious output: | |
+ | |
+ H720 | |
+ H720 | |
+ s10 | |
+ f1 | |
+ | |
+ fixed by checking for ascii mode it ptesc(), ptps() and | |
+ ptfont() in t10.c | |
+ | |
+ | |
+ Enhancement | |
+ | |
+ Added a .tm request to roff. Works just like .tm, but now | |
+ it will do it to file. The name is coined by Carmela. Great | |
+ for creating indeces & toc's (we hope). | |
+ | |
+May 18 1993: | |
+ | |
+ Compatibilty change | |
+ | |
+ Somebody complained that his favorite macro didn't work: | |
+ it had a BELL (^G) in the name. This was a non-documented | |
+ feature of earlier versions of troff (although the | |
+ documentation actually doesn't say that you can. (They can | |
+ only be used for delimiters or with the tr request), so it | |
+ isn't that important). | |
+ | |
+ But the sake of eternal backward compatibilaty I allowed | |
+ some control characters like, STX, ACK, etc. also be part | |
+ of a macro/string name. | |
+ | |
+ While at it, I made it also possible to have eight bit | |
+ characters be part of the name. It might be that this screws | |
+ up the way users think about these things. For UNICODE | |
+ versions, they probably want to do that as well, and that | |
+ won't work as easy, (because these characters are 16-bits | |
+ wide), so it is dubious whether we actually want this. | |
+ | |
+ BTW. Now | |
+ | |
+ .de \(ts\ts | |
+ .tm terminal sigma macro | |
+ .. | |
+ .\(ts\(ts | |
+ | |
+ also works, as long the internal cookie for ts isn't more then | |
+ eight bits. | |
+ | |
+May 12, 1993: | |
+ | |
+ Syntax change | |
+ | |
+ Some requests accept tabs as a separator, some don't and | |
+ this can be a nuisance. Now a tab is also recognized as | |
+ an argument separator for requests, this makes | |
+ | |
+ .so /dev/null | |
+ | |
+ works. | |
+ | |
+ To be more precise, any motion character is allowed, so | |
+ | |
+ .so\h'5i'/dev/null | |
+ | |
+ will work as well, if one really wants that. | |
+ | |
+ It will be a problem for users who really relied on this as in | |
+ | |
+ .ds x string | |
+ | |
+ and expect the tab to become part of the string a, but I haven't | |
+ seen any use of that (obscure trick). | |
+ | |
+May 6, 1993: | |
+ | |
+ Eileen count fixed | |
+ | |
+ Troff sometimes went in a loop, and exited with: ``job | |
+ looping; check abuse of macros'' (also known as the Eileen's | |
+ loop). It can be forced with the next trivial programme: | |
+ | |
+ .de ff | |
+ .di xx | |
+ .. | |
+ .wh -1 ff | |
+ .bp | |
+ | |
+ Basically what happens is that a page transition now will | |
+ happen in a diversion, which doesn't make sense. Wat really | |
+ happens is that eject() (in n7.c) doesn't eject the frame | |
+ because we are in a diversion. This cause the loop in n1.c | |
+ (because now always stack->pname <= ejl). Adding check on | |
+ whether we are not in a diversion takes care of the problem. | |
+ | |
+March 30, 1993: | |
+ | |
+ Need request, .ne | |
+ | |
+ When there is a begin of page trap set, and the first thing | |
+ in the file is a .ne request, the trap gets fired, but, | |
+ the x font R etc. cookies doen't come out, because the | |
+ troff thinks that the first page pseudo transition already | |
+ took place. Fixed by forcing the start of the first page | |
+ in the casene request with the same code as in casetl (which | |
+ caused a similar problem quite some time ago). | |
+ | |
+ Change to .cf request ``Here document'' | |
+ | |
+ If the argument of .cf starts with a <<, the rest of it is taken | |
+ as an EOF token. It will reat the rest of the input until it hits | |
+ the EOF token and copies it to the output. This is similar as | |
+ the shell's ``here document'' mechanisme and put in place to | |
+ improve the kludgy way picasso, picpack etc. now include | |
+ postscript. | |
+ | |
+ Using troff -TLatin1 (DWB version) and \N'...' caused core dump | |
+ | |
+ In t11, in chadd, it should test on NCHARS - ALPHABET to see | |
+ whether we run out of table space (and we probably should beaf | |
+ up NCHARS for the DWB version). | |
+ | |
+March 16, 1993: | |
+ | |
+ Diversion rename bug fix | |
+ | |
+ It is possible to get troff in an infinite loop by renaming a | |
+ diversion in progress, and calling it later with the | |
+ new name (as in .di xx, .rn xx yy, .yy). The effect depends on | |
+ whether troff already put stuff in the diversion or not. | |
+ | |
+ Fix by having .rn also rename the current diversion (if | |
+ there is any and when appropriate). If the diversion calls | |
+ itself by the new name and given the fix made on 11 nov | |
+ 1992, this will now result in an error. (BTW, the fix from | |
+ 11 nov is improved: diversions nest, so we have to account | |
+ for that). | |
+ | |
+December 18, 1992: | |
+ Some people have complete novels as comments, so we need | |
+ to skip comments while checking the legality of font files. | |
+ thaks Rixh | |
+ | |
+December 16, 1992 | |
+ | |
+ Some people rely on the order that -r arguments are given, | |
+ so that troff -rC1 -rC3 ends up setting register C to 3. | |
+ Because cpushback() pushes things in a LIFO order back, we | |
+ have to do the same to get -r args in a FIFO order. | |
+ | |
+Nov 17, 1992: | |
+ | |
+ Giving a -rL8 option cuased the string .nr L 8 to be printed | |
+ on the output, using the wonderful 3b2. Some garbage was | |
+ left in buf[100] in main(). Fixed by setting buf[0] explicitly | |
+ to 0 (because some C-compilers complain about ``no automatic | |
+ aggregate initialization''). | |
+ | |
+Nov 11, 1992: | |
+ | |
+ Diversion bug fix | |
+ | |
+ If a diversion was being read and the input is faulty so | |
+ the diversion was reading in itself, it caused troff to | |
+ loop undefinitely. This was easily fixed by a test in | |
+ control(a,b) in n1.c. | |
+ | |
+ Something similar things might happen with macros causing | |
+ the ``eileenct problem'', but I didn't look for that. We | |
+ have to wait until it happens. | |
+ | |
+Oct 26, 1992: | |
+ | |
+ Numeric arguments: | |
+ | |
+ Illegal argments are treated as missing arguments. This | |
+ changed the semantics of .ll, .ls, .in, .lg, .ul, .cu .lt | |
+ (which acted as if the argument was 0) and .ps which was | |
+ simply ignored with an illegal argument. | |
+ | |
+ Tidied up number parsing in atoi1(). This prevents arguments | |
+ like .x or 1.2.3.4 being interpret as a legal number (nonumb = 0) | |
+ | |
+ Numeric arguments error reporting: | |
+ | |
+ Controlled by .pt, illegal numbers are now reported (default | |
+ trace mode is 1). This is also true for the escapes: | |
+ \h'..', \v'..' \H'..', \S'..', \N'..', \D'..', \l'.., \L'.. | |
+ and \x'..'. | |
+ | |
+ \D'c' is the only drawing request which doesn't take a pair | |
+ of numbers as arguments, so a special case is put here in | |
+ setdraw() (This code actually could use an overhaul to get | |
+ better parsing. As long as the \D'..' cookies are machine | |
+ generated it is low on the priority list). | |
+ | |
+ Don't generate an error if the illegal argument to a request | |
+ is a \}. It is too painful to do right (although it can be | |
+ done, but it would clutter getch() and getcho() even more). | |
+ | |
+ Input line numbers (.c register) bug fixes: | |
+ | |
+ In not taken branches of .if or .ie, the input line # | |
+ (numtab[CD].val) should be raised when necessary (in eatblk()). | |
+ | |
+ For concealed newlines, we still should count the line for input. | |
+ | |
+ Setfield (n9.c) sometimes pushes the rest of the line back to | |
+ the input (including \n), without adjusting numtab[CD].val | |
+ | |
+ Because .c (and so numtab[CD].val) is the number of lines read | |
+ and the error might actually happen in the current line | |
+ (before seeing the '\n), we need to apply correction in | |
+ errprint when nlflg set. (This correction needs to be undone | |
+ when inside a macro because the nlflg is set by reading the | |
+ args to the macro). | |
+ | |
+ Line number setting (.lf) request bug fixes: | |
+ | |
+ I interpret that the .c register will contain the number of | |
+ read lines, not including the current one. | |
+ | |
+ Also, don't change the input line number when the first | |
+ argument of .lf is not a number. | |
+ | |
+ As a net effect, the next input | |
+ | |
+ .EQ | |
+ .EN | |
+ .ab | |
+ | |
+ will generate the same output whether eqn has been used or not. | |
+ | |
+ If request bug fix: | |
+ | |
+ A ``.if page .tm foo'' caused the next line being ignored; | |
+ This bcause when the 2nd delimiter of a string couldn't be | |
+ found in cmpstr, the next line was always eaten. Solution: | |
+ in caseif1, if the condition is false, we should check | |
+ nlflg before eating a block. (Note: We might have eaten | |
+ \{\ as well. We could disallow the \{\ in a string to be | |
+ compared to prevent that but that might break other things). | |
+ | |
+ Enhancement to .pt: | |
+ | |
+ The .pt now pops the previous values when no argument is | |
+ specified. Turned out to be handy when chasing for problems. | |
+ Just ``bracked'' the code with .pt 7 and .pt and you get | |
+ a trace of only that block. The meaning of the arguments | |
+ is now: | |
+ 01 trace numeric arguments (default on) | |
+ 02 trace requests | |
+ 04 trace macros | |
+ | |
+ Abort request (.ab) beautification: | |
+ | |
+ Don't print the extra carriage return when .ab is called | |
+ without an argument. | |
+ | |
+Oct 12, 1992: | |
+ | |
+ (Comments & spelling errors from this day on by jaap) | |
+ | |
+ replaced 32767 by INT_MAX in several places to allow for very | |
+ long pages (on 32-but machines). | |
+ | |
+ The ``.fp 1 R \"COMMENT'' complains about ``./troff: Can't | |
+ open font file /usr/lib/font/devpost/h'' on some systems. It | |
+ sees the tab as part of the optional font file. Apparently it | |
+ is system dependent whether isgraph() includes the tab | |
+ character. Fixed by using getach() in getname() in n1.c | |
+ instead. | |
+ | |
+Aug 28, 1992: | |
+ removed call to popi from rdtty(); it was eating up the | |
+ rest of the macro if it was used from within one. (thanks, jaap) | |
+ | |
+ | |
+Jul 21, 1992: | |
+ added extra test in nextfile() to pop current input file | |
+ only if not in .nx command. thanks to jaap. | |
+ | |
+ added test in getword() to avoid hyphenating after \z character, | |
+ which prevents any hyphenation inside \X'...'. thanks to jaap. | |
+ | |
+ added, then removed, code in getword() to prevent hyphenating | |
+ anything shorter than 6 characters. looks like it changed a | |
+ lot more than i thought. | |
+ | |
+Jul 12, 1992: | |
+ added .pt request to trace macros and requests (from jaap). | |
+ .pt N Print trace of macros (N=1), requests (N=2) or both (N=3) | |
+ | |
+Jun 5, 1992: | |
+ added tests to t.twrest and t.twinit to avoid 0 deref in | |
+ n2 and n10, for nroff -t xxxxx. thanks to Rich Drechsler. | |
+ | |
+May 22, 1992: | |
+ added extern decls to e.g., void Tchar (*hmot)(void) in tdef.h | |
+ and added definition to ni.c, so pointers are defined explicitly. | |
+ makes it work on turbo c++ and probably others. | |
+ | |
+ changed a couple of isdigit's and isgraph(getch()) to avoid | |
+ multiple evaluation (even though it shouldn't happen). | |
+ | |
+ Made /usr/bin/nroff a shell script. | |
+ | |
+May 12, 1992: | |
+ n1.c: need p++ after strrchr to skip / in program name. | |
+ thanks to Rich Drechsler. | |
+ | |
+Apr 17, 1992: | |
+ casefi(), n5.c: .u register should be 0 or 1, not incremented | |
+ with each .fi. | |
+ | |
+Apr 5, 1992: | |
+ fiddled n7.c and added _nmwid to the environment, to add a | |
+ 5th argument to .nm: the maximum number of digits in any | |
+ line number. default is 3, which was previously hardwired in. | |
+ | |
+ added jaap's code for yet another register which actually delivers | |
+ a string, called .S (so it can easily go in the switch in setn() | |
+ in n4.c); it delivers the current tabstop and alignment modes in | |
+ a format suitable for a subsequent .ta \n(.S command: | |
+ .ds T \n(.S | |
+ ... | |
+ .ta \*T | |
+ | |
+Mar 30, 1992: | |
+ added test in getword to avoid hyphenating things with motions | |
+ (and avoid a core dump sometimes too). | |
+ | |
+Mar 13, 1992: | |
+ \n(sb initialized wrong in setwd(). | |
+ | |
+ TYPESETTER=foo troff -Tpost used foo instead of post. | |
+ | |
+Mar 12, 1992: | |
+ rearranged tests in popf so that .so is closed properly before | |
+ moving on to the next macro package. | |
+ | |
+Mar 1, 1992: | |
+ input mechanism rearranged to use getc() instead of stack of | |
+ explicit input buffers. 5-10% slowdown. | |
+ | |
+Jan 28, 1992: | |
+ fixed .tm \(mi to print something sensible. thanks to jaap. | |
+ | |
+Jan 2, 1992: | |
+ fiddle setfp so doesn't put out font stuff if -a turned on. | |
+ | |
+Dec 17, 1991: | |
+ copy 3rd argument in .fp commands to x font ... lines when it contains | |
+ a /, for testing fonts locally. | |
+ | |
+Dec 13, 1991: | |
+ parameterize the font directories, etc., so can be set in makefiles. | |
+ added -N argument to run as nroff. | |
+ | |
+Nov 8, 1991: | |
+ add a maplow(towlower...) in n8.c to handle brain-damaged libraries. | |
+ | |
+Nov 2, 1991: | |
+ merged nroff into troff, based on Ken's plan 9 version. | |
+ merged nii.c into ni.c, removed tw.h, etc. more work needed | |
+ to make this stuff cleaner. | |
+ | |
+July 27, 1991: | |
+ added test in setn in n4 to fix bug that permitted things like | |
+ \n (ab to work "properly". thanks to jaap for finding and fixing. | |
+ | |
+ added paranoid testing in t11 to make sure font files look ok. | |
+ | |
+May 13, 1991: | |
+ moved evaluation of \(xx from copy mode to non-copy mode, so that | |
+ weird character names wouldn't get reevaluated in argument parsing. | |
+ installed july 27. | |
+ | |
+May 6, 1991: | |
+ increased size of hyphenation exception buffer to 512 from 128 | |
+ | |
+Apr 14, 1991: | |
+ added an extra redundant call of ptfont in setfp, since it appears | |
+ that some versions of adobe transcript assume that an "x font" command | |
+ means to change the actual font as well. the fix preserves the curren… | |
+ thanks to david brailsford and friends for spotting the problem. | |
+ | |
+ fixed up tests in alpha() in n8 to defend isalpha() against too-big in… | |
+ punct() argument had wrong type too. thanks to rich drexler and peter… | |
+ | |
+Mar 19, 1991: | |
+ fixed bug that prevented .rd from working with new corebuf organizatio… | |
+ | |
+ fixed bug that caused .ig inside diversions to give bad storage | |
+ allocation. thanks to arthur david olson, whose fix was on netnews | |
+ 3 years earlier. | |
+ | |
+Mar 5, 1991: | |
+ huge table sizes for kanji. | |
+ | |
+Feb ??, 1991: | |
+ working on dealing with large alphabets, notably kanji. | |
+ added "defaultwidth" to font descriptions, for characters | |
+ not given an explicit width. | |
+ | |
+Jan, 1991: | |
+ added tex hyphenation, using standard tex data files, but not the | |
+ elaborate compressed trie, which is a lot of trouble to save maybe | |
+ 40k bytes. this appears to run at exactly the same speed as before. | |
+ | |
+ so far this stuff reads into a fixed size array; that should change. | |
+ it should also be possible to deal with multiple languages. | |
+ | |
+ the command .ha sets the algorithm. .ha 1 => tex, with troff rules | |
+ if tex doesn't hyphenate; .ha 0 gives troff rules, and .ha resets | |
+ to the default, which is tex. the hyphenation algorithm is part of | |
+ the environment, a nod to a future in which i handle more than one | |
+ language. | |
+ | |
+ replaced the fixed size corebuf array for string/macro storage by | |
+ a dynamic structure that can grow. | |
+ | |
+ this appears to slow things down by maybe 3%. the code is about | |
+ the same complexity. | |
+ | |
+Dec 27, 1990: | |
+ converted to ansi c, based on some work by ken thompson, but not | |
+ as thoroughly as he did. there is a shell script unansi and an awk | |
+ program cvt that will help you step back in time if you do not have | |
+ an ansi c compiler. | |
+ | |
+ moved the special-name characters up to 256 instead of 128, although | |
+ done in terms of ALPHABET, so one can pass 8 bit characters through. | |
+ removed lots of 0177's and similar numbers. input is now not filtered, | |
+ and if a character with the 8th bit on comes in, it will go out again. | |
+ | |
+ fixed t11.c to read character names in hex or octal as well as | |
+ single-character ascii. | |
+ | |
+ unknown characters are now carried through with width = spacewidth. | |
+ needs a way to set widths. | |
+ | |
+ removed all signal handling from troff. you signal, you die. | |
+ | |
+ added -d option to print version number. | |
+ | |
+Dec 7, 1990: | |
+ .fp 3 V VERYLONGNAME used to truncate the name to 10 chars; fixed. | |
+ | |
+ increased the limit on FBUFSZ for tables with very long fields. | |
+ | |
+ changed atoi1() to use double to avoid intermediate overflow. | |
+ | |
+ moved filenames like /usr/lib/font into tdef.h for easy change. | |
+ removed some dreggish definitions. | |
+ | |
+ cleaned up non-portable error printing stuff; fixed up some messages. | |
+ | |
+Dec 12, 1989: | |
+ Removed the .! command, an undocumented synonym for .sy. | |
+ | |
+Dec 4, 1989: | |
+ Another wart to the \X code, to try to preserve blanks in all situatio… | |
+ | |
+Nov 17, 1989: | |
+ A number of small changes preparatory to getting rid of nroff. | |
+ The argument -Tnroff or -Tnroff-12 changes some internal values | |
+ so that the predicate .if n is true and certain arithmetic operations | |
+ are done as if nroff. This design is not yet final. | |
+ | |
+Nov 7, 1989: | |
+ Fixed hyphenation for nov-ice, ad-vice, de-vice, ser-vice, *-vice. | |
+ | |
+Oct 11, 1989: | |
+ It is now permitted to do an explicit change to font S. | |
+ It is not clear what will break (though nothing seems to have). | |
+ | |
+Oct 10, 1989: | |
+ Modified flush code to always put out \nH instead of sometimes h. | |
+ This makes it easier to parse the output for positioning. | |
+ | |
+Sep 9, 1989: | |
+ Fixed internal representation of \D'~...' so that it | |
+ is immune to .tr ~ and variations. No external change. | |
+ | |
+Aug 9, 1989: | |
+ Changed .tm so it outputs \e, \%, \-, \&, \(blank). | |
+ This might break indexing code. | |
+ Only in the new version, as are all subsequent fixes. | |
+ | |
+July, 1989: | |
+ A major internal change: font information is read in ascii | |
+ instead of the weird binary format of makedev (which is now dead). | |
+ character names need not all appear in DESC; new names that | |
+ appear when a font is used become part of the set of known names. | |
+ | |
+ There are some flaky bits here (it's conceivable that some \N | |
+ number will collide with a real name), and it's probably 10-15% | |
+ slower. Tant pis. | |
+ | |
+ As a by-product, nroff no longer compiles. I'll probably get | |
+ back to this, but an alternative is to bag it once and for all. | |
+ | |
+May 25, 1989: | |
+ Another bug in \l, this time when width is 0. Not installed, | |
+ since it's in the new font version. | |
+ | |
+Apr 23, 1989: | |
+ Fixed bug in n9 that caused core dump with unterminated | |
+ \l command, like \l'1.5i | |
+ | |
+ ptflush no longer called when -a is on. | |
+ | |
+Apr 12, 1989: | |
+ fixed bug in n2 that failed to suppress printing of \! | |
+ output when a -o was in effect. | |
+ | |
+Apr 5, 1989: | |
+ .fl and \X now cause output of size, font, hpos and vpos. | |
+ this is necesary for postprocessors that intend to insert | |
+ independent material, such as postscript. | |
+ | |
+Feb 1, 1989: | |
+ wait for .pi pipe to empty before exiting | |
+ | |
+Oct 2, 1988: | |
+ default is now -Tpost | |
+ | |
+Sep 19, 1988: | |
+ added abortive code to handle built-up characters by | |
+ passing something through as \D'b...'. never used. | |
+ | |
+Jul 4, 1988: | |
+ replaced the sbrk nonsense in n3.c by calls to malloc. | |
+ | |
+ \N now tests against proper font size. | |
+ | |
+ installed Jaap Akkerhuis's code (mutatis mutandis) for | |
+ permitting up to 99 fonts, swapping them into font pos 0 | |
+ as needed. fixes the long-standing problem of having | |
+ multiple font changes on a single output line. | |
+ | |
+Jul 2, 1988: | |
+ \X now preserves spaces even when contents are diverted. | |
+ | |
+ \N code safer -- NTRTAB and NWIDCACHE enlarged. | |
+ | |
+Jul 14, 1987: | |
+ Fixed obscure bug causing incorrect indentation of .mc output. | |
diff --git a/troff/Makefile b/troff/Makefile | |
@@ -0,0 +1,11 @@ | |
+# mk - mk unix port from plan9 | |
+# Depends on ../lib9 | |
+ | |
+TARG = troff | |
+ | |
+OFILES = n1.o n2.o n3.o n4.o n5.o t6.o n6.o n7.o n8.o n9.o t10.o\ | |
+ n10.o t11.o ni.o hytab.o suftab.o dwbinit.o mbwc.o | |
+MANFILES = troff.1 | |
+CFLAGS = -DUNICODE -DTMACDIR=\"tmac/tmac.\" -DTDEVNAME=\"utf\" -DFONTDIR=\"… | |
+ | |
+include ../std.mk | |
diff --git a/troff/README b/troff/README | |
@@ -0,0 +1,31 @@ | |
+To make troff (actually a.out): | |
+ | |
+ make | |
+ | |
+You will also need to write a driver for your favorite output device. | |
+d202.c provides a model, although it is specialized to a machine no | |
+one has. There are also a variety of postscript drivers that are the | |
+best thing to use if you have a postscript device. | |
+ | |
+You will also have to make a DESC file for your typesetter and some | |
+font description files; see dev202 for examples. These describe the | |
+named characters, widths, kerning information, and output codes. | |
+ | |
+Nroff is the same program as troff, so you should | |
+ | |
+ cp a.out /usr/bin/troff | |
+ ln /usr/bin/troff /usr/bin/nroff | |
+ | |
+or the equivalent. | |
+ | |
+You will also need terminal description files for your terminals; see | |
+tab.37, tab.450 and tab.lp for examples. | |
+ | |
+Troff uses files that are normally stored in /usr/lib/font; | |
+macro packages are in /usr/lib/tmac; and nroff tables are in | |
+/usr/lib/term. You can edit tdef.h to change these assumptions. | |
+ | |
+There have been a few features since the last version, and a number of | |
+significant internal changes. Not all are improvements, of course. | |
+Most of the more recent changes, including bug fixes, are in FIXES, | |
+which you should read also. | |
diff --git a/troff/cvt b/troff/cvt | |
@@ -0,0 +1,45 @@ | |
+ | |
+awk ' | |
+ | |
+/^{/ { | |
+ if (prev != "") { | |
+ # comments can be trouble (e.g. ffree()) | |
+ if ( (c = match(prev, /\/\*.*\*\/$/)) != 0 ) { | |
+ comment = substr(prev, c) | |
+ sub(/\/\*.*\*\/$/, "", prev) | |
+ } else comment = "" | |
+ | |
+ x = prev | |
+ | |
+ # isolate argument list | |
+ sub(/^[^(]*\(/, "", x) | |
+ sub(/\)[^)]*$/, "", x) | |
+ | |
+ # find the names in it | |
+ n = split(x, args) | |
+ arglist = "" | |
+ for (i = 2; i <= n; i += 2) | |
+ arglist = arglist args[i] | |
+ gsub(/\(\*f\)\(Tchar\)/, "f", arglist) # special case f… | |
+ gsub(/\[[0-9]+\]/, "", arglist) # for n8.c | |
+ gsub(/[*()\[\]]/, "", arglist) # discard noise … | |
+ gsub(/,/, ", ", arglist) # space nicely | |
+ sub(/\(.*\)/, "(" arglist ")", prev) # reconstruct | |
+ print prev comment | |
+ | |
+ # argument declarations | |
+ gsub(/,/, ";", x) | |
+ gsub(/\(\*f\)\(Tchar\)/, "(*f)()", x) # special case fo… | |
+ if (x != "") | |
+ print "\t" x ";" | |
+ } | |
+ prev = $0 | |
+ next | |
+} | |
+ | |
+{ print prev | |
+ prev = $0 | |
+} | |
+ | |
+END { print prev } | |
+' $* | |
diff --git a/troff/dwbinit.c b/troff/dwbinit.c | |
@@ -0,0 +1,317 @@ | |
+/* | |
+ * | |
+ * Pathname management routines for DWB C programs. | |
+ * | |
+ * Applications should initialize a dwbinit array with the string | |
+ * pointers and arrays that need to be updated, and then hand that | |
+ * array to DWBinit before much else happens in their main program. | |
+ * DWBinit calls DWBhome to get the current home directory. DWBhome | |
+ * uses the last definition of DWBENV (usually "DWBHOME") in file | |
+ * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that | |
+ * variable in the environment if the DWBCONFIG file doesn't exist, | |
+ * can't be read, or doesn't define DWBENV. | |
+ * | |
+ * DWBCONFIG must be a simple shell script - comments, a definition | |
+ * of DWBHOME, and perhaps an export or echo is about all that's | |
+ * allowed. The parsing in DWBhome is simple and makes no attempt | |
+ * to duplicate the shell. It only looks for DWBHOME= as the first | |
+ * non-white space string on a line, so | |
+ * | |
+ * # | |
+ * # A sample DWBCONFIG shell script | |
+ * # | |
+ * | |
+ * DWBHOME=/usr/add-on/dwb3.4 | |
+ * export DWBHOME | |
+ * | |
+ * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home | |
+ * directory. A DWBCONFIG file means there can only be one working | |
+ * copy of a DWB release on a system, which seems like a good idea. | |
+ * Using DWBCONFIG also means programs will always include correct | |
+ * versions of files (e.g., prologues or macro packages). | |
+ * | |
+ * Relying on an environment variable guarantees nothing. You could | |
+ * execute a version of dpost, but your environment might point at | |
+ * incorrect font tables or prologues. Despite the obvious problems | |
+ * we've also implemented an environment variable approach, but it's | |
+ * only used if there's no DWBCONFIG file. | |
+ * | |
+ * DWBinit calls DWBhome to get the DWB home directory prefix and | |
+ * then marches through its dwbinit argument, removing the default | |
+ * home directory and prepending the new home. DWBinit stops when | |
+ * it reaches an element that has NULL for its address and value | |
+ * fields. Pointers in a dwbinit array are reallocated and properly | |
+ * initialized; arrays are simply reinitialized if there's room. | |
+ * All pathnames that are to be adjusted should be relative. For | |
+ * example, | |
+ * | |
+ * char *fontdir = "lib/font"; | |
+ * char xyzzy[25] = "etc/xyzzy"; | |
+ * | |
+ * would be represented in a dwbinit array as, | |
+ * | |
+ * dwbinit allpaths[] = { | |
+ * &fontdir, NULL, 0, | |
+ * NULL, xyzzy, sizeof(xyzzy), | |
+ * NULL, NULL, 0 | |
+ * }; | |
+ * | |
+ * The last element must have NULL entries for the address and | |
+ * value fields. The main() routine would then do, | |
+ * | |
+ * #include "dwbinit.h" | |
+ * | |
+ * main() { | |
+ * | |
+ * DWBinit("program name", allpaths); | |
+ * ... | |
+ * } | |
+ * | |
+ * Debugging is enabled if DWBDEBUG is in the environment and has | |
+ * the value ON. Output is occasionally useful and probably should | |
+ * be documented. | |
+ * | |
+ */ | |
+ | |
+#include <u.h> | |
+#include <stdio.h> | |
+#include <ctype.h> | |
+#include <string.h> | |
+#include <stdlib.h> | |
+ | |
+#include "dwbinit.h" | |
+ | |
+#ifndef DWBCONFIG | |
+#define DWBCONFIG "/dev/null" | |
+#endif | |
+ | |
+#ifndef DWBENV | |
+#define DWBENV "DWBHOME" | |
+#endif | |
+ | |
+#ifndef DWBHOME | |
+#define DWBHOME "" | |
+#endif | |
+ | |
+#ifndef DWBDEBUG | |
+#define DWBDEBUG "DWBDEBUG" | |
+#endif | |
+ | |
+#ifndef DWBPREFIX | |
+#define DWBPREFIX "\\*(.P" | |
+#endif | |
+ | |
+/*****************************************************************************/ | |
+ | |
+void DWBdebug(dwbinit *ptr, int level) | |
+{ | |
+ | |
+ char *path; | |
+ char *home; | |
+ static char *debug = NULL; | |
+ | |
+/* | |
+ * | |
+ * Debugging output, but only if DWBDEBUG is defined to be ON in the | |
+ * environment. Dumps general info the first time through. | |
+ * | |
+ */ | |
+ | |
+ if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL ) | |
+ debug = "OFF"; | |
+ | |
+ if ( strcmp(debug, "ON") == 0 ) { | |
+ if ( level == 0 ) { | |
+ fprintf(stderr, "Environment variable: %s\n", DWBENV); | |
+ fprintf(stderr, "Configuration file: %s\n", DWBCONFIG); | |
+ fprintf(stderr, "Default home: %s\n", DWBHOME); | |
+ if ( (home = DWBhome()) != NULL ) | |
+ fprintf(stderr, "Current home: %s\n", home); | |
+ } /* End if */ | |
+ | |
+ fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final"… | |
+ for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) { | |
+ if ( (path = ptr->value) == NULL ) { | |
+ path = *ptr->address; | |
+ fprintf(stderr, " pointer: %s\n", path); | |
+ } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path); | |
+ if ( level == 0 && *path == '/' ) | |
+ fprintf(stderr, " WARNING - absolute path\n"); | |
+ } /* End for */ | |
+ } /* End if */ | |
+ | |
+} /* End of DWBdebug */ | |
+ | |
+/*****************************************************************************/ | |
+ | |
+extern char *unsharp(char*); | |
+ | |
+char *DWBhome(void) | |
+{ | |
+ | |
+ FILE *fp; | |
+ char *ptr; | |
+ char *path; | |
+ int len; | |
+ char buf[200]; | |
+ char *home = NULL; | |
+ | |
+/* | |
+ * | |
+ * Return the DWB home directory. Uses the last definition of DWBENV | |
+ * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or | |
+ * the value assigned to the variable named by the DWBENV string in | |
+ * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV. | |
+ * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if | |
+ * there's no home directory. | |
+ * | |
+ */ | |
+ | |
+ if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) { | |
+ len = strlen(DWBENV); | |
+ while ( fgets(buf, sizeof(buf), fp) != NULL ) { | |
+ for ( ptr = buf; isspace((uchar)*ptr); ptr++ ) ; | |
+ if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) { | |
+ path = ptr + len + 1; | |
+ for ( ptr = path; !isspace((uchar)*ptr) && *ptr != ';'; ptr++ … | |
+ *ptr = '\0'; | |
+ if ( home != NULL ) | |
+ free(home); | |
+ if ( (home = malloc(strlen(path)+1)) != NULL ) | |
+ strcpy(home, path); | |
+ } /* End if */ | |
+ } /* End while */ | |
+ fclose(fp); | |
+ } /* End if */ | |
+ | |
+ if ( home == NULL ) { | |
+ if ( (home = getenv(DWBENV)) == NULL ) { | |
+ if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' ) | |
+ home = NULL; | |
+ } /* End if */ | |
+ home = unsharp(home); | |
+ } /* End if */ | |
+ | |
+ while (home && *home == '/' && *(home +1) == '/') /* remove extra s… | |
+ home++; | |
+ return(home); | |
+ | |
+} /* End of DWBhome */ | |
+ | |
+/*****************************************************************************/ | |
+ | |
+void DWBinit(char *prog, dwbinit *paths) | |
+{ | |
+ | |
+ char *prefix; | |
+ char *value; | |
+ char *path; | |
+ int plen; | |
+ int length; | |
+ dwbinit *opaths = paths; | |
+ | |
+/* | |
+ * | |
+ * Adjust the pathnames listed in paths, using the home directory | |
+ * returned by DWBhome(). Stops when it reaches an element that has | |
+ * NULL address and value fields. Assumes pathnames are relative, | |
+ * but changes everything. DWBdebug issues a warning if an original | |
+ * path begins with a /. | |
+ * | |
+ * A non-NULL address refers to a pointer, which is reallocated and | |
+ * then reinitialized. A NULL address implies a non-NULL value field | |
+ * and describes a character array that we only reinitialize. The | |
+ * length field for an array is the size of that array. The length | |
+ * field of a pointer is an increment that's added to the length | |
+ * required to store the new pathname string - should help when we | |
+ * want to change character arrays to pointers in applications like | |
+ * troff. | |
+ * | |
+ */ | |
+ | |
+ if ( (prefix = DWBhome()) == NULL ) { | |
+ fprintf(stderr, "%s: no DWB home directory\n", prog); | |
+ exit(1); | |
+ } /* End if */ | |
+ | |
+ DWBdebug(opaths, 0); | |
+ plen = strlen(prefix); | |
+ | |
+ for ( ; paths->value != NULL || paths->address != NULL; paths++ ) { | |
+ if ( paths->address == NULL ) { | |
+ length = 0; | |
+ value = paths->value; | |
+ } else { | |
+ length = paths->length; | |
+ value = *paths->address; | |
+ } /* End else */ | |
+ | |
+ length += plen + 1 + strlen(value); /* +1 is for the '/' */ | |
+ | |
+ if ( (path = malloc(length+1)) == NULL ) { | |
+ fprintf(stderr, "%s: can't allocate pathname memory\n", prog); | |
+ exit(1); | |
+ } /* End if */ | |
+ | |
+ if ( *value != '\0' ) { | |
+ char *eop = prefix; | |
+ while(*eop++) | |
+ ; | |
+ eop -= 2; | |
+ if (*value != '/' && *eop != '/') { | |
+ sprintf(path, "%s/%s", prefix, value); | |
+ } else if (*value == '/' && *eop == '/') { | |
+ value++; | |
+ sprintf(path, "%s%s", prefix, value); | |
+ } else | |
+ sprintf(path, "%s%s", prefix, value); | |
+ } else | |
+ sprintf(path, "%s", prefix); | |
+ | |
+ if ( paths->address == NULL ) { | |
+ if ( strlen(path) >= paths->length ) { | |
+ fprintf(stderr, "%s: no room for %s\n", prog, path); | |
+ exit(1); | |
+ } /* End if */ | |
+ strcpy(paths->value, path); | |
+ free(path); | |
+ } else *paths->address = path; | |
+ } /* End for */ | |
+ | |
+ DWBdebug(opaths, 1); | |
+ | |
+} /* End of DWBinit */ | |
+ | |
+/*****************************************************************************/ | |
+ | |
+void DWBprefix( char *prog, char *path, int length) | |
+{ | |
+ | |
+ char *home; | |
+ char buf[512]; | |
+ int len = strlen(DWBPREFIX); | |
+ | |
+/* | |
+ * | |
+ * Replace a leading DWBPREFIX string in path by the current DWBhome(). | |
+ * Used by programs that pretend to handle .so requests. Assumes path | |
+ * is an array with room for length characters. The implementation is | |
+ * not great, but should be good enough for now. Also probably should | |
+ * have DWBhome() only do the lookup once, and remember the value if | |
+ * called again. | |
+ * | |
+ */ | |
+ | |
+ if ( strncmp(path, DWBPREFIX, len) == 0 ) { | |
+ if ( (home = DWBhome()) != NULL ) { | |
+ if ( strlen(home) + strlen(path+len) < length ) { | |
+ sprintf(buf, "%s%s", home, path+len); | |
+ strcpy(path, buf); /* assuming there's room in … | |
+ } else fprintf(stderr, "%s: no room to grow path %s", prog, path); | |
+ } /* End if */ | |
+ } /* End if */ | |
+ | |
+} /* End of DWBprefix */ | |
+ | |
+/*****************************************************************************/ | |
+ | |
diff --git a/troff/dwbinit.h b/troff/dwbinit.h | |
@@ -0,0 +1,19 @@ | |
+/* | |
+ * | |
+ * A structure used to adjust pathnames in DWB C code. Pointers | |
+ * set the address field, arrays use the value field and must | |
+ * also set length to the number elements in the array. Pointers | |
+ * are always reallocated and then reinitialized; arrays are only | |
+ * reinitialized, if there's room. | |
+ * | |
+ */ | |
+ | |
+typedef struct { | |
+ char **address; | |
+ char *value; | |
+ int length; | |
+} dwbinit; | |
+ | |
+extern void DWBinit(char *, dwbinit *); | |
+extern char* DWBhome(void); | |
+extern void DWBprefix(char *, char *, int); | |
diff --git a/troff/ext.h b/troff/ext.h | |
@@ -0,0 +1,187 @@ | |
+#define devname p9_devname | |
+ | |
+extern int TROFF; | |
+ | |
+extern int alphabet; | |
+extern char **argp; | |
+extern char *eibuf; | |
+extern char *ibufp; | |
+extern char *obufp; | |
+extern char *unlkp; | |
+extern char *xbufp; | |
+extern char *xeibuf; | |
+extern char cfname[NSO+1][NS]; | |
+extern int trace; | |
+extern char devname[]; | |
+extern char ibuf[IBUFSZ]; | |
+extern char mfiles[NMF][NS]; | |
+extern char nextf[]; | |
+extern char obuf[]; | |
+extern char termtab[]; | |
+extern char fontdir[]; | |
+extern Font fonts[MAXFONTS+1]; | |
+extern char xbuf[IBUFSZ]; | |
+extern Offset apptr; | |
+extern Offset ip; | |
+extern Offset nextb; | |
+extern Offset offset; | |
+extern Offset woff; | |
+extern Numerr numerr; | |
+extern int *pnp; | |
+extern int pstab[]; | |
+extern int nsizes; | |
+extern int app; | |
+extern int ascii; | |
+extern int bd; | |
+extern int bdtab[]; | |
+extern int ccs; | |
+extern char *chnames[]; /* chnames[n-ALPHABET] -> name of… | |
+extern int copyf; | |
+extern int cs; | |
+extern int dfact; | |
+extern int dfactd; | |
+extern int diflg; | |
+extern int dilev; | |
+extern int donef; | |
+extern int dotT; | |
+extern int dpn; | |
+extern int ds; | |
+extern int ejf; | |
+extern int em; | |
+extern int eqflg; | |
+extern int error; | |
+extern int esc; | |
+extern int eschar; | |
+extern int ev; | |
+extern int evi; | |
+extern int evlist[EVLSZ]; | |
+extern int fc; | |
+extern int flss; | |
+extern int fontlab[]; | |
+extern int hflg; | |
+extern int ibf; | |
+extern int ifi; | |
+extern int iflg; | |
+extern int init; | |
+extern int lead; | |
+extern int lg; | |
+extern int lgf; | |
+extern int macerr; | |
+extern int mflg; | |
+extern int mfont; | |
+extern int mlist[NTRAP]; | |
+extern int mpts; | |
+extern int nchnames; | |
+extern int ndone; | |
+extern int newmn; | |
+extern int nflush; | |
+extern int nfo; | |
+extern int nfonts; | |
+extern int nform; | |
+extern int nhyp; | |
+extern int nlflg; | |
+extern int nlist[NTRAP]; | |
+extern int nmfi; | |
+extern int nonumb; | |
+extern int noscale; | |
+extern int npn; | |
+extern int npnflg; | |
+extern int nx; | |
+extern int oldbits; | |
+extern int oldmn; | |
+extern int over; | |
+extern int padc; | |
+extern int pfont; | |
+extern int pfrom; | |
+extern int pipeflg; | |
+extern int pl; | |
+extern int pnlist[]; | |
+extern int po1; | |
+extern int po; | |
+extern int ppts; | |
+#define print troffprint | |
+extern int print; | |
+extern FILE *ptid; | |
+extern int pto; | |
+extern int quiet; | |
+extern int ralss; | |
+extern int rargc; | |
+extern int raw; | |
+extern int res; | |
+extern int sbold; | |
+extern int setwdf; | |
+extern int sfont; | |
+extern int smnt; | |
+extern int stdi; | |
+extern int stop; | |
+extern int sv; | |
+extern int tabch, ldrch; | |
+extern int tflg; | |
+extern int totout; | |
+extern int trap; | |
+extern Ushort trtab[]; | |
+extern int tty; | |
+extern int ulfont; | |
+extern int vflag; | |
+extern int whichroff; | |
+extern int widthp; | |
+extern int xfont; | |
+extern int xpts; | |
+extern Stack *ejl; | |
+extern Stack *frame; | |
+extern Stack *stk; | |
+extern Stack *nxf; | |
+extern Tchar **hyp; | |
+extern Tchar *olinep; | |
+extern Tchar pbbuf[NC]; | |
+extern Tchar *pbp; | |
+extern Tchar *lastpbp; | |
+extern Tchar ch; | |
+extern Tchar nrbits; | |
+extern Tbuf _oline; | |
+extern Wcache widcache[]; | |
+extern char gchtab[]; | |
+extern Diver d[NDI]; | |
+extern Diver *dip; | |
+ | |
+ | |
+extern char xchname[]; | |
+extern short xchtab[]; | |
+extern char *codestr; | |
+extern char *chnamep; | |
+extern short *chtab; | |
+extern int nchtab; | |
+ | |
+extern Numtab *numtabp; | |
+ | |
+/* these characters are used as various signals or values | |
+/* in miscellaneous places. | |
+/* values are set in specnames in t10.c | |
+*/ | |
+ | |
+extern int c_hyphen; | |
+extern int c_emdash; | |
+extern int c_rule; | |
+extern int c_minus; | |
+extern int c_fi; | |
+extern int c_fl; | |
+extern int c_ff; | |
+extern int c_ffi; | |
+extern int c_ffl; | |
+extern int c_acute; | |
+extern int c_grave; | |
+extern int c_under; | |
+extern int c_rooten; | |
+extern int c_boxrule; | |
+extern int c_lefthand; | |
+extern int c_dagger; | |
+extern int c_isalnum; | |
+ | |
+/* | |
+ * String pointers for DWB pathname management. | |
+ */ | |
+ | |
+extern char *DWBfontdir; | |
+extern char *DWBntermdir; | |
+extern char *DWBalthyphens; | |
+ | |
diff --git a/troff/find b/troff/find | |
@@ -0,0 +1 @@ | |
+grep $1 *.[ch] | |
diff --git a/troff/fns.h b/troff/fns.h | |
@@ -0,0 +1,389 @@ | |
+#define getline p9getline | |
+ | |
+/* | |
+ * other | |
+ */ | |
+#ifdef NOTDEF | |
+int pclose(FILE*); | |
+long filesize(int fd); | |
+int open(char *, int); | |
+int read(int, char *, int); | |
+int lseek(int, long, int); | |
+int close(int); | |
+int getpid(void); | |
+#endif | |
+char *unsharp(char*); | |
+ | |
+/* | |
+ * c1.c | |
+ */ | |
+void init0(void); | |
+void init2(void); | |
+void cvtime(void); | |
+void errprint(void); | |
+int control(int a, int b); | |
+void casept(void); | |
+int getrq(void); | |
+Tchar getch(void); | |
+void setxon(void); | |
+Tchar getch0(void); | |
+Tchar get1ch(FILE *); | |
+void pushback(Tchar *b); | |
+void cpushback(char *b); | |
+int nextfile(void); | |
+int popf(void); | |
+void flushi(void); | |
+int getach(void); | |
+void casenx(void); | |
+int getname(void); | |
+void caseso(void); | |
+void caself(void); | |
+void casecf(void); | |
+void getline(char *s, int n); | |
+void casesy(void); | |
+void getpn(char *a); | |
+void setrpt(void); | |
+ | |
+/* | |
+ * n2.c | |
+ */ | |
+int pchar(Tchar i); | |
+void pchar1(Tchar i); | |
+int pchar2(Tchar i); | |
+int flusho(void); | |
+void casedone(void); | |
+void caseex(void); | |
+void done(int x); | |
+void done1(int x); | |
+void done2(int x); | |
+void done3(int x); | |
+void edone(int x); | |
+void casepi(void); | |
+ | |
+/* | |
+ * c3.c | |
+ */ | |
+void blockinit(void); | |
+char* grow(char *, int, int); | |
+void mnspace(void); | |
+void caseig(void); | |
+void casern(void); | |
+void maddhash(Contab *rp); | |
+void munhash(Contab *mp); | |
+void mrehash(void); | |
+void caserm(void); | |
+void caseas(void); | |
+void caseds(void); | |
+void caseam(void); | |
+void casede(void); | |
+int findmn(int i); | |
+void clrmn(int i); | |
+Offset finds(int mn); | |
+int skip(void); | |
+int copyb(void); | |
+void copys(void); | |
+Offset alloc(void); | |
+void ffree(Offset i); | |
+void wbf(Tchar i); | |
+Tchar rbf(void); | |
+Tchar popi(void); | |
+Offset pushi(Offset newip, int mname); | |
+void* setbrk(int x); | |
+int getsn(void); | |
+Offset setstr(void); | |
+void collect(void); | |
+void seta(void); | |
+void caseda(void); | |
+void casegd(void); | |
+void casedi(void); | |
+void casedt(void); | |
+void casetl(void); | |
+void casepc(void); | |
+void casepm(void); | |
+void stackdump(void); | |
+ | |
+/* | |
+ * c4.c | |
+ */ | |
+void setn(void); | |
+int wrc(Tchar i); | |
+void setn1(int i, int form, Tchar bits); | |
+void nnspace(void); | |
+void nrehash(void); | |
+void nunhash(Numtab *rp); | |
+int findr(int i); | |
+int usedr(int i); | |
+int fnumb(int i, int (*f)(Tchar)); | |
+int decml(int i, int (*f)(Tchar)); | |
+int roman(int i, int (*f)(Tchar)); | |
+int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp); | |
+int abc(int i, int (*f)(Tchar)); | |
+int abc0(int i, int (*f)(Tchar)); | |
+long atoi0(void); | |
+long ckph(void); | |
+long atoi1(Tchar ii); | |
+void caserr(void); | |
+void casenr(void); | |
+void caseaf(void); | |
+void setaf(void); | |
+int vnumb(int *i); | |
+int hnumb(int *i); | |
+int inumb(int *n); | |
+int quant(int n, int m); | |
+ | |
+/* | |
+ * c5.c | |
+ */ | |
+void casead(void); | |
+void casena(void); | |
+void casefi(void); | |
+void casenf(void); | |
+void casers(void); | |
+void casens(void); | |
+int chget(int c); | |
+void casecc(void); | |
+void casec2(void); | |
+void casehc(void); | |
+void casetc(void); | |
+void caselc(void); | |
+void casehy(void); | |
+int max(int aa, int bb); | |
+void casenh(void); | |
+void casece(void); | |
+void casein(void); | |
+void casell(void); | |
+void caselt(void); | |
+void caseti(void); | |
+void casels(void); | |
+void casepo(void); | |
+void casepl(void); | |
+void casewh(void); | |
+void casech(void); | |
+int findn(int i); | |
+void casepn(void); | |
+void casebp(void); | |
+void casextm(void); | |
+void casetm(void); | |
+void casefm(void); | |
+void casetm1(int ab, FILE *out); | |
+void casesp(void); | |
+void casesp1(int a); | |
+void casert(void); | |
+void caseem(void); | |
+void casefl(void); | |
+void caseev(void); | |
+void envcopy(Env *e1, Env *e2); | |
+void caseel(void); | |
+void caseie(void); | |
+void casexif(void); | |
+void caseif(void); | |
+void caseif1(int); | |
+void eatblk(int inblk); | |
+int cmpstr(Tchar c); | |
+void caserd(void); | |
+int rdtty(void); | |
+void caseec(void); | |
+void caseeo(void); | |
+void caseta(void); | |
+void casene(void); | |
+void casetr(void); | |
+void casecu(void); | |
+void caseul(void); | |
+void caseuf(void); | |
+void caseit(void); | |
+void casemc(void); | |
+void casemk(void); | |
+void casesv(void); | |
+void caseos(void); | |
+void casenm(void); | |
+void getnm(int *p, int min); | |
+void casenn(void); | |
+void caseab(void); | |
+void save_tty(void); | |
+void restore_tty(void); | |
+void set_tty(void); | |
+void echo_off(void); | |
+void echo_on(void); | |
+ | |
+/* | |
+ * t6.c | |
+ */ | |
+int t_width(Tchar j); | |
+void zapwcache(int s); | |
+int onfont(int n, int f); | |
+int getcw(int i); | |
+void xbits(Tchar i, int bitf); | |
+Tchar t_setch(int c); | |
+Tchar t_setabs(void); | |
+int t_findft(int i); | |
+void caseps(void); | |
+void casps1(int i); | |
+int findps(int i); | |
+void t_mchbits(void); | |
+void t_setps(void); | |
+Tchar t_setht(void); | |
+Tchar t_setslant(void); | |
+void caseft(void); | |
+void t_setfont(int a); | |
+void t_setwd(void); | |
+Tchar t_vmot(void); | |
+Tchar t_hmot(void); | |
+Tchar t_mot(void); | |
+Tchar t_sethl(int k); | |
+Tchar t_makem(int i); | |
+Tchar getlg(Tchar i); | |
+void caselg(void); | |
+void casefp(void); | |
+char *strdupl(const char *); | |
+int setfp(int pos, int f, char *truename, int print); | |
+void casecs(void); | |
+void casebd(void); | |
+void casevs(void); | |
+void casess(void); | |
+Tchar t_xlss(void); | |
+Uchar* unpair(int i); | |
+void outascii(Tchar i); | |
+ | |
+/* | |
+ * c7.c | |
+ */ | |
+void tbreak(void); | |
+void donum(void); | |
+void text(void); | |
+void nofill(void); | |
+void callsp(void); | |
+void ckul(void); | |
+void storeline(Tchar c, int w); | |
+void newline(int a); | |
+int findn1(int a); | |
+void chkpn(void); | |
+int findt(int a); | |
+int findt1(void); | |
+void eject(Stack *a); | |
+int movword(void); | |
+void horiz(int i); | |
+void setnel(void); | |
+int getword(int x); | |
+void storeword(Tchar c, int w); | |
+Tchar gettch(void); | |
+ | |
+/* | |
+ * c8.c | |
+ */ | |
+void hyphen(Tchar *wp); | |
+int punct(Tchar i); | |
+int alph(int i); | |
+void caseha(void); | |
+void caseht(void); | |
+void casehw(void); | |
+int exword(void); | |
+int suffix(void); | |
+int maplow(int i); | |
+int vowel(int i); | |
+Tchar* chkvow(Tchar *w); | |
+void digram(void); | |
+int dilook(int a, int b, char t[26][13]); | |
+ | |
+/* | |
+ * c9.c | |
+ */ | |
+Tchar setz(void); | |
+void setline(void); | |
+int eat(int c); | |
+void setov(void); | |
+void setbra(void); | |
+void setvline(void); | |
+void setdraw(void); | |
+void casefc(void); | |
+Tchar setfield(int x); | |
+ | |
+/* | |
+ * t10.c | |
+ */ | |
+void t_ptinit(void); | |
+void t_specnames(void); | |
+void t_ptout(Tchar i); | |
+int ptout0(Tchar *pi); | |
+void ptchname(int); | |
+void ptflush(void); | |
+void ptps(void); | |
+void ptfont(void); | |
+void ptfpcmd(int f, char *s, char *fn); | |
+void t_ptlead(void); | |
+void ptesc(void); | |
+void ptpage(int n); | |
+void pttrailer(void); | |
+void ptstop(void); | |
+void t_ptpause(void); | |
+ | |
+/* | |
+ * t11.c | |
+ */ | |
+int getdesc(char *name); | |
+int getfont(char *name, int pos); | |
+int chadd(char *s, int, int); | |
+char* chname(int n); | |
+int getlig(FILE *fin); | |
+ | |
+/* | |
+ * n6.c | |
+ */ | |
+int n_width(Tchar j); | |
+Tchar n_setch(int c); | |
+Tchar n_setabs(void); | |
+int n_findft(int i); | |
+void n_mchbits(void); | |
+void n_setps(void); | |
+Tchar n_setht(void); | |
+Tchar n_setslant(void); | |
+void n_caseft(void); | |
+void n_setfont(int a); | |
+void n_setwd(void); | |
+Tchar n_vmot(void); | |
+Tchar n_hmot(void); | |
+Tchar n_mot(void); | |
+Tchar n_sethl(int k); | |
+Tchar n_makem(int i); | |
+void n_casefp(void); | |
+void n_casebd(void); | |
+void n_casevs(void); | |
+Tchar n_xlss(void); | |
+ | |
+/* | |
+ * n10.c | |
+ */ | |
+void n_ptinit(void); | |
+char* skipstr(char *s); | |
+char* getstr(char *s, char *t); | |
+char* getint(char *s, int *pn); | |
+void twdone(void); | |
+void n_specnames(void); | |
+int findch(char *s); | |
+void n_ptout(Tchar i); | |
+void ptout1(void); | |
+char* plot(char *x); | |
+void move(void); | |
+void n_ptlead(void); | |
+void n_ptpause(void); | |
+ | |
+/* | |
+ * indirect calls on TROFF/!TROFF. these are variables! | |
+ */ | |
+extern Tchar (*hmot)(void); | |
+extern Tchar (*makem)(int i); | |
+extern Tchar (*setabs)(void); | |
+extern Tchar (*setch)(int c); | |
+extern Tchar (*sethl)(int k); | |
+extern Tchar (*setht)(void); | |
+extern Tchar (*setslant)(void); | |
+extern Tchar (*vmot)(void); | |
+extern Tchar (*xlss)(void); | |
+extern int (*findft)(int i); | |
+extern int (*width)(Tchar j); | |
+extern void (*mchbits)(void); | |
+extern void (*ptlead)(void); | |
+extern void (*ptout)(Tchar i); | |
+extern void (*ptpause)(void); | |
+extern void (*setfont)(int a); | |
+extern void (*setps)(void); | |
+extern void (*setwd)(void); | |
diff --git a/troff/hytab.c b/troff/hytab.c | |
@@ -0,0 +1,126 @@ | |
+/* | |
+ * Hyphenation digram tables | |
+ */ | |
+ | |
+typedef unsigned char Uchar; | |
+ | |
+ | |
+Uchar bxh[26][13] = { | |
+ 0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0040,0000,0040 | |
+}; | |
+ | |
+Uchar hxx[26][13] = { | |
+ 0006,0042,0041,0123,0021,0024,0063,0042,0002,0043,0021,0001,0022, | |
+ 0140,0000,0200,0003,0260,0006,0000,0160,0007,0000,0140,0000,0320, | |
+ 0220,0000,0160,0005,0240,0010,0000,0100,0006,0000,0200,0000,0320, | |
+ 0240,0000,0120,0003,0140,0000,0000,0240,0010,0000,0220,0000,0160, | |
+ 0042,0023,0041,0040,0040,0022,0043,0041,0030,0064,0021,0000,0041, | |
+ 0100,0000,0140,0000,0220,0006,0000,0140,0003,0000,0200,0000,0000, | |
+ 0200,0000,0120,0002,0220,0010,0000,0160,0006,0000,0140,0000,0320, | |
+ 0020,0000,0020,0000,0020,0000,0000,0020,0000,0000,0020,0000,0000, | |
+ 0043,0163,0065,0044,0022,0043,0104,0042,0061,0146,0061,0000,0007, | |
+ 0100,0000,0140,0000,0040,0000,0000,0100,0000,0000,0120,0000,0000, | |
+ 0140,0000,0040,0011,0060,0004,0001,0120,0003,0000,0140,0000,0040, | |
+ 0200,0000,0100,0000,0140,0000,0000,0140,0000,0000,0140,0000,0240, | |
+ 0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0140,0000,0240, | |
+ 0200,0000,0140,0000,0160,0000,0000,0220,0000,0000,0060,0000,0240, | |
+ 0021,0043,0041,0121,0040,0023,0042,0003,0142,0042,0061,0001,0022, | |
+ 0120,0000,0140,0010,0140,0010,0000,0140,0002,0000,0120,0000,0120, | |
+ 0000,0000,0000,0000,0360,0000,0000,0000,0000,0000,0160,0000,0000, | |
+ 0100,0000,0040,0005,0120,0000,0000,0100,0000,0000,0060,0000,0140, | |
+ 0140,0040,0100,0001,0240,0041,0000,0242,0000,0002,0140,0000,0100, | |
+ 0240,0000,0120,0002,0200,0000,0000,0320,0007,0000,0240,0000,0340, | |
+ 0101,0021,0041,0020,0040,0005,0042,0121,0002,0021,0201,0000,0020, | |
+ 0160,0000,0100,0000,0140,0000,0000,0160,0006,0000,0220,0000,0140, | |
+ 0140,0000,0020,0001,0020,0000,0000,0100,0001,0000,0300,0000,0000, | |
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000, | |
+ 0106,0041,0040,0147,0040,0000,0063,0041,0001,0102,0160,0002,0002, | |
+ 0300,0000,0040,0017,0140,0017,0000,0240,0000,0000,0140,0000,0120 | |
+}; | |
+ | |
+Uchar bxxh[26][13] = { | |
+ 0005,0150,0153,0062,0062,0246,0152,0127,0146,0203,0310,0017,0206, | |
+ 0100,0000,0120,0000,0140,0000,0000,0100,0000,0000,0120,0000,0060, | |
+ 0100,0000,0040,0000,0060,0000,0000,0060,0000,0000,0220,0000,0040, | |
+ 0100,0000,0120,0000,0200,0000,0000,0100,0000,0000,0140,0000,0060, | |
+ 0043,0142,0046,0140,0062,0147,0210,0131,0046,0106,0246,0017,0111, | |
+ 0060,0000,0020,0000,0060,0000,0000,0040,0000,0000,0100,0000,0000, | |
+ 0060,0000,0040,0000,0040,0000,0000,0040,0000,0000,0100,0000,0040, | |
+ 0100,0000,0100,0000,0100,0000,0000,0040,0000,0000,0100,0000,0140, | |
+ 0066,0045,0145,0140,0000,0070,0377,0030,0130,0103,0003,0017,0006, | |
+ 0040,0000,0040,0000,0020,0000,0000,0040,0000,0000,0100,0000,0000, | |
+ 0200,0000,0020,0000,0140,0000,0000,0120,0000,0000,0120,0000,0040, | |
+ 0120,0000,0040,0000,0060,0000,0000,0060,0000,0000,0160,0000,0040, | |
+ 0120,0000,0040,0000,0120,0000,0000,0040,0000,0000,0160,0000,0040, | |
+ 0120,0000,0020,0000,0140,0000,0000,0120,0000,0000,0140,0000,0040, | |
+ 0051,0126,0150,0140,0060,0210,0146,0006,0006,0165,0003,0017,0244, | |
+ 0120,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0000,0140, | |
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000, | |
+ 0140,0000,0140,0000,0060,0000,0000,0100,0000,0000,0140,0000,0020, | |
+ 0120,0000,0020,0000,0060,0000,0000,0060,0000,0000,0060,0000,0040, | |
+ 0140,0000,0020,0000,0100,0000,0000,0140,0000,0000,0140,0000,0020, | |
+ 0070,0125,0051,0162,0120,0105,0126,0104,0006,0044,0000,0017,0052, | |
+ 0140,0000,0020,0000,0140,0000,0000,0060,0000,0000,0060,0000,0040, | |
+ 0020,0000,0000,0000,0020,0000,0000,0000,0000,0000,0000,0000,0060, | |
+ 0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0000,0240, | |
+ 0065,0042,0060,0200,0000,0210,0222,0146,0006,0204,0220,0012,0003, | |
+ 0240,0000,0020,0000,0120,0000,0000,0200,0000,0000,0200,0000,0240 | |
+}; | |
+ | |
+Uchar xhx[26][13] = { | |
+ 0032,0146,0042,0107,0076,0102,0042,0146,0202,0050,0006,0000,0051, | |
+ 0036,0377,0057,0013,0057,0366,0377,0057,0001,0377,0057,0000,0040, | |
+ 0037,0377,0020,0000,0100,0022,0377,0057,0362,0116,0100,0000,0017, | |
+ 0057,0377,0057,0031,0137,0363,0377,0037,0362,0270,0077,0000,0117, | |
+ 0074,0142,0012,0236,0076,0125,0063,0165,0341,0046,0047,0000,0024, | |
+ 0020,0017,0075,0377,0040,0001,0377,0017,0001,0204,0020,0000,0040, | |
+ 0057,0017,0057,0340,0140,0362,0314,0117,0003,0302,0100,0000,0057, | |
+ 0057,0357,0077,0017,0100,0366,0314,0057,0342,0346,0037,0000,0060, | |
+ 0252,0145,0072,0157,0377,0165,0063,0066,0164,0050,0363,0000,0362, | |
+ 0000,0000,0020,0000,0020,0000,0000,0017,0000,0000,0020,0000,0000, | |
+ 0117,0017,0237,0377,0200,0354,0125,0110,0004,0257,0000,0000,0300, | |
+ 0057,0367,0054,0357,0157,0216,0314,0114,0217,0353,0053,0000,0057, | |
+ 0077,0213,0077,0077,0177,0317,0377,0114,0377,0352,0077,0000,0076, | |
+ 0077,0213,0077,0077,0157,0177,0377,0054,0377,0352,0117,0000,0075, | |
+ 0125,0230,0065,0216,0057,0066,0063,0047,0345,0126,0011,0000,0033, | |
+ 0057,0377,0051,0360,0120,0361,0273,0056,0001,0256,0057,0000,0060, | |
+ 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000, | |
+ 0076,0310,0056,0310,0137,0174,0273,0055,0335,0266,0033,0000,0155, | |
+ 0077,0157,0057,0360,0057,0063,0042,0024,0077,0206,0020,0000,0040, | |
+ 0057,0037,0077,0360,0100,0365,0377,0037,0362,0176,0050,0000,0026, | |
+ 0167,0146,0042,0112,0077,0110,0062,0254,0366,0052,0377,0000,0163, | |
+ 0060,0000,0040,0000,0120,0000,0377,0060,0012,0000,0037,0000,0257, | |
+ 0037,0232,0157,0361,0040,0003,0125,0010,0001,0256,0000,0000,0340, | |
+ 0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0377,0017,0277, | |
+ 0253,0315,0257,0216,0377,0206,0146,0306,0371,0126,0232,0000,0004, | |
+ 0057,0012,0100,0360,0160,0360,0000,0040,0000,0017,0157,0000,0176 | |
+}; | |
+ | |
+Uchar xxh[26][13] = { | |
+ 0045,0150,0154,0162,0042,0246,0210,0147,0152,0103,0230,0017,0206, | |
+ 0100,0000,0040,0000,0140,0000,0000,0100,0000,0021,0120,0017,0060, | |
+ 0100,0000,0040,0002,0140,0320,0000,0060,0000,0001,0220,0017,0040, | |
+ 0100,0001,0120,0001,0241,0000,0000,0100,0000,0020,0140,0017,0060, | |
+ 0023,0162,0046,0142,0022,0207,0210,0131,0052,0106,0250,0017,0110, | |
+ 0060,0000,0042,0000,0160,0000,0000,0040,0000,0212,0100,0017,0000, | |
+ 0140,0000,0040,0002,0140,0000,0000,0120,0000,0040,0120,0017,0040, | |
+ 0100,0000,0100,0000,0140,0001,0021,0140,0000,0046,0100,0017,0140, | |
+ 0066,0045,0025,0201,0020,0130,0146,0030,0130,0103,0025,0017,0006, | |
+ 0100,0000,0040,0000,0020,0000,0000,0040,0000,0000,0200,0017,0000, | |
+ 0200,0000,0020,0001,0140,0000,0000,0140,0000,0000,0120,0017,0040, | |
+ 0120,0026,0042,0020,0140,0161,0042,0143,0000,0022,0162,0017,0040, | |
+ 0121,0042,0060,0020,0140,0200,0000,0123,0000,0021,0220,0017,0041, | |
+ 0121,0042,0060,0120,0140,0200,0000,0123,0000,0021,0160,0017,0041, | |
+ 0051,0126,0150,0141,0060,0210,0146,0066,0026,0165,0026,0017,0247, | |
+ 0120,0000,0040,0003,0160,0000,0000,0140,0000,0021,0100,0017,0140, | |
+ 0000,0000,0000,0000,0200,0000,0000,0000,0000,0000,0000,0017,0000, | |
+ 0141,0023,0122,0040,0160,0143,0042,0142,0000,0047,0143,0017,0020, | |
+ 0120,0000,0040,0006,0140,0060,0000,0141,0000,0026,0100,0017,0040, | |
+ 0140,0000,0020,0007,0100,0000,0000,0140,0000,0001,0140,0017,0020, | |
+ 0110,0125,0051,0162,0120,0125,0127,0104,0006,0104,0000,0017,0052, | |
+ 0140,0000,0040,0000,0160,0000,0000,0140,0000,0000,0060,0017,0000, | |
+ 0040,0005,0020,0000,0040,0313,0231,0030,0000,0140,0000,0017,0056, | |
+ 0140,0000,0160,0000,0200,0000,0000,0140,0000,0000,0000,0017,0240, | |
+ 0065,0042,0060,0040,0000,0206,0231,0146,0006,0224,0220,0017,0004, | |
+ 0240,0000,0020,0000,0140,0000,0000,0220,0000,0000,0200,0017,0141 | |
+}; | |
diff --git a/troff/mbwc.c b/troff/mbwc.c | |
@@ -0,0 +1,165 @@ | |
+#include <stdlib.h> | |
+ | |
+/* | |
+ * Use the FSS-UTF transformation proposed by posix. | |
+ * We define 7 byte types: | |
+ * T0 0xxxxxxx 7 free bits | |
+ * Tx 10xxxxxx 6 free bits | |
+ * T1 110xxxxx 5 free bits | |
+ * T2 1110xxxx 4 free bits | |
+ * | |
+ * Encoding is as follows. | |
+ * From hex Thru hex Sequence Bits | |
+ * 00000000 0000007F T0 7 | |
+ * 00000080 000007FF T1 Tx 11 | |
+ * 00000800 0000FFFF T2 Tx Tx 16 | |
+ */ | |
+ | |
+int | |
+mblen(const char *s, size_t n) | |
+{ | |
+ | |
+ return mbtowc(0, s, n); | |
+} | |
+ | |
+int | |
+mbtowc(wchar_t *pwc, const char *s, size_t n) | |
+{ | |
+ int c, c1, c2; | |
+ long l; | |
+ | |
+ if(!s) | |
+ return 0; | |
+ | |
+ if(n < 1) | |
+ goto bad; | |
+ c = s[0] & 0xff; | |
+ if((c & 0x80) == 0x00) { | |
+ if(pwc) | |
+ *pwc = c; | |
+ if(c == 0) | |
+ return 0; | |
+ return 1; | |
+ } | |
+ | |
+ if(n < 2) | |
+ goto bad; | |
+ c1 = (s[1] ^ 0x80) & 0xff; | |
+ if((c1 & 0xC0) != 0x00) | |
+ goto bad; | |
+ if((c & 0xE0) == 0xC0) { | |
+ l = ((c << 6) | c1) & 0x7FF; | |
+ if(l < 0x080) | |
+ goto bad; | |
+ if(pwc) | |
+ *pwc = l; | |
+ return 2; | |
+ } | |
+ | |
+ if(n < 3) | |
+ goto bad; | |
+ c2 = (s[2] ^ 0x80) & 0xff; | |
+ if((c2 & 0xC0) != 0x00) | |
+ goto bad; | |
+ if((c & 0xF0) == 0xE0) { | |
+ l = ((((c << 6) | c1) << 6) | c2) & 0xFFFF; | |
+ if(l < 0x0800) | |
+ goto bad; | |
+ if(pwc) | |
+ *pwc = l; | |
+ return 3; | |
+ } | |
+ | |
+ /* | |
+ * bad decoding | |
+ */ | |
+bad: | |
+ return -1; | |
+ | |
+} | |
+ | |
+int | |
+wctomb(char *s, wchar_t wchar) | |
+{ | |
+ long c; | |
+ | |
+ if(!s) | |
+ return 0; | |
+ | |
+ c = wchar & 0xFFFF; | |
+ if(c < 0x80) { | |
+ s[0] = c; | |
+ return 1; | |
+ } | |
+ | |
+ if(c < 0x800) { | |
+ s[0] = 0xC0 | (c >> 6); | |
+ s[1] = 0x80 | (c & 0x3F); | |
+ return 2; | |
+ } | |
+ | |
+ s[0] = 0xE0 | (c >> 12); | |
+ s[1] = 0x80 | ((c >> 6) & 0x3F); | |
+ s[2] = 0x80 | (c & 0x3F); | |
+ return 3; | |
+} | |
+ | |
+size_t | |
+mbstowcs(wchar_t *pwcs, const char *s, size_t n) | |
+{ | |
+ int i, d, c; | |
+ | |
+ for(i=0; i < n; i++) { | |
+ c = *s & 0xff; | |
+ if(c < 0x80) { | |
+ *pwcs = c; | |
+ if(c == 0) | |
+ break; | |
+ s++; | |
+ } else { | |
+ d = mbtowc(pwcs, s, 3); | |
+ if(d <= 0) | |
+ return (size_t)((d<0) ? -1 : i); | |
+ s += d; | |
+ } | |
+ pwcs++; | |
+ } | |
+ return i; | |
+} | |
+ | |
+size_t | |
+wcstombs(char *s, const wchar_t *pwcs, size_t n) | |
+{ | |
+ int d; | |
+ long c; | |
+ char *p, *pe; | |
+ char buf[3]; | |
+ | |
+ p = s; | |
+ pe = p+n-3; | |
+ while(p < pe) { | |
+ c = *pwcs++; | |
+ if(c < 0x80) | |
+ *p++ = c; | |
+ else | |
+ p += wctomb(p, c); | |
+ if(c == 0) | |
+ return p-s; | |
+ } | |
+ while(p < pe+3) { | |
+ c = *pwcs++; | |
+ d = wctomb(buf, c); | |
+ if(p+d <= pe+3) { | |
+ *p++ = buf[0]; | |
+ if(d > 1) { | |
+ *p++ = buf[2]; | |
+ if(d > 2) | |
+ *p++ = buf[3]; | |
+ } | |
+ } | |
+ if(c == 0) | |
+ break; | |
+ } | |
+ return p-s; | |
+} | |
+ | |
diff --git a/troff/mkfile b/troff/mkfile | |
@@ -0,0 +1,57 @@ | |
+<$PLAN9/src/mkhdr | |
+ | |
+TARG=troff | |
+OFILES=n1.$O\ | |
+ n2.$O\ | |
+ n3.$O\ | |
+ n4.$O\ | |
+ n5.$O\ | |
+ t6.$O\ | |
+ n6.$O\ | |
+ n7.$O\ | |
+ n8.$O\ | |
+ n9.$O\ | |
+ t10.$O\ | |
+ n10.$O\ | |
+ t11.$O\ | |
+ ni.$O\ | |
+ hytab.$O\ | |
+ suftab.$O\ | |
+ dwbinit.$O\ | |
+ mbwc.$O | |
+ | |
+HFILES=tdef.h\ | |
+ fns.h\ | |
+ ext.h\ | |
+ dwbinit.h\ | |
+ | |
+ | |
+<$PLAN9/src/mkone | |
+CFLAGS=-DUNICODE | |
+ | |
+TMACDIR='"tmac/tmac."' | |
+FONTDIR='"troff/font"' | |
+NTERMDIR='"troff/term/tab."' | |
+ALTHYPHENS='"lib/hyphen.tex"' | |
+TEXHYPHENS='"#9/lib/hyphen.tex"' | |
+DWBHOME='"#9/"' | |
+TDEVNAME='"utf"' | |
+NDEVNAME='"utf"' | |
+ | |
+ni.$O: ni.c $HFILES | |
+ $CC $CFLAGS -DTMACDIR=$TMACDIR ni.c | |
+ | |
+t10.$O: t10.c $HFILES | |
+ $CC $CFLAGS -DTDEVNAME=$TDEVNAME t10.c | |
+ | |
+n1.$O: n1.c $HFILES | |
+ $CC $CFLAGS -DFONTDIR=$FONTDIR -DNTERMDIR=$NTERMDIR -DTEXHYPHENS=$TEXH… | |
+ | |
+n10.$O: n10.c $HFILES | |
+ $CC $CFLAGS -DTDEVNAME=$NDEVNAME n10.c | |
+ | |
+n8.$O: n8.c $HFILES | |
+ $CC $CFLAGS -DTEXHYPHENS=$TEXHYPHENS n8.c | |
+ | |
+dwbinit.$O: dwbinit.c | |
+ $CC $CFLAGS -DDWBHOME=$DWBHOME dwbinit.c | |
diff --git a/troff/n1.c b/troff/n1.c | |
@@ -0,0 +1,1134 @@ | |
+/* | |
+ * n1.c | |
+ * | |
+ * consume options, initialization, main loop, | |
+ * input routines, escape function calling | |
+ */ | |
+ | |
+#include <u.h> | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+#include "dwbinit.h" | |
+ | |
+#include <setjmp.h> | |
+#include <time.h> | |
+ | |
+char *Version = "March 11, 1994"; | |
+ | |
+#ifndef DWBVERSION | |
+#define DWBVERSION "???" | |
+#endif | |
+ | |
+char *DWBfontdir = FONTDIR; | |
+char *DWBntermdir = NTERMDIR; | |
+char *DWBalthyphens = ALTHYPHENS; | |
+char *DWBhomedir = ""; | |
+ | |
+dwbinit dwbpaths[] = { | |
+ &DWBfontdir, NULL, 0, | |
+ &DWBntermdir, NULL, 0, | |
+ &DWBalthyphens, NULL, 0, | |
+ &DWBhomedir, NULL, 0, | |
+ NULL, nextf, NS, | |
+ NULL, NULL, 0 | |
+}; | |
+ | |
+int TROFF = 1; /* assume we started in troff... */ | |
+ | |
+jmp_buf sjbuf; | |
+Offset ipl[NSO]; | |
+ | |
+static FILE *ifile; | |
+static FILE *ifl[NSO]; /* open input file pointers */ | |
+char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */ | |
+int cfline[NSO]; /* input line count stack */ | |
+char *progname; /* program name (troff or nroff) */ | |
+ | |
+int trace = 0; /* tracing mode: default off */ | |
+int trace1 = 0; | |
+ | |
+int | |
+main(int argc, char *argv[]) | |
+{ | |
+ char *p; | |
+ int j; | |
+ Tchar i; | |
+ char buf[100]; | |
+ | |
+ ifile = stdin; /* gcc */ | |
+ ptid = stdout; | |
+ | |
+ buf[0] = '\0'; /* make sure it's empty (silly 3b2) */ | |
+ progname = argv[0]; | |
+ if ((p = strrchr(progname, '/')) == NULL) | |
+ p = progname; | |
+ else | |
+ p++; | |
+ DWBinit(progname, dwbpaths); | |
+ if (strcmp(p, "nroff") == 0) | |
+ TROFF = 0; | |
+#ifdef UNICODE | |
+ alphabet = 128; /* unicode for plan 9 */ | |
+#endif /*UNICODE*/ | |
+ mnspace(); | |
+ nnspace(); | |
+ mrehash(); | |
+ nrehash(); | |
+ numtabp[NL].val = -1; | |
+ | |
+ while (--argc > 0 && (++argv)[0][0] == '-') | |
+ switch (argv[0][1]) { | |
+ | |
+ case 'N': /* ought to be used first... */ | |
+ TROFF = 0; | |
+ break; | |
+ case 'd': | |
+ fprintf(stderr, "troff/nroff version %s\n", Version); | |
+ break; | |
+ case 'F': /* switch font tables from default */ | |
+ if (argv[0][2] != '\0') { | |
+ strcpy(termtab, &argv[0][2]); | |
+ strcpy(fontdir, &argv[0][2]); | |
+ } else { | |
+ argv++; argc--; | |
+ strcpy(termtab, argv[0]); | |
+ strcpy(fontdir, argv[0]); | |
+ } | |
+ break; | |
+ case 0: | |
+ goto start; | |
+ case 'i': | |
+ stdi++; | |
+ break; | |
+ case 'n': | |
+ npn = atoi(&argv[0][2]); | |
+ break; | |
+ case 'u': /* set emboldening amount */ | |
+ bdtab[3] = atoi(&argv[0][2]); | |
+ if (bdtab[3] < 0 || bdtab[3] > 50) | |
+ bdtab[3] = 0; | |
+ break; | |
+ case 's': | |
+ if (!(stop = atoi(&argv[0][2]))) | |
+ stop++; | |
+ break; | |
+ case 'r': | |
+ sprintf(buf + strlen(buf), ".nr %c %s\n", | |
+ argv[0][2], &argv[0][3]); | |
+ /* not yet cpushback(buf);*/ | |
+ /* dotnr(&argv[0][2], &argv[0][3]); */ | |
+ break; | |
+ case 'm': | |
+ if (mflg++ >= NMF) { | |
+ ERROR "Too many macro packages: %s", argv[0] W… | |
+ break; | |
+ } | |
+ strcpy(mfiles[nmfi], nextf); | |
+ strcat(mfiles[nmfi++], &argv[0][2]); | |
+ break; | |
+ case 'o': | |
+ getpn(&argv[0][2]); | |
+ break; | |
+ case 'T': | |
+ strcpy(devname, &argv[0][2]); | |
+ dotT++; | |
+ break; | |
+ case 'a': | |
+ ascii = 1; | |
+ break; | |
+ case 'h': | |
+ hflg++; | |
+ break; | |
+ case 'e': | |
+ eqflg++; | |
+ break; | |
+ case 'q': | |
+ quiet++; | |
+ save_tty(); | |
+ break; | |
+ case 'V': | |
+ fprintf(stdout, "%croff: DWB %s\n", | |
+ TROFF ? 't' : 'n', DWBVERSION); | |
+ exit(0); | |
+ case 't': | |
+ if (argv[0][2] != '\0') | |
+ trace = trace1 = argv[0][2]; | |
+ break; /* for the sake of compatibility… | |
+ default: | |
+ ERROR "unknown option %s", argv[0] WARN; | |
+ done(02); | |
+ } | |
+ | |
+start: | |
+ /* | |
+ * cpushback maintains a LIFO, so push pack the -r arguments | |
+ * in reverse order to maintain a FIFO in case someone did -rC1 -rC3 | |
+ */ | |
+ if (buf[0]) { | |
+ char *p = buf; | |
+ while(*p++) | |
+ ; | |
+ while(p > buf) { | |
+ while(strncmp(p, ".nr", 3) != 0) | |
+ p--; | |
+ cpushback(p); | |
+ *p-- = '\0'; | |
+ } | |
+ } | |
+ argp = argv; | |
+ rargc = argc; | |
+ nmfi = 0; | |
+ init2(); | |
+ setjmp(sjbuf); | |
+loop: | |
+ copyf = lgf = nb = nflush = nlflg = 0; | |
+ if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) { | |
+ nflush++; | |
+ trap = 0; | |
+ eject((Stack *)0); | |
+ goto loop; | |
+ } | |
+ i = getch(); | |
+ if (pendt) | |
+ goto Lt; | |
+ if ((j = cbits(i)) == XPAR) { | |
+ copyf++; | |
+ tflg++; | |
+ while (cbits(i) != '\n') | |
+ pchar(i = getch()); | |
+ tflg = 0; | |
+ copyf--; | |
+ goto loop; | |
+ } | |
+ if (j == cc || j == c2) { | |
+ if (j == c2) | |
+ nb++; | |
+ copyf++; | |
+ while ((j = cbits(i = getch())) == ' ' || j == '\t') | |
+ ; | |
+ ch = i; | |
+ copyf--; | |
+ control(getrq(), 1); | |
+ flushi(); | |
+ goto loop; | |
+ } | |
+Lt: | |
+ ch = i; | |
+ text(); | |
+ if (nlflg) | |
+ numtabp[HP].val = 0; | |
+ goto loop; | |
+} | |
+ | |
+ | |
+ | |
+void init2(void) | |
+{ | |
+ int i; | |
+ char buf[100]; | |
+ | |
+ for (i = NTRTAB; --i; ) | |
+ trtab[i] = i; | |
+ trtab[UNPAD] = ' '; | |
+ iflg = 0; | |
+ obufp = obuf; | |
+ if (TROFF) | |
+ t_ptinit(); | |
+ else | |
+ n_ptinit(); | |
+ mchbits(); | |
+ cvtime(); | |
+ numtabp[PID].val = getpid(); | |
+ numtabp[HP].val = init = 0; | |
+ numtabp[NL].val = -1; | |
+ nfo = 0; | |
+ copyf = raw = 0; | |
+ sprintf(buf, ".ds .T %s\n", devname); | |
+ cpushback(buf); | |
+ sprintf(buf, ".ds .P %s\n", DWBhomedir); | |
+ cpushback(buf); | |
+ numtabp[CD].val = -1; /* compensation */ | |
+ nx = mflg; | |
+ frame = stk = (Stack *)setbrk(STACKSIZE); | |
+ dip = &d[0]; | |
+ nxf = frame + 1; | |
+ for (i = 1; i < NEV; i++) /* propagate the environment */ | |
+ envcopy(&env[i], &env[0]); | |
+ for (i = 0; i < NEV; i++) { | |
+ if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar… | |
+ ERROR "not enough room for word buffers" WARN; | |
+ done2(1); | |
+ } | |
+ env[i]._word._size = WDSIZE; | |
+ if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar… | |
+ ERROR "not enough room for line buffers" WARN; | |
+ done2(1); | |
+ } | |
+ env[i]._line._size = LNSIZE; | |
+ } | |
+ if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) { | |
+ ERROR "not enough room for line buffers" WARN; | |
+ done2(1); | |
+ } | |
+ olinep = oline; | |
+ olnsize = OLNSIZE; | |
+ blockinit(); | |
+} | |
+ | |
+void cvtime(void) | |
+{ | |
+ time_t tt; | |
+ struct tm *ltime; | |
+ | |
+ time(&tt); | |
+ ltime = localtime(&tt); | |
+ numtabp[YR].val = ltime->tm_year % 100; | |
+ numtabp[YR].fmt = 2; | |
+ numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */ | |
+ numtabp[DY].val = ltime->tm_mday; | |
+ numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */ | |
+} | |
+ | |
+ | |
+ | |
+char errbuf[200]; | |
+ | |
+void errprint(void) /* error message printer */ | |
+{ | |
+ int savecd = numtabp[CD].val; | |
+ | |
+ if (!nlflg) | |
+ numtabp[CD].val++; | |
+ | |
+ fprintf(stderr, "%s: ", progname); | |
+ fputs(errbuf, stderr); | |
+ if (cfname[ifi][0]) | |
+ fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val); | |
+ fputs("\n", stderr); | |
+ if (cfname[ifi][0]) | |
+ stackdump(); | |
+ numtabp[CD].val = savecd; | |
+} | |
+ | |
+ | |
+int control(int a, int b) | |
+{ | |
+ int j, k; | |
+ extern Contab *contabp; | |
+ | |
+ numerr.type = RQERR; | |
+ numerr.req = a; | |
+ if (a == 0 || (j = findmn(a)) == -1) | |
+ return(0); | |
+ if (contabp[j].f == 0) { | |
+ if (trace & TRMAC) | |
+ fprintf(stderr, "invoke macro %s\n", unpair(a)); | |
+ if (dip != d) | |
+ for (k = dilev; k; k--) | |
+ if (d[k].curd == a) { | |
+ ERROR "diversion %s invokes itself dur… | |
+ unpair(a) WARN; | |
+ edone(0100); | |
+ } | |
+ nxf->nargs = 0; | |
+ if (b) | |
+ collect(); | |
+ flushi(); | |
+ return pushi(contabp[j].mx, a); /* BUG??? all that matt… | |
+ } | |
+ if (b) { | |
+ if (trace & TRREQ) | |
+ fprintf(stderr, "invoke request %s\n", unpair(a)); | |
+ (*contabp[j].f)(); | |
+ } | |
+ return(0); | |
+} | |
+ | |
+void casept(void) | |
+{ | |
+ int i; | |
+ | |
+ noscale++; | |
+ if (skip()) | |
+ i = trace1; | |
+ else { | |
+ i = max(inumb(&trace), 0); | |
+ if (nonumb) | |
+ i = trace1; | |
+ } | |
+ trace1 = trace; | |
+ trace = i; | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+int getrq(void) | |
+{ | |
+ int i, j; | |
+ | |
+ if ((i = getach()) == 0 || (j = getach()) == 0) | |
+ goto rtn; | |
+ i = PAIR(i, j); | |
+rtn: | |
+ return(i); | |
+} | |
+ | |
+/* | |
+ * table encodes some special characters, to speed up tests | |
+ * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch | |
+ */ | |
+ | |
+char gchtab[NCHARS] = { | |
+ 000,004,000,000,010,000,000,000, /* fc, ldr */ | |
+ 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */ | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,001,000,001,000,000,000,000, /* FLSS, ESC */ | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,001,000, /* f */ | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000, | |
+ 000,000,000,000,000,000,000,000 | |
+}; | |
+ | |
+int realcbits(Tchar c) /* return character bits, or MOTCH if motion */ | |
+{ | |
+ if (ismot(c)) | |
+ return MOTCH; | |
+ else | |
+ return c & 0xFFFF; | |
+} | |
+ | |
+Tchar getch(void) | |
+{ | |
+ int k; | |
+ Tchar i, j; | |
+ | |
+g0: | |
+ if (ch) { | |
+ i = ch; | |
+ if (cbits(i) == '\n') | |
+ nlflg++; | |
+ ch = 0; | |
+ return(i); | |
+ } | |
+ | |
+ if (nlflg) | |
+ return('\n'); | |
+ i = getch0(); | |
+ if (ismot(i)) | |
+ return(i); | |
+ k = cbits(i); | |
+ if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /*… | |
+ return(i); | |
+ if (k != ESC) { | |
+ if (k == '\n') { | |
+ nlflg++; | |
+ if (ip == 0) | |
+ numtabp[CD].val++; /* line number */ | |
+ return(k); | |
+ } | |
+ if (k == FLSS) { | |
+ copyf++; | |
+ raw++; | |
+ i = getch0(); | |
+ if (!fi) | |
+ flss = i; | |
+ copyf--; | |
+ raw--; | |
+ goto g0; | |
+ } | |
+ if (k == RPT) { | |
+ setrpt(); | |
+ goto g0; | |
+ } | |
+ if (!copyf) { | |
+ if (k == 'f' && lg && !lgf) { | |
+ i = getlg(i); | |
+ return(i); | |
+ } | |
+ if (k == fc || k == tabch || k == ldrch) { | |
+ if ((i = setfield(k)) == 0) | |
+ goto g0; | |
+ else | |
+ return(i); | |
+ } | |
+ if (k == '\b') { | |
+ i = makem(-width(' ' | chbits)); | |
+ return(i); | |
+ } | |
+ } | |
+ return(i); | |
+ } | |
+ | |
+ k = cbits(j = getch0()); | |
+ if (ismot(j)) | |
+ return(j); | |
+ | |
+ switch (k) { | |
+ case 'n': /* number register */ | |
+ setn(); | |
+ goto g0; | |
+ case '$': /* argument indicator */ | |
+ seta(); | |
+ goto g0; | |
+ case '*': /* string indicator */ | |
+ setstr(); | |
+ goto g0; | |
+ case '{': /* LEFT */ | |
+ i = LEFT; | |
+ goto gx; | |
+ case '}': /* RIGHT */ | |
+ i = RIGHT; | |
+ goto gx; | |
+ case '"': /* comment */ | |
+ while (cbits(i = getch0()) != '\n') | |
+ ; | |
+ if (ip == 0) | |
+ numtabp[CD].val++; /* line number */ | |
+ nlflg++; | |
+ return(i); | |
+ | |
+/* experiment: put it here instead of copy mode */ | |
+ case '(': /* special char name \(xx */ | |
+ case 'C': /* \C'...' */ | |
+ if ((i = setch(k)) == 0) | |
+ goto g0; | |
+ goto gx; | |
+ | |
+ case ESC: /* double backslash */ | |
+ i = eschar; | |
+ goto gx; | |
+ case 'e': /* printable version of current eschar */ | |
+ i = PRESC; | |
+ goto gx; | |
+ case '\n': /* concealed newline */ | |
+ numtabp[CD].val++; | |
+ goto g0; | |
+ case ' ': /* unpaddable space */ | |
+ i = UNPAD; | |
+ goto gx; | |
+ case '\'': /* \(aa */ | |
+ i = ACUTE; | |
+ goto gx; | |
+ case '`': /* \(ga */ | |
+ i = GRAVE; | |
+ goto gx; | |
+ case '_': /* \(ul */ | |
+ i = UNDERLINE; | |
+ goto gx; | |
+ case '-': /* current font minus */ | |
+ i = MINUS; | |
+ goto gx; | |
+ case '&': /* filler */ | |
+ i = FILLER; | |
+ goto gx; | |
+ case 'c': /* to be continued */ | |
+ i = CONT; | |
+ goto gx; | |
+ case '!': /* transparent indicator */ | |
+ i = XPAR; | |
+ goto gx; | |
+ case 't': /* tab */ | |
+ i = '\t'; | |
+ return(i); | |
+ case 'a': /* leader (SOH) */ | |
+/* old: *pbp++ = LEADER; goto g0; */ | |
+ i = LEADER; | |
+ return i; | |
+ case '%': /* ohc */ | |
+ i = OHC; | |
+ return(i); | |
+ case 'g': /* return format of a number register */ | |
+ setaf(); /* should this really be in copy mode??? */ | |
+ goto g0; | |
+ case '.': /* . */ | |
+ i = '.'; | |
+gx: | |
+ setsfbits(i, sfbits(j)); | |
+ return(i); | |
+ } | |
+ if (copyf) { | |
+ *pbp++ = j; | |
+ return(eschar); | |
+ } | |
+ switch (k) { | |
+ | |
+ case 'f': /* font indicator */ | |
+ setfont(0); | |
+ goto g0; | |
+ case 's': /* size indicator */ | |
+ setps(); | |
+ goto g0; | |
+ case 'v': /* vert mot */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ if (i = vmot()) { | |
+ return(i); | |
+ } | |
+ goto g0; | |
+ case 'h': /* horiz mot */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ if (i = hmot()) | |
+ return(i); | |
+ goto g0; | |
+ case '|': /* narrow space */ | |
+ if (NROFF) | |
+ goto g0; | |
+ return(makem((int)(EM)/6)); | |
+ case '^': /* half narrow space */ | |
+ if (NROFF) | |
+ goto g0; | |
+ return(makem((int)(EM)/12)); | |
+ case 'w': /* width function */ | |
+ setwd(); | |
+ goto g0; | |
+ case 'p': /* spread */ | |
+ spread++; | |
+ goto g0; | |
+ case 'N': /* absolute character number */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ if ((i = setabs()) == 0) | |
+ goto g0; | |
+ return i; | |
+ case 'H': /* character height */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ return(setht()); | |
+ case 'S': /* slant */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ return(setslant()); | |
+ case 'z': /* zero with char */ | |
+ return(setz()); | |
+ case 'l': /* hor line */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ setline(); | |
+ goto g0; | |
+ case 'L': /* vert line */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ setvline(); | |
+ goto g0; | |
+ case 'D': /* drawing function */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ setdraw(); | |
+ goto g0; | |
+ case 'X': /* \X'...' for copy through */ | |
+ setxon(); | |
+ goto g0; | |
+ case 'b': /* bracket */ | |
+ setbra(); | |
+ goto g0; | |
+ case 'o': /* overstrike */ | |
+ setov(); | |
+ goto g0; | |
+ case 'k': /* mark hor place */ | |
+ if ((k = findr(getsn())) != -1) { | |
+ numtabp[k].val = numtabp[HP].val; | |
+ } | |
+ goto g0; | |
+ case '0': /* number space */ | |
+ return(makem(width('0' | chbits))); | |
+ case 'x': /* extra line space */ | |
+ numerr.type = numerr.escarg = 0; numerr.esc = k; | |
+ if (i = xlss()) | |
+ return(i); | |
+ goto g0; | |
+ case 'u': /* half em up */ | |
+ case 'r': /* full em up */ | |
+ case 'd': /* half em down */ | |
+ return(sethl(k)); | |
+ default: | |
+ return(j); | |
+ } | |
+ /* NOTREACHED */ | |
+} | |
+ | |
+void setxon(void) /* \X'...' for copy through */ | |
+{ | |
+ Tchar xbuf[NC]; | |
+ Tchar *i; | |
+ Tchar c; | |
+ int delim, k; | |
+ | |
+ if (ismot(c = getch())) | |
+ return; | |
+ delim = cbits(c); | |
+ i = xbuf; | |
+ *i++ = XON | chbits; | |
+ while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1… | |
+ if (k == ' ') | |
+ setcbits(c, WORDSP); | |
+ *i++ = c | ZBIT; | |
+ } | |
+ *i++ = XOFF | chbits; | |
+ *i = 0; | |
+ pushback(xbuf); | |
+} | |
+ | |
+ | |
+char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 }; | |
+ | |
+Tchar getch0(void) | |
+{ | |
+ Tchar i; | |
+ | |
+again: | |
+ if (pbp > lastpbp) | |
+ i = *--pbp; | |
+ else if (ip) { | |
+ /* i = rbf(); */ | |
+ i = rbf0(ip); | |
+ if (i == 0) | |
+ i = rbf(); | |
+ else { | |
+ ++ip; | |
+ if (pastend(ip)) { | |
+ --ip; | |
+ rbf(); | |
+ } | |
+ } | |
+ } else { | |
+ if (donef || ndone) | |
+ done(0); | |
+ if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test … | |
+ if (nfo < 0) | |
+ ERROR "in getch0, nfo = %d", nfo WARN; | |
+ if (nfo == 0) { | |
+g0: | |
+ if (nextfile()) { | |
+ if (ip) | |
+ goto again; | |
+ } | |
+ } | |
+ nx = 0; | |
+#ifdef UNICODE | |
+ if (MB_CUR_MAX > 1) | |
+ i = get1ch(ifile); | |
+ else | |
+#endif /*UNICODE*/ | |
+ i = getc(ifile); | |
+ if (i == EOF) | |
+ goto g0; | |
+ if (ip) | |
+ goto again; | |
+ } | |
+/*g2: */ | |
+ if (i >= 040) /* zapped: && i < 0177 */ | |
+ goto g4; | |
+ i = ifilt[i]; | |
+ } | |
+ if (cbits(i) == IMP && !raw) | |
+ goto again; | |
+ if (i == 0 && !init && !raw) { /* zapped: || i == 0177… | |
+ goto again; | |
+ } | |
+g4: | |
+ if (ismot(i)) | |
+ return i; | |
+ if (copyf == 0 && sfbits(i) == 0) | |
+ i |= chbits; | |
+ if (cbits(i) == eschar && !raw) | |
+ setcbits(i, ESC); | |
+ return(i); | |
+} | |
+ | |
+ | |
+#ifdef UNICODE | |
+Tchar get1ch(FILE *fp) /* get one "character" from input, figure out wh… | |
+{ | |
+ wchar_t wc; | |
+ char buf[100], *p; | |
+ int i, n, c; | |
+ | |
+ for (i = 0, p = buf; i < MB_CUR_MAX; i++) { | |
+ if ((c = getc(fp)) == EOF) | |
+ return c; | |
+ *p++ = c; | |
+ if ((n = mbtowc(&wc, buf, p-buf)) >= 0) | |
+ break; | |
+ } | |
+ | |
+ if (n == 1) /* real ascii, presumably */ | |
+ return wc; | |
+ if (n == 0) | |
+ return p[-1]; /* illegal, but what else to do? */ | |
+ if (c == EOF) | |
+ return EOF; | |
+ *p = 0; | |
+ return chadd(buf, MBchar, Install); /* add name even if haven't… | |
+} | |
+#endif /*UNICODE*/ | |
+ | |
+void pushback(Tchar *b) | |
+{ | |
+ Tchar *ob = b; | |
+ | |
+ while (*b++) | |
+ ; | |
+ b--; | |
+ while (b > ob && pbp < &pbbuf[NC-3]) | |
+ *pbp++ = *--b; | |
+ if (pbp >= &pbbuf[NC-3]) { | |
+ ERROR "pushback overflow" WARN; | |
+ done(2); | |
+ } | |
+} | |
+ | |
+void cpushback(char *b) | |
+{ | |
+ char *ob = b; | |
+ | |
+ while (*b++) | |
+ ; | |
+ b--; | |
+ while (b > ob && pbp < &pbbuf[NC-3]) | |
+ *pbp++ = *--b; | |
+ if (pbp >= &pbbuf[NC-3]) { | |
+ ERROR "cpushback overflow" WARN; | |
+ done(2); | |
+ } | |
+} | |
+ | |
+int nextfile(void) | |
+{ | |
+ char *p; | |
+ | |
+n0: | |
+ if (ifile != stdin) | |
+ fclose(ifile); | |
+ if (ifi > 0 && !nx) { | |
+ if (popf()) | |
+ goto n0; /* popf error */ | |
+ return(1); /* popf ok */ | |
+ } | |
+ if (nx || nmfi < mflg) { | |
+ p = mfiles[nmfi++]; | |
+ if (*p != 0) | |
+ goto n1; | |
+ } | |
+ if (rargc-- <= 0) { | |
+ if ((nfo -= mflg) && !stdi) { | |
+ done(0); | |
+} | |
+ nfo++; | |
+ numtabp[CD].val = stdi = mflg = 0; | |
+ ifile = stdin; | |
+ strcpy(cfname[ifi], "stdin"); | |
+ return(0); | |
+ } | |
+ p = (argp++)[0]; | |
+ if (rargc >= 0) | |
+ cfname[ifi][0] = 0; | |
+n1: | |
+ numtabp[CD].val = 0; | |
+ if (p[0] == '-' && p[1] == 0) { | |
+ ifile = stdin; | |
+ strcpy(cfname[ifi], "stdin"); | |
+ } else if ((ifile = fopen(unsharp(p), "r")) == NULL) { | |
+ ERROR "cannot open file %s", p WARN; | |
+ nfo -= mflg; | |
+ done(02); | |
+ } else | |
+ strcpy(cfname[ifi],p); | |
+ nfo++; | |
+ return(0); | |
+} | |
+ | |
+int | |
+popf(void) | |
+{ | |
+ --ifi; | |
+ if (ifi < 0) { | |
+ ERROR "popf went negative" WARN; | |
+ return 1; | |
+ } | |
+ numtabp[CD].val = cfline[ifi]; /* restore line counter */ | |
+ ip = ipl[ifi]; /* input pointer */ | |
+ ifile = ifl[ifi]; /* input FILE * */ | |
+ return(0); | |
+} | |
+ | |
+ | |
+void flushi(void) | |
+{ | |
+ if (nflush) | |
+ return; | |
+ ch = 0; | |
+ copyf++; | |
+ while (!nlflg) { | |
+ if (donef && frame == stk) | |
+ break; | |
+ getch(); | |
+ } | |
+ copyf--; | |
+} | |
+ | |
+/* | |
+ * return 16-bit, ascii/alphabetic character, ignore chars with more bits, | |
+ * (internal names), spaces and special cookies (below 040). | |
+ * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff. | |
+ */ | |
+int | |
+getach(void) | |
+{ | |
+ Tchar i; | |
+ int j; | |
+ | |
+ lgf++; | |
+ j = cbits(i = getch()); | |
+ if (ismot(i) | |
+ || j > SHORTMASK | |
+ || (j <= 040 && j != 002 /*STX*/ | |
+ && j != 003 /*ETX*/ | |
+ && j != 005 /*ENQ*/ | |
+ && j != 006 /*ACK*/ | |
+ && j != 007)) { /*BELL*/ | |
+ ch = i; | |
+ j = 0; | |
+ } | |
+ lgf--; | |
+ return j; | |
+} | |
+ | |
+ | |
+void casenx(void) | |
+{ | |
+ lgf++; | |
+ skip(); | |
+ getname(); | |
+ nx++; | |
+ if (nmfi > 0) | |
+ nmfi--; | |
+ strcpy(mfiles[nmfi], nextf); | |
+ nextfile(); | |
+ nlflg++; | |
+ ip = 0; | |
+ pendt = 0; | |
+ frame = stk; | |
+ nxf = frame + 1; | |
+} | |
+ | |
+int | |
+getname(void) | |
+{ | |
+ int j, k; | |
+ | |
+ lgf++; | |
+ for (k = 0; k < NS - 1; k++) { | |
+ j = getach(); | |
+ if (!j) | |
+ break; | |
+ nextf[k] = j; | |
+ } | |
+ nextf[k] = 0; | |
+ lgf--; | |
+ return(nextf[0]); | |
+} | |
+ | |
+ | |
+void caseso(void) | |
+{ | |
+ FILE *fp = 0; | |
+ | |
+ lgf++; | |
+ nextf[0] = 0; | |
+ if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL … | |
+ ERROR "can't open file %s", nextf WARN; | |
+ done(02); | |
+ } | |
+ strcpy(cfname[ifi+1], nextf); | |
+ cfline[ifi] = numtabp[CD].val; /*hold line counter*/ | |
+ numtabp[CD].val = 0; | |
+ flushi(); | |
+ ifl[ifi] = ifile; | |
+ ifile = fp; | |
+ ipl[ifi] = ip; | |
+ ip = 0; | |
+ nx++; | |
+ nflush++; | |
+ ifi++; | |
+} | |
+ | |
+void caself(void) /* set line number and file */ | |
+{ | |
+ int n; | |
+ | |
+ if (skip()) | |
+ return; | |
+ n = atoi0(); | |
+ if (!nonumb) | |
+ cfline[ifi] = numtabp[CD].val = n - 1; | |
+ if (!skip()) | |
+ if (getname()) { /* eats '\n' ? */ | |
+ strcpy(cfname[ifi], nextf); | |
+ if (!nonumb) | |
+ numtabp[CD].val--; | |
+ } | |
+} | |
+ | |
+void cpout(FILE *fin, char *token) | |
+{ | |
+ int n; | |
+ char buf[1024]; | |
+ | |
+ if (token) { /* BUG: There should be no NULL bytes in input */ | |
+ char *newl = buf; | |
+ while ((fgets(buf, sizeof buf, fin)) != NULL) { | |
+ if (newl) { | |
+ numtabp[CD].val++; /* line number */ | |
+ if (strcmp(token, buf) == 0) | |
+ return; | |
+ } | |
+ newl = strchr(buf, '\n'); | |
+ fputs(buf, ptid); | |
+ } | |
+ } else { | |
+ while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0) | |
+ fwrite(buf, n, 1, ptid); | |
+ fclose(fin); | |
+ } | |
+} | |
+ | |
+void casecf(void) | |
+{ /* copy file without change */ | |
+ FILE *fd; | |
+ char *eof, *p; | |
+ extern int hpos, esc, po; | |
+ | |
+ /* this may not make much sense in nroff... */ | |
+ | |
+ lgf++; | |
+ nextf[0] = 0; | |
+ if (!skip() && getname()) { | |
+ if (strncmp("<<", nextf, 2) != 0) { | |
+ if ((fd = fopen(unsharp(nextf), "r")) == NULL) { | |
+ ERROR "can't open file %s", nextf WARN; | |
+ done(02); | |
+ } | |
+ eof = (char *) NULL; | |
+ } else { /* current file */ | |
+ if (pbp > lastpbp || ip) { | |
+ ERROR "casecf: not reading from file" WARN; | |
+ done(02); | |
+ } | |
+ eof = &nextf[2]; | |
+ if (!*eof) { | |
+ ERROR "casecf: missing end of input token" WAR… | |
+ done(02); | |
+ } | |
+ p = eof; | |
+ while(*++p) | |
+ ; | |
+ *p++ = '\n'; | |
+ *p = 0; | |
+ fd = ifile; | |
+ } | |
+ } else { | |
+ ERROR "casecf: no argument" WARN; | |
+ lgf--; | |
+ return; | |
+ } | |
+ lgf--; | |
+ | |
+ /* make it into a clean state, be sure that everything is out */ | |
+ tbreak(); | |
+ hpos = po; | |
+ esc = 0; | |
+ ptesc(); /* to left margin */ | |
+ esc = un; | |
+ ptesc(); | |
+ ptlead(); | |
+ ptps(); | |
+ ptfont(); | |
+ flusho(); | |
+ cpout(fd, eof); | |
+ ptps(); | |
+ ptfont(); | |
+} | |
+ | |
+void getline(char *s, int n) /* get rest of input line into s */ | |
+{ | |
+ int i; | |
+ | |
+ lgf++; | |
+ copyf++; | |
+ skip(); | |
+ for (i = 0; i < n-1; i++) | |
+ if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT) | |
+ break; | |
+ s[i] = 0; | |
+ copyf--; | |
+ lgf--; | |
+} | |
+ | |
+void casesy(void) /* call system */ | |
+{ | |
+ char sybuf[NTM]; | |
+ | |
+ getline(sybuf, NTM); | |
+ system(sybuf); | |
+} | |
+ | |
+ | |
+void getpn(char *a) | |
+{ | |
+ int n, neg; | |
+ | |
+ if (*a == 0) | |
+ return; | |
+ neg = 0; | |
+ for ( ; *a; a++) | |
+ switch (*a) { | |
+ case '+': | |
+ case ',': | |
+ continue; | |
+ case '-': | |
+ neg = 1; | |
+ continue; | |
+ default: | |
+ n = 0; | |
+ if (isdigit((uchar)*a)) { | |
+ do | |
+ n = 10 * n + *a++ - '0'; | |
+ while (isdigit((uchar)*a)); | |
+ a--; | |
+ } else | |
+ n = 9999; | |
+ *pnp++ = neg ? -n : n; | |
+ neg = 0; | |
+ if (pnp >= &pnlist[NPN-2]) { | |
+ ERROR "too many page numbers" WARN; | |
+ done3(-3); | |
+ } | |
+ } | |
+ if (neg) | |
+ *pnp++ = -9999; | |
+ *pnp = -INT_MAX; | |
+ print = 0; | |
+ pnp = pnlist; | |
+ if (*pnp != -INT_MAX) | |
+ chkpn(); | |
+} | |
+ | |
+ | |
+void setrpt(void) | |
+{ | |
+ Tchar i, j; | |
+ | |
+ copyf++; | |
+ raw++; | |
+ i = getch0(); | |
+ copyf--; | |
+ raw--; | |
+ if ((long) i < 0 || cbits(j = getch0()) == RPT) | |
+ return; | |
+ while (i > 0 && pbp < &pbbuf[NC-3]) { | |
+ i--; | |
+ *pbp++ = j; | |
+ } | |
+} | |
diff --git a/troff/n10.c b/troff/n10.c | |
@@ -0,0 +1,549 @@ | |
+/* | |
+n10.c | |
+ | |
+Device interfaces | |
+*/ | |
+ | |
+#include <u.h> | |
+#include "tdef.h" | |
+#include "ext.h" | |
+#include "fns.h" | |
+#include <ctype.h> | |
+ | |
+Term t; /* terminal characteristics */ | |
+ | |
+int dtab; | |
+int plotmode; | |
+int esct; | |
+ | |
+enum { Notype = 0, Type = 1 }; | |
+ | |
+static char *parse(char *s, int typeit) /* convert \0, etc to nroff dri… | |
+{ /* typeit => add a type id to the front for later use */ | |
+ static char buf[100], *t, *obuf; | |
+ int quote = 0; | |
+ wchar_t wc; | |
+ | |
+ obuf = typeit == Type ? buf : buf+1; | |
+#ifdef UNICODE | |
+ if (mbtowc(&wc, s, strlen(s)) > 1) { /* it's multibyte, */ | |
+ buf[0] = MBchar; | |
+ strcpy(buf+1, s); | |
+ return obuf; | |
+ } /* so just hand it back */ | |
+#endif /*UNICODE*/ | |
+ buf[0] = Troffchar; | |
+ t = buf + 1; | |
+ if (*s == '"') { | |
+ s++; | |
+ quote = 1; | |
+ } | |
+ for (;;) { | |
+ if (quote && *s == '"') { | |
+ s++; | |
+ break; | |
+ } | |
+ if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == … | |
+ break; | |
+ if (*s != '\\') | |
+ *t++ = *s++; | |
+ else { | |
+ s++; /* skip \\ */ | |
+ if (isdigit((uchar)s[0]) && isdigit((uchar)s[1]) && is… | |
+ *t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0… | |
+ s += 2; | |
+ } else if (isdigit((uchar)s[0])) { | |
+ *t++ = *s - '0'; | |
+ } else if (*s == 'b') { | |
+ *t++ = '\b'; | |
+ } else if (*s == 'n') { | |
+ *t++ = '\n'; | |
+ } else if (*s == 'r') { | |
+ *t++ = '\r'; | |
+ } else if (*s == 't') { | |
+ *t++ = '\t'; | |
+ } else { | |
+ *t++ = *s; | |
+ } | |
+ s++; | |
+ } | |
+ } | |
+ *t = '\0'; | |
+ return obuf; | |
+} | |
+ | |
+ | |
+static int getnrfont(FILE *fp) /* read the nroff description file */ | |
+{ | |
+ Chwid chtemp[NCHARS]; | |
+ static Chwid chinit; | |
+ int i, nw, n, wid, code, type; | |
+ char buf[100], ch[100], s1[100], s2[100]; | |
+ wchar_t wc; | |
+ | |
+ code = 0; | |
+ chinit.wid = 1; | |
+ chinit.str = ""; | |
+ for (i = 0; i < ALPHABET; i++) { | |
+ chtemp[i] = chinit; /* zero out to begin with */ | |
+ chtemp[i].num = chtemp[i].code = i; /* every alphabetic… | |
+ chtemp[i].wid = 1; /* default ascii widths */ | |
+ } | |
+ skipline(fp); | |
+ nw = ALPHABET; | |
+ while (fgets(buf, sizeof buf, fp) != NULL) { | |
+ sscanf(buf, "%s %s %[^\n]", ch, s1, s2); | |
+ if (!eq(s1, "\"")) { /* genuine new character */ | |
+ sscanf(s1, "%d", &wid); | |
+ } /* else it's a synonym for prev character, */ | |
+ /* so leave previous values intact */ | |
+ | |
+ /* decide what kind of alphabet it might come from */ | |
+ | |
+ if (strlen(ch) == 1) { /* it's ascii */ | |
+ n = ch[0]; /* origin includes non-graphics */ | |
+ chtemp[n].num = ch[0]; | |
+ } else if (ch[0] == '\\' && ch[1] == '0') { | |
+ n = strtol(ch+1, 0, 0); /* \0octal or \0xhex */ | |
+ chtemp[n].num = n; | |
+#ifdef UNICODE | |
+ } else if (mbtowc(&wc, ch, strlen(ch)) > 1) { | |
+ chtemp[nw].num = chadd(ch, MBchar, Install); | |
+ n = nw; | |
+ nw++; | |
+#endif /*UNICODE*/ | |
+ } else { | |
+ if (strcmp(ch, "---") == 0) { /* no name */ | |
+ sprintf(ch, "%d", code); | |
+ type = Number; | |
+ } else | |
+ type = Troffchar; | |
+/* BUG in here somewhere when same character occurs twice in table */ | |
+ chtemp[nw].num = chadd(ch, type, Install); | |
+ n = nw; | |
+ nw++; | |
+ } | |
+ chtemp[n].wid = wid; | |
+ chtemp[n].str = strdupl(parse(s2, Type)); | |
+ } | |
+ t.tfont.nchars = nw; | |
+ t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid)); | |
+ if (t.tfont.wp == NULL) | |
+ return -1; | |
+ for (i = 0; i < nw; i++) | |
+ t.tfont.wp[i] = chtemp[i]; | |
+ return 1; | |
+} | |
+ | |
+ | |
+void n_ptinit(void) | |
+{ | |
+ int i; | |
+ char *p; | |
+ char opt[50], cmd[100]; | |
+ FILE *fp; | |
+ | |
+ hmot = n_hmot; | |
+ makem = n_makem; | |
+ setabs = n_setabs; | |
+ setch = n_setch; | |
+ sethl = n_sethl; | |
+ setht = n_setht; | |
+ setslant = n_setslant; | |
+ vmot = n_vmot; | |
+ xlss = n_xlss; | |
+ findft = n_findft; | |
+ width = n_width; | |
+ mchbits = n_mchbits; | |
+ ptlead = n_ptlead; | |
+ ptout = n_ptout; | |
+ ptpause = n_ptpause; | |
+ setfont = n_setfont; | |
+ setps = n_setps; | |
+ setwd = n_setwd; | |
+ | |
+ if ((p = getenv("NROFFTERM")) != 0) | |
+ strcpy(devname, p); | |
+ if (termtab[0] == 0) | |
+ strcpy(termtab,DWBntermdir); | |
+ if (fontdir[0] == 0) | |
+ strcpy(fontdir, ""); | |
+ if (devname[0] == 0) | |
+ strcpy(devname, NDEVNAME); | |
+ pl = 11*INCH; | |
+ po = PO; | |
+ hyf = 0; | |
+ ascii = 1; | |
+ lg = 0; | |
+ fontlab[1] = 'R'; | |
+ fontlab[2] = 'I'; | |
+ fontlab[3] = 'B'; | |
+ fontlab[4] = PAIR('B','I'); | |
+ fontlab[5] = 'D'; | |
+ bdtab[3] = 3; | |
+ bdtab[4] = 3; | |
+ | |
+ /* hyphalg = 0; /* for testing */ | |
+ | |
+ strcat(termtab, devname); | |
+ if ((fp = fopen(unsharp(termtab), "r")) == NULL) { | |
+ ERROR "cannot open %s", termtab WARN; | |
+ exit(-1); | |
+ } | |
+ | |
+ | |
+/* this loop isn't robust about input format errors. */ | |
+/* it assumes name, name-value pairs..., charset */ | |
+/* god help us if we get out of sync. */ | |
+ | |
+ fscanf(fp, "%s", cmd); /* should be device name... */ | |
+ if (!is(devname) && trace) | |
+ ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname W… | |
+ for (;;) { | |
+ fscanf(fp, "%s", cmd); | |
+ if (is("charset")) | |
+ break; | |
+ fscanf(fp, " %[^\n]", opt); | |
+ if (is("bset")) t.bset = atoi(opt); | |
+ else if (is("breset")) t.breset = atoi(opt); | |
+ else if (is("Hor")) t.Hor = atoi(opt); | |
+ else if (is("Vert")) t.Vert = atoi(opt); | |
+ else if (is("Newline")) t.Newline = atoi(opt); | |
+ else if (is("Char")) t.Char = atoi(opt); | |
+ else if (is("Em")) t.Em = atoi(opt); | |
+ else if (is("Halfline")) t.Halfline = atoi(opt); | |
+ else if (is("Adj")) t.Adj = atoi(opt); | |
+ else if (is("twinit")) t.twinit = strdupl(parse(opt, Notype)); | |
+ else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype)); | |
+ else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype)); | |
+ else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype)); | |
+ else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype)); | |
+ else if (is("flr")) t.flr = strdupl(parse(opt, Notype)); | |
+ else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype)); | |
+ else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notype)); | |
+ else if (is("iton")) t.iton = strdupl(parse(opt, Notype)); | |
+ else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype)); | |
+ else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype)); | |
+ else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype)… | |
+ else if (is("up")) t.up = strdupl(parse(opt, Notype)); | |
+ else if (is("down")) t.down = strdupl(parse(opt, Notype)); | |
+ else if (is("right")) t.right = strdupl(parse(opt, Notype)); | |
+ else if (is("left")) t.left = strdupl(parse(opt, Notype)); | |
+ else | |
+ ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN; | |
+ } | |
+ | |
+ getnrfont(fp); | |
+ fclose(fp); | |
+ | |
+ sps = EM; | |
+ ics = EM * 2; | |
+ dtab = 8 * t.Em; | |
+ for (i = 0; i < 16; i++) | |
+ tabtab[i] = dtab * (i + 1); | |
+ pl = 11 * INCH; | |
+ po = PO; | |
+ spacesz = SS; | |
+ lss = lss1 = VS; | |
+ ll = ll1 = lt = lt1 = LL; | |
+ smnt = nfonts = 5; /* R I B BI S */ | |
+ n_specnames(); /* install names like "hyphen", etc. */ | |
+ if (eqflg) | |
+ t.Adj = t.Hor; | |
+} | |
+ | |
+ | |
+void n_specnames(void) | |
+{ | |
+ | |
+ int i; | |
+ | |
+ for (i = 0; spnames[i].n; i++) | |
+ *spnames[i].n = chadd(spnames[i].v, Troffchar, Install); | |
+ if (c_isalnum == 0) | |
+ c_isalnum = NROFFCHARS; | |
+} | |
+ | |
+void twdone(void) | |
+{ | |
+ if (!TROFF && t.twrest) { | |
+ obufp = obuf; | |
+ oputs(t.twrest); | |
+ flusho(); | |
+ if (pipeflg) { | |
+ pclose(ptid); | |
+ } | |
+ restore_tty(); | |
+ } | |
+} | |
+ | |
+ | |
+void n_ptout(Tchar i) | |
+{ | |
+ *olinep++ = i; | |
+ if (olinep >= &oline[LNSIZE]) | |
+ olinep--; | |
+ if (cbits(i) != '\n') | |
+ return; | |
+ olinep--; | |
+ lead += dip->blss + lss - t.Newline; | |
+ dip->blss = 0; | |
+ esct = esc = 0; | |
+ if (olinep > oline) { | |
+ move(); | |
+ ptout1(); | |
+ oputs(t.twnl); | |
+ } else { | |
+ lead += t.Newline; | |
+ move(); | |
+ } | |
+ lead += dip->alss; | |
+ dip->alss = 0; | |
+ olinep = oline; | |
+} | |
+ | |
+ | |
+void ptout1(void) | |
+{ | |
+ int k; | |
+ char *codep; | |
+ int w, j, phyw; | |
+ Tchar *q, i; | |
+ static int oxfont = FT; /* start off in roman */ | |
+ | |
+ for (q = oline; q < olinep; q++) { | |
+ i = *q; | |
+ if (ismot(i)) { | |
+ j = absmot(i); | |
+ if (isnmot(i)) | |
+ j = -j; | |
+ if (isvmot(i)) | |
+ lead += j; | |
+ else | |
+ esc += j; | |
+ continue; | |
+ } | |
+ if ((k = cbits(i)) <= ' ') { | |
+ switch (k) { | |
+ case ' ': /*space*/ | |
+ esc += t.Char; | |
+ break; | |
+ case '\033': | |
+ case '\007': | |
+ case '\016': | |
+ case '\017': | |
+ oput(k); | |
+ break; | |
+ } | |
+ continue; | |
+ } | |
+ phyw = w = t.Char * t.tfont.wp[k].wid; | |
+ if (iszbit(i)) | |
+ w = 0; | |
+ if (esc || lead) | |
+ move(); | |
+ esct += w; | |
+ xfont = fbits(i); | |
+ if (xfont != oxfont) { | |
+ switch (oxfont) { | |
+ case ULFONT: oputs(t.itoff); break; | |
+ case BDFONT: oputs(t.bdoff); break; | |
+ case BIFONT: oputs(t.itoff); oputs(t.bdoff); br… | |
+ } | |
+ switch (xfont) { | |
+ case ULFONT: | |
+ if (*t.iton & 0377) oputs(t.iton); break; | |
+ case BDFONT: | |
+ if (*t.bdon & 0377) oputs(t.bdon); break; | |
+ case BIFONT: | |
+ if (*t.bdon & 0377) oputs(t.bdon); | |
+ if (*t.iton & 0377) oputs(t.iton); | |
+ break; | |
+ } | |
+ oxfont = xfont; | |
+ } | |
+ if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & 0377))… | |
+ for (j = w / t.Char; j > 0; j--) | |
+ oput('_'); | |
+ for (j = w / t.Char; j > 0; j--) | |
+ oput('\b'); | |
+ } | |
+ if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFON… | |
+ j++; | |
+ else | |
+ j = 1; /* number of overstrikes for bold */ | |
+ if (k < ALPHABET) { /* ordinary ascii */ | |
+ oput(k); | |
+ while (--j > 0) { | |
+ oput('\b'); | |
+ oput(k); | |
+ } | |
+ } else if (k >= t.tfont.nchars) { /* BUG -- not really … | |
+/* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */ | |
+ oputs(chname(k)+1); /* BUG: should separate Tro… | |
+ } else if (t.tfont.wp[k].str == 0) { | |
+/* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */ | |
+ oputs(chname(k)+1); /* BUG: should separate Tro… | |
+ } else if (t.tfont.wp[k].str[0] == MBchar) { /* parse()… | |
+/* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */ | |
+ oputs(t.tfont.wp[k].str+1); | |
+ } else { | |
+ int oj = j; | |
+/* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */ | |
+ codep = t.tfont.wp[k].str+1; /* Troffchar by de… | |
+ while (*codep != 0) { | |
+ if (*codep & 0200) { | |
+ codep = plot(codep); | |
+ oput(' '); | |
+ } else { | |
+ if (*codep == '%') /* escape */ | |
+ codep++; | |
+ oput(*codep); | |
+ if (*codep == '\033') | |
+ oput(*++codep); | |
+ else if (*codep != '\b') | |
+ for (j = oj; --j > 0; ) { | |
+ oput('\b'); | |
+ oput(*codep); | |
+ } | |
+ codep++; | |
+ } | |
+ } | |
+ } | |
+ if (!w) | |
+ for (j = phyw / t.Char; j > 0; j--) | |
+ oput('\b'); | |
+ } | |
+} | |
+ | |
+ | |
+char *plot(char *x) | |
+{ | |
+ int i; | |
+ char *j, *k; | |
+ | |
+ oputs(t.ploton); | |
+ k = x; | |
+ if ((*k & 0377) == 0200) | |
+ k++; | |
+ for (; *k; k++) { | |
+ if (*k == '%') { /* quote char within plot mode */ | |
+ oput(*++k); | |
+ } else if (*k & 0200) { | |
+ if (*k & 0100) { | |
+ if (*k & 040) | |
+ j = t.up; | |
+ else | |
+ j = t.down; | |
+ } else { | |
+ if (*k & 040) | |
+ j = t.left; | |
+ else | |
+ j = t.right; | |
+ } | |
+ if ((i = *k & 037) == 0) { /* 2nd 0200 turns it… | |
+ ++k; | |
+ break; | |
+ } | |
+ while (i--) | |
+ oputs(j); | |
+ } else | |
+ oput(*k); | |
+ } | |
+ oputs(t.plotoff); | |
+ return(k); | |
+} | |
+ | |
+ | |
+void move(void) | |
+{ | |
+ int k; | |
+ char *i, *j; | |
+ char *p, *q; | |
+ int iesct, dt; | |
+ | |
+ iesct = esct; | |
+ if (esct += esc) | |
+ i = "\0"; | |
+ else | |
+ i = "\n\0"; | |
+ j = t.hlf; | |
+ p = t.right; | |
+ q = t.down; | |
+ if (lead) { | |
+ if (lead < 0) { | |
+ lead = -lead; | |
+ i = t.flr; | |
+ /* if(!esct)i = t.flr; else i = "\0";*/ | |
+ j = t.hlr; | |
+ q = t.up; | |
+ } | |
+ if (*i & 0377) { | |
+ k = lead / t.Newline; | |
+ lead = lead % t.Newline; | |
+ while (k--) | |
+ oputs(i); | |
+ } | |
+ if (*j & 0377) { | |
+ k = lead / t.Halfline; | |
+ lead = lead % t.Halfline; | |
+ while (k--) | |
+ oputs(j); | |
+ } else { /* no half-line forward, not at line begining */ | |
+ k = lead / t.Newline; | |
+ lead = lead % t.Newline; | |
+ if (k > 0) | |
+ esc = esct; | |
+ i = "\n"; | |
+ while (k--) | |
+ oputs(i); | |
+ } | |
+ } | |
+ if (esc) { | |
+ if (esc < 0) { | |
+ esc = -esc; | |
+ j = "\b"; | |
+ p = t.left; | |
+ } else { | |
+ j = " "; | |
+ if (hflg) | |
+ while ((dt = dtab - (iesct % dtab)) <= esc) { | |
+ if (dt % t.Em) | |
+ break; | |
+ oput(TAB); | |
+ esc -= dt; | |
+ iesct += dt; | |
+ } | |
+ } | |
+ k = esc / t.Em; | |
+ esc = esc % t.Em; | |
+ while (k--) | |
+ oputs(j); | |
+ } | |
+ if ((*t.ploton & 0377) && (esc || lead)) { | |
+ oputs(t.ploton); | |
+ esc /= t.Hor; | |
+ lead /= t.Vert; | |
+ while (esc--) | |
+ oputs(p); | |
+ while (lead--) | |
+ oputs(q); | |
+ oputs(t.plotoff); | |
+ } | |
+ esc = lead = 0; | |
+} | |
+ | |
+ | |
+void n_ptlead(void) | |
+{ | |
+ move(); | |
+} | |
+ | |
+ | |
+void n_ptpause(void ) | |
+{ | |
+ char junk; | |
+ | |
+ flusho(); | |
+ read(2, &junk, 1); | |
+} | |
diff --git a/troff/n2.c b/troff/n2.c | |
@@ -0,0 +1,325 @@ | |
+/* | |
+ * n2.c | |
+ * | |
+ * output, cleanup | |
+ */ | |
+ | |
+#define _BSD_SOURCE 1 /* popen */ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+#include <setjmp.h> | |
+ | |
+#ifdef STRICT | |
+ /* not in ANSI or POSIX */ | |
+FILE* popen(char*, char*); | |
+#endif | |
+ | |
+ | |
+extern jmp_buf sjbuf; | |
+int toolate; | |
+int error; | |
+ | |
+char obuf[2*BUFSIZ]; | |
+char *obufp = obuf; | |
+ | |
+ /* pipe command structure; allows redicously long commends for .pi */ | |
+struct Pipe { | |
+ char *buf; | |
+ int tick; | |
+ int cnt; | |
+} Pipe; | |
+ | |
+ | |
+int xon = 0; /* records if in middle of \X */ | |
+ | |
+int pchar(Tchar i) | |
+{ | |
+ int j; | |
+ static int hx = 0; /* records if have seen HX */ | |
+ | |
+ if (hx) { | |
+ hx = 0; | |
+ j = absmot(i); | |
+ if (isnmot(i)) { | |
+ if (j > dip->blss) | |
+ dip->blss = j; | |
+ } else { | |
+ if (j > dip->alss) | |
+ dip->alss = j; | |
+ ralss = dip->alss; | |
+ } | |
+ return 0; | |
+ } | |
+ if (ismot(i)) { | |
+ pchar1(i); | |
+ return 0; | |
+ } | |
+ switch (j = cbits(i)) { | |
+ case 0: | |
+ case IMP: | |
+ case RIGHT: | |
+ case LEFT: | |
+ return 0; | |
+ case HX: | |
+ hx = 1; | |
+ return 0; | |
+ case XON: | |
+ xon++; | |
+ break; | |
+ case XOFF: | |
+ xon--; | |
+ break; | |
+ case PRESC: | |
+ if (!xon && !tflg && dip == &d[0]) | |
+ j = eschar; /* fall through */ | |
+ default: | |
+ setcbits(i, trtab[j]); | |
+ } | |
+ if (NROFF & xon) /* rob fix for man2html */ | |
+ return 0; | |
+ pchar1(i); | |
+ return 0; | |
+} | |
+ | |
+ | |
+void pchar1(Tchar i) | |
+{ | |
+ int j; | |
+ | |
+ j = cbits(i); | |
+ if (dip != &d[0]) { | |
+ wbf(i); | |
+ dip->op = offset; | |
+ return; | |
+ } | |
+ if (!tflg && !print) { | |
+ if (j == '\n') | |
+ dip->alss = dip->blss = 0; | |
+ return; | |
+ } | |
+ if (j == FILLER && !xon) | |
+ return; | |
+ if (tflg) { /* transparent mode, undiverted */ | |
+ if (print) /* assumes that it's ok to p… | |
+ /* OUT "%c", j PUT; /* i.e., is ascii */ | |
+ outascii(i); | |
+ return; | |
+ } | |
+ if (TROFF && ascii) | |
+ outascii(i); | |
+ else | |
+ ptout(i); | |
+} | |
+ | |
+ | |
+void outweird(int k) /* like ptchname() but ascii */ | |
+{ | |
+ char *chn = chname(k); | |
+ | |
+ switch (chn[0]) { | |
+ case MBchar: | |
+ OUT "%s", chn+1 PUT; /* \n not needed? */ | |
+ break; | |
+ case Number: | |
+ OUT "\\N'%s'", chn+1 PUT; | |
+ break; | |
+ case Troffchar: | |
+ if (strlen(chn+1) == 2) | |
+ OUT "\\(%s", chn+1 PUT; | |
+ else | |
+ OUT "\\C'%s'", chn+1 PUT; | |
+ break; | |
+ default: | |
+ OUT " %s? ", chn PUT; | |
+ break; | |
+ } | |
+} | |
+ | |
+void outascii(Tchar i) /* print i in best-guess ascii */ | |
+{ | |
+ int j = cbits(i); | |
+ | |
+/* is this ever called with NROFF set? probably doesn't work at all. */ | |
+ | |
+ if (ismot(i)) | |
+ oput(' '); | |
+ else if (j < ALPHABET && j >= ' ' || j == '\n' || j == '\t') | |
+ oput(j); | |
+ else if (j == DRAWFCN) | |
+ oputs("\\D"); | |
+ else if (j == HYPHEN) | |
+ oput('-'); | |
+ else if (j == MINUS) /* special pleading for strange encodings … | |
+ oputs("\\-"); | |
+ else if (j == PRESC) | |
+ oputs("\\e"); | |
+ else if (j == FILLER) | |
+ oputs("\\&"); | |
+ else if (j == UNPAD) | |
+ oputs("\\ "); | |
+ else if (j == OHC) /* this will never occur; stripped out earl… | |
+ oputs("\\%"); | |
+ else if (j == XON) | |
+ oputs("\\X"); | |
+ else if (j == XOFF) | |
+ oputs(" "); | |
+ else if (j == LIG_FI) | |
+ oputs("fi"); | |
+ else if (j == LIG_FL) | |
+ oputs("fl"); | |
+ else if (j == LIG_FF) | |
+ oputs("ff"); | |
+ else if (j == LIG_FFI) | |
+ oputs("ffi"); | |
+ else if (j == LIG_FFL) | |
+ oputs("ffl"); | |
+ else if (j == WORDSP) { /* nothing at all */ | |
+ if (xon) /* except in \X */ | |
+ oput(' '); | |
+ | |
+ } else | |
+ outweird(j); | |
+} | |
+ | |
+int flusho(void) | |
+{ | |
+ if (NROFF && !toolate && t.twinit) | |
+ fwrite(t.twinit, strlen(t.twinit), 1, ptid); | |
+ | |
+ if (obufp > obuf) { | |
+ if (pipeflg && !toolate) { | |
+ /* fprintf(stderr, "Pipe to <%s>\n", Pipe.buf); */ | |
+ if (!Pipe.buf[0] || (ptid = popen(Pipe.buf, "w")) == N… | |
+ ERROR "pipe %s not created.", Pipe.buf WARN; | |
+ if (Pipe.buf) | |
+ free(Pipe.buf); | |
+ } | |
+ if (!toolate) | |
+ toolate++; | |
+ *obufp = 0; | |
+ fputs(obuf, ptid); | |
+ fflush(ptid); | |
+ obufp = obuf; | |
+ } | |
+ return 1; | |
+} | |
+ | |
+ | |
+void caseex(void) | |
+{ | |
+ done(0); | |
+} | |
+ | |
+ | |
+void done(int x) | |
+{ | |
+ int i; | |
+ | |
+ error |= x; | |
+ app = ds = lgf = 0; | |
+ if (i = em) { | |
+ donef = -1; | |
+ eschar = '\\'; | |
+ em = 0; | |
+ if (control(i, 0)) | |
+ longjmp(sjbuf, 1); | |
+ } | |
+ if (!nfo) | |
+ done3(0); | |
+ mflg = 0; | |
+ dip = &d[0]; | |
+ if (woff) /* BUG!!! This isn't set anywhere */ | |
+ wbf((Tchar)0); | |
+ if (pendw) | |
+ getword(1); | |
+ pendnf = 0; | |
+ if (donef == 1) | |
+ done1(0); | |
+ donef = 1; | |
+ ip = 0; | |
+ frame = stk; | |
+ nxf = frame + 1; | |
+ if (!ejf) | |
+ tbreak(); | |
+ nflush++; | |
+ eject((Stack *)0); | |
+ longjmp(sjbuf, 1); | |
+} | |
+ | |
+ | |
+void done1(int x) | |
+{ | |
+ error |= x; | |
+ if (numtabp[NL].val) { | |
+ trap = 0; | |
+ eject((Stack *)0); | |
+ longjmp(sjbuf, 1); | |
+ } | |
+ if (!ascii) | |
+ pttrailer(); | |
+ done2(0); | |
+} | |
+ | |
+ | |
+void done2(int x) | |
+{ | |
+ ptlead(); | |
+ if (TROFF && !ascii) | |
+ ptstop(); | |
+ flusho(); | |
+ done3(x); | |
+} | |
+ | |
+void done3(int x) | |
+{ | |
+ error |= x; | |
+ flusho(); | |
+ if (NROFF) | |
+ twdone(); | |
+ if (pipeflg) | |
+ pclose(ptid); | |
+ exit(error); | |
+} | |
+ | |
+ | |
+void edone(int x) | |
+{ | |
+ frame = stk; | |
+ nxf = frame + 1; | |
+ ip = 0; | |
+ done(x); | |
+} | |
+ | |
+ | |
+void casepi(void) | |
+{ | |
+ int j; | |
+ char buf[NTM]; | |
+ | |
+ if (Pipe.buf == NULL) { | |
+ if ((Pipe.buf = (char *)calloc(NTM, sizeof(char))) == NULL) { | |
+ ERROR "No buf space for pipe cmd" WARN; | |
+ return; | |
+ } | |
+ Pipe.tick = 1; | |
+ } else | |
+ Pipe.buf[Pipe.cnt++] = '|'; | |
+ | |
+ getline(buf, NTM); | |
+ j = strlen(buf); | |
+ if (toolate) { | |
+ ERROR "Cannot create pipe to %s", buf WARN; | |
+ return; | |
+ } | |
+ Pipe.cnt += j; | |
+ if (j >= NTM +1) { | |
+ Pipe.tick++; | |
+ if ((Pipe.buf = (char *)realloc(Pipe.buf, Pipe.tick * NTM * si… | |
+ ERROR "No more buf space for pipe cmd" WARN; | |
+ return; | |
+ } | |
+ } | |
+ strcat(Pipe.buf, buf); | |
+ pipeflg++; | |
+} | |
diff --git a/troff/n3.c b/troff/n3.c | |
@@ -0,0 +1,954 @@ | |
+/* | |
+ * troff3.c | |
+ * | |
+ * macro and string routines, storage allocation | |
+ */ | |
+ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+Tchar *argtop; | |
+int pagech = '%'; | |
+int strflg; | |
+ | |
+#define MHASHSIZE 128 /* must be 2**n */ | |
+#define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1) | |
+Contab *mhash[MHASHSIZE]; | |
+ | |
+ | |
+Blockp *blist; /* allocated blocks for macros and string… | |
+int nblist; /* how many there are */ | |
+int bfree = -1; /* first (possible) free block in the list */ | |
+ | |
+Contab *contabp = NULL; | |
+#define MDELTA 500 | |
+int nm = 0; | |
+ | |
+int savname; /* name of macro/string being defined */ | |
+int savslot; /* place in Contab of savname */ | |
+int freeslot = -1; /* first (possible) free slot in contab */ | |
+ | |
+void prcontab(Contab *p) | |
+{ | |
+ int i; | |
+ for (i = 0; i < nm; i++) | |
+ if (p) | |
+ if (p[i].rq != 0) | |
+ fprintf(stderr, "slot %d, %-2.2s\n", i, unpair… | |
+ else | |
+ fprintf(stderr, "slot %d empty\n", i); | |
+ else | |
+ fprintf(stderr, "slot %d empty\n", i); | |
+} | |
+ | |
+ | |
+void blockinit(void) | |
+{ | |
+ blist = (Blockp *) calloc(NBLIST, sizeof(Blockp)); | |
+ if (blist == NULL) { | |
+ ERROR "not enough room for %d blocks", NBLIST WARN; | |
+ done2(1); | |
+ } | |
+ nblist = NBLIST; | |
+ blist[0].nextoff = blist[1].nextoff = -1; | |
+ blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); | |
+ blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); | |
+ /* -1 prevents blist[0] from being used; temporary fix */ | |
+ /* for a design botch: offset==0 is overloaded. */ | |
+ /* blist[1] reserved for .rd indicator -- also unused. */ | |
+ /* but someone unwittingly looks at these, so allocate somethi… | |
+ bfree = 2; | |
+} | |
+ | |
+ | |
+char *grow(char *ptr, int num, int size) /* make array bigger */ | |
+{ | |
+ char *p; | |
+ | |
+ if (ptr == NULL) | |
+ p = (char *) calloc(num, size); | |
+ else | |
+ p = (char *) realloc(ptr, num * size); | |
+ return p; | |
+} | |
+ | |
+void mnspace(void) | |
+{ | |
+ nm = sizeof(contab)/sizeof(Contab) + MDELTA; | |
+ freeslot = sizeof(contab)/sizeof(Contab) + 1; | |
+ contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab)); | |
+ if (contabp == NULL) { | |
+ ERROR "not enough memory for namespace of %d marcos", nm WARN; | |
+ exit(1); | |
+ } | |
+ contabp = (Contab *) memcpy((char *) contabp, (char *)contab, | |
+ sizeof(contab)); | |
+ if (contabp == NULL) { | |
+ ERROR "Cannot reinitialize macro/request name list" WARN; | |
+ exit(1); | |
+ } | |
+ | |
+} | |
+ | |
+void caseig(void) | |
+{ | |
+ int i; | |
+ Offset oldoff = offset; | |
+ | |
+ offset = 0; | |
+ i = copyb(); | |
+ offset = oldoff; | |
+ if (i != '.') | |
+ control(i, 1); | |
+} | |
+ | |
+ | |
+void casern(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ lgf++; | |
+ skip(); | |
+ if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0) | |
+ return; | |
+ skip(); | |
+ clrmn(findmn(j = getrq())); | |
+ if (j) { | |
+ munhash(&contabp[oldmn]); | |
+ contabp[oldmn].rq = j; | |
+ maddhash(&contabp[oldmn]); | |
+ if (dip != d ) | |
+ for (k = dilev; k; k--) | |
+ if (d[k].curd == i) | |
+ d[k].curd = j; | |
+ } | |
+} | |
+ | |
+void maddhash(Contab *rp) | |
+{ | |
+ Contab **hp; | |
+ | |
+ if (rp->rq == 0) | |
+ return; | |
+ hp = &mhash[MHASH(rp->rq)]; | |
+ rp->link = *hp; | |
+ *hp = rp; | |
+} | |
+ | |
+void munhash(Contab *mp) | |
+{ | |
+ Contab *p; | |
+ Contab **lp; | |
+ | |
+ if (mp->rq == 0) | |
+ return; | |
+ lp = &mhash[MHASH(mp->rq)]; | |
+ p = *lp; | |
+ while (p) { | |
+ if (p == mp) { | |
+ *lp = p->link; | |
+ p->link = 0; | |
+ return; | |
+ } | |
+ lp = &p->link; | |
+ p = p->link; | |
+ } | |
+} | |
+ | |
+void mrehash(void) | |
+{ | |
+ Contab *p; | |
+ int i; | |
+ | |
+ for (i=0; i < MHASHSIZE; i++) | |
+ mhash[i] = 0; | |
+ for (p=contabp; p < &contabp[nm]; p++) | |
+ p->link = 0; | |
+ for (p=contabp; p < &contabp[nm]; p++) { | |
+ if (p->rq == 0) | |
+ continue; | |
+ i = MHASH(p->rq); | |
+ p->link = mhash[i]; | |
+ mhash[i] = p; | |
+ } | |
+} | |
+ | |
+void caserm(void) | |
+{ | |
+ int j; | |
+ int k = 0; | |
+ | |
+ lgf++; | |
+g0: | |
+ while (!skip() && (j = getrq()) != 0) { | |
+ if (dip != d) | |
+ for (k = dilev; k; k--) | |
+ if (d[k].curd == j) { | |
+ ERROR "cannot remove diversion %s duri… | |
+ unpair(j) WARN; | |
+ goto g0; | |
+ } | |
+ clrmn(findmn(j)); | |
+ } | |
+ lgf--; | |
+} | |
+ | |
+ | |
+void caseas(void) | |
+{ | |
+ app++; | |
+ caseds(); | |
+} | |
+ | |
+ | |
+void caseds(void) | |
+{ | |
+ ds++; | |
+ casede(); | |
+} | |
+ | |
+ | |
+void caseam(void) | |
+{ | |
+ app++; | |
+ casede(); | |
+} | |
+ | |
+ | |
+void casede(void) | |
+{ | |
+ int i, req; | |
+ Offset savoff; | |
+ | |
+ req = '.'; | |
+ lgf++; | |
+ skip(); | |
+ if ((i = getrq()) == 0) | |
+ goto de1; | |
+ if ((offset = finds(i)) == 0) | |
+ goto de1; | |
+ if (newmn) | |
+ savslot = newmn; | |
+ else | |
+ savslot = findmn(i); | |
+ savname = i; | |
+ if (ds) | |
+ copys(); | |
+ else | |
+ req = copyb(); | |
+ clrmn(oldmn); | |
+ if (newmn) { | |
+ if (contabp[newmn].rq) | |
+ munhash(&contabp[newmn]); | |
+ contabp[newmn].rq = i; | |
+ maddhash(&contabp[newmn]); | |
+ | |
+ } | |
+ if (apptr) { | |
+ savoff = offset; | |
+ offset = apptr; | |
+ wbf((Tchar) IMP); | |
+ offset = savoff; | |
+ } | |
+ offset = dip->op; | |
+ if (req != '.') | |
+ control(req, 1); | |
+de1: | |
+ ds = app = 0; | |
+} | |
+ | |
+ | |
+int findmn(int i) | |
+{ | |
+ Contab *p; | |
+ | |
+ for (p = mhash[MHASH(i)]; p; p = p->link) | |
+ if (i == p->rq) | |
+ return(p - contabp); | |
+ return(-1); | |
+} | |
+ | |
+ | |
+void clrmn(int i) | |
+{ | |
+ if (i >= 0) { | |
+ if (contabp[i].mx) | |
+ ffree(contabp[i].mx); | |
+ munhash(&contabp[i]); | |
+ contabp[i].rq = 0; | |
+ contabp[i].mx = 0; | |
+ contabp[i].emx = 0; | |
+ contabp[i].f = 0; | |
+ if (contabp[i].divsiz != NULL) { | |
+ free(contabp[i].divsiz); | |
+ contabp[i].divsiz = NULL; | |
+ } | |
+ if (freeslot > i) | |
+ freeslot = i; | |
+ } | |
+} | |
+ | |
+void growcontab(void) | |
+{ | |
+ nm += MDELTA; | |
+ contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab)); | |
+ if (contabp == NULL) { | |
+ ERROR "Too many (%d) string/macro names", nm WARN; | |
+ done2(02); | |
+ } else { | |
+ memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab), | |
+ 0, MDELTA * sizeof(Contab)); | |
+ mrehash(); | |
+ } | |
+} | |
+ | |
+ | |
+Offset finds(int mn) | |
+{ | |
+ int i; | |
+ Offset savip; | |
+ | |
+ oldmn = findmn(mn); | |
+ newmn = 0; | |
+ apptr = 0; | |
+ if (app && oldmn >= 0 && contabp[oldmn].mx) { | |
+ savip = ip; | |
+ ip = contabp[oldmn].emx; | |
+ oldmn = -1; | |
+ apptr = ip; | |
+ if (!diflg) | |
+ ip = incoff(ip); | |
+ nextb = ip; | |
+ ip = savip; | |
+ } else { | |
+ for (i = freeslot; i < nm; i++) { | |
+ if (contabp[i].rq == 0) | |
+ break; | |
+ } | |
+ if (i == nm) | |
+ growcontab(); | |
+ freeslot = i + 1; | |
+ if ((nextb = alloc()) == -1) { | |
+ app = 0; | |
+ if (macerr++ > 1) | |
+ done2(02); | |
+ if (nextb == 0) | |
+ ERROR "Not enough space for string/macro names… | |
+ edone(04); | |
+ return(offset = 0); | |
+ } | |
+ contabp[i].mx = nextb; | |
+ if (!diflg) { | |
+ newmn = i; | |
+ if (oldmn == -1) | |
+ contabp[i].rq = -1; | |
+ } else { | |
+ contabp[i].rq = mn; | |
+ maddhash(&contabp[i]); | |
+ } | |
+ } | |
+ app = 0; | |
+ return(offset = nextb); | |
+} | |
+ | |
+int skip(void) | |
+{ | |
+ Tchar i; | |
+ | |
+ while (cbits(i = getch()) == ' ' || ismot(i)) | |
+ ; | |
+ ch = i; | |
+ return(nlflg); | |
+} | |
+ | |
+ | |
+int copyb(void) | |
+{ | |
+ int i, j, state; | |
+ Tchar ii; | |
+ int req, k; | |
+ Offset savoff; | |
+ Uchar *p; | |
+ | |
+ savoff = 0; | |
+ if (skip() || !(j = getrq())) | |
+ j = '.'; | |
+ req = j; | |
+ p = unpair(j); | |
+ /* was: k = j >> BYTE; j &= BYTEMASK; */ | |
+ j = p[0]; | |
+ k = p[1]; | |
+ copyf++; | |
+ flushi(); | |
+ nlflg = 0; | |
+ state = 1; | |
+ | |
+/* state 0 eat up | |
+ * state 1 look for . | |
+ * state 2 look for first char of end macro | |
+ * state 3 look for second char of end macro | |
+ */ | |
+ | |
+ while (1) { | |
+ i = cbits(ii = getch()); | |
+ if (state == 3) { | |
+ if (i == k) | |
+ break; | |
+ if (!k) { | |
+ ch = ii; | |
+ i = getach(); | |
+ ch = ii; | |
+ if (!i) | |
+ break; | |
+ } | |
+ state = 0; | |
+ goto c0; | |
+ } | |
+ if (i == '\n') { | |
+ state = 1; | |
+ nlflg = 0; | |
+ goto c0; | |
+ } | |
+ if (state == 1 && i == '.') { | |
+ state++; | |
+ savoff = offset; | |
+ goto c0; | |
+ } | |
+ if (state == 2 && i == j) { | |
+ state++; | |
+ goto c0; | |
+ } | |
+ state = 0; | |
+c0: | |
+ if (offset) | |
+ wbf(ii); | |
+ } | |
+ if (offset) { | |
+ offset = savoff; | |
+ wbf((Tchar)0); | |
+ } | |
+ copyf--; | |
+ return(req); | |
+} | |
+ | |
+ | |
+void copys(void) | |
+{ | |
+ Tchar i; | |
+ | |
+ copyf++; | |
+ if (skip()) | |
+ goto c0; | |
+ if (cbits(i = getch()) != '"') | |
+ wbf(i); | |
+ while (cbits(i = getch()) != '\n') | |
+ wbf(i); | |
+c0: | |
+ wbf((Tchar)0); | |
+ copyf--; | |
+} | |
+ | |
+ | |
+Offset alloc(void) /* return free Offset in nextb */ | |
+{ | |
+ int i, j; | |
+ | |
+ for (i = bfree; i < nblist; i++) | |
+ if (blist[i].nextoff == 0) | |
+ break; | |
+ if (i == nblist) { | |
+ blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof… | |
+ if (blist == NULL) { | |
+ ERROR "can't grow blist for string/macro defns" WARN; | |
+ done2(2); | |
+ } | |
+ nblist *= 2; | |
+ for (j = i; j < nblist; j++) { | |
+ blist[j].nextoff = 0; | |
+ blist[j].bp = 0; | |
+ } | |
+ } | |
+ blist[i].nextoff = -1; /* this block is the end */ | |
+ bfree = i + 1; | |
+ if (blist[i].bp == 0) | |
+ blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); | |
+ if (blist[i].bp == NULL) { | |
+ ERROR "can't allocate memory for string/macro definitions" WAR… | |
+ done2(2); | |
+ } | |
+ nextb = (Offset) i * BLK; | |
+ return nextb; | |
+} | |
+ | |
+ | |
+void ffree(Offset i) /* free list of blocks starting at blist(o) */ | |
+{ /* (doesn't actually free the blocks, just the pointe… | |
+ int j; | |
+ | |
+ for ( ; blist[j = bindex(i)].nextoff != -1; ) { | |
+ if (bfree > j) | |
+ bfree = j; | |
+ i = blist[j].nextoff; | |
+ blist[j].nextoff = 0; | |
+ } | |
+ blist[j].nextoff = 0; | |
+} | |
+ | |
+ | |
+void wbf(Tchar i) /* store i into offset, get ready for next one */ | |
+{ | |
+ int j, off; | |
+ | |
+ if (!offset) | |
+ return; | |
+ j = bindex(offset); | |
+ if (i == 0) | |
+ contabp[savslot].emx = offset; | |
+ off = boffset(offset); | |
+ blist[j].bp[off++] = i; | |
+ offset++; | |
+ if (pastend(offset)) { /* off the end of this block */ | |
+ if (blist[j].nextoff == -1) { | |
+ if ((nextb = alloc()) == -1) { | |
+ ERROR "Out of temp file space" WARN; | |
+ done2(01); | |
+ } | |
+ blist[j].nextoff = nextb; | |
+ } | |
+ offset = blist[j].nextoff; | |
+ } | |
+} | |
+ | |
+ | |
+Tchar rbf(void) /* return next char from blist[] block */ | |
+{ | |
+ Tchar i, j; | |
+ | |
+ if (ip == RD_OFFSET) { /* for rdtty */ | |
+ if (j = rdtty()) | |
+ return(j); | |
+ else | |
+ return(popi()); | |
+ } | |
+ | |
+ i = rbf0(ip); | |
+ if (i == 0) { | |
+ if (!app) | |
+ i = popi(); | |
+ return(i); | |
+ } | |
+ ip = incoff(ip); | |
+ return(i); | |
+} | |
+ | |
+ | |
+Offset xxxincoff(Offset p) /* get next blist[] block */ | |
+{ | |
+ p++; | |
+ if (pastend(p)) { /* off the end of this block */ | |
+ if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and no… | |
+ ERROR "Bad storage allocation" WARN; | |
+ done2(-5); | |
+ } | |
+ } | |
+ return(p); | |
+} | |
+ | |
+ | |
+Tchar popi(void) | |
+{ | |
+ Stack *p; | |
+ | |
+ if (frame == stk) | |
+ return(0); | |
+ if (strflg) | |
+ strflg--; | |
+ p = nxf = frame; | |
+ p->nargs = 0; | |
+ frame = p->pframe; | |
+ ip = p->pip; | |
+ pendt = p->ppendt; | |
+ lastpbp = p->lastpbp; | |
+ return(p->pch); | |
+} | |
+ | |
+/* | |
+ * test that the end of the allocation is above a certain location | |
+ * in memory | |
+ */ | |
+#define SPACETEST(base, size) \ | |
+ if ((char*)base + size >= (char*)stk+STACKSIZE) \ | |
+ ERROR "Stacksize overflow in n3" WARN | |
+ | |
+Offset pushi(Offset newip, int mname) | |
+{ | |
+ Stack *p; | |
+ | |
+ SPACETEST(nxf, sizeof(Stack)); | |
+ p = nxf; | |
+ p->pframe = frame; | |
+ p->pip = ip; | |
+ p->ppendt = pendt; | |
+ p->pch = ch; | |
+ p->lastpbp = lastpbp; | |
+ p->mname = mname; | |
+ lastpbp = pbp; | |
+ pendt = ch = 0; | |
+ frame = nxf; | |
+ if (nxf->nargs == 0) | |
+ nxf += 1; | |
+ else | |
+ nxf = (Stack *)argtop; | |
+ return(ip = newip); | |
+} | |
+ | |
+ | |
+void *setbrk(int x) | |
+{ | |
+ char *i; | |
+ | |
+ if ((i = (char *) calloc(x, 1)) == 0) { | |
+ ERROR "Core limit reached" WARN; | |
+ edone(0100); | |
+ } | |
+ return(i); | |
+} | |
+ | |
+ | |
+int getsn(void) | |
+{ | |
+ int i; | |
+ | |
+ if ((i = getach()) == 0) | |
+ return(0); | |
+ if (i == '(') | |
+ return(getrq()); | |
+ else | |
+ return(i); | |
+} | |
+ | |
+ | |
+Offset setstr(void) | |
+{ | |
+ int i, j; | |
+ | |
+ lgf++; | |
+ if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) { | |
+ lgf--; | |
+ return(0); | |
+ } else { | |
+ SPACETEST(nxf, sizeof(Stack)); | |
+ nxf->nargs = 0; | |
+ strflg++; | |
+ lgf--; | |
+ return pushi(contabp[j].mx, i); | |
+ } | |
+} | |
+ | |
+ | |
+ | |
+void collect(void) | |
+{ | |
+ int j; | |
+ Tchar i, *strp, *lim, **argpp, **argppend; | |
+ int quote; | |
+ Stack *savnxf; | |
+ | |
+ copyf++; | |
+ nxf->nargs = 0; | |
+ savnxf = nxf; | |
+ if (skip()) | |
+ goto rtn; | |
+ | |
+ { | |
+ char *memp; | |
+ memp = (char *)savnxf; | |
+ /* | |
+ * 1 s structure for the macro descriptor | |
+ * APERMAC Tchar *'s for pointers into the strings | |
+ * space for the Tchar's themselves | |
+ */ | |
+ memp += sizeof(Stack); | |
+ /* | |
+ * CPERMAC = the total # of characters for ALL arguments | |
+ */ | |
+#define CPERMAC 200 | |
+#define APERMAC 9 | |
+ memp += APERMAC * sizeof(Tchar *); | |
+ memp += CPERMAC * sizeof(Tchar); | |
+ nxf = (Stack *)memp; | |
+ } | |
+ lim = (Tchar *)nxf; | |
+ argpp = (Tchar **)(savnxf + 1); | |
+ argppend = &argpp[APERMAC]; | |
+ SPACETEST(argppend, sizeof(Tchar *)); | |
+ strp = (Tchar *)argppend; | |
+ /* | |
+ * Zero out all the string pointers before filling them in. | |
+ */ | |
+ for (j = 0; j < APERMAC; j++) | |
+ argpp[j] = 0; | |
+ /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x… | |
+ * savnxf, nxf, argpp, strp, lim WARN; | |
+ */ | |
+ strflg = 0; | |
+ while (argpp != argppend && !skip()) { | |
+ *argpp++ = strp; | |
+ quote = 0; | |
+ if (cbits(i = getch()) == '"') | |
+ quote++; | |
+ else | |
+ ch = i; | |
+ while (1) { | |
+ i = getch(); | |
+/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */ | |
+ if (nlflg || (!quote && argpp != argppend && cbits(i) … | |
+ break; /* collects rest into $9 */ | |
+ if ( quote | |
+ && cbits(i) == '"' | |
+ && cbits(i = getch()) != '"') { | |
+ ch = i; | |
+ break; | |
+ } | |
+ *strp++ = i; | |
+ if (strflg && strp >= lim) { | |
+ /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WA… | |
+ ERROR "Macro argument too long" WARN; | |
+ copyf--; | |
+ edone(004); | |
+ } | |
+ SPACETEST(strp, 3 * sizeof(Tchar)); | |
+ } | |
+ *strp++ = 0; | |
+ } | |
+ nxf = savnxf; | |
+ nxf->nargs = argpp - (Tchar **)(savnxf + 1); | |
+ argtop = strp; | |
+rtn: | |
+ copyf--; | |
+} | |
+ | |
+ | |
+void seta(void) | |
+{ | |
+ int i; | |
+ | |
+ i = cbits(getch()) - '0'; | |
+ if (i > 0 && i <= APERMAC && i <= frame->nargs) | |
+ pushback(*(((Tchar **)(frame + 1)) + i - 1)); | |
+} | |
+ | |
+ | |
+void caseda(void) | |
+{ | |
+ app++; | |
+ casedi(); | |
+} | |
+ | |
+void casegd(void) | |
+{ | |
+ int i, j; | |
+ | |
+ skip(); | |
+ if ((i = getrq()) == 0) | |
+ return; | |
+ if ((j = findmn(i)) >= 0) { | |
+ if (contabp[j].divsiz != NULL) { | |
+ numtabp[DN].val = contabp[j].divsiz->dix; | |
+ numtabp[DL].val = contabp[j].divsiz->diy; | |
+ } | |
+ } | |
+} | |
+ | |
+#define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \ | |
+ ERROR "lost diversion %s", unpair(dip->curd) WARN | |
+ | |
+void casedi(void) | |
+{ | |
+ int i, j, *k; | |
+ | |
+ lgf++; | |
+ if (skip() || (i = getrq()) == 0) { | |
+ if (dip != d) { | |
+ FINDDIV(savslot); | |
+ wbf((Tchar)0); | |
+ } | |
+ if (dilev > 0) { | |
+ numtabp[DN].val = dip->dnl; | |
+ numtabp[DL].val = dip->maxl; | |
+ FINDDIV(j); | |
+ if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divs… | |
+ ERROR "Cannot alloc diversion size" WARN; | |
+ done2(1); | |
+ } else { | |
+ contabp[j].divsiz->dix = numtabp[DN].val; | |
+ contabp[j].divsiz->diy = numtabp[DL].val; | |
+ } | |
+ dip = &d[--dilev]; | |
+ offset = dip->op; | |
+ } | |
+ goto rtn; | |
+ } | |
+ if (++dilev == NDI) { | |
+ --dilev; | |
+ ERROR "Diversions nested too deep" WARN; | |
+ edone(02); | |
+ } | |
+ if (dip != d) { | |
+ FINDDIV(j); | |
+ savslot = j; | |
+ wbf((Tchar)0); | |
+ } | |
+ diflg++; | |
+ dip = &d[dilev]; | |
+ dip->op = finds(i); | |
+ dip->curd = i; | |
+ clrmn(oldmn); | |
+ k = (int *) & dip->dnl; | |
+ for (j = 0; j < 10; j++) | |
+ k[j] = 0; /*not op and curd*/ | |
+rtn: | |
+ app = 0; | |
+ diflg = 0; | |
+} | |
+ | |
+ | |
+void casedt(void) | |
+{ | |
+ lgf++; | |
+ dip->dimac = dip->ditrap = dip->ditf = 0; | |
+ skip(); | |
+ dip->ditrap = vnumb((int *)0); | |
+ if (nonumb) | |
+ return; | |
+ skip(); | |
+ dip->dimac = getrq(); | |
+} | |
+ | |
+#define LNSIZE 4000 | |
+void casetl(void) | |
+{ | |
+ int j; | |
+ int w[3]; | |
+ Tchar buf[LNSIZE]; | |
+ Tchar *tp; | |
+ Tchar i, delim; | |
+ | |
+ /* | |
+ * bug fix | |
+ * | |
+ * if .tl is the first thing in the file, the p1 | |
+ * doesn't come out, also the pagenumber will be 0 | |
+ * | |
+ * tends too confuse the device filter (and the user as well) | |
+ */ | |
+ if (dip == d && numtabp[NL].val == -1) | |
+ newline(1); | |
+ dip->nls = 0; | |
+ skip(); | |
+ if (ismot(delim = getch())) { | |
+ ch = delim; | |
+ delim = '\''; | |
+ } else | |
+ delim = cbits(delim); | |
+ tp = buf; | |
+ numtabp[HP].val = 0; | |
+ w[0] = w[1] = w[2] = 0; | |
+ j = 0; | |
+ while (cbits(i = getch()) != '\n') { | |
+ if (cbits(i) == cbits(delim)) { | |
+ if (j < 3) | |
+ w[j] = numtabp[HP].val; | |
+ numtabp[HP].val = 0; | |
+ if (w[j] != 0) | |
+ *tp++ = WORDSP; | |
+ j++; | |
+ *tp++ = 0; | |
+ } else { | |
+ if (cbits(i) == pagech) { | |
+ setn1(numtabp[PN].val, numtabp[findr('%')].fmt, | |
+ i&SFMASK); | |
+ continue; | |
+ } | |
+ numtabp[HP].val += width(i); | |
+ if (tp < &buf[LNSIZE-10]) { | |
+ if (cbits(i) == ' ' && *tp != WORDSP) | |
+ *tp++ = WORDSP; | |
+ *tp++ = i; | |
+ } else { | |
+ ERROR "Overflow in casetl" WARN; | |
+ } | |
+ } | |
+ } | |
+ if (j<3) | |
+ w[j] = numtabp[HP].val; | |
+ *tp++ = 0; | |
+ *tp++ = 0; | |
+ *tp = 0; | |
+ tp = buf; | |
+ if (NROFF) | |
+ horiz(po); | |
+ while (i = *tp++) | |
+ pchar(i); | |
+ if (w[1] || w[2]) | |
+ horiz(j = quant((lt - w[1]) / 2 - w[0], HOR)); | |
+ while (i = *tp++) | |
+ pchar(i); | |
+ if (w[2]) { | |
+ horiz(lt - w[0] - w[1] - w[2] - j); | |
+ while (i = *tp++) | |
+ pchar(i); | |
+ } | |
+ newline(0); | |
+ if (dip != d) { | |
+ if (dip->dnl > dip->hnl) | |
+ dip->hnl = dip->dnl; | |
+ } else { | |
+ if (numtabp[NL].val > dip->hnl) | |
+ dip->hnl = numtabp[NL].val; | |
+ } | |
+} | |
+ | |
+ | |
+void casepc(void) | |
+{ | |
+ pagech = chget(IMP); | |
+} | |
+ | |
+ | |
+void casepm(void) | |
+{ | |
+ int i, k; | |
+ int xx, cnt, tcnt, kk, tot; | |
+ Offset j; | |
+ | |
+ kk = cnt = tcnt = 0; | |
+ tot = !skip(); | |
+ stackdump(); | |
+ for (i = 0; i < nm; i++) { | |
+ if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0) | |
+ continue; | |
+ tcnt++; | |
+ j = contabp[i].mx; | |
+ for (k = 1; (j = blist[bindex(j)].nextoff) != -1; ) | |
+ k++; | |
+ cnt++; | |
+ kk += k; | |
+ if (!tot) | |
+ fprintf(stderr, "%-2.2s %d\n", unpair(xx), k); | |
+ } | |
+ fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk); | |
+} | |
+ | |
+void stackdump(void) /* dumps stack of macros in process */ | |
+{ | |
+ Stack *p; | |
+ | |
+ if (frame != stk) { | |
+ fprintf(stderr, "stack: "); | |
+ for (p = frame; p != stk; p = p->pframe) | |
+ fprintf(stderr, "%s ", unpair(p->mname)); | |
+ fprintf(stderr, "\n"); | |
+ } | |
+} | |
diff --git a/troff/n4.c b/troff/n4.c | |
@@ -0,0 +1,828 @@ | |
+/* | |
+ * troff4.c | |
+ * | |
+ * number registers, conversion, arithmetic | |
+ */ | |
+ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+ | |
+int regcnt = NNAMES; | |
+int falsef = 0; /* on if inside false branch of if */ | |
+ | |
+#define NHASHSIZE 128 /* must be 2**n */ | |
+#define NHASH(i) ((i>>6)^i) & (NHASHSIZE-1) | |
+Numtab *nhash[NHASHSIZE]; | |
+ | |
+Numtab *numtabp = NULL; | |
+#define NDELTA 400 | |
+int ncnt = 0; | |
+ | |
+void setn(void) | |
+{ | |
+ int i, j, f; | |
+ Tchar ii; | |
+ Uchar *p; | |
+ char buf[NTM]; /* for \n(.S */ | |
+ | |
+ f = nform = 0; | |
+ if ((i = cbits(ii = getach())) == '+') | |
+ f = 1; | |
+ else if (i == '-') | |
+ f = -1; | |
+ else if (ii) /* don't put it back if it's already back (thanks … | |
+ ch = ii; | |
+ if (falsef) | |
+ f = 0; | |
+ if ((i = getsn()) == 0) | |
+ return; | |
+ p = unpair(i); | |
+ if (p[0] == '.') | |
+ switch (p[1]) { | |
+ case 's': | |
+ i = pts; | |
+ break; | |
+ case 'v': | |
+ i = lss; | |
+ break; | |
+ case 'f': | |
+ i = font; | |
+ break; | |
+ case 'p': | |
+ i = pl; | |
+ break; | |
+ case 't': | |
+ i = findt1(); | |
+ break; | |
+ case 'o': | |
+ i = po; | |
+ break; | |
+ case 'l': | |
+ i = ll; | |
+ break; | |
+ case 'i': | |
+ i = in; | |
+ break; | |
+ case '$': | |
+ i = frame->nargs; | |
+ break; | |
+ case 'A': | |
+ i = ascii; | |
+ break; | |
+ case 'c': | |
+ i = numtabp[CD].val; | |
+ break; | |
+ case 'n': | |
+ i = lastl; | |
+ break; | |
+ case 'a': | |
+ i = ralss; | |
+ break; | |
+ case 'h': | |
+ i = dip->hnl; | |
+ break; | |
+ case 'd': | |
+ if (dip != d) | |
+ i = dip->dnl; | |
+ else | |
+ i = numtabp[NL].val; | |
+ break; | |
+ case 'u': | |
+ i = fi; | |
+ break; | |
+ case 'j': | |
+ i = ad + 2 * admod; | |
+ break; | |
+ case 'w': | |
+ i = widthp; | |
+ break; | |
+ case 'x': | |
+ i = nel; | |
+ break; | |
+ case 'y': | |
+ i = un; | |
+ break; | |
+ case 'T': | |
+ i = dotT; | |
+ break; /* -Tterm used in nroff */ | |
+ case 'V': | |
+ i = VERT; | |
+ break; | |
+ case 'H': | |
+ i = HOR; | |
+ break; | |
+ case 'k': | |
+ i = ne; | |
+ break; | |
+ case 'P': | |
+ i = print; | |
+ break; | |
+ case 'L': | |
+ i = ls; | |
+ break; | |
+ case 'R': /* maximal # of regs that can be addressed */ | |
+ i = 255*256 - regcnt; | |
+ break; | |
+ case 'z': | |
+ p = unpair(dip->curd); | |
+ *pbp++ = p[1]; /* watch order */ | |
+ *pbp++ = p[0]; | |
+ return; | |
+ case 'b': | |
+ i = bdtab[font]; | |
+ break; | |
+ case 'F': | |
+ cpushback(cfname[ifi]); | |
+ return; | |
+ case 'S': | |
+ buf[0] = j = 0; | |
+ for( i = 0; tabtab[i] != 0 && i < NTAB; i++) { | |
+ if (i > 0) | |
+ buf[j++] = ' '; | |
+ sprintf(&buf[j], "%ld", tabtab[i] & TABMASK); | |
+ j = strlen(buf); | |
+ if ( tabtab[i] & RTAB) | |
+ sprintf(&buf[j], "uR"); | |
+ else if (tabtab[i] & CTAB) | |
+ sprintf(&buf[j], "uC"); | |
+ else | |
+ sprintf(&buf[j], "uL"); | |
+ j += 2; | |
+ } | |
+ cpushback(buf); | |
+ return; | |
+ default: | |
+ goto s0; | |
+ } | |
+ else { | |
+s0: | |
+ if ((j = findr(i)) == -1) | |
+ i = 0; | |
+ else { | |
+ i = numtabp[j].val = numtabp[j].val + numtabp[j].inc *… | |
+ nform = numtabp[j].fmt; | |
+ } | |
+ } | |
+ setn1(i, nform, (Tchar) 0); | |
+} | |
+ | |
+Tchar numbuf[25]; | |
+Tchar *numbufp; | |
+ | |
+int wrc(Tchar i) | |
+{ | |
+ if (numbufp >= &numbuf[24]) | |
+ return(0); | |
+ *numbufp++ = i; | |
+ return(1); | |
+} | |
+ | |
+ | |
+ | |
+/* insert into input number i, in format form, with size-font bits bits */ | |
+void setn1(int i, int form, Tchar bits) | |
+{ | |
+ numbufp = numbuf; | |
+ nrbits = bits; | |
+ nform = form; | |
+ fnumb(i, wrc); | |
+ *numbufp = 0; | |
+ pushback(numbuf); | |
+} | |
+ | |
+void prnumtab(Numtab *p) | |
+{ | |
+ int i; | |
+ for (i = 0; i < ncnt; i++) | |
+ if (p) | |
+ if (p[i].r != 0) | |
+ fprintf(stderr, "slot %d, %s, val %d\n", i, un… | |
+ else | |
+ fprintf(stderr, "slot %d empty\n", i); | |
+ else | |
+ fprintf(stderr, "slot %d empty\n", i); | |
+} | |
+ | |
+void nnspace(void) | |
+{ | |
+ ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA; | |
+ numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab)); | |
+ if (numtabp == NULL) { | |
+ ERROR "not enough memory for registers (%d)", ncnt WARN; | |
+ exit(1); | |
+ } | |
+ numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab, | |
+ sizeof(numtab)); | |
+ if (numtabp == NULL) { | |
+ ERROR "Cannot initialize registers" WARN; | |
+ exit(1); | |
+ } | |
+} | |
+ | |
+void grownumtab(void) | |
+{ | |
+ ncnt += NDELTA; | |
+ numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab)); | |
+ if (numtabp == NULL) { | |
+ ERROR "Too many number registers (%d)", ncnt WARN; | |
+ done2(04); | |
+ } else { | |
+ memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab), | |
+ 0, NDELTA * sizeof(Numtab)); | |
+ nrehash(); | |
+ } | |
+} | |
+ | |
+void nrehash(void) | |
+{ | |
+ Numtab *p; | |
+ int i; | |
+ | |
+ for (i=0; i<NHASHSIZE; i++) | |
+ nhash[i] = 0; | |
+ for (p=numtabp; p < &numtabp[ncnt]; p++) | |
+ p->link = 0; | |
+ for (p=numtabp; p < &numtabp[ncnt]; p++) { | |
+ if (p->r == 0) | |
+ continue; | |
+ i = NHASH(p->r); | |
+ p->link = nhash[i]; | |
+ nhash[i] = p; | |
+ } | |
+} | |
+ | |
+void nunhash(Numtab *rp) | |
+{ | |
+ Numtab *p; | |
+ Numtab **lp; | |
+ | |
+ if (rp->r == 0) | |
+ return; | |
+ lp = &nhash[NHASH(rp->r)]; | |
+ p = *lp; | |
+ while (p) { | |
+ if (p == rp) { | |
+ *lp = p->link; | |
+ p->link = 0; | |
+ return; | |
+ } | |
+ lp = &p->link; | |
+ p = p->link; | |
+ } | |
+} | |
+ | |
+int findr(int i) | |
+{ | |
+ Numtab *p; | |
+ int h = NHASH(i); | |
+ | |
+ if (i == 0) | |
+ return(-1); | |
+a0: | |
+ for (p = nhash[h]; p; p = p->link) | |
+ if (i == p->r) | |
+ return(p - numtabp); | |
+ for (p = numtabp; p < &numtabp[ncnt]; p++) { | |
+ if (p->r == 0) { | |
+ p->r = i; | |
+ p->link = nhash[h]; | |
+ nhash[h] = p; | |
+ regcnt++; | |
+ return(p - numtabp); | |
+ } | |
+ } | |
+ grownumtab(); | |
+ goto a0; | |
+} | |
+ | |
+int usedr(int i) /* returns -1 if nr i has never been used */ | |
+{ | |
+ Numtab *p; | |
+ | |
+ if (i == 0) | |
+ return(-1); | |
+ for (p = nhash[NHASH(i)]; p; p = p->link) | |
+ if (i == p->r) | |
+ return(p - numtabp); | |
+ return -1; | |
+} | |
+ | |
+ | |
+int fnumb(int i, int (*f)(Tchar)) | |
+{ | |
+ int j; | |
+ | |
+ j = 0; | |
+ if (i < 0) { | |
+ j = (*f)('-' | nrbits); | |
+ i = -i; | |
+ } | |
+ switch (nform) { | |
+ default: | |
+ case '1': | |
+ case 0: | |
+ return decml(i, f) + j; | |
+ case 'i': | |
+ case 'I': | |
+ return roman(i, f) + j; | |
+ case 'a': | |
+ case 'A': | |
+ return abc(i, f) + j; | |
+ } | |
+} | |
+ | |
+ | |
+int decml(int i, int (*f)(Tchar)) | |
+{ | |
+ int j, k; | |
+ | |
+ k = 0; | |
+ nform--; | |
+ if ((j = i / 10) || (nform > 0)) | |
+ k = decml(j, f); | |
+ return(k + (*f)((i % 10 + '0') | nrbits)); | |
+} | |
+ | |
+ | |
+int roman(int i, int (*f)(Tchar)) | |
+{ | |
+ | |
+ if (!i) | |
+ return((*f)('0' | nrbits)); | |
+ if (nform == 'i') | |
+ return(roman0(i, f, "ixcmz", "vldw")); | |
+ else | |
+ return(roman0(i, f, "IXCMZ", "VLDW")); | |
+} | |
+ | |
+ | |
+int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp) | |
+{ | |
+ int q, rem, k; | |
+ | |
+ if (!i) | |
+ return(0); | |
+ k = roman0(i / 10, f, onesp + 1, fivesp + 1); | |
+ q = (i = i % 10) / 5; | |
+ rem = i % 5; | |
+ if (rem == 4) { | |
+ k += (*f)(*onesp | nrbits); | |
+ if (q) | |
+ i = *(onesp + 1); | |
+ else | |
+ i = *fivesp; | |
+ return(k += (*f)(i | nrbits)); | |
+ } | |
+ if (q) | |
+ k += (*f)(*fivesp | nrbits); | |
+ while (--rem >= 0) | |
+ k += (*f)(*onesp | nrbits); | |
+ return(k); | |
+} | |
+ | |
+ | |
+int abc(int i, int (*f)(Tchar)) | |
+{ | |
+ if (!i) | |
+ return((*f)('0' | nrbits)); | |
+ else | |
+ return(abc0(i - 1, f)); | |
+} | |
+ | |
+ | |
+int abc0(int i, int (*f)(Tchar)) | |
+{ | |
+ int j, k; | |
+ | |
+ k = 0; | |
+ if (j = i / 26) | |
+ k = abc0(j - 1, f); | |
+ return(k + (*f)((i % 26 + nform) | nrbits)); | |
+} | |
+ | |
+long atoi0(void) | |
+{ | |
+ int c, k, cnt; | |
+ Tchar ii; | |
+ long i, acc; | |
+ | |
+ acc = 0; | |
+ nonumb = 0; | |
+ cnt = -1; | |
+a0: | |
+ cnt++; | |
+ ii = getch(); | |
+ c = cbits(ii); | |
+ switch (c) { | |
+ default: | |
+ ch = ii; | |
+ if (cnt) | |
+ break; | |
+ case '+': | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ acc += i; | |
+ goto a0; | |
+ case '-': | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ acc -= i; | |
+ goto a0; | |
+ case '*': | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ acc *= i; | |
+ goto a0; | |
+ case '/': | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ if (i == 0) { | |
+ flusho(); | |
+ ERROR "divide by zero." WARN; | |
+ acc = 0; | |
+ } else | |
+ acc /= i; | |
+ goto a0; | |
+ case '%': | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ acc %= i; | |
+ goto a0; | |
+ case '&': /*and*/ | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ if ((acc > 0) && (i > 0)) | |
+ acc = 1; | |
+ else | |
+ acc = 0; | |
+ goto a0; | |
+ case ':': /*or*/ | |
+ i = ckph(); | |
+ if (nonumb) | |
+ break; | |
+ if ((acc > 0) || (i > 0)) | |
+ acc = 1; | |
+ else | |
+ acc = 0; | |
+ goto a0; | |
+ case '=': | |
+ if (cbits(ii = getch()) != '=') | |
+ ch = ii; | |
+ i = ckph(); | |
+ if (nonumb) { | |
+ acc = 0; | |
+ break; | |
+ } | |
+ if (i == acc) | |
+ acc = 1; | |
+ else | |
+ acc = 0; | |
+ goto a0; | |
+ case '>': | |
+ k = 0; | |
+ if (cbits(ii = getch()) == '=') | |
+ k++; | |
+ else | |
+ ch = ii; | |
+ i = ckph(); | |
+ if (nonumb) { | |
+ acc = 0; | |
+ break; | |
+ } | |
+ if (acc > (i - k)) | |
+ acc = 1; | |
+ else | |
+ acc = 0; | |
+ goto a0; | |
+ case '<': | |
+ k = 0; | |
+ if (cbits(ii = getch()) == '=') | |
+ k++; | |
+ else | |
+ ch = ii; | |
+ i = ckph(); | |
+ if (nonumb) { | |
+ acc = 0; | |
+ break; | |
+ } | |
+ if (acc < (i + k)) | |
+ acc = 1; | |
+ else | |
+ acc = 0; | |
+ goto a0; | |
+ case ')': | |
+ break; | |
+ case '(': | |
+ acc = atoi0(); | |
+ goto a0; | |
+ } | |
+ return(acc); | |
+} | |
+ | |
+ | |
+long ckph(void) | |
+{ | |
+ Tchar i; | |
+ long j; | |
+ | |
+ if (cbits(i = getch()) == '(') | |
+ j = atoi0(); | |
+ else { | |
+ j = atoi1(i); | |
+ } | |
+ return(j); | |
+} | |
+ | |
+ | |
+/* | |
+ * print error about illegal numeric argument; | |
+ */ | |
+void prnumerr(void) | |
+{ | |
+ char err_buf[40]; | |
+ static char warn[] = "Numeric argument expected"; | |
+ int savcd = numtabp[CD].val; | |
+ | |
+ if (numerr.type == RQERR) | |
+ sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc), | |
+ unpair(numerr.req), warn); | |
+ else | |
+ sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg, | |
+ warn); | |
+ if (frame != stk) /* uncertainty correction */ | |
+ numtabp[CD].val--; | |
+ ERROR "%s", err_buf WARN; | |
+ numtabp[CD].val = savcd; | |
+} | |
+ | |
+ | |
+long atoi1(Tchar ii) | |
+{ | |
+ int i, j, digits; | |
+ double acc; /* this is the only double in troff! */ | |
+ int neg, abs, field, decpnt; | |
+ extern int ifnum; | |
+ | |
+ | |
+ neg = abs = field = decpnt = digits = 0; | |
+ acc = 0; | |
+ for (;;) { | |
+ i = cbits(ii); | |
+ switch (i) { | |
+ default: | |
+ break; | |
+ case '+': | |
+ ii = getch(); | |
+ continue; | |
+ case '-': | |
+ neg = 1; | |
+ ii = getch(); | |
+ continue; | |
+ case '|': | |
+ abs = 1 + neg; | |
+ neg = 0; | |
+ ii = getch(); | |
+ continue; | |
+ } | |
+ break; | |
+ } | |
+a1: | |
+ while (i >= '0' && i <= '9') { | |
+ field++; | |
+ digits++; | |
+ acc = 10 * acc + i - '0'; | |
+ ii = getch(); | |
+ i = cbits(ii); | |
+ } | |
+ if (i == '.' && !decpnt++) { | |
+ field++; | |
+ digits = 0; | |
+ ii = getch(); | |
+ i = cbits(ii); | |
+ goto a1; | |
+ } | |
+ if (!field) { | |
+ ch = ii; | |
+ goto a2; | |
+ } | |
+ switch (i) { | |
+ case 'u': | |
+ i = j = 1; /* should this be related to HOR?? */ | |
+ break; | |
+ case 'v': /*VSs - vert spacing*/ | |
+ j = lss; | |
+ i = 1; | |
+ break; | |
+ case 'm': /*Ems*/ | |
+ j = EM; | |
+ i = 1; | |
+ break; | |
+ case 'n': /*Ens*/ | |
+ j = EM; | |
+ if (TROFF) | |
+ i = 2; | |
+ else | |
+ i = 1; /*Same as Ems in NROFF*/ | |
+ break; | |
+ case 'p': /*Points*/ | |
+ j = INCH; | |
+ i = 72; | |
+ break; | |
+ case 'i': /*Inches*/ | |
+ j = INCH; | |
+ i = 1; | |
+ break; | |
+ case 'c': /*Centimeters*/ | |
+ /* if INCH is too big, this will overflow */ | |
+ j = INCH * 50; | |
+ i = 127; | |
+ break; | |
+ case 'P': /*Picas*/ | |
+ j = INCH; | |
+ i = 6; | |
+ break; | |
+ default: | |
+ j = dfact; | |
+ ch = ii; | |
+ i = dfactd; | |
+ } | |
+ if (neg) | |
+ acc = -acc; | |
+ if (!noscale) { | |
+ acc = (acc * j) / i; | |
+ } | |
+ if (field != digits && digits > 0) | |
+ while (digits--) | |
+ acc /= 10; | |
+ if (abs) { | |
+ if (dip != d) | |
+ j = dip->dnl; | |
+ else | |
+ j = numtabp[NL].val; | |
+ if (!vflag) { | |
+ j = numtabp[HP].val; | |
+ } | |
+ if (abs == 2) | |
+ j = -j; | |
+ acc -= j; | |
+ } | |
+a2: | |
+ nonumb = (!field || field == decpnt); | |
+ if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) { | |
+ if (cbits(ii) != RIGHT ) /* Too painful to do right */ | |
+ prnumerr(); | |
+ } | |
+ return(acc); | |
+} | |
+ | |
+ | |
+void caserr(void) | |
+{ | |
+ int i, j; | |
+ Numtab *p; | |
+ | |
+ lgf++; | |
+ while (!skip() && (i = getrq()) ) { | |
+ j = usedr(i); | |
+ if (j < 0) | |
+ continue; | |
+ p = &numtabp[j]; | |
+ nunhash(p); | |
+ p->r = p->val = p->inc = p->fmt = 0; | |
+ regcnt--; | |
+ } | |
+} | |
+ | |
+/* | |
+ * .nr request; if tracing, don't check optional | |
+ * 2nd argument because tbl generates .in 1.5n | |
+ */ | |
+void casenr(void) | |
+{ | |
+ int i, j; | |
+ int savtr = trace; | |
+ | |
+ lgf++; | |
+ skip(); | |
+ if ((i = findr(getrq())) == -1) | |
+ goto rtn; | |
+ skip(); | |
+ j = inumb(&numtabp[i].val); | |
+ if (nonumb) | |
+ goto rtn; | |
+ numtabp[i].val = j; | |
+ skip(); | |
+ trace = 0; | |
+ j = atoi0(); /* BUG??? */ | |
+ trace = savtr; | |
+ if (nonumb) | |
+ goto rtn; | |
+ numtabp[i].inc = j; | |
+rtn: | |
+ return; | |
+} | |
+ | |
+void caseaf(void) | |
+{ | |
+ int i, k; | |
+ Tchar j; | |
+ | |
+ lgf++; | |
+ if (skip() || !(i = getrq()) || skip()) | |
+ return; | |
+ k = 0; | |
+ j = getch(); | |
+ if (!isalpha(cbits(j))) { | |
+ ch = j; | |
+ while ((j = cbits(getch())) >= '0' && j <= '9') | |
+ k++; | |
+ } | |
+ if (!k) | |
+ k = j; | |
+ numtabp[findr(i)].fmt = k; /* was k & BYTEMASK */ | |
+} | |
+ | |
+void setaf(void) /* return format of number register */ | |
+{ | |
+ int i, j; | |
+ | |
+ i = usedr(getsn()); | |
+ if (i == -1) | |
+ return; | |
+ if (numtabp[i].fmt > 20) /* it was probably a, A, i or I */ | |
+ *pbp++ = numtabp[i].fmt; | |
+ else | |
+ for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--) | |
+ *pbp++ = '0'; | |
+} | |
+ | |
+ | |
+int vnumb(int *i) | |
+{ | |
+ vflag++; | |
+ dfact = lss; | |
+ res = VERT; | |
+ return(inumb(i)); | |
+} | |
+ | |
+ | |
+int hnumb(int *i) | |
+{ | |
+ dfact = EM; | |
+ res = HOR; | |
+ return(inumb(i)); | |
+} | |
+ | |
+ | |
+int inumb(int *n) | |
+{ | |
+ int i, j, f; | |
+ Tchar ii; | |
+ | |
+ f = 0; | |
+ if (n) { | |
+ if ((j = cbits(ii = getch())) == '+') | |
+ f = 1; | |
+ else if (j == '-') | |
+ f = -1; | |
+ else | |
+ ch = ii; | |
+ } | |
+ i = atoi0(); | |
+ if (n && f) | |
+ i = *n + f * i; | |
+ i = quant(i, res); | |
+ vflag = 0; | |
+ res = dfactd = dfact = 1; | |
+ if (nonumb) | |
+ i = 0; | |
+ return(i); | |
+} | |
+ | |
+ | |
+int quant(int n, int m) | |
+{ | |
+ int i, neg; | |
+ | |
+ neg = 0; | |
+ if (n < 0) { | |
+ neg++; | |
+ n = -n; | |
+ } | |
+ /* better as i = ((n + m/2)/m)*m */ | |
+ i = n / m; | |
+ if (n - m * i > m / 2) | |
+ i += 1; | |
+ i *= m; | |
+ if (neg) | |
+ i = -i; | |
+ return(i); | |
+} | |
diff --git a/troff/n5.c b/troff/n5.c | |
@@ -0,0 +1,1150 @@ | |
+/* | |
+ * troff5.c | |
+ * | |
+ * misc processing requests | |
+ */ | |
+ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+int iflist[NIF]; | |
+int ifx; | |
+int ifnum = 0; /* trying numeric expression for .if or .ie condi… | |
+ | |
+void casead(void) | |
+{ | |
+ int i; | |
+ | |
+ ad = 1; | |
+ /* leave admod alone */ | |
+ if (skip()) | |
+ return; | |
+ switch (i = cbits(getch())) { | |
+ case 'r': /* right adj, left ragged */ | |
+ admod = 2; | |
+ break; | |
+ case 'l': /* left adj, right ragged */ | |
+ admod = ad = 0; /* same as casena */ | |
+ break; | |
+ case 'c': /*centered adj*/ | |
+ admod = 1; | |
+ break; | |
+ case 'b': | |
+ case 'n': | |
+ admod = 0; | |
+ break; | |
+ case '0': | |
+ case '2': | |
+ case '4': | |
+ ad = 0; | |
+ case '1': | |
+ case '3': | |
+ case '5': | |
+ admod = (i - '0') / 2; | |
+ } | |
+} | |
+ | |
+ | |
+void casena(void) | |
+{ | |
+ ad = 0; | |
+} | |
+ | |
+ | |
+void casefi(void) | |
+{ | |
+ tbreak(); | |
+ fi = 1; | |
+ pendnf = 0; | |
+} | |
+ | |
+ | |
+void casenf(void) | |
+{ | |
+ tbreak(); | |
+ fi = 0; | |
+} | |
+ | |
+ | |
+void casers(void) | |
+{ | |
+ dip->nls = 0; | |
+} | |
+ | |
+ | |
+void casens(void) | |
+{ | |
+ dip->nls++; | |
+} | |
+ | |
+int | |
+chget(int c) | |
+{ | |
+ Tchar i; | |
+ | |
+ i = 0; | |
+ if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n… | |
+ ch = i; | |
+ return(c); | |
+ } else | |
+ return cbits(i); /* was (i & BYTEMASK) */ | |
+} | |
+ | |
+ | |
+void casecc(void) | |
+{ | |
+ cc = chget('.'); | |
+} | |
+ | |
+ | |
+void casec2(void) | |
+{ | |
+ c2 = chget('\''); | |
+} | |
+ | |
+ | |
+void casehc(void) | |
+{ | |
+ ohc = chget(OHC); | |
+} | |
+ | |
+ | |
+void casetc(void) | |
+{ | |
+ tabc = chget(0); | |
+} | |
+ | |
+ | |
+void caselc(void) | |
+{ | |
+ dotc = chget(0); | |
+} | |
+ | |
+ | |
+void casehy(void) | |
+{ | |
+ int i; | |
+ | |
+ hyf = 1; | |
+ if (skip()) | |
+ return; | |
+ noscale++; | |
+ i = atoi0(); | |
+ noscale = 0; | |
+ if (nonumb) | |
+ return; | |
+ hyf = max(i, 0); | |
+} | |
+ | |
+ | |
+void casenh(void) | |
+{ | |
+ hyf = 0; | |
+} | |
+ | |
+int | |
+max(int aa, int bb) | |
+{ | |
+ if (aa > bb) | |
+ return(aa); | |
+ else | |
+ return(bb); | |
+} | |
+ | |
+ | |
+void casece(void) | |
+{ | |
+ int i; | |
+ | |
+ noscale++; | |
+ skip(); | |
+ i = max(atoi0(), 0); | |
+ if (nonumb) | |
+ i = 1; | |
+ tbreak(); | |
+ ce = i; | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void casein(void) | |
+{ | |
+ int i; | |
+ | |
+ if (skip()) | |
+ i = in1; | |
+ else { | |
+ i = max(hnumb(&in), 0); | |
+ if (nonumb) | |
+ i = in1; | |
+ } | |
+ tbreak(); | |
+ in1 = in; | |
+ in = i; | |
+ if (!nc) { | |
+ un = in; | |
+ setnel(); | |
+ } | |
+} | |
+ | |
+ | |
+void casell(void) | |
+{ | |
+ int i; | |
+ | |
+ if (skip()) | |
+ i = ll1; | |
+ else { | |
+ i = max(hnumb(&ll), INCH / 10); | |
+ if (nonumb) | |
+ i = ll1; | |
+ } | |
+ ll1 = ll; | |
+ ll = i; | |
+ setnel(); | |
+} | |
+ | |
+ | |
+void caselt(void) | |
+{ | |
+ int i; | |
+ | |
+ if (skip()) | |
+ i = lt1; | |
+ else { | |
+ i = max(hnumb(<), 0); | |
+ if (nonumb) | |
+ i = lt1; | |
+ } | |
+ lt1 = lt; | |
+ lt = i; | |
+} | |
+ | |
+ | |
+void caseti(void) | |
+{ | |
+ int i; | |
+ | |
+ if (skip()) | |
+ return; | |
+ i = max(hnumb(&in), 0); | |
+ tbreak(); | |
+ un1 = i; | |
+ setnel(); | |
+} | |
+ | |
+ | |
+void casels(void) | |
+{ | |
+ int i; | |
+ | |
+ noscale++; | |
+ if (skip()) | |
+ i = ls1; | |
+ else { | |
+ i = max(inumb(&ls), 1); | |
+ if (nonumb) | |
+ i = ls1; | |
+ } | |
+ ls1 = ls; | |
+ ls = i; | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void casepo(void) | |
+{ | |
+ int i; | |
+ | |
+ if (skip()) | |
+ i = po1; | |
+ else { | |
+ i = max(hnumb(&po), 0); | |
+ if (nonumb) | |
+ i = po1; | |
+ } | |
+ po1 = po; | |
+ po = i; | |
+ if (TROFF & !ascii) | |
+ esc += po - po1; | |
+} | |
+ | |
+ | |
+void casepl(void) | |
+{ | |
+ int i; | |
+ | |
+ skip(); | |
+ if ((i = vnumb(&pl)) == 0) | |
+ pl = 11 * INCH; /*11in*/ | |
+ else | |
+ pl = i; | |
+ if (numtabp[NL].val > pl) | |
+ numtabp[NL].val = pl; | |
+} | |
+ | |
+ | |
+void casewh(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ lgf++; | |
+ skip(); | |
+ i = vnumb((int *)0); | |
+ if (nonumb) | |
+ return; | |
+ skip(); | |
+ j = getrq(); | |
+ if ((k = findn(i)) != NTRAP) { | |
+ mlist[k] = j; | |
+ return; | |
+ } | |
+ for (k = 0; k < NTRAP; k++) | |
+ if (mlist[k] == 0) | |
+ break; | |
+ if (k == NTRAP) { | |
+ flusho(); | |
+ ERROR "cannot plant trap." WARN; | |
+ return; | |
+ } | |
+ mlist[k] = j; | |
+ nlist[k] = i; | |
+} | |
+ | |
+ | |
+void casech(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ lgf++; | |
+ skip(); | |
+ if (!(j = getrq())) | |
+ return; | |
+ else | |
+ for (k = 0; k < NTRAP; k++) | |
+ if (mlist[k] == j) | |
+ break; | |
+ if (k == NTRAP) | |
+ return; | |
+ skip(); | |
+ i = vnumb((int *)0); | |
+ if (nonumb) | |
+ mlist[k] = 0; | |
+ nlist[k] = i; | |
+} | |
+ | |
+int | |
+findn(int i) | |
+{ | |
+ int k; | |
+ | |
+ for (k = 0; k < NTRAP; k++) | |
+ if ((nlist[k] == i) && (mlist[k] != 0)) | |
+ break; | |
+ return(k); | |
+} | |
+ | |
+ | |
+void casepn(void) | |
+{ | |
+ int i; | |
+ | |
+ skip(); | |
+ noscale++; | |
+ i = max(inumb(&numtabp[PN].val), 0); | |
+ noscale = 0; | |
+ if (!nonumb) { | |
+ npn = i; | |
+ npnflg++; | |
+ } | |
+} | |
+ | |
+ | |
+void casebp(void) | |
+{ | |
+ int i; | |
+ Stack *savframe; | |
+ | |
+ if (dip != d) | |
+ return; | |
+ savframe = frame; | |
+ skip(); | |
+ if ((i = inumb(&numtabp[PN].val)) < 0) | |
+ i = 0; | |
+ tbreak(); | |
+ if (!nonumb) { | |
+ npn = i; | |
+ npnflg++; | |
+ } else if (dip->nls) | |
+ return; | |
+ eject(savframe); | |
+} | |
+ | |
+void casetm(void) | |
+{ | |
+ casetm1(0, stderr); | |
+} | |
+ | |
+ | |
+void casefm(void) | |
+{ | |
+ static struct fcache { | |
+ char *name; | |
+ FILE *fp; | |
+ } fcache[15]; | |
+ int i; | |
+ | |
+ if ( skip() || !getname()) { | |
+ ERROR "fm: missing filename" WARN; | |
+ return; | |
+ } | |
+ | |
+ for (i = 0; i < 15 && fcache[i].fp != NULL; i++) { | |
+ if (strcmp(nextf, fcache[i].name) == 0) | |
+ break; | |
+ } | |
+ if (i >= 15) { | |
+ ERROR "fm: too many streams" WARN; | |
+ return; | |
+ } | |
+ if (fcache[i].fp == NULL) { | |
+ if( (fcache[i].fp = fopen(unsharp(nextf), "w")) == NULL) { | |
+ ERROR "fm: cannot open %s", nextf WARN; | |
+ return; | |
+ } | |
+ fcache[i].name = strdupl(nextf); | |
+ } | |
+ casetm1(0, fcache[i].fp); | |
+} | |
+ | |
+void casetm1(int ab, FILE *out) | |
+{ | |
+ int i, j, c; | |
+ char *p; | |
+ char tmbuf[NTM]; | |
+ | |
+ lgf++; | |
+ copyf++; | |
+ if (ab) { | |
+ if (skip()) | |
+ ERROR "User Abort" WARN; | |
+ else { | |
+ extern int error; | |
+ int savtrac = trace; | |
+ i = trace = 0; | |
+ noscale++; | |
+ i = inumb(&trace); | |
+ noscale--; | |
+ if (i) { | |
+ error = i; | |
+ if (nlflg || skip()) | |
+ ERROR "User Abort, exit code %d", i WA… | |
+ } | |
+ trace = savtrac; | |
+ } | |
+ } else | |
+ skip(); | |
+ for (i = 0; i < NTM - 2; ) { | |
+ if ((c = cbits(getch())) == '\n' || c == RIGHT) | |
+ break; | |
+ else if (c == MINUS) { /* special pleading for strange … | |
+ tmbuf[i++] = '\\'; | |
+ tmbuf[i++] = '-'; | |
+ } else if (c == PRESC) { | |
+ tmbuf[i++] = '\\'; | |
+ tmbuf[i++] = 'e'; | |
+ } else if (c == FILLER) { | |
+ tmbuf[i++] = '\\'; | |
+ tmbuf[i++] = '&'; | |
+ } else if (c == UNPAD) { | |
+ tmbuf[i++] = '\\'; | |
+ tmbuf[i++] = ' '; | |
+ } else if (c == OHC) { | |
+ tmbuf[i++] = '\\'; | |
+ tmbuf[i++] = '%'; | |
+ } else if (c >= ALPHABET) { | |
+ p = chname(c); | |
+ switch (*p) { | |
+ case MBchar: | |
+ strcpy(&tmbuf[i], p+1); | |
+ break; | |
+ case Number: | |
+ sprintf(&tmbuf[i], "\\N'%s'", p+1); | |
+ break; | |
+ case Troffchar: | |
+ if ((j = strlen(p+1)) == 2) | |
+ sprintf(&tmbuf[i], "\\(%s", p+1); | |
+ else | |
+ sprintf(&tmbuf[i], "\\C'%s'", p+1); | |
+ break; | |
+ default: | |
+ sprintf(&tmbuf[i]," %s? ", p); | |
+ break; | |
+ } | |
+ j = strlen(&tmbuf[i]); | |
+ i += j; | |
+ } else | |
+ tmbuf[i++] = c; | |
+ } | |
+ tmbuf[i] = 0; | |
+ if (ab) /* truncate output */ | |
+ obufp = obuf; /* should be a function in n2.c */ | |
+ flusho(); | |
+ if (i) | |
+ fprintf(out, "%s\n", tmbuf); | |
+ fflush(out); | |
+ copyf--; | |
+ lgf--; | |
+} | |
+ | |
+ | |
+void casesp(void) | |
+{ | |
+ casesp1(0); | |
+} | |
+ | |
+void casesp1(int a) | |
+{ | |
+ int i, j, savlss; | |
+ | |
+ tbreak(); | |
+ if (dip->nls || trap) | |
+ return; | |
+ i = findt1(); | |
+ if (!a) { | |
+ skip(); | |
+ j = vnumb((int *)0); | |
+ if (nonumb) | |
+ j = lss; | |
+ } else | |
+ j = a; | |
+ if (j == 0) | |
+ return; | |
+ if (i < j) | |
+ j = i; | |
+ savlss = lss; | |
+ if (dip != d) | |
+ i = dip->dnl; | |
+ else | |
+ i = numtabp[NL].val; | |
+ if ((i + j) < 0) | |
+ j = -i; | |
+ lss = j; | |
+ newline(0); | |
+ lss = savlss; | |
+} | |
+ | |
+ | |
+void casert(void) | |
+{ | |
+ int a, *p; | |
+ | |
+ skip(); | |
+ if (dip != d) | |
+ p = &dip->dnl; | |
+ else | |
+ p = &numtabp[NL].val; | |
+ a = vnumb(p); | |
+ if (nonumb) | |
+ a = dip->mkline; | |
+ if ((a < 0) || (a >= *p)) | |
+ return; | |
+ nb++; | |
+ casesp1(a - *p); | |
+} | |
+ | |
+ | |
+void caseem(void) | |
+{ | |
+ lgf++; | |
+ skip(); | |
+ em = getrq(); | |
+} | |
+ | |
+ | |
+void casefl(void) | |
+{ | |
+ tbreak(); | |
+ if (!ascii) | |
+ ptflush(); | |
+ flusho(); | |
+} | |
+ | |
+ | |
+void caseev(void) | |
+{ | |
+ int nxev; | |
+ | |
+ if (skip()) { | |
+e0: | |
+ if (evi == 0) | |
+ return; | |
+ nxev = evlist[--evi]; | |
+ goto e1; | |
+ } | |
+ noscale++; | |
+ nxev = atoi0(); | |
+ noscale = 0; | |
+ if (nonumb) | |
+ goto e0; | |
+ flushi(); | |
+ if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) { | |
+ flusho(); | |
+ ERROR "cannot do .ev %d", nxev WARN; | |
+ if (error) | |
+ done2(040); | |
+ else | |
+ edone(040); | |
+ return; | |
+ } | |
+ evlist[evi++] = ev; | |
+e1: | |
+ if (ev == nxev) | |
+ return; | |
+ ev = nxev; | |
+ envp = &env[ev]; | |
+} | |
+ | |
+void envcopy(Env *e1, Env *e2) /* copy env e2 to e1 */ | |
+{ | |
+ *e1 = *e2; /* rumor hath that this fails on some machines */ | |
+} | |
+ | |
+ | |
+void caseel(void) | |
+{ | |
+ if (--ifx < 0) { | |
+ ifx = 0; | |
+ iflist[0] = 0; | |
+ } | |
+ caseif1(2); | |
+} | |
+ | |
+ | |
+void caseie(void) | |
+{ | |
+ if (ifx >= NIF) { | |
+ ERROR "if-else overflow." WARN; | |
+ ifx = 0; | |
+ edone(040); | |
+ } | |
+ caseif1(1); | |
+ ifx++; | |
+} | |
+ | |
+ | |
+void caseif(void) | |
+{ | |
+ caseif1(0); | |
+} | |
+ | |
+void caseif1(int x) | |
+{ | |
+ extern int falsef; | |
+ int notflag, true; | |
+ Tchar i; | |
+ | |
+ if (x == 2) { | |
+ notflag = 0; | |
+ true = iflist[ifx]; | |
+ goto i1; | |
+ } | |
+ true = 0; | |
+ skip(); | |
+ if ((cbits(i = getch())) == '!') { | |
+ notflag = 1; | |
+ } else { | |
+ notflag = 0; | |
+ ch = i; | |
+ } | |
+ ifnum++; | |
+ i = atoi0(); | |
+ ifnum = 0; | |
+ if (!nonumb) { | |
+ if (i > 0) | |
+ true++; | |
+ goto i1; | |
+ } | |
+ i = getch(); | |
+ switch (cbits(i)) { | |
+ case 'e': | |
+ if (!(numtabp[PN].val & 01)) | |
+ true++; | |
+ break; | |
+ case 'o': | |
+ if (numtabp[PN].val & 01) | |
+ true++; | |
+ break; | |
+ case 'n': | |
+ if (NROFF) | |
+ true++; | |
+ break; | |
+ case 't': | |
+ if (TROFF) | |
+ true++; | |
+ break; | |
+ case ' ': | |
+ break; | |
+ default: | |
+ true = cmpstr(i); | |
+ } | |
+i1: | |
+ true ^= notflag; | |
+ if (x == 1) | |
+ iflist[ifx] = !true; | |
+ if (true) { | |
+i2: | |
+ while ((cbits(i = getch())) == ' ') | |
+ ; | |
+ if (cbits(i) == LEFT) | |
+ goto i2; | |
+ ch = i; | |
+ nflush++; | |
+ } else { | |
+ if (!nlflg) { | |
+ copyf++; | |
+ falsef++; | |
+ eatblk(0); | |
+ copyf--; | |
+ falsef--; | |
+ } | |
+ } | |
+} | |
+ | |
+void eatblk(int inblk) | |
+{ | |
+ int cnt, i; | |
+ | |
+ cnt = 0; | |
+ do { | |
+ if (ch) { | |
+ i = cbits(ch); | |
+ ch = 0; | |
+ } else | |
+ i = cbits(getch0()); | |
+ if (i == ESC) | |
+ cnt++; | |
+ else { | |
+ if (cnt == 1) | |
+ switch (i) { | |
+ case '{': i = LEFT; break; | |
+ case '}': i = RIGHT; break; | |
+ case '\n': i = 'x'; break; | |
+ } | |
+ cnt = 0; | |
+ } | |
+ if (i == LEFT) eatblk(1); | |
+ } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT))); | |
+ if (i == '\n') { | |
+ nlflg++; | |
+ if (ip == 0) | |
+ numtabp[CD].val++; | |
+ } | |
+} | |
+ | |
+int | |
+cmpstr(Tchar c) | |
+{ | |
+ int j, delim; | |
+ Tchar i; | |
+ int val; | |
+ int savapts, savapts1, savfont, savfont1, savpts, savpts1; | |
+ Tchar string[1280]; | |
+ Tchar *sp; | |
+ | |
+ if (ismot(c)) | |
+ return(0); | |
+ delim = cbits(c); | |
+ savapts = apts; | |
+ savapts1 = apts1; | |
+ savfont = font; | |
+ savfont1 = font1; | |
+ savpts = pts; | |
+ savpts1 = pts1; | |
+ sp = string; | |
+ while ((j = cbits(i = getch()))!=delim && j!='\n' && sp<&string[1280-1… | |
+ *sp++ = i; | |
+ if (sp >= string + 1280) { | |
+ ERROR "too-long string compare." WARN; | |
+ edone(0100); | |
+ } | |
+ if (nlflg) { | |
+ val = sp==string; | |
+ goto rtn; | |
+ } | |
+ *sp = 0; | |
+ apts = savapts; | |
+ apts1 = savapts1; | |
+ font = savfont; | |
+ font1 = savfont1; | |
+ pts = savpts; | |
+ pts1 = savpts1; | |
+ mchbits(); | |
+ val = 1; | |
+ sp = string; | |
+ while ((j = cbits(i = getch())) != delim && j != '\n') { | |
+ if (*sp != i) { | |
+ eat(delim); | |
+ val = 0; | |
+ goto rtn; | |
+ } | |
+ sp++; | |
+ } | |
+ if (*sp) | |
+ val = 0; | |
+rtn: | |
+ apts = savapts; | |
+ apts1 = savapts1; | |
+ font = savfont; | |
+ font1 = savfont1; | |
+ pts = savpts; | |
+ pts1 = savpts1; | |
+ mchbits(); | |
+ return(val); | |
+} | |
+ | |
+ | |
+void caserd(void) | |
+{ | |
+ | |
+ lgf++; | |
+ skip(); | |
+ getname(); | |
+ if (!iflg) { | |
+ if (quiet) { | |
+ if (NROFF) { | |
+ echo_off(); | |
+ flusho(); | |
+ } | |
+ fprintf(stderr, "\007"); /*bell*/ | |
+ } else { | |
+ if (nextf[0]) { | |
+ fprintf(stderr, "%s:", nextf); | |
+ } else { | |
+ fprintf(stderr, "\007"); /*bell*/ | |
+ } | |
+ } | |
+ } | |
+ collect(); | |
+ tty++; | |
+ pushi(RD_OFFSET, PAIR('r','d')); | |
+} | |
+ | |
+int | |
+rdtty(void) | |
+{ | |
+ char onechar; | |
+ | |
+ onechar = 0; | |
+ if (read(0, &onechar, 1) == 1) { | |
+ if (onechar == '\n') | |
+ tty++; | |
+ else | |
+ tty = 1; | |
+ if (tty != 3) | |
+ return(onechar); | |
+ } | |
+ tty = 0; | |
+ if (NROFF && quiet) | |
+ echo_on(); | |
+ return(0); | |
+} | |
+ | |
+ | |
+void caseec(void) | |
+{ | |
+ eschar = chget('\\'); | |
+} | |
+ | |
+ | |
+void caseeo(void) | |
+{ | |
+ eschar = 0; | |
+} | |
+ | |
+ | |
+void caseta(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ tabtab[0] = nonumb = 0; | |
+ for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) { | |
+ if (skip()) | |
+ break; | |
+ k = tabtab[max(i-1, 0)] & TABMASK; | |
+ if ((j = max(hnumb(&k), 0)) > TABMASK) { | |
+ ERROR "Tab too far away" WARN; | |
+ j = TABMASK; | |
+ } | |
+ tabtab[i] = j & TABMASK; | |
+ if (!nonumb) | |
+ switch (cbits(ch)) { | |
+ case 'C': | |
+ tabtab[i] |= CTAB; | |
+ break; | |
+ case 'R': | |
+ tabtab[i] |= RTAB; | |
+ break; | |
+ default: /*includes L*/ | |
+ break; | |
+ } | |
+ nonumb = ch = 0; | |
+ } | |
+ if (!skip()) | |
+ ERROR "Too many tab stops" WARN; | |
+ tabtab[i] = 0; | |
+} | |
+ | |
+ | |
+void casene(void) | |
+{ | |
+ int i, j; | |
+ | |
+ skip(); | |
+ i = vnumb((int *)0); | |
+ if (nonumb) | |
+ i = lss; | |
+ if (dip == d && numtabp[NL].val == -1) { | |
+ newline(1); | |
+ return; | |
+ } | |
+ if (i > (j = findt1())) { | |
+ i = lss; | |
+ lss = j; | |
+ dip->nls = 0; | |
+ newline(0); | |
+ lss = i; | |
+ } | |
+} | |
+ | |
+ | |
+void casetr(void) | |
+{ | |
+ int i, j; | |
+ Tchar k; | |
+ | |
+ lgf++; | |
+ skip(); | |
+ while ((i = cbits(k=getch())) != '\n') { | |
+ if (ismot(k)) | |
+ return; | |
+ if (ismot(k = getch())) | |
+ return; | |
+ if ((j = cbits(k)) == '\n') | |
+ j = ' '; | |
+ trtab[i] = j; | |
+ } | |
+} | |
+ | |
+ | |
+void casecu(void) | |
+{ | |
+ cu++; | |
+ caseul(); | |
+} | |
+ | |
+ | |
+void caseul(void) | |
+{ | |
+ int i; | |
+ | |
+ noscale++; | |
+ skip(); | |
+ i = max(atoi0(), 0); | |
+ if (nonumb) | |
+ i = 1; | |
+ if (ul && (i == 0)) { | |
+ font = sfont; | |
+ ul = cu = 0; | |
+ } | |
+ if (i) { | |
+ if (!ul) { | |
+ sfont = font; | |
+ font = ulfont; | |
+ } | |
+ ul = i; | |
+ } | |
+ noscale = 0; | |
+ mchbits(); | |
+} | |
+ | |
+ | |
+void caseuf(void) | |
+{ | |
+ int i, j; | |
+ | |
+ if (skip() || !(i = getrq()) || i == 'S' || (j = findft(i)) == -1) | |
+ ulfont = ULFONT; /*default underline position*/ | |
+ else | |
+ ulfont = j; | |
+ if (NROFF && ulfont == FT) | |
+ ulfont = ULFONT; | |
+} | |
+ | |
+ | |
+void caseit(void) | |
+{ | |
+ int i; | |
+ | |
+ lgf++; | |
+ it = itmac = 0; | |
+ noscale++; | |
+ skip(); | |
+ i = atoi0(); | |
+ skip(); | |
+ if (!nonumb && (itmac = getrq())) | |
+ it = i; | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void casemc(void) | |
+{ | |
+ int i; | |
+ | |
+ if (icf > 1) | |
+ ic = 0; | |
+ icf = 0; | |
+ if (skip()) | |
+ return; | |
+ ic = getch(); | |
+ icf = 1; | |
+ skip(); | |
+ i = max(hnumb((int *)0), 0); | |
+ if (!nonumb) | |
+ ics = i; | |
+} | |
+ | |
+ | |
+void casemk(void) | |
+{ | |
+ int i, j; | |
+ | |
+ if (dip != d) | |
+ j = dip->dnl; | |
+ else | |
+ j = numtabp[NL].val; | |
+ if (skip()) { | |
+ dip->mkline = j; | |
+ return; | |
+ } | |
+ if ((i = getrq()) == 0) | |
+ return; | |
+ numtabp[findr(i)].val = j; | |
+} | |
+ | |
+ | |
+void casesv(void) | |
+{ | |
+ int i; | |
+ | |
+ skip(); | |
+ if ((i = vnumb((int *)0)) < 0) | |
+ return; | |
+ if (nonumb) | |
+ i = 1; | |
+ sv += i; | |
+ caseos(); | |
+} | |
+ | |
+ | |
+void caseos(void) | |
+{ | |
+ int savlss; | |
+ | |
+ if (sv <= findt1()) { | |
+ savlss = lss; | |
+ lss = sv; | |
+ newline(0); | |
+ lss = savlss; | |
+ sv = 0; | |
+ } | |
+} | |
+ | |
+ | |
+void casenm(void) | |
+{ | |
+ int i; | |
+ | |
+ lnmod = nn = 0; | |
+ if (skip()) | |
+ return; | |
+ lnmod++; | |
+ noscale++; | |
+ i = inumb(&numtabp[LN].val); | |
+ if (!nonumb) | |
+ numtabp[LN].val = max(i, 0); | |
+ getnm(&ndf, 1); | |
+ getnm(&nms, 0); | |
+ getnm(&ni, 0); | |
+ getnm(&nmwid, 3); /* really kludgy! */ | |
+ noscale = 0; | |
+ nmbits = chbits; | |
+} | |
+ | |
+/* | |
+ * .nm relies on the fact that illegal args are skipped; don't warn | |
+ * for illegality of these | |
+ */ | |
+void getnm(int *p, int min) | |
+{ | |
+ int i; | |
+ int savtr = trace; | |
+ | |
+ eat(' '); | |
+ if (skip()) | |
+ return; | |
+ trace = 0; | |
+ i = atoi0(); | |
+ if (nonumb) | |
+ return; | |
+ *p = max(i, min); | |
+ trace = savtr; | |
+} | |
+ | |
+ | |
+void casenn(void) | |
+{ | |
+ noscale++; | |
+ skip(); | |
+ nn = max(atoi0(), 1); | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void caseab(void) | |
+{ | |
+ casetm1(1, stderr); | |
+ done3(0); | |
+} | |
+ | |
+ | |
+/* nroff terminal handling has been pretty well excised */ | |
+/* as part of the merge with troff. these are ghostly remnants, */ | |
+/* called, but doing nothing. restore them at your peril. */ | |
+ | |
+ | |
+void save_tty(void) /*save any tty settings that may be… | |
+{ | |
+} | |
+ | |
+ | |
+void restore_tty(void) /*restore tty settings from begi… | |
+{ | |
+} | |
+ | |
+ | |
+void set_tty(void) | |
+{ | |
+} | |
+ | |
+ | |
+void echo_off(void) /*turn off ECHO for .rd in "-q" mod… | |
+{ | |
+} | |
+ | |
+ | |
+void echo_on(void) /*restore ECHO after .rd in "-q" mod… | |
+{ | |
+} | |
diff --git a/troff/n6.c b/troff/n6.c | |
@@ -0,0 +1,363 @@ | |
+#include "tdef.h" | |
+#include "ext.h" | |
+#include "fns.h" | |
+#include <ctype.h> | |
+ | |
+/* | |
+ * n6.c -- width functions, sizes and fonts | |
+*/ | |
+ | |
+int | |
+n_width(Tchar j) | |
+{ | |
+ int i, k; | |
+ | |
+ if (iszbit(j)) | |
+ return 0; | |
+ if (ismot(j)) { | |
+ if (isvmot(j)) | |
+ return(0); | |
+ k = absmot(j); | |
+ if (isnmot(j)) | |
+ k = -k; | |
+ return(k); | |
+ } | |
+ i = cbits(j); | |
+ if (i < ' ') { | |
+ if (i == '\b') | |
+ return(-widthp); | |
+ if (i == PRESC) | |
+ i = eschar; | |
+ else if (i == HX) | |
+ return(0); | |
+ } | |
+ if (i == ohc) | |
+ return(0); | |
+ i = trtab[i]; | |
+ if (i < ' ') | |
+ return(0); | |
+ if (i >= t.tfont.nchars) /* not on the font */ | |
+ k = t.Char; /* really ought to check properly */ | |
+ else | |
+ k = t.tfont.wp[i].wid * t.Char; | |
+ widthp = k; | |
+ return(k); | |
+} | |
+ | |
+ | |
+Tchar n_setch(int c) | |
+{ | |
+ return t_setch(c); | |
+} | |
+ | |
+Tchar n_setabs(void) /* set absolute char from \N'...' */ | |
+{ /* for now, a no-op */ | |
+ return t_setabs(); | |
+} | |
+ | |
+int n_findft(int i) | |
+{ | |
+ int k; | |
+ | |
+ if ((k = i - '0') >= 0 && k <= nfonts && k < smnt) | |
+ return(k); | |
+ for (k = 0; fontlab[k] != i; k++) | |
+ if (k > nfonts) | |
+ return(-1); | |
+ return(k); | |
+} | |
+ | |
+ | |
+ | |
+void n_mchbits(void) | |
+{ | |
+ chbits = 0; | |
+ setfbits(chbits, font); | |
+ sps = width(' ' | chbits); | |
+} | |
+ | |
+ | |
+void n_setps(void ) | |
+{ | |
+ int i, j; | |
+ | |
+ i = cbits(getch()); | |
+ if (isdigit(i)) { /* \sd or \sdd */ | |
+ i -= '0'; | |
+ if (i == 0) /* \s0 */ | |
+ ; | |
+ else if (i <= 3 && (ch=getch()) && isdigit(cbits(ch))) { … | |
+ ch = 0; | |
+ } | |
+ } else if (i == '(') { /* \s(dd */ | |
+ getch(); | |
+ getch(); | |
+ } else if (i == '+' || i == '-') { /* \s+, \s- */ | |
+ j = cbits(getch()); | |
+ if (isdigit(j)) { /* \s+d, \s-d */ | |
+ ; | |
+ } else if (j == '(') { /* \s+(dd, \s-(dd */ | |
+ getch(); | |
+ getch(); | |
+ } | |
+ } | |
+} | |
+ | |
+ | |
+Tchar n_setht(void) /* set character height from \H'...' */ | |
+{ | |
+ | |
+ getch(); | |
+ inumb(&apts); | |
+ getch(); | |
+ return(0); | |
+} | |
+ | |
+ | |
+Tchar n_setslant(void) /* set slant from \S'...' */ | |
+{ | |
+ int n; | |
+ | |
+ getch(); | |
+ n = 0; | |
+ n = inumb(&n); | |
+ getch(); | |
+ return(0); | |
+} | |
+ | |
+ | |
+void n_caseft(void) | |
+{ | |
+ skip(); | |
+ setfont(1); | |
+} | |
+ | |
+ | |
+void n_setfont(int a) | |
+{ | |
+ int i, j; | |
+ | |
+ if (a) | |
+ i = getrq(); | |
+ else | |
+ i = getsn(); | |
+ if (!i || i == 'P') { | |
+ j = font1; | |
+ goto s0; | |
+ } | |
+ if (i == 'S' || i == '0') | |
+ return; | |
+ if ((j = findft(i)) == -1) | |
+ return; | |
+s0: | |
+ font1 = font; | |
+ font = j; | |
+ mchbits(); | |
+} | |
+ | |
+ | |
+void n_setwd(void) | |
+{ | |
+ int base, wid; | |
+ Tchar i; | |
+ int delim, emsz, k; | |
+ int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts… | |
+ | |
+ base = numtabp[ST].val = numtabp[ST].val = wid = numtabp[CT].val = 0; | |
+ if (ismot(i = getch())) | |
+ return; | |
+ delim = cbits(i); | |
+ savhp = numtabp[HP].val; | |
+ numtabp[HP].val = 0; | |
+ savapts = apts; | |
+ savapts1 = apts1; | |
+ savfont = font; | |
+ savfont1 = font1; | |
+ savpts = pts; | |
+ savpts1 = pts1; | |
+ setwdf++; | |
+ while (cbits(i = getch()) != delim && !nlflg) { | |
+ k = width(i); | |
+ wid += k; | |
+ numtabp[HP].val += k; | |
+ if (!ismot(i)) { | |
+ emsz = (INCH * pts + 36) / 72; | |
+ } else if (isvmot(i)) { | |
+ k = absmot(i); | |
+ if (isnmot(i)) | |
+ k = -k; | |
+ base -= k; | |
+ emsz = 0; | |
+ } else | |
+ continue; | |
+ if (base < numtabp[SB].val) | |
+ numtabp[SB].val = base; | |
+ if ((k = base + emsz) > numtabp[ST].val) | |
+ numtabp[ST].val = k; | |
+ } | |
+ setn1(wid, 0, (Tchar) 0); | |
+ numtabp[HP].val = savhp; | |
+ apts = savapts; | |
+ apts1 = savapts1; | |
+ font = savfont; | |
+ font1 = savfont1; | |
+ pts = savpts; | |
+ pts1 = savpts1; | |
+ mchbits(); | |
+ setwdf = 0; | |
+} | |
+ | |
+ | |
+Tchar n_vmot(void) | |
+{ | |
+ dfact = lss; | |
+ vflag++; | |
+ return n_mot(); | |
+} | |
+ | |
+ | |
+Tchar n_hmot(void) | |
+{ | |
+ dfact = EM; | |
+ return n_mot(); | |
+} | |
+ | |
+ | |
+Tchar n_mot(void) | |
+{ | |
+ int j, n; | |
+ Tchar i; | |
+ | |
+ j = HOR; | |
+ getch(); /*eat delim*/ | |
+ if (n = atoi0()) { | |
+ if (vflag) | |
+ j = VERT; | |
+ i = makem(quant(n, j)); | |
+ } else | |
+ i = 0; | |
+ getch(); | |
+ vflag = 0; | |
+ dfact = 1; | |
+ return(i); | |
+} | |
+ | |
+ | |
+Tchar n_sethl(int k) | |
+{ | |
+ int j; | |
+ Tchar i; | |
+ | |
+ j = t.Halfline; | |
+ if (k == 'u') | |
+ j = -j; | |
+ else if (k == 'r') | |
+ j = -2 * j; | |
+ vflag++; | |
+ i = makem(j); | |
+ vflag = 0; | |
+ return(i); | |
+} | |
+ | |
+ | |
+Tchar n_makem(int i) | |
+{ | |
+ Tchar j; | |
+ | |
+ if (i >= 0) | |
+ j = i; | |
+ else | |
+ j = -i; | |
+ j |= MOT; | |
+ if (i < 0) | |
+ j |= NMOT; | |
+ if (vflag) | |
+ j |= VMOT; | |
+ return(j); | |
+} | |
+ | |
+ | |
+void n_casefp(void) | |
+{ | |
+ int i, j; | |
+ | |
+ skip(); | |
+ if ((i = cbits(getch()) - '0') < 0 || i > nfonts) | |
+ return; | |
+ if (skip() || !(j = getrq())) | |
+ return; | |
+ fontlab[i] = j; | |
+} | |
+ | |
+ | |
+ | |
+void n_casebd(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ j = k = 0; | |
+bd0: | |
+ if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { | |
+ if (k) | |
+ goto bd1; | |
+ else | |
+ return; | |
+ } | |
+ if (j == smnt) { | |
+ k = smnt; | |
+ goto bd0; | |
+ } | |
+ if (k) { | |
+ sbold = j; | |
+ j = k; | |
+ } | |
+bd1: | |
+ skip(); | |
+ noscale++; | |
+ bdtab[j] = atoi0(); | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void n_casevs(void) | |
+{ | |
+ int i; | |
+ | |
+ skip(); | |
+ vflag++; | |
+ dfact = INCH; /*default scaling is points!*/ | |
+ dfactd = 72; | |
+ res = VERT; | |
+ i = inumb(&lss); | |
+ if (nonumb) | |
+ i = lss1; | |
+ if (i < VERT) | |
+ i = VERT; /* was VERT */ | |
+ lss1 = lss; | |
+ lss = i; | |
+} | |
+ | |
+ | |
+ | |
+ | |
+Tchar n_xlss(void) | |
+{ | |
+ /* stores \x'...' into | |
+ /* two successive Tchars. | |
+ /* the first contains HX, the second the value, | |
+ /* encoded as a vertical motion. | |
+ /* decoding is done in n2.c by pchar(). | |
+ */ | |
+ int i; | |
+ | |
+ getch(); | |
+ dfact = lss; | |
+ i = quant(atoi0(), VERT); | |
+ dfact = 1; | |
+ getch(); | |
+ if (i >= 0) | |
+ *pbp++ = MOT | VMOT | i; | |
+ else | |
+ *pbp++ = MOT | VMOT | NMOT | -i; | |
+ return(HX); | |
+} | |
diff --git a/troff/n7.c b/troff/n7.c | |
@@ -0,0 +1,837 @@ | |
+#define _BSD_SOURCE 1 /* isascii */ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+#ifdef STRICT | |
+ /* not in ANSI or POSIX */ | |
+#define isascii(a) ((a) >= 0 && (a) <= 127) | |
+#endif | |
+ | |
+#define GETCH gettch | |
+Tchar gettch(void); | |
+ | |
+ | |
+/* | |
+ * troff7.c | |
+ * | |
+ * text | |
+ */ | |
+ | |
+int brflg; | |
+ | |
+void tbreak(void) | |
+{ | |
+ int pad, k; | |
+ Tchar *i, j; | |
+ int resol; | |
+ int un0 = un; | |
+ | |
+ trap = 0; | |
+ if (nb) | |
+ return; | |
+ if (dip == d && numtabp[NL].val == -1) { | |
+ newline(1); | |
+ return; | |
+ } | |
+ if (!nc) { | |
+ setnel(); | |
+ if (!wch) | |
+ return; | |
+ if (pendw) | |
+ getword(1); | |
+ movword(); | |
+ } else if (pendw && !brflg) { | |
+ getword(1); | |
+ movword(); | |
+ } | |
+ *linep = dip->nls = 0; | |
+ if (NROFF && dip == d) | |
+ horiz(po); | |
+ if (lnmod) | |
+ donum(); | |
+ lastl = ne; | |
+ if (brflg != 1) { | |
+ totout = 0; | |
+ } else if (ad) { | |
+ if ((lastl = ll - un) < ne) | |
+ lastl = ne; | |
+ } | |
+ if (admod && ad && (brflg != 2)) { | |
+ lastl = ne; | |
+ adsp = adrem = 0; | |
+ if (admod == 1) | |
+ un += quant(nel / 2, HOR); | |
+ else if (admod == 2) | |
+ un += nel; | |
+ } | |
+ totout++; | |
+ brflg = 0; | |
+ if (lastl + un > dip->maxl) | |
+ dip->maxl = lastl + un; | |
+ horiz(un); | |
+ if (NROFF) { | |
+ if (adrem % t.Adj) | |
+ resol = t.Hor; | |
+ else | |
+ resol = t.Adj; | |
+ } else | |
+ resol = HOR; | |
+ | |
+ lastl = ne + (nwd-1) * adsp + adrem; | |
+ for (i = line; nc > 0; ) { | |
+ if ((cbits(j = *i++)) == ' ') { | |
+ pad = 0; | |
+ do { | |
+ pad += width(j); | |
+ nc--; | |
+ } while ((cbits(j = *i++)) == ' '); | |
+ i--; | |
+ pad += adsp; | |
+ --nwd; | |
+ if (adrem) { | |
+ if (adrem < 0) { | |
+ pad -= resol; | |
+ adrem += resol; | |
+ } else if ((totout & 01) || adrem / resol >= n… | |
+ pad += resol; | |
+ adrem -= resol; | |
+ } | |
+ } | |
+ pchar((Tchar) WORDSP); | |
+ horiz(pad); | |
+ } else { | |
+ pchar(j); | |
+ nc--; | |
+ } | |
+ } | |
+ if (ic) { | |
+ if ((k = ll - un0 - lastl + ics) > 0) | |
+ horiz(k); | |
+ pchar(ic); | |
+ } | |
+ if (icf) | |
+ icf++; | |
+ else | |
+ ic = 0; | |
+ ne = nwd = 0; | |
+ un = in; | |
+ setnel(); | |
+ newline(0); | |
+ if (dip != d) { | |
+ if (dip->dnl > dip->hnl) | |
+ dip->hnl = dip->dnl; | |
+ } else { | |
+ if (numtabp[NL].val > dip->hnl) | |
+ dip->hnl = numtabp[NL].val; | |
+ } | |
+ for (k = ls - 1; k > 0 && !trap; k--) | |
+ newline(0); | |
+ spread = 0; | |
+} | |
+ | |
+void donum(void) | |
+{ | |
+ int i, nw; | |
+ int lnv = numtabp[LN].val; | |
+ | |
+ nrbits = nmbits; | |
+ nw = width('1' | nrbits); | |
+ if (nn) { | |
+ nn--; | |
+ goto d1; | |
+ } | |
+ if (lnv % ndf) { | |
+ numtabp[LN].val++; | |
+d1: | |
+ un += nw * (nmwid + nms + ni); | |
+ return; | |
+ } | |
+ i = 0; | |
+ do { /* count digits in numtabp[LN].val */ | |
+ i++; | |
+ } while ((lnv /= 10) > 0); | |
+ horiz(nw * (ni + max(nmwid-i, 0))); | |
+ nform = 0; | |
+ fnumb(numtabp[LN].val, pchar); | |
+ un += nw * nms; | |
+ numtabp[LN].val++; | |
+} | |
+ | |
+ | |
+void text(void) | |
+{ | |
+ Tchar i; | |
+ static int spcnt; | |
+ | |
+ nflush++; | |
+ numtabp[HP].val = 0; | |
+ if ((dip == d) && (numtabp[NL].val == -1)) { | |
+ newline(1); | |
+ return; | |
+ } | |
+ setnel(); | |
+ if (ce || !fi) { | |
+ nofill(); | |
+ return; | |
+ } | |
+ if (pendw) | |
+ goto t4; | |
+ if (pendt) | |
+ if (spcnt) | |
+ goto t2; | |
+ else | |
+ goto t3; | |
+ pendt++; | |
+ if (spcnt) | |
+ goto t2; | |
+ while ((cbits(i = GETCH())) == ' ') { | |
+ spcnt++; | |
+ numtabp[HP].val += sps; | |
+ widthp = sps; | |
+ } | |
+ if (nlflg) { | |
+t1: | |
+ nflush = pendt = ch = spcnt = 0; | |
+ callsp(); | |
+ return; | |
+ } | |
+ ch = i; | |
+ if (spcnt) { | |
+t2: | |
+ tbreak(); | |
+ if (nc || wch) | |
+ goto rtn; | |
+ un += spcnt * sps; | |
+ spcnt = 0; | |
+ setnel(); | |
+ if (trap) | |
+ goto rtn; | |
+ if (nlflg) | |
+ goto t1; | |
+ } | |
+t3: | |
+ if (spread) | |
+ goto t5; | |
+ if (pendw || !wch) | |
+t4: | |
+ if (getword(0)) | |
+ goto t6; | |
+ if (!movword()) | |
+ goto t3; | |
+t5: | |
+ if (nlflg) | |
+ pendt = 0; | |
+ adsp = adrem = 0; | |
+ if (ad) { | |
+ if (nwd == 1) | |
+ adsp = nel; | |
+ else | |
+ adsp = nel / (nwd - 1); | |
+ adsp = (adsp / HOR) * HOR; | |
+ adrem = nel - adsp*(nwd-1); | |
+ } | |
+ brflg = 1; | |
+ tbreak(); | |
+ spread = 0; | |
+ if (!trap) | |
+ goto t3; | |
+ if (!nlflg) | |
+ goto rtn; | |
+t6: | |
+ pendt = 0; | |
+ ckul(); | |
+rtn: | |
+ nflush = 0; | |
+} | |
+ | |
+ | |
+void nofill(void) | |
+{ | |
+ int j; | |
+ Tchar i; | |
+ | |
+ if (!pendnf) { | |
+ over = 0; | |
+ tbreak(); | |
+ if (trap) | |
+ goto rtn; | |
+ if (nlflg) { | |
+ ch = nflush = 0; | |
+ callsp(); | |
+ return; | |
+ } | |
+ adsp = adrem = 0; | |
+ nwd = 10000; | |
+ } | |
+ while ((j = (cbits(i = GETCH()))) != '\n') { | |
+ if (j == ohc) | |
+ continue; | |
+ if (j == CONT) { | |
+ pendnf++; | |
+ nflush = 0; | |
+ flushi(); | |
+ ckul(); | |
+ return; | |
+ } | |
+ j = width(i); | |
+ widthp = j; | |
+ numtabp[HP].val += j; | |
+ storeline(i, j); | |
+ } | |
+ if (ce) { | |
+ ce--; | |
+ if ((i = quant(nel / 2, HOR)) > 0) | |
+ un += i; | |
+ } | |
+ if (!nc) | |
+ storeline((Tchar)FILLER, 0); | |
+ brflg = 2; | |
+ tbreak(); | |
+ ckul(); | |
+rtn: | |
+ pendnf = nflush = 0; | |
+} | |
+ | |
+ | |
+void callsp(void) | |
+{ | |
+ int i; | |
+ | |
+ if (flss) | |
+ i = flss; | |
+ else | |
+ i = lss; | |
+ flss = 0; | |
+ casesp1(i); | |
+} | |
+ | |
+ | |
+void ckul(void) | |
+{ | |
+ if (ul && (--ul == 0)) { | |
+ cu = 0; | |
+ font = sfont; | |
+ mchbits(); | |
+ } | |
+ if (it && --it == 0 && itmac) | |
+ control(itmac, 0); | |
+} | |
+ | |
+ | |
+void storeline(Tchar c, int w) | |
+{ | |
+ int diff; | |
+ | |
+ if (linep >= line + lnsize - 2) { | |
+ lnsize += LNSIZE; | |
+ diff = linep - line; | |
+ if (( line = (Tchar *)realloc((char *)line, lnsize * sizeof(Tc… | |
+ if (linep && diff) | |
+ linep = line + diff; | |
+ } else { | |
+ if (over) { | |
+ return; | |
+ } else { | |
+ flusho(); | |
+ ERROR "Line overflow." WARN; | |
+ over++; | |
+ *linep++ = LEFTHAND; | |
+ w = width(LEFTHAND); | |
+ nc++; | |
+ c = '\n'; | |
+ } | |
+ } | |
+ } | |
+ *linep++ = c; | |
+ ne += w; | |
+ nel -= w; | |
+ nc++; | |
+} | |
+ | |
+ | |
+void newline(int a) | |
+{ | |
+ int i, j, nlss; | |
+ int opn; | |
+ | |
+ nlss = 0; | |
+ if (a) | |
+ goto nl1; | |
+ if (dip != d) { | |
+ j = lss; | |
+ pchar1((Tchar)FLSS); | |
+ if (flss) | |
+ lss = flss; | |
+ i = lss + dip->blss; | |
+ dip->dnl += i; | |
+ pchar1((Tchar)i); | |
+ pchar1((Tchar)'\n'); | |
+ lss = j; | |
+ dip->blss = flss = 0; | |
+ if (dip->alss) { | |
+ pchar1((Tchar)FLSS); | |
+ pchar1((Tchar)dip->alss); | |
+ pchar1((Tchar)'\n'); | |
+ dip->dnl += dip->alss; | |
+ dip->alss = 0; | |
+ } | |
+ if (dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && di… | |
+ if (control(dip->dimac, 0)) { | |
+ trap++; | |
+ dip->ditf++; | |
+ } | |
+ return; | |
+ } | |
+ j = lss; | |
+ if (flss) | |
+ lss = flss; | |
+ nlss = dip->alss + dip->blss + lss; | |
+ numtabp[NL].val += nlss; | |
+ if (TROFF && ascii) { | |
+ dip->alss = dip->blss = 0; | |
+ } | |
+ pchar1((Tchar)'\n'); | |
+ flss = 0; | |
+ lss = j; | |
+ if (numtabp[NL].val < pl) | |
+ goto nl2; | |
+nl1: | |
+ ejf = dip->hnl = numtabp[NL].val = 0; | |
+ ejl = frame; | |
+ if (donef) { | |
+ if ((!nc && !wch) || ndone) | |
+ done1(0); | |
+ ndone++; | |
+ donef = 0; | |
+ if (frame == stk) | |
+ nflush++; | |
+ } | |
+ opn = numtabp[PN].val; | |
+ numtabp[PN].val++; | |
+ if (npnflg) { | |
+ numtabp[PN].val = npn; | |
+ npn = npnflg = 0; | |
+ } | |
+nlpn: | |
+ if (numtabp[PN].val == pfrom) { | |
+ print++; | |
+ pfrom = -1; | |
+ } else if (opn == pto) { | |
+ print = 0; | |
+ opn = -1; | |
+ chkpn(); | |
+ goto nlpn; | |
+ } | |
+ if (print) | |
+ ptpage(numtabp[PN].val); /* supposedly in a clean state… | |
+ if (stop && print) { | |
+ dpn++; | |
+ if (dpn >= stop) { | |
+ dpn = 0; | |
+ ptpause(); | |
+ } | |
+ } | |
+nl2: | |
+ trap = 0; | |
+ if (numtabp[NL].val == 0) { | |
+ if ((j = findn(0)) != NTRAP) | |
+ trap = control(mlist[j], 0); | |
+ } else if ((i = findt(numtabp[NL].val - nlss)) <= nlss) { | |
+ if ((j = findn1(numtabp[NL].val - nlss + i)) == NTRAP) { | |
+ flusho(); | |
+ ERROR "Trap botch." WARN; | |
+ done2(-5); | |
+ } | |
+ trap = control(mlist[j], 0); | |
+ } | |
+} | |
+ | |
+int | |
+findn1(int a) | |
+{ | |
+ int i, j; | |
+ | |
+ for (i = 0; i < NTRAP; i++) { | |
+ if (mlist[i]) { | |
+ if ((j = nlist[i]) < 0) | |
+ j += pl; | |
+ if (j == a) | |
+ break; | |
+ } | |
+ } | |
+ return(i); | |
+} | |
+ | |
+ | |
+void chkpn(void) | |
+{ | |
+ pto = *(pnp++); | |
+ pfrom = pto>=0 ? pto : -pto; | |
+ if (pto == -INT_MAX) { | |
+ flusho(); | |
+ done1(0); | |
+ } | |
+ if (pto < 0) { | |
+ pto = -pto; | |
+ print++; | |
+ pfrom = 0; | |
+ } | |
+} | |
+ | |
+int | |
+findt(int a) | |
+{ | |
+ int i, j, k; | |
+ | |
+ k = INT_MAX; | |
+ if (dip != d) { | |
+ if (dip->dimac && (i = dip->ditrap - a) > 0) | |
+ k = i; | |
+ return(k); | |
+ } | |
+ for (i = 0; i < NTRAP; i++) { | |
+ if (mlist[i]) { | |
+ if ((j = nlist[i]) < 0) | |
+ j += pl; | |
+ if ((j -= a) <= 0) | |
+ continue; | |
+ if (j < k) | |
+ k = j; | |
+ } | |
+ } | |
+ i = pl - a; | |
+ if (k > i) | |
+ k = i; | |
+ return(k); | |
+} | |
+ | |
+int | |
+findt1(void) | |
+{ | |
+ int i; | |
+ | |
+ if (dip != d) | |
+ i = dip->dnl; | |
+ else | |
+ i = numtabp[NL].val; | |
+ return(findt(i)); | |
+} | |
+ | |
+ | |
+void eject(Stack *a) | |
+{ | |
+ int savlss; | |
+ | |
+ if (dip != d) | |
+ return; | |
+ ejf++; | |
+ if (a) | |
+ ejl = a; | |
+ else | |
+ ejl = frame; | |
+ if (trap) | |
+ return; | |
+e1: | |
+ savlss = lss; | |
+ lss = findt(numtabp[NL].val); | |
+ newline(0); | |
+ lss = savlss; | |
+ if (numtabp[NL].val && !trap) | |
+ goto e1; | |
+} | |
+ | |
+int | |
+movword(void) | |
+{ | |
+ int w; | |
+ Tchar i, *wp; | |
+ int savwch, hys; | |
+ | |
+ over = 0; | |
+ wp = wordp; | |
+ if (!nwd) { | |
+ while (cbits(*wp++) == ' ') { | |
+ wch--; | |
+ wne -= sps; | |
+ } | |
+ wp--; | |
+ } | |
+ if (wne > nel && !hyoff && hyf && (!nwd || nel > 3 * sps) && | |
+ (!(hyf & 02) || (findt1() > lss))) | |
+ hyphen(wp); | |
+ savwch = wch; | |
+ hyp = hyptr; | |
+ nhyp = 0; | |
+ while (*hyp && *hyp <= wp) | |
+ hyp++; | |
+ while (wch) { | |
+ if (hyoff != 1 && *hyp == wp) { | |
+ hyp++; | |
+ if (!wdstart || (wp > wdstart + 1 && wp < wdend && | |
+ (!(hyf & 04) || wp < wdend - 1) && /… | |
+ (!(hyf & 010) || wp > wdstart + 2))) { /* 01… | |
+ nhyp++; | |
+ storeline((Tchar)IMP, 0); | |
+ } | |
+ } | |
+ i = *wp++; | |
+ w = width(i); | |
+ wne -= w; | |
+ wch--; | |
+ storeline(i, w); | |
+ } | |
+ if (nel >= 0) { | |
+ nwd++; | |
+ return(0); /* line didn't fill up */ | |
+ } | |
+ if (TROFF) | |
+ xbits((Tchar)HYPHEN, 1); | |
+ hys = width((Tchar)HYPHEN); | |
+m1: | |
+ if (!nhyp) { | |
+ if (!nwd) | |
+ goto m3; | |
+ if (wch == savwch) | |
+ goto m4; | |
+ } | |
+ if (*--linep != IMP) | |
+ goto m5; | |
+ if (!(--nhyp)) | |
+ if (!nwd) | |
+ goto m2; | |
+ if (nel < hys) { | |
+ nc--; | |
+ goto m1; | |
+ } | |
+m2: | |
+ if ((i = cbits(*(linep - 1))) != '-' && i != EMDASH) { | |
+ *linep = (*(linep - 1) & SFMASK) | HYPHEN; | |
+ w = width(*linep); | |
+ nel -= w; | |
+ ne += w; | |
+ linep++; | |
+ } | |
+m3: | |
+ nwd++; | |
+m4: | |
+ wordp = wp; | |
+ return(1); /* line filled up */ | |
+m5: | |
+ nc--; | |
+ w = width(*linep); | |
+ ne -= w; | |
+ nel += w; | |
+ wne += w; | |
+ wch++; | |
+ wp--; | |
+ goto m1; | |
+} | |
+ | |
+ | |
+void horiz(int i) | |
+{ | |
+ vflag = 0; | |
+ if (i) | |
+ pchar(makem(i)); | |
+} | |
+ | |
+ | |
+void setnel(void) | |
+{ | |
+ if (!nc) { | |
+ linep = line; | |
+ if (un1 >= 0) { | |
+ un = un1; | |
+ un1 = -1; | |
+ } | |
+ nel = ll - un; | |
+ ne = adsp = adrem = 0; | |
+ } | |
+} | |
+ | |
+int | |
+getword(int x) | |
+{ | |
+ int j, k; | |
+ Tchar i, *wp; | |
+ int noword; | |
+ int obits; | |
+ | |
+ j = 0; | |
+ noword = 0; | |
+ if (x) | |
+ if (pendw) { | |
+ *pendw = 0; | |
+ goto rtn; | |
+ } | |
+ if (wordp = pendw) | |
+ goto g1; | |
+ hyp = hyptr; | |
+ wordp = word; | |
+ over = wne = wch = 0; | |
+ hyoff = 0; | |
+ obits = chbits; | |
+ while (1) { /* picks up 1st char of word */ | |
+ j = cbits(i = GETCH()); | |
+ if (j == '\n') { | |
+ wne = wch = 0; | |
+ noword = 1; | |
+ goto rtn; | |
+ } | |
+ if (j == ohc) { | |
+ hyoff = 1; /* 1 => don't hyphenate */ | |
+ continue; | |
+ } | |
+ if (j == ' ') { | |
+ numtabp[HP].val += sps; | |
+ widthp = sps; | |
+ storeword(i, sps); | |
+ continue; | |
+ } | |
+ break; | |
+ } | |
+ storeword(' ' | obits, sps); | |
+ if (spflg) { | |
+ storeword(' ' | obits, sps); | |
+ spflg = 0; | |
+ } | |
+g0: | |
+ if (j == CONT) { | |
+ pendw = wordp; | |
+ nflush = 0; | |
+ flushi(); | |
+ return(1); | |
+ } | |
+ if (hyoff != 1) { | |
+ if (j == ohc) { | |
+ hyoff = 2; | |
+ *hyp++ = wordp; | |
+ if (hyp > hyptr + NHYP - 1) | |
+ hyp = hyptr + NHYP - 1; | |
+ goto g1; | |
+ } | |
+ if (((j == '-' || j == EMDASH)) && !(i & ZBIT)) /* zbit… | |
+ if (wordp > word + 1) { | |
+ hyoff = 2; | |
+ *hyp++ = wordp + 1; | |
+ if (hyp > hyptr + NHYP - 1) | |
+ hyp = hyptr + NHYP - 1; | |
+ } | |
+ } | |
+ j = width(i); | |
+ numtabp[HP].val += j; | |
+ storeword(i, j); | |
+g1: | |
+ j = cbits(i = GETCH()); | |
+ if (j != ' ') { | |
+ static char *sentchar = ".?!"; /* sentence terminators … | |
+ if (j != '\n') | |
+ goto g0; | |
+ wp = wordp-1; /* handle extra space at end of sentence … | |
+ while (wp >= word) { | |
+ j = cbits(*wp--); | |
+ if (j=='"' || j=='\'' || j==')' || j==']' || j=='*' ||… | |
+ continue; | |
+ for (k = 0; sentchar[k]; k++) | |
+ if (j == sentchar[k]) { | |
+ spflg++; | |
+ break; | |
+ } | |
+ break; | |
+ } | |
+ } | |
+ *wordp = 0; | |
+ numtabp[HP].val += sps; | |
+rtn: | |
+ for (wp = word; *wp; wp++) { | |
+ if (ismot(j)) | |
+ break; /* drechsler */ | |
+ j = cbits(*wp); | |
+ if (j == ' ') | |
+ continue; | |
+ if (!(isascii(j) && isdigit(j)) && j != '-') | |
+ break; | |
+ } | |
+ if (*wp == 0) /* all numbers, so don't hyphenate */ | |
+ hyoff = 1; | |
+ wdstart = 0; | |
+ wordp = word; | |
+ pendw = 0; | |
+ *hyp++ = 0; | |
+ setnel(); | |
+ return(noword); | |
+} | |
+ | |
+ | |
+void storeword(Tchar c, int w) | |
+{ | |
+ Tchar *savp; | |
+ int i; | |
+ | |
+ if (wordp >= word + wdsize - 2) { | |
+ wdsize += WDSIZE; | |
+ savp = word; | |
+ if (( word = (Tchar *)realloc((char *)word, wdsize * sizeof(Tc… | |
+ if (wordp) | |
+ wordp = word + (wordp - savp); | |
+ if (pendw) | |
+ pendw = word + (pendw - savp); | |
+ if (wdstart) | |
+ wdstart = word + (wdstart - savp); | |
+ if (wdend) | |
+ wdend = word + (wdend - savp); | |
+ for (i = 0; i < NHYP; i++) | |
+ if (hyptr[i]) | |
+ hyptr[i] = word + (hyptr[i] - savp); | |
+ } else { | |
+ if (over) { | |
+ return; | |
+ } else { | |
+ flusho(); | |
+ ERROR "Word overflow." WARN; | |
+ over++; | |
+ c = LEFTHAND; | |
+ w = width(LEFTHAND); | |
+ } | |
+ } | |
+ } | |
+ widthp = w; | |
+ wne += w; | |
+ *wordp++ = c; | |
+ wch++; | |
+} | |
+ | |
+ | |
+Tchar gettch(void) | |
+{ | |
+ extern int c_isalnum; | |
+ Tchar i; | |
+ int j; | |
+ | |
+ if (TROFF) | |
+ return getch(); | |
+ | |
+ i = getch(); | |
+ j = cbits(i); | |
+ if (ismot(i) || fbits(i) != ulfont) | |
+ return(i); | |
+ if (cu) { | |
+ if (trtab[j] == ' ') { | |
+ setcbits(i, '_'); | |
+ setfbits(i, FT); /* default */ | |
+ } | |
+ return(i); | |
+ } | |
+ /* should test here for characters that ought to be underlined */ | |
+ /* in the old nroff, that was the 200 bit on the width! */ | |
+ /* for now, just do letters, digits and certain special chars */ | |
+ if (j <= 127) { | |
+ if (!isalnum(j)) | |
+ setfbits(i, FT); | |
+ } else { | |
+ if (j < c_isalnum) | |
+ setfbits(i, FT); | |
+ } | |
+ return(i); | |
+} | |
diff --git a/troff/n8.c b/troff/n8.c | |
@@ -0,0 +1,545 @@ | |
+#include <u.h> | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+#define HY_BIT 0200 /* stuff in here only works for 7-bit… | |
+ /* this value is used (as a literal) in suftab.c */ | |
+ /* to encode possible hyphenation points in suffixes. … | |
+ /* it could be changed, by widening the tables */ | |
+ /* to be shorts instead of chars. */ | |
+ | |
+/* | |
+ * troff8.c | |
+ * | |
+ * hyphenation | |
+ */ | |
+ | |
+int hexsize = 0; /* hyphenation exception list size */ | |
+char *hbufp = NULL; /* base of list */ | |
+char *nexth = NULL; /* first free slot in list */ | |
+Tchar *hyend; | |
+ | |
+#define THRESH 160 /* digram goodness threshold */ | |
+int thresh = THRESH; | |
+ | |
+int texhyphen(void); | |
+static int alpha(Tchar); | |
+ | |
+void hyphen(Tchar *wp) | |
+{ | |
+ int j; | |
+ Tchar *i; | |
+ | |
+ i = wp; | |
+ while (punct((*i++))) | |
+ ; | |
+ if (!alpha(*--i)) | |
+ return; | |
+ wdstart = i++; | |
+ while (alpha(*i++)) | |
+ ; | |
+ hyend = wdend = --i - 1; | |
+ while (punct((*i++))) | |
+ ; | |
+ if (*--i) | |
+ return; | |
+ if (wdend - wdstart < 4) /* 4 chars is too short to hyphenate */ | |
+ return; | |
+ hyp = hyptr; | |
+ *hyp = 0; | |
+ hyoff = 2; | |
+ | |
+ /* for now, try exceptions first, then tex (if hyphalg is non-zero), | |
+ then suffix and digram if tex didn't hyphenate it at all. | |
+ */ | |
+ | |
+ if (!exword() && !texhyphen() && !suffix()) | |
+ digram(); | |
+ | |
+ /* this appears to sort hyphenation points into increasing order */ | |
+ *hyp++ = 0; | |
+ if (*hyptr) | |
+ for (j = 1; j; ) { | |
+ j = 0; | |
+ for (hyp = hyptr + 1; *hyp != 0; hyp++) { | |
+ if (*(hyp - 1) > *hyp) { | |
+ j++; | |
+ i = *hyp; | |
+ *hyp = *(hyp - 1); | |
+ *(hyp - 1) = i; | |
+ } | |
+ } | |
+ } | |
+} | |
+ | |
+static int alpha(Tchar i) /* non-zero if really alphabetic */ | |
+{ | |
+ if (ismot(i)) | |
+ return 0; | |
+ else if (cbits(i) >= ALPHABET) /* this isn't very elegant, but … | |
+ return 0; /* no good way to make sure i is in r… | |
+ else /* the call of isalpha */ | |
+ return isalpha(cbits(i)); | |
+} | |
+ | |
+int | |
+punct(Tchar i) | |
+{ | |
+ if (!i || alpha(i)) | |
+ return(0); | |
+ else | |
+ return(1); | |
+} | |
+ | |
+ | |
+void caseha(void) /* set hyphenation algorithm */ | |
+{ | |
+ hyphalg = HYPHALG; | |
+ if (skip()) | |
+ return; | |
+ noscale++; | |
+ hyphalg = atoi0(); | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void caseht(void) /* set hyphenation threshold; not in manual! */ | |
+{ | |
+ thresh = THRESH; | |
+ if (skip()) | |
+ return; | |
+ noscale++; | |
+ thresh = atoi0(); | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+char *growh(char *where) | |
+{ | |
+ char *new; | |
+ | |
+ hexsize += NHEX; | |
+ if ((new = grow(hbufp, hexsize, sizeof(char))) == NULL) | |
+ return NULL; | |
+ if (new == hbufp) { | |
+ return where; | |
+ } else { | |
+ int diff; | |
+ diff = where - hbufp; | |
+ hbufp = new; | |
+ return new + diff; | |
+ } | |
+} | |
+ | |
+ | |
+void casehw(void) | |
+{ | |
+ int i, k; | |
+ char *j; | |
+ Tchar t; | |
+ | |
+ if (nexth == NULL) { | |
+ if ((nexth = hbufp = grow(hbufp, NHEX, sizeof(char))) == NULL)… | |
+ ERROR "No space for exception word list." WARN; | |
+ return; | |
+ } | |
+ hexsize = NHEX; | |
+ } | |
+ k = 0; | |
+ while (!skip()) { | |
+ if ((j = nexth) >= hbufp + hexsize - 2) | |
+ if ((j = nexth = growh(j)) == NULL) | |
+ goto full; | |
+ for (;;) { | |
+ if (ismot(t = getch())) | |
+ continue; | |
+ i = cbits(t); | |
+ if (i == ' ' || i == '\n') { | |
+ *j++ = 0; | |
+ nexth = j; | |
+ *j = 0; | |
+ if (i == ' ') | |
+ break; | |
+ else | |
+ return; | |
+ } | |
+ if (i == '-') { | |
+ k = HY_BIT; | |
+ continue; | |
+ } | |
+ *j++ = maplow(i) | k; | |
+ k = 0; | |
+ if (j >= hbufp + hexsize - 2) | |
+ if ((j = growh(j)) == NULL) | |
+ goto full; | |
+ } | |
+ } | |
+ return; | |
+full: | |
+ ERROR "Cannot grow exception word list." WARN; | |
+ *nexth = 0; | |
+} | |
+ | |
+ | |
+int exword(void) | |
+{ | |
+ Tchar *w; | |
+ char *e, *save; | |
+ | |
+ e = hbufp; | |
+ while (1) { | |
+ save = e; | |
+ if (e == NULL || *e == 0) | |
+ return(0); | |
+ w = wdstart; | |
+ while (*e && w <= hyend && (*e & 0177) == maplow(cbits(*w))) { | |
+ e++; | |
+ w++; | |
+ } | |
+ if (!*e) { | |
+ if (w-1 == hyend || (w == wdend && maplow(cbits(*w)) =… | |
+ w = wdstart; | |
+ for (e = save; *e; e++) { | |
+ if (*e & HY_BIT) | |
+ *hyp++ = w; | |
+ if (hyp > hyptr + NHYP - 1) | |
+ hyp = hyptr + NHYP - 1; | |
+ w++; | |
+ } | |
+ return(1); | |
+ } else { | |
+ e++; | |
+ continue; | |
+ } | |
+ } else | |
+ while (*e++) | |
+ ; | |
+ } | |
+} | |
+ | |
+int | |
+suffix(void) | |
+{ | |
+ Tchar *w; | |
+ char *s, *s0; | |
+ Tchar i; | |
+ extern char *suftab[]; | |
+ | |
+again: | |
+ i = cbits(*hyend); | |
+ if (!alpha(i)) | |
+ return(0); | |
+ if (i < 'a') | |
+ i -= 'A' - 'a'; | |
+ if ((s0 = suftab[i-'a']) == 0) | |
+ return(0); | |
+ for (;;) { | |
+ if ((i = *s0 & 017) == 0) | |
+ return(0); | |
+ s = s0 + i - 1; | |
+ w = hyend - 1; | |
+ while (s > s0 && w >= wdstart && (*s & 0177) == maplow(cbits(*… | |
+ s--; | |
+ w--; | |
+ } | |
+ if (s == s0) | |
+ break; | |
+ s0 += i; | |
+ } | |
+ s = s0 + i - 1; | |
+ w = hyend; | |
+ if (*s0 & HY_BIT) | |
+ goto mark; | |
+ while (s > s0) { | |
+ w--; | |
+ if (*s-- & HY_BIT) { | |
+mark: | |
+ hyend = w - 1; | |
+ if (*s0 & 0100) /* 0100 used in suftab to encod… | |
+ continue; | |
+ if (!chkvow(w)) | |
+ return(0); | |
+ *hyp++ = w; | |
+ } | |
+ } | |
+ if (*s0 & 040) | |
+ return(0); | |
+ if (exword()) | |
+ return(1); | |
+ goto again; | |
+} | |
+ | |
+int | |
+maplow(int i) | |
+{ | |
+ if (isupper(i)) | |
+ i = tolower(i); | |
+ return(i); | |
+} | |
+ | |
+int | |
+vowel(int i) | |
+{ | |
+ switch (i) { | |
+ case 'a': case 'A': | |
+ case 'e': case 'E': | |
+ case 'i': case 'I': | |
+ case 'o': case 'O': | |
+ case 'u': case 'U': | |
+ case 'y': case 'Y': | |
+ return(1); | |
+ default: | |
+ return(0); | |
+ } | |
+} | |
+ | |
+ | |
+Tchar *chkvow(Tchar *w) | |
+{ | |
+ while (--w >= wdstart) | |
+ if (vowel(cbits(*w))) | |
+ return(w); | |
+ return(0); | |
+} | |
+ | |
+ | |
+void digram(void) | |
+{ | |
+ Tchar *w; | |
+ int val; | |
+ Tchar *nhyend, *maxw; | |
+ int maxval; | |
+ extern char bxh[26][13], bxxh[26][13], xxh[26][13], xhx[26][13], hxx[2… | |
+ maxw = 0; | |
+again: | |
+ if (!(w = chkvow(hyend + 1))) | |
+ return; | |
+ hyend = w; | |
+ if (!(w = chkvow(hyend))) | |
+ return; | |
+ nhyend = w; | |
+ maxval = 0; | |
+ w--; | |
+ while (++w < hyend && w < wdend - 1) { | |
+ val = 1; | |
+ if (w == wdstart) | |
+ val *= dilook('a', cbits(*w), bxh); | |
+ else if (w == wdstart + 1) | |
+ val *= dilook(cbits(*(w-1)), cbits(*w), bxxh); | |
+ else | |
+ val *= dilook(cbits(*(w-1)), cbits(*w), xxh); | |
+ val *= dilook(cbits(*w), cbits(*(w+1)), xhx); | |
+ val *= dilook(cbits(*(w+1)), cbits(*(w+2)), hxx); | |
+ if (val > maxval) { | |
+ maxval = val; | |
+ maxw = w + 1; | |
+ } | |
+ } | |
+ hyend = nhyend; | |
+ if (maxval > thresh) | |
+ *hyp++ = maxw; | |
+ goto again; | |
+} | |
+ | |
+int | |
+dilook(int a, int b, char t[26][13]) | |
+{ | |
+ int i, j; | |
+ | |
+ i = t[maplow(a)-'a'][(j = maplow(b)-'a')/2]; | |
+ if (!(j & 01)) | |
+ i >>= 4; | |
+ return(i & 017); | |
+} | |
+ | |
+ | |
+/* here beginneth the tex hyphenation code, as interpreted freely */ | |
+/* the main difference is that there is no attempt to squeeze space */ | |
+/* as tightly at tex does. */ | |
+ | |
+static int texit(Tchar *, Tchar *); | |
+static int readpats(void); | |
+static void install(char *); | |
+static void fixup(void); | |
+static int trieindex(int, int); | |
+ | |
+static char pats[50000]; /* size ought to be computed dynamicall… | |
+static char *nextpat = pats; | |
+static char *trie[27*27]; /* english-specific sizes */ | |
+ | |
+int texhyphen(void) | |
+{ | |
+ static int loaded = 0; /* -1: couldn't find tex file */ | |
+ | |
+ if (hyphalg == 0 || loaded == -1) /* non-zero => tex for now */ | |
+ return 0; | |
+ if (loaded == 0) { | |
+ if (readpats()) | |
+ loaded = 1; | |
+ else | |
+ loaded = -1; | |
+ } | |
+ return texit(wdstart, wdend); | |
+} | |
+ | |
+static int texit(Tchar *start, Tchar *end) /* hyphenate as in tex, retu… | |
+{ | |
+ int nw, i, k, equal, cnt[500]; | |
+ char w[500+1], *np, *pp, *wp, *xpp, *xwp; | |
+ | |
+ w[0] = '.'; | |
+ for (nw = 1; start <= end && nw < 500-1; nw++, start++) | |
+ w[nw] = maplow(tolower(cbits(*start))); | |
+ start -= (nw - 1); | |
+ w[nw++] = '.'; | |
+ w[nw] = 0; | |
+/* | |
+ * printf("try %s\n", w); | |
+*/ | |
+ for (i = 0; i <= nw; i++) | |
+ cnt[i] = '0'; | |
+ | |
+ for (wp = w; wp+1 < w+nw; wp++) { | |
+ for (pp = trie[trieindex(*wp, *(wp+1))]; pp < nextpat; ) { | |
+ if (pp == 0 /* no trie entry */ | |
+ || *pp != *wp /* no match on 1st lette… | |
+ || *(pp+1) != *(wp+1)) /* no match on 2nd lett… | |
+ break; /* so move to next let… | |
+ equal = 1; | |
+ for (xpp = pp+2, xwp = wp+2; *xpp; ) | |
+ if (*xpp++ != *xwp++) { | |
+ equal = 0; | |
+ break; | |
+ } | |
+ if (equal) { | |
+ np = xpp+1; /* numpat */ | |
+ for (k = wp-w; *np; k++, np++) | |
+ if (*np > cnt[k]) | |
+ cnt[k] = *np; | |
+/* | |
+ * printf("match: %s %s\n", pp, xpp+1); | |
+*/ | |
+ } | |
+ pp += *(pp-1); /* skip over pattern and numbers… | |
+ } | |
+ } | |
+/* | |
+ * for (i = 0; i < nw; i++) printf("%c", w[i]); | |
+ * printf(" "); | |
+ * for (i = 0; i <= nw; i++) printf("%c", cnt[i]); | |
+ * printf("\n"); | |
+*/ | |
+/* | |
+ * for (i = 1; i < nw - 1; i++) { | |
+ * if (i > 2 && i < nw - 3 && cnt[i] % 2) | |
+ * printf("-"); | |
+ * if (cbits(start[i-1]) != '.') | |
+ * printf("%c", cbits(start[i-1])); | |
+ * } | |
+ * printf("\n"); | |
+*/ | |
+ for (i = 1; i < nw -1; i++) | |
+ if (i > 2 && i < nw - 3 && cnt[i] % 2) | |
+ *hyp++ = start + i - 1; | |
+ return hyp - hyptr; /* non-zero if a hyphen was found */ | |
+} | |
+ | |
+/* | |
+ This code assumes that hyphen.tex looks like | |
+ % some comments | |
+ \patterns{ % more comments | |
+ pat5ter4ns, 1 per line, SORTED, nothing else | |
+ } | |
+ more goo | |
+ \hyphenation{ % more comments | |
+ ex-cep-tions, one per line; i ignore this part for now | |
+ } | |
+ | |
+ this code is NOT robust against variations. unfortunately, | |
+ it looks like every local language version of this file has | |
+ a different format. i have also made no provision for weird | |
+ characters. sigh. | |
+*/ | |
+ | |
+static int readpats(void) | |
+{ | |
+ FILE *fp; | |
+ char buf[200], buf1[200]; | |
+ | |
+ if ((fp = fopen(unsharp(TEXHYPHENS), "r")) == NULL | |
+ && (fp = fopen(unsharp(DWBalthyphens), "r")) == NULL) { | |
+ ERROR "warning: can't find hyphen.tex" WARN; | |
+ return 0; | |
+ } | |
+ | |
+ while (fgets(buf, sizeof buf, fp) != NULL) { | |
+ sscanf(buf, "%s", buf1); | |
+ if (strcmp(buf1, "\\patterns{") == 0) | |
+ break; | |
+ } | |
+ while (fgets(buf, sizeof buf, fp) != NULL) { | |
+ if (buf[0] == '}') | |
+ break; | |
+ install(buf); | |
+ } | |
+ fclose(fp); | |
+ fixup(); | |
+ return 1; | |
+} | |
+ | |
+static void install(char *s) /* map ab4c5de to: 12 abcde \0 00405 \0 */ | |
+{ | |
+ int npat, lastpat; | |
+ char num[500], *onextpat = nextpat; | |
+ | |
+ num[0] = '0'; | |
+ *nextpat++ = ' '; /* fill in with count later */ | |
+ for (npat = lastpat = 0; *s != '\n' && *s != '\0'; s++) { | |
+ if (isdigit((uchar)*s)) { | |
+ num[npat] = *s; | |
+ lastpat = npat; | |
+ } else { | |
+ *nextpat++ = *s; | |
+ npat++; | |
+ num[npat] = '0'; | |
+ } | |
+ } | |
+ *nextpat++ = 0; | |
+ if (nextpat > pats + sizeof(pats)-20) { | |
+ ERROR "tex hyphenation table overflow, tail end ignored" WARN; | |
+ nextpat = onextpat; | |
+ } | |
+ num[lastpat+1] = 0; | |
+ strcat(nextpat, num); | |
+ nextpat += strlen(nextpat) + 1; | |
+} | |
+ | |
+static void fixup(void) /* build indexes of where . a b c ... start */ | |
+{ | |
+ char *p, *lastc; | |
+ int n; | |
+ | |
+ for (lastc = pats, p = pats+1; p < nextpat; p++) | |
+ if (*p == ' ') { | |
+ *lastc = p - lastc; | |
+ lastc = p; | |
+ } | |
+ *lastc = p - lastc; | |
+ for (p = pats+1; p < nextpat; ) { | |
+ n = trieindex(p[0], p[1]); | |
+ if (trie[n] == 0) | |
+ trie[n] = p; | |
+ p += p[-1]; | |
+ } | |
+ /* printf("pats = %d\n", nextpat - pats); */ | |
+} | |
+ | |
+static int trieindex(int d1, int d2) | |
+{ | |
+ int z; | |
+ | |
+ z = 27 * (d1 == '.' ? 0 : d1 - 'a' + 1) + (d2 == '.' ? 0 : d2 - 'a' + … | |
+ assert(z >= 0 && z < 27*27); | |
+ return z; | |
+} | |
diff --git a/troff/n9.c b/troff/n9.c | |
@@ -0,0 +1,489 @@ | |
+#include "tdef.h" | |
+#include "ext.h" | |
+#include "fns.h" | |
+ | |
+/* | |
+ * troff9.c | |
+ * | |
+ * misc functions | |
+ */ | |
+ | |
+Tchar setz(void) | |
+{ | |
+ Tchar i; | |
+ | |
+ if (!ismot(i = getch())) | |
+ i |= ZBIT; | |
+ return(i); | |
+} | |
+ | |
+void setline(void) | |
+{ | |
+ Tchar *i; | |
+ Tchar c; | |
+ int length; | |
+ int j, w, cnt, delim, rem, temp; | |
+ Tchar linebuf[NC]; | |
+ | |
+ if (ismot(c = getch())) | |
+ return; | |
+ delim = cbits(c); | |
+ vflag = 0; | |
+ dfact = EM; | |
+ length = quant(atoi0(), HOR); | |
+ dfact = 1; | |
+ if (!length) { | |
+ eat(delim); | |
+ return; | |
+ } | |
+s0: | |
+ if ((j = cbits(c = getch())) == delim || j == '\n') { | |
+ ch = c; | |
+ c = RULE | chbits; | |
+ } else if (cbits(c) == FILLER) | |
+ goto s0; | |
+ w = width(c); | |
+ if (w <= 0) { | |
+ ERROR "zero-width underline character ignored" WARN; | |
+ c = RULE | chbits; | |
+ w = width(c); | |
+ } | |
+ i = linebuf; | |
+ if (length < 0) { | |
+ *i++ = makem(length); | |
+ length = -length; | |
+ } | |
+ if (!(cnt = length / w)) { | |
+ *i++ = makem(-(temp = ((w - length) / 2))); | |
+ *i++ = c; | |
+ *i++ = makem(-(w - length - temp)); | |
+ goto s1; | |
+ } | |
+ if (rem = length % w) { | |
+ if (cbits(c) == RULE || cbits(c) == UNDERLINE || cbits(c) == R… | |
+ *i++ = c | ZBIT; | |
+ *i++ = makem(rem); | |
+ } | |
+ if (cnt) { | |
+ *i++ = RPT; | |
+ *i++ = cnt; | |
+ *i++ = c; | |
+ } | |
+s1: | |
+ *i = 0; | |
+ eat(delim); | |
+ pushback(linebuf); | |
+} | |
+ | |
+int | |
+eat(int c) | |
+{ | |
+ int i; | |
+ | |
+ while ((i = cbits(getch())) != c && i != '\n') | |
+ ; | |
+ return(i); | |
+} | |
+ | |
+ | |
+void setov(void) | |
+{ | |
+ int j, k; | |
+ Tchar i, o[NOV+1]; | |
+ int delim, w[NOV+1]; | |
+ | |
+ if (ismot(i = getch())) | |
+ return; | |
+ delim = cbits(i); | |
+ for (k = 0; k < NOV && (j = cbits(i = getch())) != delim && j != '\n';… | |
+ o[k] = i; | |
+ w[k] = width(i); | |
+ } | |
+ o[k] = w[k] = 0; | |
+ if (o[0]) | |
+ for (j = 1; j; ) { | |
+ j = 0; | |
+ for (k = 1; o[k] ; k++) { | |
+ if (w[k-1] < w[k]) { | |
+ j++; | |
+ i = w[k]; | |
+ w[k] = w[k-1]; | |
+ w[k-1] = i; | |
+ i = o[k]; | |
+ o[k] = o[k-1]; | |
+ o[k-1] = i; | |
+ } | |
+ } | |
+ } | |
+ else | |
+ return; | |
+ *pbp++ = makem(w[0] / 2); | |
+ for (k = 0; o[k]; k++) | |
+ ; | |
+ while (k>0) { | |
+ k--; | |
+ *pbp++ = makem(-((w[k] + w[k+1]) / 2)); | |
+ *pbp++ = o[k]; | |
+ } | |
+} | |
+ | |
+ | |
+void setbra(void) | |
+{ | |
+ int k; | |
+ Tchar i, *j, dwn; | |
+ int cnt, delim; | |
+ Tchar brabuf[NC]; | |
+ | |
+ if (ismot(i = getch())) | |
+ return; | |
+ delim = cbits(i); | |
+ j = brabuf + 1; | |
+ cnt = 0; | |
+ if (NROFF) | |
+ dwn = (2 * t.Halfline) | MOT | VMOT; | |
+ else | |
+ dwn = EM | MOT | VMOT; | |
+ while ((k = cbits(i = getch())) != delim && k != '\n' && j <= brabuf +… | |
+ *j++ = i | ZBIT; | |
+ *j++ = dwn; | |
+ cnt++; | |
+ } | |
+ if (--cnt < 0) | |
+ return; | |
+ else if (!cnt) { | |
+ ch = *(j - 2); | |
+ return; | |
+ } | |
+ *j = 0; | |
+ if (NROFF) | |
+ *--j = *brabuf = (cnt * t.Halfline) | MOT | NMOT | VMOT; | |
+ else | |
+ *--j = *brabuf = (cnt * EM) / 2 | MOT | NMOT | VMOT; | |
+ *--j &= ~ZBIT; | |
+ pushback(brabuf); | |
+} | |
+ | |
+ | |
+void setvline(void) | |
+{ | |
+ int i; | |
+ Tchar c, rem, ver, neg; | |
+ int cnt, delim, v; | |
+ Tchar vlbuf[NC]; | |
+ Tchar *vlp; | |
+ | |
+ if (ismot(c = getch())) | |
+ return; | |
+ delim = cbits(c); | |
+ dfact = lss; | |
+ vflag++; | |
+ i = quant(atoi0(), VERT); | |
+ dfact = 1; | |
+ if (!i) { | |
+ eat(delim); | |
+ vflag = 0; | |
+ return; | |
+ } | |
+ if ((cbits(c = getch())) == delim) { | |
+ c = BOXRULE | chbits; /*default box rule*/ | |
+ } else | |
+ getch(); | |
+ c |= ZBIT; | |
+ neg = 0; | |
+ if (i < 0) { | |
+ i = -i; | |
+ neg = NMOT; | |
+ } | |
+ if (NROFF) | |
+ v = 2 * t.Halfline; | |
+ else { | |
+ v = EM; | |
+ if (v < VERT) /* ATT EVK hack: Erik van Konijne… | |
+ v = VERT; /* hvlpb!evkonij, ATT NSI Hilversum, … | |
+ } | |
+ | |
+ cnt = i / v; | |
+ rem = makem(i % v) | neg; | |
+ ver = makem(v) | neg; | |
+ vlp = vlbuf; | |
+ if (!neg) | |
+ *vlp++ = ver; | |
+ if (absmot(rem) != 0) { | |
+ *vlp++ = c; | |
+ *vlp++ = rem; | |
+ } | |
+ while (vlp < vlbuf + NC - 3 && cnt--) { | |
+ *vlp++ = c; | |
+ *vlp++ = ver; | |
+ } | |
+ *(vlp - 2) &= ~ZBIT; | |
+ if (!neg) | |
+ vlp--; | |
+ *vlp = 0; | |
+ pushback(vlbuf); | |
+ vflag = 0; | |
+} | |
+ | |
+#define NPAIR (NC/2-6) /* max pairs in spline, etc. */ | |
+ | |
+void setdraw(void) /* generate internal cookies for a drawing function … | |
+{ | |
+ int i, j, k, dx[NPAIR], dy[NPAIR], delim, type; | |
+ Tchar c, drawbuf[NC]; | |
+ int drawch = '.'; /* character to draw with */ | |
+ | |
+ /* input is \D'f dx dy dx dy ... c' (or at least it had better be) */ | |
+ /* this does drawing function f with character c and the */ | |
+ /* specified dx,dy pairs interpreted as appropriate */ | |
+ /* pairs are deltas from last point, except for radii */ | |
+ | |
+ /* l dx dy: line from here by dx,dy */ | |
+ /* c x: circle of diameter x, left side here */ | |
+ /* e x y: ellipse of diameters x,y, left side here */ | |
+ /* a dx1 dy1 dx2 dy2: | |
+ ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from ther… | |
+ /* ~ dx1 dy1 dx2 dy2...: | |
+ spline to dx1,dy1 to dx2,dy2 ... */ | |
+ /* b x c: | |
+ built-up character of type c, ht x */ | |
+ /* f dx dy ...: f is any other char: like spline */ | |
+ | |
+ if (ismot(c = getch())) | |
+ return; | |
+ delim = cbits(c); | |
+ numerr.escarg = type = cbits(getch()); | |
+ if (type == '~') /* head off the .tr ~ problem */ | |
+ type = 's'; | |
+ for (i = 0; i < NPAIR ; i++) { | |
+ skip(); | |
+ vflag = 0; | |
+ dfact = EM; | |
+ dx[i] = quant(atoi0(), HOR); | |
+ if (dx[i] > MAXMOT) | |
+ dx[i] = MAXMOT; | |
+ else if (dx[i] < -MAXMOT) | |
+ dx[i] = -MAXMOT; | |
+ skip(); | |
+ if (type == 'c') { | |
+ dy[i] = 0; | |
+ goto eat; | |
+ } | |
+ vflag = 1; | |
+ dfact = lss; | |
+ dy[i] = quant(atoi0(), VERT); | |
+ if (dy[i] > MAXMOT) | |
+ dy[i] = MAXMOT; | |
+ else if (dy[i] < -MAXMOT) | |
+ dy[i] = -MAXMOT; | |
+eat: | |
+ if (cbits(c = getch()) != ' ') { /* must be the end */ | |
+ if (cbits(c) != delim) { | |
+ drawch = cbits(c); | |
+ getch(); | |
+ } | |
+ i++; | |
+ break; | |
+ } | |
+ } | |
+ dfact = 1; | |
+ vflag = 0; | |
+ if (TROFF) { | |
+ drawbuf[0] = DRAWFCN | chbits | ZBIT; | |
+ drawbuf[1] = type | chbits | ZBIT; | |
+ drawbuf[2] = drawch | chbits | ZBIT; | |
+ for (k = 0, j = 3; k < i; k++) { | |
+ drawbuf[j++] = MOT | ((dx[k] >= 0) ? dx[k] : (NMOT | -… | |
+ drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ? dy[k] : (N… | |
+ } | |
+ if (type == DRAWELLIPSE) { | |
+ drawbuf[5] = drawbuf[4] | NMOT; /* so the net v… | |
+ j = 6; | |
+ } else if (type == DRAWBUILD) { | |
+ drawbuf[4] = drawbuf[3] | NMOT; /* net horizont… | |
+ drawbuf[2] &= ~ZBIT; /* width taken fro… | |
+ j = 5; | |
+ } | |
+ drawbuf[j++] = DRAWFCN | chbits | ZBIT; /* marks end fo… | |
+ drawbuf[j] = 0; | |
+ pushback(drawbuf); | |
+ } | |
+} | |
+ | |
+ | |
+void casefc(void) | |
+{ | |
+ int i; | |
+ Tchar j; | |
+ | |
+ gchtab[fc] &= ~FCBIT; | |
+ fc = IMP; | |
+ padc = ' '; | |
+ if (skip() || ismot(j = getch()) || (i = cbits(j)) == '\n') | |
+ return; | |
+ fc = i; | |
+ gchtab[fc] |= FCBIT; | |
+ if (skip() || ismot(ch) || (ch = cbits(ch)) == fc) | |
+ return; | |
+ padc = ch; | |
+} | |
+ | |
+ | |
+Tchar setfield(int x) | |
+{ | |
+ Tchar ii, jj, *fp; | |
+ int i, j; | |
+ int length, ws, npad, temp, type; | |
+ Tchar **pp, *padptr[NPP]; | |
+ Tchar fbuf[FBUFSZ]; | |
+ int savfc, savtc, savlc; | |
+ Tchar rchar; | |
+ int savepos; | |
+ static Tchar wbuf[] = { WORDSP, 0}; | |
+ | |
+ rchar = 0; | |
+ if (x == tabch) | |
+ rchar = tabc | chbits; | |
+ else if (x == ldrch) | |
+ rchar = dotc | chbits; | |
+ temp = npad = ws = 0; | |
+ savfc = fc; | |
+ savtc = tabch; | |
+ savlc = ldrch; | |
+ tabch = ldrch = fc = IMP; | |
+ savepos = numtabp[HP].val; | |
+ gchtab[tabch] &= ~TABBIT; | |
+ gchtab[ldrch] &= ~LDRBIT; | |
+ gchtab[fc] &= ~FCBIT; | |
+ gchtab[IMP] |= TABBIT|LDRBIT|FCBIT; | |
+ for (j = 0; ; j++) { | |
+ if ((tabtab[j] & TABMASK) == 0) { | |
+ if (x == savfc) | |
+ ERROR "zero field width." WARN; | |
+ jj = 0; | |
+ goto rtn; | |
+ } | |
+ if ((length = ((tabtab[j] & TABMASK) - numtabp[HP].val)) > 0 ) | |
+ break; | |
+ } | |
+ type = tabtab[j] & ~TABMASK; | |
+ fp = fbuf; | |
+ pp = padptr; | |
+ if (x == savfc) { | |
+ while (1) { | |
+ j = cbits(ii = getch()); | |
+ jj = width(ii); | |
+ widthp = jj; | |
+ numtabp[HP].val += jj; | |
+ if (j == padc) { | |
+ npad++; | |
+ *pp++ = fp; | |
+ if (pp > padptr + NPP - 1) | |
+ break; | |
+ goto s1; | |
+ } else if (j == savfc) | |
+ break; | |
+ else if (j == '\n') { | |
+ temp = j; | |
+ if (nlflg && ip == 0) { | |
+ numtabp[CD].val--; | |
+ nlflg = 0; | |
+ } | |
+ break; | |
+ } | |
+ ws += jj; | |
+s1: | |
+ *fp++ = ii; | |
+ if (fp > fbuf + FBUFSZ - 3) | |
+ break; | |
+ } | |
+ if (ws) | |
+ *fp++ = WORDSP; | |
+ if (!npad) { | |
+ npad++; | |
+ *pp++ = fp; | |
+ *fp++ = 0; | |
+ } | |
+ *fp++ = temp; | |
+ *fp = 0; | |
+ temp = i = (j = length - ws) / npad; | |
+ i = (i / HOR) * HOR; | |
+ if ((j -= i * npad) < 0) | |
+ j = -j; | |
+ ii = makem(i); | |
+ if (temp < 0) | |
+ ii |= NMOT; | |
+ for (; npad > 0; npad--) { | |
+ *(*--pp) = ii; | |
+ if (j) { | |
+ j -= HOR; | |
+ (*(*pp)) += HOR; | |
+ } | |
+ } | |
+ pushback(fbuf); | |
+ jj = 0; | |
+ } else if (type == 0) { | |
+ /*plain tab or leader*/ | |
+ if ((j = width(rchar)) > 0) { | |
+ int nchar = length / j; | |
+ while (nchar-->0 && pbp < &pbbuf[NC-3]) { | |
+ numtabp[HP].val += j; | |
+ widthp = j; | |
+ *pbp++ = rchar; | |
+ } | |
+ length %= j; | |
+ } | |
+ if (length) | |
+ jj = length | MOT; | |
+ else | |
+ jj = getch0(); | |
+ if (savepos > 0) | |
+ pushback(wbuf); | |
+ } else { | |
+ /*center tab*/ | |
+ /*right tab*/ | |
+ while ((j = cbits(ii = getch())) != savtc && j != '\n' && j !=… | |
+ jj = width(ii); | |
+ ws += jj; | |
+ numtabp[HP].val += jj; | |
+ widthp = jj; | |
+ *fp++ = ii; | |
+ if (fp > fbuf + FBUFSZ - 3) | |
+ break; | |
+ } | |
+ *fp++ = ii; | |
+ *fp = 0; | |
+ if (type == RTAB) | |
+ length -= ws; | |
+ else | |
+ length -= ws / 2; /*CTAB*/ | |
+ pushback(fbuf); | |
+ if ((j = width(rchar)) != 0 && length > 0) { | |
+ int nchar = length / j; | |
+ while (nchar-- > 0 && pbp < &pbbuf[NC-3]) | |
+ *pbp++ = rchar; | |
+ length %= j; | |
+ } | |
+ if (savepos > 0) | |
+ pushback(wbuf); | |
+ length = (length / HOR) * HOR; | |
+ jj = makem(length); | |
+ if (nlflg) { | |
+ if (ip == 0) | |
+ numtabp[CD].val--; | |
+ nlflg = 0; | |
+ } | |
+ } | |
+rtn: | |
+ gchtab[fc] &= ~FCBIT; | |
+ gchtab[tabch] &= ~TABBIT; | |
+ gchtab[ldrch] &= ~LDRBIT; | |
+ fc = savfc; | |
+ tabch = savtc; | |
+ ldrch = savlc; | |
+ gchtab[fc] |= FCBIT; | |
+ gchtab[tabch] = TABBIT; | |
+ gchtab[ldrch] |= LDRBIT; | |
+ numtabp[HP].val = savepos; | |
+ return(jj); | |
+} | |
diff --git a/troff/ni.c b/troff/ni.c | |
@@ -0,0 +1,390 @@ | |
+#include <stdio.h> | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+char termtab[NS]; /* term type added in ptinit() */ | |
+char fontdir[NS]; /* added in casefp; not used by nroff */ | |
+char devname[20]; /* default output device */ | |
+ | |
+Numtab numtab[NN] = { | |
+ { PAIR('%', 0) }, | |
+ { PAIR('n', 'l') }, | |
+ { PAIR('y', 'r') }, | |
+ { PAIR('h', 'p') }, | |
+ { PAIR('c', 't') }, | |
+ { PAIR('d', 'n') }, | |
+ { PAIR('m', 'o') }, | |
+ { PAIR('d', 'y') }, | |
+ { PAIR('d', 'w') }, | |
+ { PAIR('l', 'n') }, | |
+ { PAIR('d', 'l') }, | |
+ { PAIR('s', 't') }, | |
+ { PAIR('s', 'b') }, | |
+ { PAIR('c', '.') }, | |
+ { PAIR('$', '$') } | |
+}; | |
+ | |
+ | |
+int alphabet = 256; /* latin-1 */ | |
+int pto = 10000; | |
+int pfrom = 1; | |
+int print = 1; | |
+char nextf[NS] = TMACDIR; | |
+char mfiles[NMF][NS]; | |
+int nmfi = 0; | |
+int oldbits = -1; | |
+int init = 1; | |
+int fc = IMP; /* field character */ | |
+int eschar = '\\'; | |
+int pl; | |
+int po; | |
+FILE *ptid; | |
+ | |
+int dfact = 1; | |
+int dfactd = 1; | |
+int res = 1; | |
+int smnt = 0; /* beginning of special fonts */ | |
+int ascii = 0; /* ascii normally off for troff, on for nr… | |
+int lg; | |
+int pnlist[NPN] = { -1 }; | |
+ | |
+ | |
+int *pnp = pnlist; | |
+int npn = 1; | |
+int npnflg = 1; | |
+int dpn = -1; | |
+int totout = 1; | |
+int ulfont = ULFONT; | |
+int tabch = TAB; | |
+int ldrch = LEADER; | |
+ | |
+ | |
+Contab contab[NM] = { | |
+ C(PAIR('d', 's'), caseds), | |
+ C(PAIR('a', 's'), caseas), | |
+ C(PAIR('s', 'p'), casesp), | |
+ C(PAIR('f', 't'), caseft), | |
+ C(PAIR('p', 's'), caseps), | |
+ C(PAIR('v', 's'), casevs), | |
+ C(PAIR('n', 'r'), casenr), | |
+ C(PAIR('i', 'f'), caseif), | |
+ C(PAIR('i', 'e'), caseie), | |
+ C(PAIR('e', 'l'), caseel), | |
+ C(PAIR('p', 'o'), casepo), | |
+ C(PAIR('t', 'l'), casetl), | |
+ C(PAIR('t', 'm'), casetm), | |
+ C(PAIR('f', 'm'), casefm), | |
+ C(PAIR('b', 'p'), casebp), | |
+ C(PAIR('c', 'h'), casech), | |
+ C(PAIR('p', 'n'), casepn), | |
+ C(PAIR('b', 'r'), tbreak), | |
+ C(PAIR('t', 'i'), caseti), | |
+ C(PAIR('n', 'e'), casene), | |
+ C(PAIR('n', 'f'), casenf), | |
+ C(PAIR('c', 'e'), casece), | |
+ C(PAIR('f', 'i'), casefi), | |
+ C(PAIR('i', 'n'), casein), | |
+ C(PAIR('l', 'l'), casell), | |
+ C(PAIR('n', 's'), casens), | |
+ C(PAIR('m', 'k'), casemk), | |
+ C(PAIR('r', 't'), casert), | |
+ C(PAIR('a', 'm'), caseam), | |
+ C(PAIR('d', 'e'), casede), | |
+ C(PAIR('d', 'i'), casedi), | |
+ C(PAIR('d', 'a'), caseda), | |
+ C(PAIR('w', 'h'), casewh), | |
+ C(PAIR('d', 't'), casedt), | |
+ C(PAIR('i', 't'), caseit), | |
+ C(PAIR('r', 'm'), caserm), | |
+ C(PAIR('r', 'r'), caserr), | |
+ C(PAIR('r', 'n'), casern), | |
+ C(PAIR('a', 'd'), casead), | |
+ C(PAIR('r', 's'), casers), | |
+ C(PAIR('n', 'a'), casena), | |
+ C(PAIR('p', 'l'), casepl), | |
+ C(PAIR('t', 'a'), caseta), | |
+ C(PAIR('t', 'r'), casetr), | |
+ C(PAIR('u', 'l'), caseul), | |
+ C(PAIR('c', 'u'), casecu), | |
+ C(PAIR('l', 't'), caselt), | |
+ C(PAIR('n', 'x'), casenx), | |
+ C(PAIR('s', 'o'), caseso), | |
+ C(PAIR('i', 'g'), caseig), | |
+ C(PAIR('t', 'c'), casetc), | |
+ C(PAIR('f', 'c'), casefc), | |
+ C(PAIR('e', 'c'), caseec), | |
+ C(PAIR('e', 'o'), caseeo), | |
+ C(PAIR('l', 'c'), caselc), | |
+ C(PAIR('e', 'v'), caseev), | |
+ C(PAIR('r', 'd'), caserd), | |
+ C(PAIR('a', 'b'), caseab), | |
+ C(PAIR('f', 'l'), casefl), | |
+ C(PAIR('e', 'x'), caseex), | |
+ C(PAIR('s', 's'), casess), | |
+ C(PAIR('f', 'p'), casefp), | |
+ C(PAIR('c', 's'), casecs), | |
+ C(PAIR('b', 'd'), casebd), | |
+ C(PAIR('l', 'g'), caselg), | |
+ C(PAIR('h', 'c'), casehc), | |
+ C(PAIR('h', 'y'), casehy), | |
+ C(PAIR('n', 'h'), casenh), | |
+ C(PAIR('n', 'm'), casenm), | |
+ C(PAIR('n', 'n'), casenn), | |
+ C(PAIR('s', 'v'), casesv), | |
+ C(PAIR('o', 's'), caseos), | |
+ C(PAIR('l', 's'), casels), | |
+ C(PAIR('c', 'c'), casecc), | |
+ C(PAIR('c', '2'), casec2), | |
+ C(PAIR('e', 'm'), caseem), | |
+ C(PAIR('a', 'f'), caseaf), | |
+ C(PAIR('h', 'a'), caseha), | |
+ C(PAIR('h', 'w'), casehw), | |
+ C(PAIR('m', 'c'), casemc), | |
+ C(PAIR('p', 'm'), casepm), | |
+ C(PAIR('p', 'i'), casepi), | |
+ C(PAIR('u', 'f'), caseuf), | |
+ C(PAIR('p', 'c'), casepc), | |
+ C(PAIR('h', 't'), caseht), | |
+ C(PAIR('c', 'f'), casecf), | |
+ C(PAIR('s', 'y'), casesy), | |
+ C(PAIR('l', 'f'), caself), | |
+ C(PAIR('p', 't'), casept), | |
+ C(PAIR('g', 'd'), casegd) | |
+}; | |
+ | |
+ | |
+Tbuf _oline; | |
+ | |
+/* | |
+ * troff environment block | |
+ */ | |
+ | |
+Env env[NEV] = { { /* this sets up env[0] */ | |
+/* int ics */ 0, /* insertion character space, se… | |
+/* int sps */ 0, | |
+/* int spacesz */ 0, | |
+/* int lss */ 0, | |
+/* int lss1 */ 0, | |
+/* int ll */ 0, | |
+/* int ll1 */ 0, | |
+/* int lt */ 0, | |
+/* int lt1 */ 0, | |
+/* Tchar ic */ 0, /* insertion character (= margin chara… | |
+/* int icf */ 0, /* insertion character flag */ | |
+/* Tchar chbits */ 0, /* size+font bits for current char… | |
+/* Tchar spbits */ 0, | |
+/* Tchar nmbits */ 0, /* size+font bits for number from … | |
+/* int apts */ PS, /* actual point size -- as req… | |
+/* int apts1 */ PS, /* need not match an existent… | |
+/* int pts */ PS, /* hence, this is the size that… | |
+/* int pts1 */ PS, | |
+/* int font */ FT, | |
+/* int font1 */ FT, | |
+/* int ls */ 1, | |
+/* int ls1 */ 1, | |
+/* int ad */ 1, | |
+/* int nms */ 1, /* .nm multiplier */ | |
+/* int ndf */ 1, /* .nm separator */ | |
+/* int nmwid */ 3, /* max width of .nm numbers */ | |
+/* int fi */ 1, | |
+/* int cc */ '.', | |
+/* int c2 */ '\'', | |
+/* int ohc */ OHC, | |
+/* int tdelim */ IMP, | |
+/* int hyf */ 1, | |
+/* int hyoff */ 0, | |
+/* int hyphalg */ HYPHALG, | |
+/* int un1 */ -1, | |
+/* int tabc */ 0, | |
+/* int dotc */ '.', | |
+/* int adsp */ 0, /* add this much space to each … | |
+/* int adrem */ 0, /* excess space to add until i… | |
+/* int lastl */ 0, /* last text on current output… | |
+/* int nel */ 0, /* how much space left on curren… | |
+/* int admod */ 0, /* adjust mode */ | |
+/* Tchar *wordp */ 0, | |
+/* int spflg */ 0, /* probably to indicate space … | |
+/* Tchar *linep */ 0, | |
+/* Tchar *wdend */ 0, | |
+/* Tchar *wdstart */ 0, | |
+/* int wne */ 0, | |
+/* int ne */ 0, /* how much space taken on curren… | |
+/* int nc */ 0, /* #characters (incl blank) on ou… | |
+/* int nb */ 0, | |
+/* int lnmod */ 0, /* line number mode, set by .n… | |
+/* int nwd */ 0, /* number of words on current ou… | |
+/* int nn */ 0, /* from .nn command */ | |
+/* int ni */ 0, /* indent of .nm numbers, probabl… | |
+/* int ul */ 0, | |
+/* int cu */ 0, | |
+/* int ce */ 0, | |
+/* int in */ 0, /* indent and previous value */ | |
+/* int in1 */ 0, | |
+/* int un */ 0, /* unindent of left margin in som… | |
+/* int wch */ 0, | |
+/* int pendt */ 0, | |
+/* Tchar *pendw */ (Tchar *)0, | |
+/* int pendnf */ 0, | |
+/* int spread */ 0, | |
+/* int it */ 0, /* input trap count */ | |
+/* int itmac */ 0 | |
+} }; | |
+ | |
+Env *envp = env; /* start off in env 0 */ | |
+ | |
+Numerr numerr; | |
+ | |
+Stack *frame, *stk, *ejl; | |
+Stack *nxf; | |
+ | |
+int pipeflg; | |
+int hflg; /* used in nroff only */ | |
+int eqflg; /* used in nroff only */ | |
+ | |
+int xpts; | |
+int ppts; | |
+int pfont; | |
+int mpts; | |
+int mfont; | |
+int cs; | |
+int ccs; | |
+int bd; | |
+ | |
+int stdi; | |
+int quiet; | |
+int stop; | |
+char ibuf[IBUFSZ]; | |
+char xbuf[IBUFSZ]; | |
+char *ibufp; | |
+char *xbufp; | |
+char *eibuf; | |
+char *xeibuf; | |
+Tchar pbbuf[NC]; /* pushback buffer for arguments, \n, e… | |
+Tchar *pbp = pbbuf; /* next free slot in pbbuf */ | |
+Tchar *lastpbp = pbbuf; /* pbp in previous stack frame */ | |
+int nx; | |
+int mflg; | |
+Tchar ch = 0; | |
+int ibf; | |
+int ifi; | |
+int iflg; | |
+int rargc; | |
+char **argp; | |
+Ushort trtab[NTRTAB]; | |
+int lgf; | |
+int copyf; | |
+Offset ip; | |
+int nlflg; | |
+int donef; | |
+int nflush; | |
+int nfo; | |
+int padc; | |
+int raw; | |
+int flss; | |
+int nonumb; | |
+int trap; | |
+int tflg; | |
+int ejf; | |
+int dilev; | |
+Offset offset; | |
+int em; | |
+int ds; | |
+Offset woff; | |
+int app; | |
+int ndone; | |
+int lead; | |
+int ralss; | |
+Offset nextb; | |
+Tchar nrbits; | |
+int nform; | |
+int oldmn; | |
+int newmn; | |
+int macerr; | |
+Offset apptr; | |
+int diflg; | |
+int evi; | |
+int vflag; | |
+int noscale; | |
+int po1; | |
+int nlist[NTRAP]; | |
+int mlist[NTRAP]; | |
+int evlist[EVLSZ]; | |
+int ev; | |
+int tty; | |
+int sfont = FT; /* appears to be "standard" font; used by… | |
+int sv; | |
+int esc; | |
+int widthp; | |
+int xfont; | |
+int setwdf; | |
+int over; | |
+int nhyp; | |
+Tchar **hyp; | |
+Tchar *olinep; | |
+int dotT; | |
+char *unlkp; | |
+Wcache widcache[NWIDCACHE]; | |
+Diver d[NDI]; | |
+Diver *dip; | |
+ | |
+int c_hyphen; | |
+int c_emdash; | |
+int c_rule; | |
+int c_minus; | |
+int c_fi; | |
+int c_fl; | |
+int c_ff; | |
+int c_ffi; | |
+int c_ffl; | |
+int c_acute; | |
+int c_grave; | |
+int c_under; | |
+int c_rooten; | |
+int c_boxrule; | |
+int c_lefthand; | |
+int c_dagger; | |
+int c_isalnum; | |
+ | |
+Spnames spnames[] = | |
+{ | |
+ &c_hyphen, "hy", | |
+ &c_emdash, "em", | |
+ &c_rule, "ru", | |
+ &c_minus, "\\-", | |
+ &c_fi, "fi", | |
+ &c_fl, "fl", | |
+ &c_ff, "ff", | |
+ &c_ffi, "Fi", | |
+ &c_ffl, "Fl", | |
+ &c_acute, "aa", | |
+ &c_grave, "ga", | |
+ &c_under, "ul", | |
+ &c_rooten, "rn", | |
+ &c_boxrule, "br", | |
+ &c_lefthand, "lh", | |
+ &c_dagger, "dg", /* not in nroff?? */ | |
+ &c_isalnum, "__", | |
+ 0, 0 | |
+}; | |
+ | |
+ | |
+Tchar (*hmot)(void); | |
+Tchar (*makem)(int i); | |
+Tchar (*setabs)(void); | |
+Tchar (*setch)(int c); | |
+Tchar (*sethl)(int k); | |
+Tchar (*setht)(void); | |
+Tchar (*setslant)(void); | |
+Tchar (*vmot)(void); | |
+Tchar (*xlss)(void); | |
+int (*findft)(int i); | |
+int (*width)(Tchar j); | |
+void (*mchbits)(void); | |
+void (*ptlead)(void); | |
+void (*ptout)(Tchar i); | |
+void (*ptpause)(void); | |
+void (*setfont)(int a); | |
+void (*setps)(void); | |
+void (*setwd)(void); | |
+ | |
diff --git a/troff/suftab.c b/troff/suftab.c | |
@@ -0,0 +1,612 @@ | |
+/* | |
+ * Suffix table | |
+ */ | |
+ | |
+typedef unsigned char Uchar; | |
+ | |
+static Uchar sufa[] = { | |
+ 02,0200+'t', /* -TA */ | |
+ 02,0200+'s', /* -SA */ | |
+ 03,0200+'t','r', /* -TRA */ | |
+ 03,0200+'d','r', /* -DRA */ | |
+ 03,0200+'b','r', /* -BRA */ | |
+ 02,0200+'p', /* -PA */ | |
+ 02,0200+'n', /* -NA */ | |
+ 02,0200+'m', /* -MA */ | |
+ 03,0200+'p','l', /* -PLA */ | |
+ 02,0200+'l', /* -LA */ | |
+ 02,0200+'k', /* -KA */ | |
+ 03,0200+'t','h', /* -THA */ | |
+ 03,0200+'s','h', /* -SHA */ | |
+ 02,0200+'g', /* -GA */ | |
+ 02,0200+'d', /* -DA */ | |
+ 02,0200+'c', /* -CA */ | |
+ 02,0200+'b', /* -BA */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufc[] = { | |
+ 04,'e','t',0200+'i', /* ET-IC */ | |
+ 07,'a','l',0200+'i','s',0200+'t','i', /* AL-IS-TIC */ | |
+ 04,'s',0200+'t','i', /* S-TIC */ | |
+ 04,'p',0200+'t','i', /* P-TIC */ | |
+ 05,0200+'l','y','t',0200+'i', /* -LYT-IC */ | |
+ 04,'o','t',0200+'i', /* OT-IC */ | |
+ 05,'a','n',0200+'t','i', /* AN-TIC */ | |
+ 04,'n',0200+'t','i', /* N-TIC */ | |
+ 04,'c',0200+'t','i', /* C-TIC */ | |
+ 04,'a','t',0200+'i', /* AT-IC */ | |
+ 04,'h',0200+'n','i', /* H-NIC */ | |
+ 03,'n',0200+'i', /* N-IC */ | |
+ 03,'m',0200+'i', /* M-IC */ | |
+ 04,'l',0200+'l','i', /* L-LIC */ | |
+ 04,'b',0200+'l','i', /* B-LIC */ | |
+ 04,0200+'c','l','i', /* -CLIC */ | |
+ 03,'l',0200+'i', /* L-IC */ | |
+ 03,'h',0200+'i', /* H-IC */ | |
+ 03,'f',0200+'i', /* F-IC */ | |
+ 03,'d',0200+'i', /* D-IC */ | |
+ 03,0200+'b','i', /* -BIC */ | |
+ 03,'a',0200+'i', /* A-IC */ | |
+ 03,0200+'m','a', /* -MAC */ | |
+ 03,'i',0200+'a', /* I-AC */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufd[] = { | |
+ 04,0200+'w','o','r', /* -WORD */ | |
+ 04,0200+'l','o','r', /* -LORD */ | |
+ 04,0200+'f','o','r', /* -FORD */ | |
+ 04,0200+'y','a','r', /* -YARD */ | |
+ 04,0200+'w','a','r', /* -WARD */ | |
+ 05,0200+'g','u','a','r', /* -GUARD */ | |
+ 04,0200+'t','a','r', /* -TARD */ | |
+ 05,0200+'b','o','a','r', /* -BOARD */ | |
+ 04,0200+'n','a','r', /* -NARD */ | |
+ 05,0200+'l','i','a','r', /* -LIARD */ | |
+ 04,0200+'i','a','r', /* -IARD */ | |
+ 04,0200+'g','a','r', /* -GARD */ | |
+ 04,0200+'b','a','r', /* -BARD */ | |
+ 03,0200+'r','o', /* -ROD */ | |
+ 04,0200+'w','o','o', /* -WOOD */ | |
+ 04,0200+'h','o','o', /* -HOOD */ | |
+ 04,0200+'m','o','n', /* -MOND */ | |
+ 04,0200+'t','e','n', /* -TEND */ | |
+ 05,0200+'s','t','a','n', /* -STAND */ | |
+ 04,0200+'l','a','n', /* -LAND */ | |
+ 04,0200+'h','a','n', /* -HAND */ | |
+ 04,0200+'h','o','l', /* -HOLD */ | |
+ 04,0200+'f','o','l', /* -FOLD */ | |
+ 05,0200+'f','i','e','l', /* -FIELD */ | |
+ 03,0200+'v','i', /* -VID */ | |
+ 03,0200+'c','i', /* -CID */ | |
+ 04,0200+'s','a','i', /* -SAID */ | |
+ 04,0200+'m','a','i', /* -MAID */ | |
+ 04,'t',0200+'t','e', /* T-TED */ | |
+ 03,'t',0200+'e', /* T-ED */ | |
+ 04,0200+'d','r','e', /* -DRED */ | |
+ 04,0200+'c','r','e', /* -CRED */ | |
+ 04,0200+'b','r','e', /* -BRED */ | |
+ 05,'v',0200+'e','l','e', /* V-ELED */ | |
+ 0100+04,'a','l',0200+'e', /* AL/ED */ | |
+ 0140+03,0200+'e','e', /* /EED */ | |
+ 040+05,'e','d',0200+'d','e', /* ED-DED */ | |
+ 04,'d',0200+'d','e', /* D-DED */ | |
+ 040+04,'e','d',0200+'e', /* ED-ED */ | |
+ 03,'d',0200+'e', /* D-ED */ | |
+ 05,0200+'d','u','c','e', /* -DUCED */ | |
+ 0300+02,'e', /* E/D */ | |
+ 05,0200+'s','t','e','a', /* -STEAD */ | |
+ 05,0200+'a','h','e','a', /* -AHEAD */ | |
+ 04,0200+'h','e','a', /* -HEAD */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufe[] = { | |
+ 05,'a','r',0200+'i','z', /* AR-IZE */ | |
+ 05,'a','n',0200+'i','z', /* AN-IZE */ | |
+ 05,'a','l',0200+'i','z', /* AL-IZE */ | |
+ 06,0200+'a','r','d',0200+'i','z', /* -ARD-IZE */ | |
+ 05,0200+'s','e','l','v', /* -SELVE */ | |
+ 05,0200+'k','n','i','v', /* -KNIVE */ | |
+ 05,0200+'l','i','e','v', /* -LIEVE */ | |
+ 0100+03,0200+'q','u', /* /QUE */ | |
+ 07,'o','n',0200+'t','i','n',0200+'u', /* ON-TIN-UE */ | |
+ 03,0200+'n','u', /* -NUE */ | |
+ 03,0200+'d','u', /* -DUE */ | |
+ 0300+02,'u', /* U/E */ | |
+ 0300+05,'q','u','a','t', /* QUAT/E */ | |
+ 04,'u',0200+'a','t', /* U-ATE */ | |
+ 05,0200+'s','t','a','t', /* -STATE */ | |
+ 04,0200+'t','a','t', /* -TATE */ | |
+ 06,0200+'t','o','r',0200+'a','t', /* -TOR-ATE */ | |
+ 05,'e','n',0200+'a','t', /* EN-ATE */ | |
+ 04,0200+'m','a','t', /* -MATE */ | |
+ 05,0200+'h','o','u','s', /* -HOUSE */ | |
+ 05,0200+'c','l','o','s', /* -CLOSE */ | |
+ 04,'i',0200+'o','s', /* I-OSE */ | |
+ 04,0200+'w','i','s', /* -WISE */ | |
+ 05,'a','s',0200+'u','r', /* AS-URE */ | |
+ 040+04,0200+'s','u','r', /* -SURE */ | |
+ 06,0200+'f','i','g',0200+'u','r', /* -FIG-URE */ | |
+ 040+03,0200+'t','r', /* -TRE */ | |
+ 05,0200+'s','t','o','r', /* -STORE */ | |
+ 04,0200+'f','o','r', /* -FORE */ | |
+ 05,0200+'w','h','e','r', /* -WHERE */ | |
+ 06,0200+'s','p','h','e','r', /* -SPHERE */ | |
+ 03,0200+'d','r', /* -DRE */ | |
+ 03,0200+'c','r', /* -CRE */ | |
+ 03,0200+'b','r', /* -BRE */ | |
+ 05,0200+'s','c','o','p', /* -SCOPE */ | |
+ 04,'y',0200+'o','n', /* Y-ONE */ | |
+ 05,0200+'s','t','o','n', /* -STONE */ | |
+ 05,0200+'p','h','o','n', /* -PHONE */ | |
+ 04,0200+'g','o','n', /* -GONE */ | |
+ 04,'e',0200+'o','n', /* E-ONE */ | |
+ 040+04,0200+'e','n','n', /* -ENNE */ | |
+ 040+05,'a',0200+'r','i','n', /* A-RINE */ | |
+ 05,0200+'c','l','i','n', /* -CLINE */ | |
+ 04,0200+'l','i','n', /* -LINE */ | |
+ 007,00200+'r','o','u',00200+'t','i','n', /*-ROU-TINE */ | |
+ 04,0200+'s','o','m', /* -SOME */ | |
+ 04,0200+'c','o','m', /* -COME */ | |
+ 04,0200+'t','i','m', /* -TIME */ | |
+ 03,0200+'z','l', /* -ZLE */ | |
+ 03,0200+'t','l', /* -TLE */ | |
+ 03,0200+'s','l', /* -SLE */ | |
+ 03,0200+'p','l', /* -PLE */ | |
+ 05,0200+'v','i','l','l', /* -VILLE */ | |
+ 04,'c','k',0200+'l', /* CK-LE */ | |
+ 03,0200+'k','l', /* -KLE */ | |
+ 03,0200+'g','l', /* -GLE */ | |
+ 03,0200+'f','l', /* -FLE */ | |
+ 03,0200+'d','l', /* -DLE */ | |
+ 03,0200+'c','l', /* -CLE */ | |
+ 05,0200+'p','a',0200+'b','l', /* -PA-BLE */ | |
+ 05,'f','a',0200+'b','l', /* FA-BLE */ | |
+ 05,0200+'c','a',0200+'b','l', /* -CA-BLE */ | |
+ 06,0200+'s','t','a','b','l', /* -STABLE */ | |
+ 04,0200+'a','b','l', /* -ABLE */ | |
+ 03,0200+'b','l', /* -BLE */ | |
+ 04,0200+'d','a','l', /* -DALE */ | |
+ 04,0200+'m','a','l', /* -MALE */ | |
+ 04,0200+'s','a','l', /* -SALE */ | |
+ 04,0200+'l','i','k', /* -LIKE */ | |
+ 0340+05,'g',0200+'u','a','g', /* -G/UAGE */ | |
+ 05,0200+'r','i','a','g', /* -RIAGE */ | |
+ 05,'e','r',0200+'a','g', /* ER-AGE */ | |
+ 04,'m',0200+'a','g', /* M-AGE */ | |
+ 04,'k',0200+'a','g', /* K-AGE */ | |
+ 04,'d',0200+'a','g', /* D-AGE */ | |
+ 04,0200+'w','i','f', /* -WIFE */ | |
+ 05,0200+'k','n','i','f', /* -KNIFE */ | |
+ 03,0200+'s','e', /* -SEE */ | |
+ 04,0200+'f','r','e', /* -FREE */ | |
+ 0340+02,'e', /* EE */ | |
+ 04,0200+'w','i','d', /* -WIDE */ | |
+ 04,0200+'t','i','d', /* -TIDE */ | |
+ 04,0200+'s','i','d', /* -SIDE */ | |
+ 06,0200+'q','u','e','n','c', /* -QUENCE */ | |
+ 07,0200+'f','l','u',0200+'e','n','c', /* -FLU-ENCE */ | |
+ 040+06,'e','s',0200+'e','n','c', /* ES-ENCE */ | |
+ 06,'e','r',0200+'e','n','c', /* ER-ENCE */ | |
+ 05,'i',0200+'e','n','c', /* I-ENCE */ | |
+ 040+05,0200+'s','a','n','c', /* -SANCE */ | |
+ 06,'e','r',0200+'a','n','c', /* ER-ANCE */ | |
+ 06,'a','r',0200+'a','n','c', /* AR-ANCE */ | |
+ 05,0200+'n','a','n','c', /* -NANCE */ | |
+ 07,0200+'b','a','l',0200+'a','n','c', /* -BAL-ANCE */ | |
+ 05,'i',0200+'a','n','c', /* I-ANCE */ | |
+ 07,0200+'j','u','s',0200+'t','i','c', /* -JUS-TICE */ | |
+ 05,0200+'s','t','i','c', /* -STICE */ | |
+ 06,0200+'n','o','v',0200+'i','c', /* NOV-ICE */ | |
+ 04,0200+'v','i','c', /* -VICE */ | |
+ 05,0200+'p','i','e','c', /* -PIECE */ | |
+ 05,0200+'p','l','a','c', /* -PLACE */ | |
+ 0340+01, /* /E */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar suff[] = { | |
+ 03,0200+'o','f', /* -OFF */ | |
+ 05,0200+'p','r','o','o', /* -PROOF */ | |
+ 04,0200+'s','e','l', /* -SELF */ | |
+ 03,0200+'r','i', /* -RIF */ | |
+ 040+04,0200+'l','i','e', /* -LIEF */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufg[] = { | |
+ 03,0200+'l','o', /* -LOG */ | |
+ 04,0200+'l','o','n', /* -LONG */ | |
+ 05,'t',0200+'t','i','n', /* T-TING */ | |
+ 06,0200+'s','t','r','i','n', /* -STRING */ | |
+ 05,'r',0200+'r','i','n', /* R-RING */ | |
+ 05,'p',0200+'p','i','n', /* P-PING */ | |
+ 05,'n',0200+'n','i','n', /* N-NING */ | |
+ 05,'m',0200+'m','i','n', /* M-MING */ | |
+ 05,'l',0200+'l','i','n', /* L-LING */ | |
+ 05,0200+'z','l','i','n', /* -ZLING */ | |
+ 05,0200+'t','l','i','n', /* -TLING */ | |
+ 040+05,'s',0200+'l','i','n', /* S-LING */ | |
+ 05,'r',0200+'l','i','n', /* R-LING */ | |
+ 05,0200+'p','l','i','n', /* -PLING */ | |
+ 06,'n',0200+'k','l','i','n', /* N-KLING */ | |
+ 05,'k',0200+'l','i','n', /* K-LING */ | |
+ 05,0200+'g','l','i','n', /* -GLING */ | |
+ 05,0200+'f','l','i','n', /* -FLING */ | |
+ 05,0200+'d','l','i','n', /* -DLING */ | |
+ 05,0200+'c','l','i','n', /* -CLING */ | |
+ 05,0200+'b','l','i','n', /* -BLING */ | |
+ 06,'y',0200+'t','h','i','n', /* Y-THING */ | |
+ 07,'e','e','t','h',0200+'i','n', /* EETH-ING */ | |
+ 06,'e',0200+'t','h','i','n', /* E-THING */ | |
+ 05,'g',0200+'g','i','n', /* G-GING */ | |
+ 05,'d',0200+'d','i','n', /* D-DING */ | |
+ 05,'b',0200+'b','i','n', /* B-BING */ | |
+ 03,0200+'i','n', /* -ING */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufh[] = { | |
+ 05,0200+'m','o','u','t', /* -MOUTH */ | |
+ 05,0200+'w','o','r','t', /* -WORTH */ | |
+ 04,0200+'w','i','t', /* -WITH */ | |
+ 05,'t',0200+'t','i','s', /* T-TISH */ | |
+ 05,'e',0200+'t','i','s', /* E-TISH */ | |
+ 05,'p',0200+'p','i','s', /* P-PISH */ | |
+ 05,'r',0200+'n','i','s', /* R-NISH */ | |
+ 05,'n',0200+'n','i','s', /* N-NISH */ | |
+ 05,0200+'p','l','i','s', /* -PLISH */ | |
+ 05,0200+'g','u','i','s', /* -GUISH */ | |
+ 05,0200+'g','l','i','s', /* -GLISH */ | |
+ 05,'b',0200+'l','i','s', /* B-LISH */ | |
+ 05,'g',0200+'g','i','s', /* G-GISH */ | |
+ 05,'d',0200+'d','i','s', /* D-DISH */ | |
+ 03,0200+'i','s', /* -ISH */ | |
+ 05,0200+'g','r','a','p', /* -GRAPH */ | |
+ 07,0200+'b','o','r',0200+'o','u','g', /* -BOR-OUGH */ | |
+ 05,0200+'b','u','r','g', /* -BURGH */ | |
+ 04,0200+'v','i','c', /* -VICH */ | |
+ 03,0200+'n','a', /* -NAH */ | |
+ 03,0200+'l','a', /* -LAH */ | |
+ 04,0200+'m','i',0200+'a', /* -MI-AH */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufi[] = { | |
+ 03,0200+'t','r', /* -TRI */ | |
+ 03,0200+'c','h', /* -CHI */ | |
+ 0200+03,'i','f', /* IF-I */ | |
+ 0200+03,'e','d', /* ED-I */ | |
+ 05,0200+'a','s','c','i', /* -ASCII */ | |
+ 04,0200+'s','e','m', /* -SEMI */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufk[] = { | |
+ 04,0200+'w','o','r', /* -WORK */ | |
+ 04,0200+'m','a','r', /* -MARK */ | |
+ 04,0200+'b','o','o', /* -BOOK */ | |
+ 04,0200+'w','a','l', /* -WALK */ | |
+ 05,0200+'c','r','a','c', /* -CRACK */ | |
+ 04,0200+'b','a','c', /* -BACK */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufl[] = { | |
+ 03,0200+'f','u', /* -FUL */ | |
+ 05,'s',0200+'w','e','l', /* S-WELL */ | |
+ 04,0200+'t','e','l', /* -TELL */ | |
+ 05,0200+'s','h','e','l', /* -SHELL */ | |
+ 05,0200+'s','t','a','l', /* -STALL */ | |
+ 04,'s',0200+'t','a', /* S-TAL */ | |
+ 04,0200+'b','a','l', /* -BALL */ | |
+ 04,0200+'c','a','l', /* -CALL */ | |
+ 03,'v',0200+'e', /* V-EL */ | |
+ 03,'u',0200+'e', /* U-EL */ | |
+ 03,'k',0200+'e', /* K-EL */ | |
+ 04,'t','h',0200+'e', /* TH-EL */ | |
+ 05,'t','c','h',0200+'e', /* TCH-EL */ | |
+ 03,'a',0200+'e', /* A-EL */ | |
+ 0140+04,0200+'q','u','a', /* /QUAL */ | |
+ 040+03,'u',0200+'a', /* U-AL */ | |
+ 03,0200+'t','a', /* -TAL */ | |
+ 04,'u','r',0200+'a', /* UR-AL */ | |
+ 040+05,'g',0200+'o',0200+'n','a', /* G-O-NAL */ | |
+ 04,'o','n',0200+'a', /* ON-AL */ | |
+ 03,0200+'n','a', /* -NAL */ | |
+ 04,0200+'t','i','a', /* -TIAL */ | |
+ 04,0200+'s','i','a', /* -SIAL */ | |
+ 040+05,0200+'t','r','i',0200+'a', /* -TRI-AL */ | |
+ 04,'r','i',0200+'a', /* RI-AL */ | |
+ 04,0200+'n','i',0200+'a', /* -NI-AL */ | |
+ 04,0200+'d','i',0200+'a', /* -DI-AL */ | |
+ 04,0200+'c','i','a', /* -CIAL */ | |
+ 03,0200+'g','a', /* -GAL */ | |
+ 04,0200+'m','e','a', /* -MEAL */ | |
+/* 040+04,0200+'r','e',0200+'a', /* -RE-AL */ | |
+ 040+04,0200+'r','e','a', /* -REAL */ | |
+ 06,'c',0200+'t','i',0200+'c','a', /* C-TI-CAL */ | |
+ 05,0200+'s','i',0200+'c','a', /* -SI-CAL */ | |
+ 04,0200+'i',0200+'c','a', /* -I-CAL */ | |
+ 03,0200+'c','a', /* -CAL */ | |
+ 03,0200+'b','a', /* -BAL */ | |
+ 06,0200+'n','o',0200+'m','i',0200+'a', /* -NO-MI-AL */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufm[] = { | |
+ 03,0200+'n','u', /* -NUM */ | |
+ 05,'o',0200+'r','i',0200+'u', /* O-RI-UM */ | |
+ 040+03,'i',0200+'u', /* I-UM */ | |
+ 040+03,'e',0200+'u', /* E-UM */ | |
+ 05,'i','v',0200+'i','s', /* IV-ISM */ | |
+ 04,0200+'t','i','s', /* -TISM */ | |
+ 05,'i',0200+'m','i','s', /* I-MISM */ | |
+ 05,'a','l',0200+'i','s', /* AL-ISM */ | |
+ 040+04,'e',0200+'i','s', /* E-ISM */ | |
+ 040+04,'a',0200+'i','s', /* A-ISM */ | |
+ 04,0200+'r','o','o', /* -ROOM */ | |
+ 03,0200+'d','o', /* -DOM */ | |
+ 03,0200+'h','a', /* -HAM */ | |
+ 06,0200+'a',0200+'r','i','t','h', /* -A-RITHM */ | |
+ 05,0200+'r','i','t','h', /* -RITHM */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufn[] = { | |
+ 05,0200+'k','n','o','w', /* -KNOWN */ | |
+ 04,0200+'t','o','w', /* -TOWN */ | |
+ 04,0200+'d','o','w', /* -DOWN */ | |
+ 04,0200+'t','u','r', /* -TURN */ | |
+ 05,0200+'s','p','o','o', /* -SPOON */ | |
+ 04,0200+'n','o','o', /* -NOON */ | |
+ 04,0200+'m','o','o', /* -MOON */ | |
+ 011,'a','l',0200+'i',0200+'z','a',0200+'t','i','o', /* AL-I-ZA-… | |
+ 07,0200+'i',0200+'z','a',0200+'t','i','o', /* -I-ZA-TION */ | |
+ 07,'l',0200+'i',0200+'a',0200+'t','i','o', /* L-I-A-TION */ | |
+ 04,0200+'t','i','o', /* -TION */ | |
+ 040+05,'s',0200+'s','i','o', /* S-SION */ | |
+ 04,0200+'s','i','o', /* -SION */ | |
+ 04,'n',0200+'i','o', /* N-ION */ | |
+ 04,0200+'g','i','o', /* -GION */ | |
+ 04,0200+'c','i','o', /* -CION */ | |
+ 03,0200+'c','o', /* -CON */ | |
+ 05,0200+'c','o','l','o', /* -COLON */ | |
+ 03,0200+'t','o', /* -TON */ | |
+ 04,'i','s',0200+'o', /* IS-ON */ | |
+ 03,0200+'s','o', /* -SON */ | |
+ 03,0200+'r','i', /* -RIN */ | |
+ 03,0200+'p','i', /* -PIN */ | |
+ 03,0200+'n','i', /* -NIN */ | |
+ 03,0200+'m','i', /* -MIN */ | |
+ 03,0200+'l','i', /* -LIN */ | |
+ 03,0200+'k','i', /* -KIN */ | |
+ 05,0200+'s','t','e','i', /* -STEIN */ | |
+ 04,0200+'t','a','i', /* -TAIN */ | |
+ 05,'g','h','t',0200+'e', /* GHT-EN */ | |
+ 05,0200+'w','o','m',0200+'e', /* -WOM-EN */ | |
+ 03,0200+'m','e', /* -MEN */ | |
+ 04,'o',0200+'k','e', /* O-KEN */ | |
+ 03,'k',0200+'e', /* K-EN */ | |
+ 04,0200+'t','e','e', /* -TEEN */ | |
+ 04,0200+'s','e','e', /* -SEEN */ | |
+ 040+03,0200+'s','a', /* -SAN */ | |
+ 05,0200+'w','o','m',0200+'a', /* -WOM-AN */ | |
+ 03,0200+'m','a', /* -MAN */ | |
+ 04,0200+'t','i','a', /* -TIAN */ | |
+ 04,0200+'s','i','a', /* -SIAN */ | |
+ 040+04,'e',0200+'i','a', /* E-IAN */ | |
+ 04,0200+'c','i','a', /* -CIAN */ | |
+ 0300+03,'i','a', /* IA/N */ | |
+ 05,0200+'c','l','e','a', /* -CLEAN */ | |
+ 04,0200+'m','e','a', /* -MEAN */ | |
+ 040+03,'e',0200+'a', /* E-AN */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufo[] = { | |
+ 05,0200+'m','a','c',0200+'r', /* -MAC-RO */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufp[] = { | |
+ 05,0200+'g','r','o','u', /* -GROUP */ | |
+ 02,0200+'u', /* -UP */ | |
+ 04,0200+'s','h','i', /* -SHIP */ | |
+ 04,0200+'k','e','e', /* -KEEP */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufr[] = { | |
+ 04,0200+'z','a','r', /* -ZARR */ | |
+ 0300+02,'r', /* R/R */ | |
+ 03,0200+'t','o', /* -TOR */ | |
+ 040+03,0200+'s','o', /* -SOR */ | |
+ 040+04,0200+'r','i',0200+'o', /* -RI-OR */ | |
+ 04,'i','z',0200+'e', /* IZ-ER */ | |
+ 05,0200+'c','o','v',0200+'e', /* -COV-ER */ | |
+ 04,0200+'o','v','e', /* -OVER */ | |
+ 04,0200+'e','v',0200+'e', /* -EV-ER */ | |
+ 8,0200+'c','o','m',0200+'p','u','t',0200+'e', /* -COM-PUT-ER */ | |
+ 040+05,'u','s',0200+'t','e', /* US-TER */ | |
+ 05,'o','s','t',0200+'e', /* OST-ER */ | |
+ 040+05,0200+'a','c',0200+'t','e', /* -AC-TER */ | |
+ 06,0200+'w','r','i','t',0200+'e', /* -WRIT-ER */ | |
+ 040+05,'i','s',0200+'t','e', /* IS-TER */ | |
+ 040+05,'e','s',0200+'t','e', /* ES-TER */ | |
+ 040+05,'a','s',0200+'t','e', /* AS-TER */ | |
+ 04,0200+'s','t','e', /* -STER */ | |
+ 05,'a','r',0200+'t','e', /* AR-TER */ | |
+ 04,'r','t',0200+'e', /* RT-ER */ | |
+ 040+05,'m',0200+'e',0200+'t','e', /* M-E-TER */ | |
+ 05,0200+'w','a',0200+'t','e', /* -WA-TER */ | |
+ 03,'r',0200+'e', /* R-ER */ | |
+ 04,'o','p',0200+'e', /* OP-ER */ | |
+ 05,0200+'p','a',0200+'p','e', /* -PA-PER */ | |
+ 04,'w','n',0200+'e', /* WN-ER */ | |
+ 040+04,'s',0200+'n','e', /* S-NER */ | |
+ 04,'o','n',0200+'e', /* ON-ER */ | |
+ 04,'r','m',0200+'e', /* RM-ER */ | |
+ 03,0200+'m','e', /* -MER */ | |
+ 04,'l','l',0200+'e', /* LL-ER */ | |
+ 05,'d',0200+'d','l','e', /* D-DLER */ | |
+ 04,0200+'b','l','e', /* -BLER */ | |
+ 03,'k',0200+'e', /* K-ER */ | |
+ 05,'n',0200+'t','h','e', /* N-THER */ | |
+ 06,0200+'f','a',0200+'t','h','e', /* -FA-THER */ | |
+ 06,'e','i',0200+'t','h','e', /* EI-THER */ | |
+ 04,'t','h',0200+'e', /* TH-ER */ | |
+ 04,'s','h',0200+'e', /* SH-ER */ | |
+ 04,0200+'p','h','e', /* -PHER */ | |
+ 04,'c','h',0200+'e', /* CH-ER */ | |
+ 04,'d','g',0200+'e', /* DG-ER */ | |
+ 04,'r','d',0200+'e', /* RD-ER */ | |
+ 06,'o','u','n','d',0200+'e', /* OUND-ER */ | |
+ 04,'l','d',0200+'e', /* LD-ER */ | |
+ 04,'i','d',0200+'e', /* ID-ER */ | |
+ 05,0200+'d','u','c',0200+'e', /* -DUC-ER */ | |
+ 04,'n','c',0200+'e', /* NC-ER */ | |
+ 0100+02, 0200+'e', /* /ER */ | |
+ 03,0200+'s','a', /* -SAR */ | |
+ 040+06,'a','c',0200+'u',0200+'l','a', /* AC-U-LAR */ | |
+ 040+06,'e','c',0200+'u',0200+'l','a', /* EC-U-LAR */ | |
+ 040+06,'i','c',0200+'u',0200+'l','a', /* IC-U-LAR */ | |
+ 040+06,'e','g',0200+'u',0200+'l','a', /* EG-U-LAR */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufs[] = { | |
+ 040+04,'u',0200+'o','u', /* U-OUS */ | |
+ 05,0200+'t','i','o','u', /* -TIOUS */ | |
+ 05,0200+'g','i','o','u', /* -GIOUS */ | |
+ 05,0200+'c','i','o','u', /* -CIOUS */ | |
+ 040+04,'i',0200+'o','u', /* I-OUS */ | |
+ 05,0200+'g','e','o','u', /* -GEOUS */ | |
+ 05,0200+'c','e','o','u', /* -CEOUS */ | |
+ 04,'e',0200+'o','u', /* E-OUS */ | |
+ 0140+02,0200+'u', /* /US */ | |
+ 04,0200+'n','e','s', /* -NESS */ | |
+ 04,0200+'l','e','s', /* -LESS */ | |
+ 0140+02,0200+'s', /* /SS */ | |
+ 040+05,'p',0200+'o',0200+'l','i', /* P-O-LIS */ | |
+ 0140+02,0200+'i', /* /IS */ | |
+ 0100+03,0200+'x','e', /* X/ES */ | |
+ 0100+03,0200+'s','e', /* S/ES */ | |
+ 0100+04,'s','h',0200+'e', /* SH/ES */ | |
+ 0100+04,'c','h',0200+'e', /* CH/ES */ | |
+ 0300+01, /* /S */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar suft[] = { | |
+ 05,0200+'l','i','m',0200+'i', /* -LIM-IT */ | |
+ 06,'i','o','n',0200+'i','s', /* ION-IST */ | |
+ 05,'i','n',0200+'i','s', /* IN-IST */ | |
+ 05,'a','l',0200+'i','s', /* AL-IST */ | |
+ 06,'l',0200+'o',0200+'g','i','s', /* L-O-GIST */ | |
+ 05,'h','t',0200+'e','s', /* HT-EST */ | |
+ 04,'i',0200+'e','s', /* I-EST */ | |
+ 05,'g',0200+'g','e','s', /* G-GEST */ | |
+ 04,'g',0200+'e','s', /* G-EST */ | |
+ 05,'d',0200+'d','e','s', /* D-DEST */ | |
+ 04,'d',0200+'e','s', /* D-EST */ | |
+ 04,0200+'c','a','s', /* -CAST */ | |
+ 05,0200+'h','e','a','r', /* -HEART */ | |
+ 04,0200+'f','o','o', /* -FOOT */ | |
+ 03,'i',0200+'o', /* I-OT */ | |
+ 05,0200+'f','r','o','n', /* -FRONT */ | |
+ 05,0200+'p','r','i','n', /* -PRINT */ | |
+ 04,0200+'m','e','n', /* -MENT */ | |
+ 05,0200+'c','i','e','n', /* -CIENT */ | |
+ 04,'i',0200+'a','n', /* I-ANT */ | |
+ 06,0200+'w','r','i','g','h', /* -WRIGHT */ | |
+ 06,0200+'b','r','i','g','h', /* -BRIGHT */ | |
+ 06,0200+'f','l','i','g','h', /* -FLIGHT */ | |
+ 06,0200+'w','e','i','g','h', /* -WEIGHT */ | |
+ 05,0200+'s','h','i','f', /* -SHIFT */ | |
+ 05,0200+'c','r','a','f', /* -CRAFT */ | |
+ 040+04,'d','g',0200+'e', /* DG-ET */ | |
+ 04,0200+'g','o','a', /* -GOAT */ | |
+ 04,0200+'c','o','a', /* -COAT */ | |
+ 04,0200+'b','o','a', /* -BOAT */ | |
+ 04,0200+'w','h','a', /* -WHAT */ | |
+ 04,0200+'c','u','i', /* -CUIT */ | |
+ 00 | |
+}; | |
+ | |
+static Uchar sufy[] = { | |
+ 040+04,'e','s',0200+'t', /* ES-TY */ | |
+ 040+05,'q','u','i',0200+'t', /* QUI-TY */ | |
+ 04,0200+'t','i',0200+'t', /* -TI-TY */ | |
+ 040+05,'o','s',0200+'i',0200+'t', /* OS-I-TY */ | |
+ 04,0200+'s','i',0200+'t', /* -SI-TY */ | |
+ 05,'i','n',0200+'i',0200+'t', /* IN-I-TY */ | |
+ 04,'n','i',0200+'t', /* NI-TY */ | |
+ 040+010,'f','a',0200+'b','i','l',0200+'i',0200+'t', /* FA-BIL-I… | |
+ 010,0200+'c','a',0200+'b','i','l',0200+'i',0200+'t', /* -CA-BIL… | |
+ 010,0200+'p','a',0200+'b','i','l',0200+'i',0200+'t', /* -PA-BIL… | |
+ 06,0200+'b','i','l',0200+'i',0200+'t', /* -BIL-I-TY */ | |
+ 03,'i',0200+'t', /* I-TY */ | |
+ 04,0200+'b','u','r', /* -BUR-Y */ | |
+ 04,0200+'t','o',0200+'r', /* -TO-RY */ | |
+ 05,0200+'q','u','a','r', /* -QUAR-Y */ | |
+ 040+04,'u',0200+'a','r', /* U-ARY */ | |
+ 07,0200+'m','e','n',0200+'t','a',0200+'r', /* -MEN-TA-RY */ | |
+ 06,'i','o','n',0200+'a','r', /* ION-ARY */ | |
+ 04,'i',0200+'a','r', /* I-ARY */ | |
+ 04,'n',0200+'o',0200+'m', /* N-O-MY */ | |
+ 03,0200+'p','l', /* -PLY */ | |
+ 04,'g',0200+'g','l', /* G-GLY */ | |
+ 05,0200+'p','a',0200+'b','l', /* -PA-BLY */ | |
+ 05,'f','a',0200+'b','l', /* FA-BLY */ | |
+ 05,0200+'c','a',0200+'b','l', /* -CA-BLY */ | |
+ 04,0200+'a','b','l', /* -ABLY */ | |
+ 03,0200+'b','l', /* -BLY */ | |
+ 02,0200+'l', /* -LY */ | |
+ 03,0200+'s','k', /* -SKY */ | |
+ 040+06,'g',0200+'r','a',0200+'p','h', /* G-RA-PHY */ | |
+ 04,'l',0200+'o',0200+'g', /* L-O-GY */ | |
+ 02,0200+'f', /* -FY */ | |
+ 03,0200+'n','e', /* -NEY */ | |
+ 03,0200+'l','e', /* -LEY */ | |
+ 04,'c','k',0200+'e', /* CK-EY */ | |
+ 03,0200+'k','e', /* -KEY */ | |
+ 04,0200+'b','o','d', /* -BODY */ | |
+ 05,0200+'s','t','u','d', /* -STUDY */ | |
+ 0340+04,'e','e','d', /* EEDY */ | |
+ 02,0200+'b', /* -BY */ | |
+ 03,0200+'w','a', /* -WAY */ | |
+ 03,0200+'d','a', /* -DAY */ | |
+ 00 | |
+}; | |
+ | |
+Uchar *suftab[] = { | |
+ sufa, | |
+ 0, | |
+ sufc, | |
+ sufd, | |
+ sufe, | |
+ suff, | |
+ sufg, | |
+ sufh, | |
+ sufi, | |
+ 0, | |
+ sufk, | |
+ sufl, | |
+ sufm, | |
+ sufn, | |
+ sufo, | |
+ sufp, | |
+ 0, | |
+ sufr, | |
+ sufs, | |
+ suft, | |
+ 0, | |
+ 0, | |
+ 0, | |
+ 0, | |
+ sufy, | |
+ 0 | |
+}; | |
diff --git a/troff/t10.c b/troff/t10.c | |
@@ -0,0 +1,513 @@ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+/* | |
+ * troff10.c | |
+ * | |
+ * typesetter interface | |
+ */ | |
+ | |
+int vpos = 0; /* absolute vertical position on page */ | |
+int hpos = 0; /* ditto horizontal */ | |
+ | |
+extern Font fonts[MAXFONTS+1]; | |
+ | |
+int Inch; | |
+int Hor; | |
+int Vert; | |
+int Unitwidth; | |
+int nfonts; | |
+ | |
+ | |
+ | |
+void t_ptinit(void) | |
+{ | |
+ int i; | |
+ char buf[100], *p; | |
+ | |
+ hmot = t_hmot; | |
+ makem = t_makem; | |
+ setabs = t_setabs; | |
+ setch = t_setch; | |
+ sethl = t_sethl; | |
+ setht = t_setht; | |
+ setslant = t_setslant; | |
+ vmot = t_vmot; | |
+ xlss = t_xlss; | |
+ findft = t_findft; | |
+ width = t_width; | |
+ mchbits = t_mchbits; | |
+ ptlead = t_ptlead; | |
+ ptout = t_ptout; | |
+ ptpause = t_ptpause; | |
+ setfont = t_setfont; | |
+ setps = t_setps; | |
+ setwd = t_setwd; | |
+ | |
+ /* open table for device, */ | |
+ /* read in resolution, size info, font info, etc., set params */ | |
+ if ((p = getenv("TYPESETTER")) != 0) | |
+ strcpy(devname, p); | |
+ if (termtab[0] == 0) | |
+ strcpy(termtab, DWBfontdir); | |
+ if (fontdir[0] == 0) | |
+ strcpy(fontdir, DWBfontdir); | |
+ if (devname[0] == 0) | |
+ strcpy(devname, TDEVNAME); | |
+ hyf = 1; | |
+ lg = 1; | |
+ | |
+ sprintf(buf, "/dev%s/DESC", devname); | |
+ strcat(termtab, buf); | |
+ if (getdesc(termtab) < 0) { | |
+ ERROR "can't open DESC file %s", termtab WARN; | |
+ done3(1); | |
+ } | |
+ if (!ascii) { | |
+ OUT "x T %s\n", devname PUT; | |
+ OUT "x res %d %d %d\n", Inch, Hor, Vert PUT; | |
+ OUT "x init\n" PUT; | |
+ } | |
+ for (i = 1; i <= nfonts; i++) | |
+ setfp(i, fontlab[i], (char *) 0, 0); | |
+ sps = EM/3; /* space size */ | |
+ ics = EM; /* insertion character space */ | |
+ for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++) | |
+ tabtab[i] = DTAB * (i + 1); | |
+ tabtab[NTAB-1] = 0; | |
+ pl = 11 * INCH; /* paper length */ | |
+ po = PO; /* page offset */ | |
+ spacesz = SS; | |
+ lss = lss1 = VS; | |
+ ll = ll1 = lt = lt1 = LL; | |
+ t_specnames(); /* install names like "hyphen", etc. */ | |
+} | |
+ | |
+void t_specnames(void) | |
+{ | |
+ int i; | |
+ | |
+ for (i = 0; spnames[i].n; i++) | |
+ *spnames[i].n = chadd(spnames[i].v, Troffchar, Install); | |
+} | |
+ | |
+void t_ptout(Tchar i) | |
+{ | |
+ int dv; | |
+ Tchar *k; | |
+ int temp, a, b; | |
+ int diff; | |
+ | |
+ if (cbits(i) != '\n') { | |
+ if (olinep >= oline + olnsize) { | |
+ diff = olinep - oline; | |
+ olnsize += OLNSIZE; | |
+ if ((oline = (Tchar *)realloc((char *)oline, olnsize *… | |
+ if (diff && olinep) | |
+ olinep = oline + diff; | |
+ } else { | |
+ ERROR "Output line overflow." WARN; | |
+ done(2); | |
+ } | |
+ } | |
+ *olinep++ = i; | |
+ return; | |
+ } | |
+ if (olinep == oline) { | |
+ lead += lss; | |
+ return; | |
+ } | |
+ | |
+ hpos = po; /* ??? */ | |
+ esc = 0; /* ??? */ | |
+ ptesc(); /* the problem is to get back to the left end of the l… | |
+ dv = 0; | |
+ for (k = oline; k < olinep; k++) { | |
+ if (ismot(*k) && isvmot(*k)) { | |
+ temp = absmot(*k); | |
+ if (isnmot(*k)) | |
+ temp = -temp; | |
+ dv += temp; | |
+ } | |
+ } | |
+ if (dv) { | |
+ vflag++; | |
+ *olinep++ = makem(-dv); | |
+ vflag = 0; | |
+ } | |
+ | |
+ b = dip->blss + lss; | |
+ lead += dip->blss + lss; | |
+ dip->blss = 0; | |
+ for (k = oline; k < olinep; ) | |
+ k += ptout0(k); /* now passing a pointer! */ | |
+ olinep = oline; | |
+ lead += dip->alss; | |
+ a = dip->alss; | |
+ dip->alss = 0; | |
+ /* | |
+ OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT; | |
+*/ | |
+ OUT "n%d %d\n", b, a PUT; /* be nice to chuck */ | |
+} | |
+ | |
+int ptout0(Tchar *pi) | |
+{ | |
+ int j, k, w; | |
+ int z, dx, dy, dx2, dy2, n; | |
+ Tchar i; | |
+ int outsize; /* size of object being printed */ | |
+ | |
+ w = 0; | |
+ outsize = 1; /* default */ | |
+ i = *pi; | |
+ k = cbits(i); | |
+ if (ismot(i)) { | |
+ j = absmot(i); | |
+ if (isnmot(i)) | |
+ j = -j; | |
+ if (isvmot(i)) | |
+ lead += j; | |
+ else | |
+ esc += j; | |
+ return(outsize); | |
+ } | |
+ if (k == CHARHT) { | |
+ xpts = fbits(i); /* sneaky, font bits as size bits */ | |
+ if (xpts != mpts) | |
+ ptps(); | |
+ OUT "x H %ld\n", sbits(i) PUT; | |
+ return(outsize); | |
+ } | |
+ if (k == SLANT) { | |
+ OUT "x S %ld\n", sfbits(i)-180 PUT; | |
+ return(outsize); | |
+ } | |
+ if (k == WORDSP) { | |
+ oput('w'); | |
+ return(outsize); | |
+ } | |
+ if (sfbits(i) == oldbits) { | |
+ xfont = pfont; | |
+ xpts = ppts; | |
+ } else | |
+ xbits(i, 2); | |
+ if (k == XON) { | |
+ extern int xon; | |
+ ptflush(); /* guarantee that everything is out */ | |
+ if (esc) | |
+ ptesc(); | |
+ if (xfont != mfont) | |
+ ptfont(); | |
+ if (xpts != mpts) | |
+ ptps(); | |
+ if (lead) | |
+ ptlead(); | |
+ OUT "x X " PUT; | |
+ xon++; | |
+ for (j = 1; cbits(pi[j]) != XOFF; j++) | |
+ outascii(pi[j]); | |
+ oput('\n'); | |
+ xon--; | |
+ return j+1; | |
+ } | |
+ if (k < 040 && k != DRAWFCN) | |
+ return(outsize); | |
+ j = z = 0; | |
+ if (k != DRAWFCN) { | |
+ if (widcache[k].fontpts == (xfont<<8) + xpts && !setwdf) { | |
+ w = widcache[k].width; | |
+ bd = 0; | |
+ cs = 0; | |
+ } else | |
+ w = getcw(k); | |
+ if (cs) { | |
+ if (bd) | |
+ w += (bd - 1) * HOR; | |
+ j = (cs - w) / 2; | |
+ w = cs - j; | |
+ if (bd) | |
+ w -= (bd - 1) * HOR; | |
+ } | |
+ if (iszbit(i)) { | |
+ if (cs) | |
+ w = -j; | |
+ else | |
+ w = 0; | |
+ z = 1; | |
+ } | |
+ } | |
+ esc += j; | |
+ if (xfont != mfont) | |
+ ptfont(); | |
+ if (xpts != mpts) | |
+ ptps(); | |
+ if (lead) | |
+ ptlead(); | |
+ /* put out the real character here */ | |
+ if (k == DRAWFCN) { | |
+ if (esc) | |
+ ptesc(); | |
+ w = 0; | |
+ dx = absmot(pi[3]); | |
+ if (isnmot(pi[3])) | |
+ dx = -dx; | |
+ dy = absmot(pi[4]); | |
+ if (isnmot(pi[4])) | |
+ dy = -dy; | |
+ switch (cbits(pi[1])) { | |
+ case DRAWCIRCLE: /* circle */ | |
+ OUT "D%c %d\n", DRAWCIRCLE, dx PUT; /* dx is di… | |
+ hpos += dx; | |
+ break; | |
+ case DRAWELLIPSE: | |
+ OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT; | |
+ hpos += dx; | |
+ break; | |
+ case DRAWBUILD: | |
+ k = cbits(pi[2]); | |
+ OUT "D%c %d ", DRAWBUILD, dx PUT; | |
+ if (k < ALPHABET) | |
+ OUT "%c\n", k PUT; | |
+ else | |
+ ptchname(k); | |
+ hpos += dx; | |
+ break; | |
+ case DRAWLINE: /* line */ | |
+ k = cbits(pi[2]); | |
+ OUT "D%c %d %d ", DRAWLINE, dx, dy PUT; | |
+ if (k < ALPHABET) | |
+ OUT "%c\n", k PUT; | |
+ else | |
+ ptchname(k); | |
+ hpos += dx; | |
+ vpos += dy; | |
+ break; | |
+ case DRAWARC: /* arc */ | |
+ dx2 = absmot(pi[5]); | |
+ if (isnmot(pi[5])) | |
+ dx2 = -dx2; | |
+ dy2 = absmot(pi[6]); | |
+ if (isnmot(pi[6])) | |
+ dy2 = -dy2; | |
+ OUT "D%c %d %d %d %d\n", DRAWARC, | |
+ dx, dy, dx2, dy2 PUT; | |
+ hpos += dx + dx2; | |
+ vpos += dy + dy2; | |
+ break; | |
+ | |
+ case 's': /* using 's' internally to avoid .tr ~ */ | |
+ pi[1] = '~'; | |
+ case DRAWSPLINE: /* spline */ | |
+ default: /* something else; copy it like spline */ | |
+ OUT "D%c %d %d", (char)cbits(pi[1]), dx, dy PUT; | |
+ hpos += dx; | |
+ vpos += dy; | |
+ if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN… | |
+ /* it was somehow defective */ | |
+ OUT "\n" PUT; | |
+ break; | |
+ } | |
+ for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) { | |
+ dx = absmot(pi[n]); | |
+ if (isnmot(pi[n])) | |
+ dx = -dx; | |
+ dy = absmot(pi[n+1]); | |
+ if (isnmot(pi[n+1])) | |
+ dy = -dy; | |
+ OUT " %d %d", dx, dy PUT; | |
+ hpos += dx; | |
+ vpos += dy; | |
+ } | |
+ OUT "\n" PUT; | |
+ break; | |
+ } | |
+ for (n = 3; cbits(pi[n]) != DRAWFCN; n++) | |
+ ; | |
+ outsize = n + 1; | |
+ } else if (k < ALPHABET) { | |
+ /* try to go faster and compress output */ | |
+ /* by printing nnc for small positive motion followed by c */ | |
+ /* kludgery; have to make sure set all the vars too */ | |
+ if (esc > 0 && esc < 100) { | |
+ oput(esc / 10 + '0'); | |
+ oput(esc % 10 + '0'); | |
+ oput(k); | |
+ hpos += esc; | |
+ esc = 0; | |
+ } else { | |
+ if (esc) | |
+ ptesc(); | |
+ oput('c'); | |
+ oput(k); | |
+ oput('\n'); | |
+ } | |
+ } else { | |
+ if (esc) | |
+ ptesc(); | |
+ ptchname(k); | |
+ } | |
+ if (bd) { | |
+ bd -= HOR; | |
+ if (esc += bd) | |
+ ptesc(); | |
+ if (k < ALPHABET) | |
+ OUT "c%c\n", k PUT; | |
+ else | |
+ ptchname(k); | |
+ if (z) | |
+ esc -= bd; | |
+ } | |
+ esc += w; | |
+ return(outsize); | |
+} | |
+ | |
+void ptchname(int k) | |
+{ | |
+ char *chn = chname(k); | |
+ | |
+ switch (chn[0]) { | |
+ case MBchar: | |
+ OUT "c%s\n", chn+1 PUT; /* \n not needed? */ | |
+ break; | |
+ case Number: | |
+ OUT "N%s\n", chn+1 PUT; | |
+ break; | |
+ case Troffchar: | |
+ OUT "C%s\n", chn+1 PUT; | |
+ break; | |
+ default: | |
+ ERROR "illegal char type %s", chn WARN; | |
+ break; | |
+ } | |
+} | |
+ | |
+void ptflush(void) /* get us to a clean output state */ | |
+{ | |
+ if (TROFF) { | |
+ /* ptesc(); but always H, no h */ | |
+ hpos += esc; | |
+ OUT "\nH%d\n", hpos PUT; | |
+ esc = 0; | |
+ ptps(); | |
+ ptfont(); | |
+ ptlead(); | |
+ } | |
+} | |
+ | |
+void ptps(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ i = xpts; | |
+ for (j = 0; i > (k = pstab[j]); j++) | |
+ if (!k) { | |
+ k = pstab[--j]; | |
+ break; | |
+ } | |
+ if (!ascii) | |
+ OUT "s%d\n", k PUT; /* really should put out string rep… | |
+ mpts = i; | |
+} | |
+ | |
+void ptfont(void) | |
+{ | |
+ mfont = xfont; | |
+ if (ascii) | |
+ return; | |
+ if (xfont > nfonts) { | |
+ ptfpcmd(0, fonts[xfont].longname, 0); /* Put the desire… | |
+ * fontcache of the filter */ | |
+ OUT "f0\n" PUT; /* make sure that it gets noticed */ | |
+ } else | |
+ OUT "f%d\n", xfont PUT; | |
+} | |
+ | |
+void ptfpcmd(int f, char *s, char *longname) | |
+{ | |
+ if (f > nfonts) /* a bit risky? */ | |
+ f = 0; | |
+ if (longname) { | |
+ OUT "x font %d %s %s\n", f, s, longname PUT; | |
+ } else { | |
+ OUT "x font %d %s\n", f, s PUT; | |
+ } | |
+/* OUT "f%d\n", xfont PUT; /* need this for buggy version of ado… | |
+ /* which apparently believes that x font means… | |
+ /* to set the font, not just the position. */ | |
+} | |
+ | |
+void t_ptlead(void) | |
+{ | |
+ vpos += lead; | |
+ if (!ascii) | |
+ OUT "V%d\n", vpos PUT; | |
+ lead = 0; | |
+} | |
+ | |
+void ptesc(void) | |
+{ | |
+ hpos += esc; | |
+ if (!ascii) | |
+ if (esc > 0) { | |
+ oput('h'); | |
+ if (esc>=10 && esc<100) { | |
+ oput(esc/10 + '0'); | |
+ oput(esc%10 + '0'); | |
+ } else | |
+ OUT "%d", esc PUT; | |
+ } else | |
+ OUT "H%d\n", hpos PUT; | |
+ esc = 0; | |
+} | |
+ | |
+void ptpage(int n) /* called at end of each output page, we hope */ | |
+{ | |
+ int i; | |
+ | |
+ if (NROFF) | |
+ return; | |
+ ptlead(); | |
+ vpos = 0; | |
+ if (ascii) | |
+ return; | |
+ OUT "p%d\n", n PUT; /* new page */ | |
+ for (i = 0; i <= nfonts; i++) | |
+ if (fontlab[i]) { | |
+ if (fonts[i].truename) | |
+ OUT "x font %d %s %s\n", i, fonts[i].longname,… | |
+ else | |
+ OUT "x font %d %s\n", i, fonts[i].longname PUT; | |
+ } | |
+ ptps(); | |
+ ptfont(); | |
+} | |
+ | |
+void pttrailer(void) | |
+{ | |
+ if (TROFF) | |
+ OUT "x trailer\n" PUT; | |
+} | |
+ | |
+void ptstop(void) | |
+{ | |
+ if (TROFF) | |
+ OUT "x stop\n" PUT; | |
+} | |
+ | |
+void t_ptpause(void) | |
+{ | |
+ if (ascii) | |
+ return; | |
+ ptlead(); | |
+ vpos = 0; | |
+ pttrailer(); | |
+ ptlead(); | |
+ OUT "x pause\n" PUT; | |
+ flusho(); | |
+ mpts = mfont = 0; | |
+ ptesc(); | |
+ esc = po; | |
+ hpos = vpos = 0; /* probably in wrong place */ | |
+} | |
diff --git a/troff/t11.c b/troff/t11.c | |
@@ -0,0 +1,260 @@ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+#define MAXCH NCHARS /* maximum number of global char na… | |
+char *chnames[MAXCH]; /* chnames[n-ALPHABET] -> name of char n */ | |
+int nchnames; /* number of Cxy names currently seen */ | |
+ | |
+#define MAXPS 100 /* max number of point sizes */ | |
+int pstab[MAXPS]; /* point sizes */ | |
+int nsizes; /* number in DESC */ | |
+ | |
+Font fonts[MAXFONTS+1]; /* font info + ptr to width info */ | |
+ | |
+ | |
+#define skipline(f) while (getc(f) != '\n') | |
+ | |
+#define eq(s1, s2) (strcmp(s1, s2) == 0) | |
+ | |
+int | |
+getdesc(char *name) | |
+{ | |
+ FILE *fin; | |
+ char cmd[100], s[100]; | |
+ int i, v; | |
+ | |
+ if ((fin = fopen(unsharp(name), "r")) == NULL) | |
+ return -1; | |
+ while (fscanf(fin, "%s", cmd) != EOF) { | |
+ if (strcmp(cmd, "res") == 0) { | |
+ fscanf(fin, "%d", &Inch); | |
+ } else if (strcmp(cmd, "hor") == 0) { | |
+ fscanf(fin, "%d", &Hor); | |
+ } else if (strcmp(cmd, "vert") == 0) { | |
+ fscanf(fin, "%d", &Vert); | |
+ } else if (strcmp(cmd, "unitwidth") == 0) { | |
+ fscanf(fin, "%d", &Unitwidth); | |
+ } else if (strcmp(cmd, "sizes") == 0) { | |
+ nsizes = 0; | |
+ while (fscanf(fin, "%d", &v) != EOF && v != 0 && nsize… | |
+ pstab[nsizes++] = v; | |
+ } else if (strcmp(cmd, "fonts") == 0) { | |
+ fscanf(fin, "%d", &nfonts); | |
+ for (i = 1; i <= nfonts; i++) { | |
+ fscanf(fin, "%s", s); | |
+ fontlab[i] = PAIR(s[0], s[1]); | |
+ } | |
+ } else if (strcmp(cmd, "charset") == 0) { /* add any na… | |
+ while (fscanf(fin, "%s", s) != EOF) | |
+ chadd(s, Troffchar, Install); | |
+ break; | |
+ } | |
+ /* else | |
+ just skip anything else */ | |
+ skipline(fin); | |
+ } | |
+ fclose(fin); | |
+ return 1; | |
+} | |
+ | |
+static int checkfont(char *name) | |
+{ /* in case it's not really a font description file */ | |
+ /* really paranoid, but consider \f. */ | |
+ FILE *fp; | |
+ char buf[300], buf2[300]; | |
+ int i, status = -1; | |
+ | |
+ if ((fp = fopen(unsharp(name), "r")) == NULL) | |
+ return -1; | |
+ for (i = 1; i <= 10; i++) { | |
+ if (fgets(buf, sizeof buf, fp) == NULL) | |
+ break; | |
+ sscanf(buf, "%s", buf2); | |
+ if (buf2[0] == '#') { | |
+ i--; | |
+ continue; | |
+ } | |
+ if (eq(buf2, "name") || eq(buf2, "fontname") || | |
+ eq(buf2, "special") || eq(buf2, "charset")) { | |
+ status = 1; | |
+ break; | |
+ } | |
+ } | |
+ fclose(fp); | |
+ return status; | |
+ | |
+} | |
+ | |
+int | |
+getfont(char *name, int pos) /* create width tab for font */ | |
+{ | |
+ FILE *fin; | |
+ Font *ftemp = &fonts[pos]; | |
+ Chwid chtemp[MAXCH]; | |
+ static Chwid chinit; | |
+ int i, nw, n, wid, kern, code, type; | |
+ char buf[100], ch[100], s1[100], s2[100], s3[100], cmd[300]; | |
+ | |
+ nw = code = 0; | |
+ /* fprintf(stderr, "read font %s onto %d\n", name, pos); */ | |
+ if (checkfont(name) == -1) | |
+ return -1; | |
+ if ((fin = fopen(unsharp(name), "r")) == NULL) | |
+ return -1; | |
+ for (i = 0; i < ALPHABET; i++) | |
+ chtemp[i] = chinit; /* zero out to begin with */ | |
+ ftemp->specfont = ftemp->ligfont = 0; | |
+ ftemp->defaultwidth = ftemp->spacewidth = Inch * Unitwidth / 72 / 3; /… | |
+ while (fscanf(fin, "%s", cmd) != EOF) { | |
+ if (strcmp(cmd, "name") == 0) | |
+ fscanf(fin, "%s", ftemp->longname); | |
+ else if (strcmp(cmd, "special") == 0) | |
+ ftemp->specfont = 1; | |
+ else if (strcmp(cmd, "ligatures") == 0) { | |
+ ftemp->ligfont = getlig(fin); | |
+ } else if (strcmp(cmd, "spacewidth") == 0) { | |
+ fscanf(fin, "%d", &ftemp->spacewidth); | |
+ } else if (strcmp(cmd, "defaultwidth") == 0) { | |
+ fscanf(fin, "%d", &ftemp->defaultwidth); | |
+ } else if (strcmp(cmd, "charset") == 0) { | |
+ wchar_t wc; | |
+ skipline(fin); | |
+ nw = ALPHABET; | |
+ while (fgets(buf, sizeof buf, fin) != NULL) { | |
+ sscanf(buf, "%s %s %s %s", ch, s1, s2, s3); | |
+ if (s1[0] != '"') { /* genuine new char… | |
+ sscanf(s1, "%d", &wid); | |
+ sscanf(s2, "%d", &kern); | |
+ code = strtol(s3, 0, 0); /* dec… | |
+ } | |
+ /* otherwise it's a synonym for prev character… | |
+ /* so leave previous values intact */ | |
+ | |
+ | |
+ /* decide what kind of alphabet it might come … | |
+ | |
+ | |
+ if (strlen(ch) == 1) { /* it's ascii */ | |
+ n = ch[0]; /* origin includes n… | |
+ chtemp[n].num = ch[0]; | |
+ } else if (ch[0] == '\\' && ch[1] == '0') { | |
+ n = strtol(ch+1, 0, 0); /* \0oc… | |
+ chtemp[n].num = n; | |
+#ifdef UNICODE | |
+ } else if (mbtowc(&wc, ch, strlen(ch)) > 1) { | |
+ chtemp[nw].num = chadd(ch, MBchar, In… | |
+ n = nw; | |
+ nw++; | |
+#endif /*UNICODE*/ | |
+ } else { | |
+ if (strcmp(ch, "---") == 0) { /* no na… | |
+ sprintf(ch, "%d", code); | |
+ type = Number; | |
+ } else | |
+ type = Troffchar; | |
+ chtemp[nw].num = chadd(ch, type, Insta… | |
+ n = nw; | |
+ nw++; | |
+ } | |
+ chtemp[n].wid = wid; | |
+ chtemp[n].kern = kern; | |
+ chtemp[n].code = code; | |
+ /*fprintf(stderr, "font %2.2s char %4.4s num %… | |
+ ftemp->longname, ch, n, wid, code); | |
+ */ | |
+ } | |
+ break; | |
+ } | |
+ skipline(fin); | |
+ } | |
+ fclose(fin); | |
+ chtemp[' '].wid = ftemp->spacewidth; /* width of space on this … | |
+ ftemp->nchars = nw; | |
+ if (ftemp->wp) | |
+ free(ftemp->wp); /* god help us if this wasn't allocate… | |
+ ftemp->wp = (Chwid *) malloc(nw * sizeof(Chwid)); | |
+ if (ftemp->wp == NULL) | |
+ return -1; | |
+ for (i = 0; i < nw; i++) | |
+ ftemp->wp[i] = chtemp[i]; | |
+/* | |
+ * printf("%d chars: ", nw); | |
+ * for (i = 0; i < nw; i++) | |
+ * if (ftemp->wp[i].num > 0 && ftemp->wp[i].num < ALPHABET) { | |
+ * printf("%c %d ", ftemp->wp[i].num, ftemp->wp[i].wid); | |
+ * else if (i >= ALPHABET) | |
+ * printf("%d (%s) %d ", ftemp->wp[i].num, | |
+ * chnames[ftemp->wp[i].num-ALPHABET], ftemp->w… | |
+ * } | |
+ * printf("\n"); | |
+ */ | |
+ return 1; | |
+} | |
+ | |
+int | |
+chadd(char *s, int type, int install) /* add s to global character name… | |
+{ /* or just look it up */ | |
+ | |
+ /* a temporary kludge: store the "type" as the first character */ | |
+ /* of the string, so we can remember from whence it came */ | |
+ | |
+ char *p; | |
+ int i; | |
+ | |
+/* fprintf(stderr, "into chadd %s %c %c\n", s, type, install); /* */ | |
+ for (i = 0; i < nchnames; i++) | |
+ if (type == chnames[i][0] && eq(s, chnames[i]+1)) /* +1 since … | |
+ break; | |
+/* fprintf(stderr, "i %d, nchnames %d\n", i, nchnames); /* */ | |
+ if (i < nchnames) /* found same type and bytes at posit… | |
+ return ALPHABET + i; | |
+ else if (install == Lookup) /* not found, and we were just look… | |
+ return -1; | |
+ | |
+ chnames[nchnames] = p = (char *) malloc(strlen(s)+1+1); /* type… | |
+ if (p == NULL) { | |
+ ERROR "out of space adding character %s", s WARN; | |
+ return LEFTHAND; | |
+ } | |
+ if (nchnames >= NCHARS - ALPHABET) { | |
+ ERROR "out of table space adding character %s", s WARN; | |
+ return LEFTHAND; | |
+ } | |
+ strcpy(chnames[nchnames]+1, s); | |
+ chnames[nchnames][0] = type; | |
+/* fprintf(stderr, "installed %c%s at %d\n", type, s, nchnames); /* */ | |
+ return nchnames++ + ALPHABET; | |
+} | |
+ | |
+char *chname(int n) /* return string for char with index n */ | |
+{ /* includes type char at front, to be peeled off else… | |
+ if (n >= ALPHABET && n < nchnames + ALPHABET) | |
+ return chnames[n-ALPHABET]; | |
+ else | |
+ return ""; | |
+} | |
+ | |
+int | |
+getlig(FILE *fin) /* pick up ligature list */ | |
+{ | |
+ int lig; | |
+ char temp[200]; | |
+ | |
+ lig = 0; | |
+ while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) { | |
+ if (strcmp(temp, "fi") == 0) | |
+ lig |= LFI; | |
+ else if (strcmp(temp, "fl") == 0) | |
+ lig |= LFL; | |
+ else if (strcmp(temp, "ff") == 0) | |
+ lig |= LFF; | |
+ else if (strcmp(temp, "ffi") == 0) | |
+ lig |= LFFI; | |
+ else if (strcmp(temp, "ffl") == 0) | |
+ lig |= LFFL; | |
+ else | |
+ fprintf(stderr, "illegal ligature %s ignored\n", temp); | |
+ } | |
+ return lig; | |
+} | |
diff --git a/troff/t6.c b/troff/t6.c | |
@@ -0,0 +1,889 @@ | |
+/* | |
+ * t6.c | |
+ * | |
+ * width functions, sizes and fonts | |
+ */ | |
+ | |
+#include "tdef.h" | |
+#include "fns.h" | |
+#include "ext.h" | |
+ | |
+int fontlab[MAXFONTS+1]; | |
+int cstab[MAXFONTS+1]; | |
+int ccstab[MAXFONTS+1]; | |
+int bdtab[MAXFONTS+1]; | |
+int sbold = 0; | |
+ | |
+int | |
+t_width(Tchar j) | |
+{ | |
+ int i, k; | |
+ | |
+ if (iszbit(j)) | |
+ return 0; | |
+ if (ismot(j)) { | |
+ if (isvmot(j)) | |
+ return(0); | |
+ k = absmot(j); | |
+ if (isnmot(j)) | |
+ k = -k; | |
+ return(k); | |
+ } | |
+ i = cbits(j); | |
+ if (i < ' ') { | |
+ if (i == '\b') | |
+ return(-widthp); | |
+ if (i == PRESC) | |
+ i = eschar; | |
+ else if (i == HX) | |
+ return(0); | |
+ } | |
+ if (i == ohc) | |
+ return(0); | |
+ i = trtab[i]; | |
+ if (i < ' ') | |
+ return(0); | |
+ if (sfbits(j) == oldbits) { | |
+ xfont = pfont; | |
+ xpts = ppts; | |
+ } else | |
+ xbits(j, 0); | |
+ if (i < nchnames + ALPHABET && widcache[i].fontpts == (xfont<<8) + xpt… | |
+ k = widcache[i].width; | |
+ else { | |
+ k = getcw(i); | |
+ if (bd) | |
+ k += (bd - 1) * HOR; | |
+ if (cs) | |
+ k = cs; | |
+ } | |
+ widthp = k; | |
+ return(k); | |
+} | |
+ | |
+/* | |
+ * clear width cache-- s means just space | |
+ */ | |
+void zapwcache(int s) | |
+{ | |
+ int i; | |
+ | |
+ if (s) { | |
+ widcache[' '].fontpts = 0; | |
+ return; | |
+ } | |
+ for (i=0; i<NWIDCACHE; i++) | |
+ widcache[i].fontpts = 0; | |
+} | |
+ | |
+int | |
+onfont(int n, int f) /* is char n on font f? */ | |
+{ | |
+ int i; | |
+ Font *fp = &fonts[f]; | |
+ Chwid *cp, *ep; | |
+ char *np; | |
+ | |
+ if (n < ALPHABET) { | |
+ if (fp->wp[n].num == n) /* ascii at front */ | |
+ return n; | |
+ else | |
+ return -1; | |
+ } | |
+ cp = &fp->wp[ALPHABET]; | |
+ ep = &fp->wp[fp->nchars]; | |
+ for ( ; cp < ep; cp++) /* search others */ | |
+ if (cp->num == n) | |
+ return cp - &fp->wp[0]; | |
+ /* maybe it was a \N... */ | |
+ np = chname(n); | |
+ if (*np == Number) { | |
+ i = atoi(np+1); /* sscanf(np+1, "%d", &i); */ | |
+ cp = &fp->wp[0]; | |
+ ep = &fp->wp[fp->nchars]; | |
+ for ( ; cp < ep; cp++) { /* search others */ | |
+ if (cp->code == i) | |
+ return cp - &fp->wp[0]; | |
+ } | |
+ return -2; /* a \N that doesn't have an entry */ | |
+ } | |
+ return -1; /* vanilla not found */ | |
+} | |
+ | |
+int | |
+getcw(int i) | |
+{ | |
+ int k, n, x; | |
+ Font *fp; | |
+ int nocache = 0; | |
+ if (i < ' ') | |
+ return 0; | |
+ bd = 0; | |
+ fp = &fonts[xfont]; | |
+ if (i == ' ') { /* a blank */ | |
+ k = (fp->spacewidth * spacesz + 6) / 12; | |
+ /* this nonsense because .ss cmd uses 1/36 em as its units */ | |
+ /* and default is 12 */ | |
+ } else if ((n = onfont(i, xfont)) >= 0) { /* on this font at n … | |
+ k = fp->wp[n].wid; | |
+ if (setwdf) | |
+ numtabp[CT].val |= fp->wp[n].kern; | |
+ } else if (n == -2) { /* \N with default width */ | |
+ | |
+ k = fp->defaultwidth; | |
+ } else { /* not on current font */ | |
+ nocache = 1; | |
+ k = fp->defaultwidth; /* default-size space */ | |
+ if (smnt) { | |
+ int ii, jj; | |
+ for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts … | |
+ if ((n = onfont(i, ii)) >= 0) { | |
+ k = fonts[ii].wp[n].wid; | |
+ if (xfont == sbold) | |
+ bd = bdtab[ii]; | |
+ if (setwdf) | |
+ numtabp[CT].val |= fonts[ii].w… | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ if (!bd) | |
+ bd = bdtab[xfont]; | |
+ if (cs = cstab[xfont]) { | |
+ nocache = 1; | |
+ if (ccs = ccstab[xfont]) | |
+ x = ccs; | |
+ else | |
+ x = xpts; | |
+ cs = (cs * EMPTS(x)) / 36; | |
+ } | |
+ /* was (k & BYTEMASK); since .wid is unsigned, should never happen */ | |
+ if (k < 0) | |
+ ERROR "can't happen: negative width %d in getcw %d\n", k, i WA… | |
+ k = (k * xpts + (Unitwidth / 2)) / Unitwidth; | |
+ if (nocache|bd) | |
+ widcache[i].fontpts = 0; | |
+ else { | |
+ widcache[i].fontpts = (xfont<<8) + xpts; | |
+ widcache[i].width = k; | |
+ } | |
+ return(k); | |
+ /* Unitwidth is Units/Point, where | |
+ /* Units is the fundamental digitization | |
+ /* of the character set widths, and | |
+ /* Point is the number of goobies in a point | |
+ /* e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6 | |
+ /* In effect, it's the size at which the widths | |
+ /* translate directly into units. | |
+ */ | |
+} | |
+ | |
+void xbits(Tchar i, int bitf) | |
+{ | |
+ int k; | |
+ | |
+ if(TROFF) { | |
+ xfont = fbits(i); | |
+ k = sbits(i); | |
+ if(k) { | |
+ xpts = pstab[k-1]; | |
+ oldbits = sfbits(i); | |
+ pfont = xfont; | |
+ ppts = xpts; | |
+ return; | |
+ } | |
+ switch(bitf) { | |
+ case 0: | |
+ xfont = font; | |
+ xpts = pts; | |
+ break; | |
+ case 1: | |
+ xfont = pfont; | |
+ xpts = ppts; | |
+ break; | |
+ case 2: | |
+ xfont = mfont; | |
+ xpts = mpts; | |
+ } | |
+ } | |
+} | |
+ | |
+ | |
+/* these next two functions ought to be the same in troff and nroff, */ | |
+/* but the data structures they search are different. */ | |
+/* silly historical problem. */ | |
+ | |
+ | |
+Tchar t_setch(int c) | |
+{ | |
+ int j; | |
+ char temp[50]; | |
+ char *s; | |
+ | |
+ j = 0; | |
+ s = temp; | |
+ if (c == '(') { /* \(xx */ | |
+ if ((*s++ = getach()) == 0 || (*s++ = getach()) == 0) | |
+ return(0); | |
+ } else { /* \C'...' */ | |
+ c = getach(); | |
+ while ((*s = getach()) != c && *s != 0 && s < temp + sizeof(te… | |
+ s++; | |
+ } | |
+ *s = '\0'; | |
+#ifdef UNICODE | |
+ return chadd(temp, Troffchar, Install) | chbits; /* add name even if h… | |
+#else | |
+ if (NROFF) { | |
+ j = chadd(temp, Troffchar, Lookup); | |
+ if ( j == -1) | |
+ return 0; | |
+ else | |
+ return j | chbits; | |
+ } else | |
+ return chadd(temp, Troffchar, Install) | chbits; /* add name e… | |
+ | |
+#endif /*UNICODE*/ | |
+} | |
+ | |
+Tchar t_setabs(void) /* set absolute char from \N'...' */ | |
+{ | |
+ int n; | |
+ char temp[10]; | |
+ | |
+ getch(); /* delim */ | |
+ n = 0; | |
+ n = inumb(&n); | |
+ getch(); /* delim */ | |
+ if (nonumb) | |
+ return 0; | |
+ sprintf(temp, "%d", n); /* convert into "#n" */ | |
+ n = chadd(temp, Number, Install); | |
+ return n | chbits; | |
+} | |
+ | |
+ | |
+/* | |
+ * fontlab[] is a cache that contains font information | |
+ * for each font. | |
+ * fontlab[] contains the 1- or 2-character name of the | |
+ * font current associated with that font. | |
+ * fonts 1..nfonts correspond to the mounted fonts; | |
+ * the last of these are the special fonts. | |
+ * If we don't use the (named) font in one of the | |
+ * standard positions, we install the name in the next | |
+ * free slot of fontlab[] and font[]. | |
+ * Whenever we need info about the font, we | |
+ * read in the data into the next free slot with getfont. | |
+ * The ptfont() (t10.c) routine will tell | |
+ * the device filter to put the font always at position | |
+ * zero if xfont > nfonts, so no need to change these filters. | |
+ * Yes, this is a bit kludgy. | |
+ * | |
+ * This gives the new specs of findft: | |
+ * find the font name i, where i also can be a number. | |
+ * Installs the font(name) i when not present | |
+ * returns -1 on error | |
+ */ | |
+ | |
+int | |
+t_findft(int i) | |
+{ | |
+ int k; | |
+ Uchar *p; | |
+ | |
+ p = unpair(i); | |
+ | |
+ if (isdigit(p[0])) { /* first look for numbers */ | |
+ k = p[0] - '0'; | |
+ if (p[1] > 0 && isdigit(p[1])) | |
+ k = 10 * k + p[1] - '0'; | |
+ if (k > 0 && k <= nfonts && k < smnt) | |
+ return(k); /* mounted font: .ft 3 */ | |
+ if (fontlab[k] && k <= MAXFONTS) { /* translate */ | |
+ return(k); /*number to a name */ | |
+ } else { | |
+ fprintf(stderr, "troff: no font at position %d\n", k); | |
+ return(-1); /* wild number */ | |
+ } | |
+ } | |
+ | |
+ /* | |
+ * Now we look for font names | |
+ */ | |
+ for (k = 1; fontlab[k] != i; k++) { | |
+ if (k > MAXFONTS) | |
+ return(-1); /* running out of fontlab space */ | |
+ if (fontlab[k] == 0) { /* passed all existing names */ | |
+ if (setfp(k, i, (char *) 0, 1) == -1) | |
+ return(-1); | |
+ else { | |
+ fontlab[k] = i; /* install the name */ | |
+ return(k); | |
+ } | |
+ } | |
+ } | |
+ return(k); /* was one of the existing names */ | |
+} | |
+ | |
+ | |
+void caseps(void) | |
+{ | |
+ int i; | |
+ | |
+ if (TROFF) { | |
+ if(skip()) | |
+ i = apts1; | |
+ else { | |
+ noscale++; | |
+ i = inumb(&apts); /* this is a disaster for fra… | |
+ noscale = 0; | |
+ if(nonumb) | |
+ i = apts1; | |
+ } | |
+ casps1(i); | |
+ } | |
+} | |
+ | |
+ | |
+void casps1(int i) | |
+{ | |
+ | |
+/* | |
+ * in olden times, it used to ignore changes to 0 or negative. | |
+ * this is meant to allow the requested size to be anything, | |
+ * in particular so eqn can generate lots of \s-3's and still | |
+ * get back by matching \s+3's. | |
+ | |
+ if (i <= 0) | |
+ return; | |
+*/ | |
+ apts1 = apts; | |
+ apts = i; | |
+ pts1 = pts; | |
+ pts = findps(i); | |
+ mchbits(); | |
+} | |
+ | |
+int | |
+findps(int i) | |
+{ | |
+ int j, k; | |
+ | |
+ for (j=k=0 ; pstab[j] != 0 ; j++) | |
+ if (abs(pstab[j]-i) < abs(pstab[k]-i)) | |
+ k = j; | |
+ | |
+ return(pstab[k]); | |
+} | |
+ | |
+ | |
+void t_mchbits(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ i = pts; | |
+ for (j = 0; i > (k = pstab[j]); j++) | |
+ if (!k) { | |
+ j--; | |
+ break; | |
+ } | |
+ chbits = 0; | |
+ setsbits(chbits, ++j); | |
+ setfbits(chbits, font); | |
+ sps = width(' ' | chbits); | |
+ zapwcache(1); | |
+} | |
+ | |
+void t_setps(void) | |
+{ | |
+ int i, j; | |
+ | |
+ j = 0; | |
+ i = cbits(getch()); | |
+ if (isdigit(i)) { /* \sd or \sdd */ | |
+ i -= '0'; | |
+ if (i == 0) /* \s0 */ | |
+ j = apts1; | |
+ else if (i <= 3 && (ch=getch()) && isdigit(j = cbits(ch))) { … | |
+ j = 10 * i + j - '0'; | |
+ ch = 0; | |
+ } else /* \sd */ | |
+ j = i; | |
+ } else if (i == '(') { /* \s(dd */ | |
+ j = cbits(getch()) - '0'; | |
+ j = 10 * j + cbits(getch()) - '0'; | |
+ if (j == 0) /* \s(00 */ | |
+ j = apts1; | |
+ } else if (i == '+' || i == '-') { /* \s+, \s- */ | |
+ j = cbits(getch()); | |
+ if (isdigit(j)) { /* \s+d, \s-d */ | |
+ j -= '0'; | |
+ } else if (j == '(') { /* \s+(dd, \s-(dd */ | |
+ j = cbits(getch()) - '0'; | |
+ j = 10 * j + cbits(getch()) - '0'; | |
+ } | |
+ if (i == '-') | |
+ j = -j; | |
+ j += apts; | |
+ } | |
+ casps1(j); | |
+} | |
+ | |
+ | |
+Tchar t_setht(void) /* set character height from \H'...' */ | |
+{ | |
+ int n; | |
+ Tchar c; | |
+ | |
+ getch(); | |
+ n = inumb(&apts); | |
+ getch(); | |
+ if (n == 0 || nonumb) | |
+ n = apts; /* does this work? */ | |
+ c = CHARHT; | |
+ c |= ZBIT; | |
+ setsbits(c, n); | |
+ setfbits(c, pts); /* sneaky, CHARHT font bits are size bits */ | |
+ return(c); | |
+} | |
+ | |
+Tchar t_setslant(void) /* set slant from \S'...' */ | |
+{ | |
+ int n; | |
+ Tchar c; | |
+ | |
+ getch(); | |
+ n = 0; | |
+ n = inumb(&n); | |
+ getch(); | |
+ if (nonumb) | |
+ n = 0; | |
+ c = SLANT; | |
+ c |= ZBIT; | |
+ setsfbits(c, n+180); | |
+ return(c); | |
+} | |
+ | |
+ | |
+void caseft(void) | |
+{ | |
+ if (!TROFF) { | |
+ n_caseft(); | |
+ return; | |
+ } | |
+ skip(); | |
+ setfont(1); | |
+} | |
+ | |
+ | |
+void t_setfont(int a) | |
+{ | |
+ int i, j; | |
+ | |
+ if (a) | |
+ i = getrq(); | |
+ else | |
+ i = getsn(); | |
+ if (!i || i == 'P') { | |
+ j = font1; | |
+ goto s0; | |
+ } | |
+ if (/* i == 'S' || */ i == '0') /* an experiment -- why can't w… | |
+ return; | |
+ if ((j = findft(i)) == -1) | |
+ if ((j = setfp(0, i, (char*) 0, 1)) == -1) /* try to pu… | |
+ return; | |
+s0: | |
+ font1 = font; | |
+ font = j; | |
+ mchbits(); | |
+} | |
+ | |
+ | |
+void t_setwd(void) | |
+{ | |
+ int base, wid; | |
+ Tchar i; | |
+ int delim, emsz, k; | |
+ int savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1; | |
+ | |
+ base = numtabp[ST].val = numtabp[SB].val = wid = numtabp[CT].val = 0; | |
+ if (ismot(i = getch())) | |
+ return; | |
+ delim = cbits(i); | |
+ savhp = numtabp[HP].val; | |
+ numtabp[HP].val = 0; | |
+ savapts = apts; | |
+ savapts1 = apts1; | |
+ savfont = font; | |
+ savfont1 = font1; | |
+ savpts = pts; | |
+ savpts1 = pts1; | |
+ setwdf++; | |
+ while (cbits(i = getch()) != delim && !nlflg) { | |
+ k = width(i); | |
+ wid += k; | |
+ numtabp[HP].val += k; | |
+ if (!ismot(i)) { | |
+ emsz = (INCH/72) * xpts; | |
+ } else if (isvmot(i)) { | |
+ k = absmot(i); | |
+ if (isnmot(i)) | |
+ k = -k; | |
+ base -= k; | |
+ emsz = 0; | |
+ } else | |
+ continue; | |
+ if (base < numtabp[SB].val) | |
+ numtabp[SB].val = base; | |
+ if ((k = base + emsz) > numtabp[ST].val) | |
+ numtabp[ST].val = k; | |
+ } | |
+ setn1(wid, 0, (Tchar) 0); | |
+ numtabp[HP].val = savhp; | |
+ apts = savapts; | |
+ apts1 = savapts1; | |
+ font = savfont; | |
+ font1 = savfont1; | |
+ pts = savpts; | |
+ pts1 = savpts1; | |
+ mchbits(); | |
+ setwdf = 0; | |
+} | |
+ | |
+ | |
+Tchar t_vmot(void) | |
+{ | |
+ dfact = lss; | |
+ vflag++; | |
+ return t_mot(); | |
+} | |
+ | |
+ | |
+Tchar t_hmot(void) | |
+{ | |
+ dfact = EM; | |
+ return t_mot(); | |
+} | |
+ | |
+ | |
+Tchar t_mot(void) | |
+{ | |
+ int j, n; | |
+ Tchar i; | |
+ | |
+ j = HOR; | |
+ getch(); /*eat delim*/ | |
+ if (n = atoi0()) { | |
+ if (vflag) | |
+ j = VERT; | |
+ i = makem(quant(n, j)); | |
+ } else | |
+ i = 0; | |
+ getch(); | |
+ vflag = 0; | |
+ dfact = 1; | |
+ return(i); | |
+} | |
+ | |
+ | |
+Tchar t_sethl(int k) | |
+{ | |
+ int j; | |
+ Tchar i; | |
+ | |
+ j = EM / 2; | |
+ if (k == 'u') | |
+ j = -j; | |
+ else if (k == 'r') | |
+ j = -2 * j; | |
+ vflag++; | |
+ i = makem(j); | |
+ vflag = 0; | |
+ return(i); | |
+} | |
+ | |
+ | |
+Tchar t_makem(int i) | |
+{ | |
+ Tchar j; | |
+ | |
+ if (i >= 0) | |
+ j = i; | |
+ else | |
+ j = -i; | |
+ if (Hor > 1 && !vflag) | |
+ j = (j + Hor/2)/Hor * Hor; | |
+ j |= MOT; | |
+ if (i < 0) | |
+ j |= NMOT; | |
+ if (vflag) | |
+ j |= VMOT; | |
+ return(j); | |
+} | |
+ | |
+ | |
+Tchar getlg(Tchar i) | |
+{ | |
+ Tchar j, k; | |
+ int lf; | |
+ | |
+ if (!TROFF) | |
+ return i; | |
+ if ((lf = fonts[fbits(i)].ligfont) == 0) /* font lacks ligatures */ | |
+ return(i); | |
+ j = getch0(); | |
+ if (cbits(j) == 'i' && (lf & LFI)) | |
+ j = LIG_FI; | |
+ else if (cbits(j) == 'l' && (lf & LFL)) | |
+ j = LIG_FL; | |
+ else if (cbits(j) == 'f' && (lf & LFF)) { | |
+ if ((lf & (LFFI|LFFL)) && lg != 2) { | |
+ k = getch0(); | |
+ if (cbits(k)=='i' && (lf&LFFI)) | |
+ j = LIG_FFI; | |
+ else if (cbits(k)=='l' && (lf&LFFL)) | |
+ j = LIG_FFL; | |
+ else { | |
+ *pbp++ = k; | |
+ j = LIG_FF; | |
+ } | |
+ } else | |
+ j = LIG_FF; | |
+ } else { | |
+ *pbp++ = j; | |
+ j = i; | |
+ } | |
+ return(i & SFMASK | j); | |
+} | |
+ | |
+ | |
+void caselg(void) | |
+{ | |
+ | |
+ if(TROFF) { | |
+ skip(); | |
+ lg = atoi0(); | |
+ if (nonumb) | |
+ lg = 1; | |
+ } | |
+} | |
+ | |
+void casefp(void) | |
+{ | |
+ int i, j; | |
+ | |
+ if (!TROFF) { | |
+ n_casefp(); | |
+ return; | |
+ } | |
+ skip(); | |
+ i = cbits(getch()); | |
+ if (isdigit(i)) { | |
+ i -= '0'; | |
+ j = cbits(getch()); | |
+ if (isdigit(j)) | |
+ i = 10 * i + j - '0'; | |
+ } | |
+ if (i <= 0 || i > nfonts) | |
+ ERROR "fp: bad font position %d", i WARN; | |
+ else if (skip() || !(j = getrq())) | |
+ ERROR "fp: no font name" WARN; | |
+ else if (skip() || !getname()) | |
+ setfp(i, j, (char*) 0, 1); | |
+ else /* 3rd argument = filename */ | |
+ setfp(i, j, nextf, 1); | |
+} | |
+ | |
+char *strdupl(const char *s) /* make a copy of s */ | |
+{ | |
+ char *t; | |
+ | |
+ t = (char *) malloc(strlen(s) + 1); | |
+ if (t == NULL) | |
+ ERROR "out of space in strdupl(%s)", s FATAL; | |
+ strcpy(t, s); | |
+ return t; | |
+} | |
+ | |
+int | |
+setfp(int pos, int f, char *truename, int print) /* mount font f at pos… | |
+{ | |
+ char pathname[NS], shortname[NS], *sl; | |
+ | |
+ sl = (char*)0; | |
+ zapwcache(0); | |
+ if (truename) | |
+ strcpy(shortname, truename); | |
+ else | |
+ strcpy(shortname, (char *) unpair(f)); | |
+ if (truename && strrchr(truename, '/')) { /* .fp 1 R dir/file: … | |
+ sprintf(pathname, "%s", truename); | |
+ if (fonts[pos].truename) | |
+ free(fonts[pos].truename); | |
+ fonts[pos].truename = strdupl(truename); | |
+ } else if (truename) { /* synonym: .fp 1 R Avan… | |
+ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, truename); | |
+ truename = 0; /* so doesn't get repeated by ptfpcmd */ | |
+ } else /* vanilla: .fp 5 XX */ | |
+ sprintf(pathname, "%s/dev%s/%s", fontdir, devname, shortname); | |
+ if (truename == 0 && fonts[pos].truename != 0) { | |
+ free(fonts[pos].truename); | |
+ fonts[pos].truename = 0; | |
+ } | |
+ if (getfont(pathname, pos) < 0) { | |
+ ERROR "Can't open font file %s", pathname WARN; | |
+ return -1; | |
+ } | |
+ if (print && !ascii) { | |
+ ptfpcmd(pos, fonts[pos].longname, truename); | |
+ ptfont(); | |
+ } | |
+ if (pos == smnt) { | |
+ smnt = 0; | |
+ sbold = 0; | |
+ } | |
+ fontlab[pos] = f; | |
+ if (smnt == 0 && fonts[pos].specfont) | |
+ smnt = pos; | |
+ bdtab[pos] = cstab[pos] = ccstab[pos] = 0; | |
+ return pos; | |
+} | |
+ | |
+/* | |
+ * .cs request; don't check legality of optional arguments | |
+ */ | |
+void casecs(void) | |
+{ | |
+ int i, j; | |
+ | |
+ if (TROFF) { | |
+ int savtr = trace; | |
+ | |
+ trace = 0; | |
+ noscale++; | |
+ skip(); | |
+ if (!(i = getrq()) || (i = findft(i)) < 0) | |
+ goto rtn; | |
+ skip(); | |
+ cstab[i] = atoi0(); | |
+ skip(); | |
+ j = atoi0(); | |
+ if(nonumb) | |
+ ccstab[i] = 0; | |
+ else | |
+ ccstab[i] = findps(j); | |
+ rtn: | |
+ zapwcache(0); | |
+ noscale = 0; | |
+ trace = savtr; | |
+ } | |
+} | |
+ | |
+ | |
+void casebd(void) | |
+{ | |
+ int i, j, k; | |
+ | |
+ j=0; | |
+ if (!TROFF) { | |
+ n_casebd(); | |
+ return; | |
+ } | |
+ zapwcache(0); | |
+ k = 0; | |
+bd0: | |
+ if (skip() || !(i = getrq()) || (j = findft(i)) == -1) { | |
+ if (k) | |
+ goto bd1; | |
+ else | |
+ return; | |
+ } | |
+ if (j == smnt) { | |
+ k = smnt; | |
+ goto bd0; | |
+ } | |
+ if (k) { | |
+ sbold = j; | |
+ j = k; | |
+ } | |
+bd1: | |
+ skip(); | |
+ noscale++; | |
+ bdtab[j] = atoi0(); | |
+ noscale = 0; | |
+} | |
+ | |
+ | |
+void casevs(void) | |
+{ | |
+ int i; | |
+ | |
+ if (!TROFF) { | |
+ n_casevs(); | |
+ return; | |
+ } | |
+ skip(); | |
+ vflag++; | |
+ dfact = INCH; /* default scaling is points! */ | |
+ dfactd = 72; | |
+ res = VERT; | |
+ i = inumb(&lss); | |
+ if (nonumb) | |
+ i = lss1; | |
+ if (i < VERT) | |
+ i = VERT; | |
+ lss1 = lss; | |
+ lss = i; | |
+} | |
+ | |
+ | |
+void casess(void) | |
+{ | |
+ int i; | |
+ | |
+ if(TROFF) { | |
+ noscale++; | |
+ skip(); | |
+ if(i = atoi0()) { | |
+ spacesz = i & 0177; | |
+ zapwcache(0); | |
+ sps = width(' ' | chbits); | |
+ } | |
+ noscale = 0; | |
+ } | |
+} | |
+ | |
+ | |
+Tchar t_xlss(void) | |
+{ | |
+ /* stores \x'...' into two successive Tchars. | |
+ /* the first contains HX, the second the value, | |
+ /* encoded as a vertical motion. | |
+ /* decoding is done in n2.c by pchar(). | |
+ */ | |
+ int i; | |
+ | |
+ getch(); | |
+ dfact = lss; | |
+ i = quant(atoi0(), VERT); | |
+ dfact = 1; | |
+ getch(); | |
+ if (i >= 0) | |
+ *pbp++ = MOT | VMOT | i; | |
+ else | |
+ *pbp++ = MOT | VMOT | NMOT | -i; | |
+ return(HX); | |
+} | |
+ | |
+Uchar *unpair(int i) | |
+{ | |
+ static Uchar name[3]; | |
+ | |
+ name[0] = i & SHORTMASK; | |
+ name[1] = (i >> SHORT) & SHORTMASK; | |
+ name[2] = 0; | |
+ return name; | |
+} | |
diff --git a/troff/tdef.h b/troff/tdef.h | |
@@ -0,0 +1,673 @@ | |
+#include <stdio.h> | |
+#include <stdlib.h> | |
+#include <limits.h> | |
+#include <ctype.h> | |
+#include <string.h> | |
+#include <unistd.h> | |
+ | |
+#undef MB_CUR_MAX | |
+#define MB_CUR_MAX 3 | |
+ | |
+#define NROFF (!TROFF) | |
+ | |
+/* Site dependent definitions */ | |
+ | |
+#ifndef TMACDIR | |
+#define TMACDIR "lib/tmac/tmac." | |
+#endif | |
+#ifndef FONTDIR | |
+#define FONTDIR "lib/font" | |
+#endif | |
+#ifndef NTERMDIR | |
+#define NTERMDIR "lib/term/tab." | |
+#endif | |
+#ifndef TDEVNAME | |
+#define TDEVNAME "post" | |
+#endif | |
+#ifndef NDEVNAME | |
+#define NDEVNAME "37" | |
+#endif | |
+#ifndef TEXHYPHENS | |
+#define TEXHYPHENS "/usr/lib/tex/macros/hyphen.tex" | |
+#endif | |
+#ifndef ALTHYPHENS | |
+#define ALTHYPHENS "lib/tmac/hyphen.tex" /* another place… | |
+#endif | |
+ | |
+typedef unsigned char Uchar; | |
+typedef unsigned short Ushort; | |
+ | |
+typedef /*unsigned*/ long Tchar; | |
+ | |
+typedef struct Blockp Blockp; | |
+typedef struct Diver Diver; | |
+typedef struct Stack Stack; | |
+typedef struct Divsiz Divsiz; | |
+typedef struct Contab Contab; | |
+typedef struct Numtab Numtab; | |
+typedef struct Numerr Numerr; | |
+typedef struct Env Env; | |
+typedef struct Term Term; | |
+typedef struct Chwid Chwid; | |
+typedef struct Font Font; | |
+typedef struct Spnames Spnames; | |
+typedef struct Wcache Wcache; | |
+typedef struct Tbuf Tbuf; | |
+ | |
+/* this simulates printf into a buffer that gets flushed sporadically */ | |
+/* the BSD goo is because SunOS sprintf doesn't return anything useful */ | |
+ | |
+#ifdef BSD4_2 | |
+#define OUT (obufp += strlen(sprintf(obufp, | |
+#define PUT ))) > obuf+BUFSIZ ? flusho() : 1 | |
+#else | |
+#define OUT (obufp += sprintf(obufp, | |
+#define PUT )) > obuf+BUFSIZ ? flusho() : 1 | |
+#endif | |
+ | |
+#define oputs(a) OUT "%s", a PUT | |
+#define oput(c) ( *obufp++ = (c), obufp > obuf+BUFSIZ ? … | |
+ | |
+extern char errbuf[]; | |
+#define ERROR sprintf(errbuf, | |
+#define WARN ), errprint() | |
+#define FATAL ), errprint(), exit(1) | |
+ | |
+/* starting values for typesetting parameters: */ | |
+ | |
+#define PS 10 /* default point size */ | |
+#define FT 1 /* default font position */ | |
+#define ULFONT 2 /* default underline font */ | |
+#define BDFONT 3 /* default emboldening font */ | |
+#define BIFONT 4 /* default bold italic font */ | |
+#define LL (unsigned) 65*INCH/10 /* line length; 39picas=… | |
+#define VS ((12*INCH)/72) /* initial vert space */ | |
+ | |
+ | |
+#define EMPTS(pts) (((long)Inch*(pts) + 36) / 72) | |
+#define EM (TROFF? EMPTS(pts): t.Em) | |
+#define INCH (TROFF? Inch: 240) | |
+#define HOR (TROFF? Hor: t.Adj) | |
+#define VERT (TROFF? Vert: t.Vert) | |
+#define PO (TROFF? Inch: 0) | |
+#define SPS (TROFF? EMPTS(pts)/3: INCH/10) | |
+#define SS (TROFF? 12: INCH/10) | |
+#define ICS (TROFF? EMPTS(pts): 2*INCH/10) | |
+#define DTAB (TROFF? (INCH/2): 0) | |
+ | |
+/* These "characters" are used to encode various internal functions | |
+/* Some make use of the fact that most ascii characters between | |
+/* 0 and 040 don't have any graphic or other function. | |
+/* The few that do have a purpose (e.g., \n, \b, \t, ... | |
+/* are avoided by the ad hoc choices here. | |
+/* See ifilt[] in n1.c for others -- 1, 2, 3, 5, 6, 7, 010, 011, 012 | |
+*/ | |
+ | |
+#define LEADER 001 | |
+#define IMP 004 /* impossible char; glues things together… | |
+#define TAB 011 | |
+#define RPT 014 /* next character is to be repeated many … | |
+#define CHARHT 015 /* size field sets character height */ | |
+#define SLANT 016 /* size field sets amount of slant */ | |
+#define DRAWFCN 017 /* next several chars describe arb dr… | |
+# define DRAWLINE 'l' /* line: 'l' dx dy char */ | |
+# define DRAWCIRCLE 'c' /* circle: 'c' r */ | |
+# define DRAWELLIPSE 'e' /* ellipse: 'e' rx ry */ | |
+# define DRAWARC 'a' /* arc: 'a' dx dy dx … | |
+# define DRAWSPLINE '~' /* quadratic B spline: '~'… | |
+ /* other splines go thru too */ | |
+/* NOTE: the use of ~ is a botch since it's often used in .tr commands */ | |
+/* better to use a letter like s, but change it in the postprocessors too */ | |
+/* for now, this is taken care of in n9.c and t10.c */ | |
+# define DRAWBUILD 'b' /* built-up character (e.g.… | |
+ | |
+#define LEFT 020 /* \{ */ | |
+#define RIGHT 021 /* \} */ | |
+#define FILLER 022 /* \& and similar purposes */ | |
+#define XON 023 /* \X'...' starts here */ | |
+#define OHC 024 /* optional hyphenation character \% */ | |
+#define CONT 025 /* \c character */ | |
+#define PRESC 026 /* printable escape */ | |
+#define UNPAD 027 /* unpaddable blank */ | |
+#define XPAR 030 /* transparent mode indicator */ | |
+#define FLSS 031 /* next Tchar contains vertical space */ | |
+ /* used when recalling diverted text */ | |
+#define WORDSP 032 /* paddable word space */ | |
+#define ESC 033 /* current escape character */ | |
+#define XOFF 034 /* \X'...' ends here */ | |
+ /* matches XON, but they will probably never nest */ | |
+ /* so could drop this when another control is needed */ | |
+#define HX 035 /* next character is value of \x'...' */ | |
+#define MOTCH 036 /* this "character" is really motion; used by … | |
+ | |
+#define HYPHEN c_hyphen | |
+#define EMDASH c_emdash /* \(em */ | |
+#define RULE c_rule /* \(ru */ | |
+#define MINUS c_minus /* minus sign on current fo… | |
+#define LIG_FI c_fi /* \(ff */ | |
+#define LIG_FL c_fl /* \(fl */ | |
+#define LIG_FF c_ff /* \(ff */ | |
+#define LIG_FFI c_ffi /* \(Fi */ | |
+#define LIG_FFL c_ffl /* \(Fl */ | |
+#define ACUTE c_acute /* acute accent \(aa */ | |
+#define GRAVE c_grave /* grave accent \(ga */ | |
+#define UNDERLINE c_under /* \(ul */ | |
+#define ROOTEN c_rooten /* root en \(rn */ | |
+#define BOXRULE c_boxrule /* box rule \(br */ | |
+#define LEFTHAND c_lefthand /* left hand for word overflow */ | |
+#define DAGGER c_dagger /* dagger for end of sentence/fo… | |
+ | |
+#define HYPHALG 1 /* hyphenation algorithm: 0=>good old t… | |
+ | |
+ | |
+/* array sizes, and similar limits: */ | |
+ | |
+#define MAXFONTS 99 /* Maximum number of fonts in fontab */ | |
+#define NM 91 /* requests + macros */ | |
+#define NN NNAMES /* number registers */ | |
+#define NNAMES 15 /* predefined reg names */ | |
+#define NIF 15 /* if-else nesting */ | |
+#define NS 128 /* name buffer */ | |
+#define NTM 1024 /* tm buffer */ | |
+#define NEV 3 /* environments */ | |
+#define EVLSZ 10 /* size of ev stack */ | |
+ | |
+#define STACKSIZE (12*1024) /* stack for macros and strings in p… | |
+#define NHYP 10 /* max hyphens per word */ | |
+#define NHEX 512 /* byte size of exception word list */ | |
+#define NTAB 100 /* tab stops */ | |
+#define NSO 5 /* "so" depth */ | |
+#define NMF 5 /* number of -m flags */ | |
+#define WDSIZE 500 /* word buffer click size */ | |
+#define LNSIZE 4000 /* line buffer click size */ | |
+#define OLNSIZE 5000 /* output line buffer click; bigger … | |
+#define NDI 5 /* number of diversions */ | |
+ | |
+#define ALPHABET alphabet /* number of characters in basic alpha… | |
+ /* 128 for parochial USA 7-bit ascii, */ | |
+ /* 256 for "European" mode with e.g., Latin-1 */ | |
+ | |
+ /* NCHARS must be greater than | |
+ ALPHABET (ascii stuff) + total number of distinct char names | |
+ from all fonts that will be run in this job (including | |
+ unnamed ones and \N's) | |
+ */ | |
+ | |
+#define NCHARS (8*1024) /* maximum size of troff characte… | |
+ | |
+ | |
+ /* However for nroff you want only : | |
+ 1. number of special codes in charset of DESC, which ends up being the | |
+ value of nchtab and which must be less than 512. | |
+ 2. ALPHABET, which apparently is the size of the portion of the tables… | |
+ for special control symbols | |
+ Apparently the max N of \N is irrelevant; */ | |
+ /* to allow \N of up to 254 with up to 338 special characters | |
+ you need NCHARS of 338 + ALPHABET = 466 */ | |
+ | |
+#define NROFFCHARS 1024 /* maximum size of nroff characte… | |
+ | |
+#define NTRTAB NCHARS /* number of items in trtab… | |
+#define NWIDCACHE NCHARS /* number of items in widcache[] */ | |
+ | |
+#define NTRAP 20 /* number of traps */ | |
+#define NPN 20 /* numbers in "-o" */ | |
+#define FBUFSZ 512 /* field buf size words */ | |
+#define IBUFSZ 4096 /* bytes */ | |
+#define NC 1024 /* cbuf size words */ | |
+#define NOV 10 /* number of overstrike chars */ | |
+#define NPP 10 /* pads per field */ | |
+ | |
+/* | |
+ Internal character representation: | |
+ Internally, every character is carried around as | |
+ a 32 bit cookie, called a "Tchar" (typedef long). | |
+ Bits are numbered 31..0 from left to right. | |
+ If bit 15 is 1, the character is motion, with | |
+ if bit 16 it's vertical motion | |
+ if bit 17 it's negative motion | |
+ If bit 15 is 0, the character is a real character. | |
+ if bit 31 zero motion | |
+ bits 30..24 size | |
+ bits 23..16 font | |
+*/ | |
+ | |
+/* in the following, "L" should really be a Tchar, but ... */ | |
+/* numerology leaves room for 16 bit chars */ | |
+ | |
+#define MOT (01uL << 16) /* motion character indicator */ | |
+#define VMOT (01uL << 30) /* vertical motion bit */ | |
+#define NMOT (01uL << 29) /* negative motion indicator */ | |
+/* #define MOTV (MOT|VMOT|NMOT) /* motion flags */ | |
+/* #define MAXMOT (~MOTV) /* maximum motion permi… | |
+#define MAXMOT 0xFFFF | |
+ | |
+#define ismot(n) ((n) & MOT) | |
+#define isvmot(n) (((n) & (MOT|VMOT)) == (MOT|VMOT)) /* m… | |
+#define isnmot(n) (((n) & (MOT|NMOT)) == (MOT|NMOT)) /* d… | |
+#define absmot(n) ((n) & 0xFFFF) | |
+ | |
+#define ZBIT (01uL << 31) /* zero width char */ | |
+#define iszbit(n) ((n) & ZBIT) | |
+ | |
+#define FSHIFT 17 | |
+#define SSHIFT (FSHIFT+7) | |
+#define SMASK (0177uL << SSHIFT) /* 128 distinct … | |
+#define FMASK (0177uL << FSHIFT) /* 128 distinct … | |
+#define SFMASK (SMASK|FMASK) /* size and font in … | |
+#define sbits(n) (((n) >> SSHIFT) & 0177) | |
+#define fbits(n) (((n) >> FSHIFT) & 0177) | |
+#define sfbits(n) (((n) & SFMASK) >> FSHIFT) | |
+#define cbits(n) ((n) & 0x1FFFF) /* isolate chara… | |
+ /* but don't include motions */ | |
+extern int realcbits(Tchar); | |
+ | |
+#define setsbits(n,s) n = (n & ~SMASK) | (Tchar)(s) << SSHIFT | |
+#define setfbits(n,f) n = (n & ~FMASK) | (Tchar)(f) << FSHIFT | |
+#define setsfbits(n,sf) n = (n & ~SFMASK) | (Tchar)(sf) << FSHIFT | |
+#define setcbits(n,c) n = (n & ~0xFFFFuL | (c)) /* set ch… | |
+ | |
+#define BYTEMASK 0377 | |
+#define BYTE 8 | |
+ | |
+#define SHORTMASK 0XFFFF | |
+#define SHORT 16 | |
+ | |
+#define TABMASK ((unsigned) INT_MAX >> 1) | |
+#define RTAB ((TABMASK << 1) & ~TABMASK) | |
+#define CTAB (RTAB << 1) | |
+ | |
+#define TABBIT 02 /* bits in gchtab */ | |
+#define LDRBIT 04 | |
+#define FCBIT 010 | |
+ | |
+#define PAIR(A,B) (A|(B<<SHORT)) | |
+ | |
+ | |
+extern int Inch, Hor, Vert, Unitwidth; | |
+ | |
+struct Spnames | |
+{ | |
+ int *n; | |
+ char *v; | |
+}; | |
+ | |
+extern Spnames spnames[]; | |
+ | |
+/* | |
+ String and macro definitions are stored conceptually in a giant array | |
+ indexed by type Offset. In olden times, this array was real, and thus | |
+ both huge and limited in size, leading to the "Out of temp file space" | |
+ error. In this version, the array is represented by a list of blocks, | |
+ pointed to by blist[].bp. Each block is of size BLK Tchars, and BLK | |
+ MUST be a power of 2 for the macros below to work. | |
+ | |
+ The blocks associated with a particular string or macro are chained | |
+ together in the array blist[]. Each blist[i].nextoff contains the | |
+ Offset associated with the next block in the giant array, or -1 if | |
+ this is the last block in the chain. If .nextoff is 0, the block is | |
+ free. | |
+ | |
+ To find the right index in blist for an Offset, divide by BLK. | |
+*/ | |
+ | |
+#define NBLIST 2048 /* starting number of blocks in all d… | |
+ | |
+#define BLK 128 /* number of Tchars in a block; must be 2… | |
+ | |
+#define rbf0(o) (blist[bindex(o)].bp[boffset(o)]) | |
+#define bindex(o) ((o) / BLK) | |
+#define boffset(o) ((o) & (BLK-1)) | |
+#define pastend(o) (((o) & (BLK-1)) == 0) | |
+/* #define incoff(o) ( (++o & (BLK-1)) ? o : blist[bindex(o-1)].… | |
+#define incoff(o) ( (((o)+1) & (BLK-1)) ? o+1 : blist[bindex(o)]… | |
+ | |
+#define skipline(f) while (getc(f) != '\n') | |
+#define is(s) (strcmp(cmd, s) == 0) | |
+#define eq(s1, s2) (strcmp(s1, s2) == 0) | |
+ | |
+ | |
+typedef unsigned long Offset; /* an offset in mac… | |
+ | |
+struct Blockp { /* info about a block: */ | |
+ Tchar *bp; /* the data */ | |
+ Offset nextoff; /* offset of next block in a chain */ | |
+}; | |
+ | |
+extern Blockp *blist; | |
+ | |
+#define RD_OFFSET (1 * BLK) /* .rd command uses block 1 */ | |
+ | |
+struct Diver { /* diversion */ | |
+ Offset op; | |
+ int dnl; | |
+ int dimac; | |
+ int ditrap; | |
+ int ditf; | |
+ int alss; | |
+ int blss; | |
+ int nls; | |
+ int mkline; | |
+ int maxl; | |
+ int hnl; | |
+ int curd; | |
+}; | |
+ | |
+struct Stack { /* stack frame */ | |
+ int nargs; | |
+ Stack *pframe; | |
+ Offset pip; | |
+ int pnchar; | |
+ Tchar prchar; | |
+ int ppendt; | |
+ Tchar pch; | |
+ Tchar *lastpbp; | |
+ int mname; | |
+}; | |
+ | |
+extern Stack s; | |
+ | |
+struct Divsiz { | |
+ int dix; | |
+ int diy; | |
+}; | |
+ | |
+struct Contab { /* command or macro */ | |
+ unsigned int rq; | |
+ Contab *link; | |
+ void (*f)(void); | |
+ Offset mx; | |
+ Offset emx; | |
+ Divsiz *divsiz; | |
+}; | |
+ | |
+#define C(a,b) {a, 0, b, 0, 0} /* how to initiali… | |
+ | |
+extern Contab contab[NM]; | |
+ | |
+struct Numtab { /* number registers */ | |
+ unsigned int r; /* name */ | |
+ int val; | |
+ short fmt; | |
+ short inc; | |
+ Numtab *link; | |
+}; | |
+ | |
+extern Numtab numtab[NN]; | |
+ | |
+#define PN 0 | |
+#define NL 1 | |
+#define YR 2 | |
+#define HP 3 | |
+#define CT 4 | |
+#define DN 5 | |
+#define MO 6 | |
+#define DY 7 | |
+#define DW 8 | |
+#define LN 9 | |
+#define DL 10 | |
+#define ST 11 | |
+#define SB 12 | |
+#define CD 13 | |
+#define PID 14 | |
+ | |
+struct Wcache { /* width cache, indexed by character */ | |
+ short fontpts; | |
+ short width; | |
+}; | |
+ | |
+struct Tbuf { /* growable Tchar buffer */ | |
+ Tchar *_bufp; | |
+ unsigned int _size; | |
+}; | |
+ | |
+/* the infamous environment block */ | |
+ | |
+#define ics envp->_ics | |
+#define sps envp->_sps | |
+#define spacesz envp->_spacesz | |
+#define lss envp->_lss | |
+#define lss1 envp->_lss1 | |
+#define ll envp->_ll | |
+#define ll1 envp->_ll1 | |
+#define lt envp->_lt | |
+#define lt1 envp->_lt1 | |
+#define ic envp->_ic | |
+#define icf envp->_icf | |
+#define chbits envp->_chbits | |
+#define spbits envp->_spbits | |
+#define nmbits envp->_nmbits | |
+#define apts envp->_apts | |
+#define apts1 envp->_apts1 | |
+#define pts envp->_pts | |
+#define pts1 envp->_pts1 | |
+#define font envp->_font | |
+#define font1 envp->_font1 | |
+#define ls envp->_ls | |
+#define ls1 envp->_ls1 | |
+#define ad envp->_ad | |
+#define nms envp->_nms | |
+#define ndf envp->_ndf | |
+#define nmwid envp->_nmwid | |
+#define fi envp->_fi | |
+#define cc envp->_cc | |
+#define c2 envp->_c2 | |
+#define ohc envp->_ohc | |
+#define tdelim envp->_tdelim | |
+#define hyf envp->_hyf | |
+#define hyoff envp->_hyoff | |
+#define hyphalg envp->_hyphalg | |
+#define un1 envp->_un1 | |
+#define tabc envp->_tabc | |
+#define dotc envp->_dotc | |
+#define adsp envp->_adsp | |
+#define adrem envp->_adrem | |
+#define lastl envp->_lastl | |
+#define nel envp->_nel | |
+#define admod envp->_admod | |
+#define wordp envp->_wordp | |
+#define spflg envp->_spflg | |
+#define linep envp->_linep | |
+#define wdend envp->_wdend | |
+#define wdstart envp->_wdstart | |
+#define wne envp->_wne | |
+#define ne envp->_ne | |
+#define nc envp->_nc | |
+#define nb envp->_nb | |
+#define lnmod envp->_lnmod | |
+#define nwd envp->_nwd | |
+#define nn envp->_nn | |
+#define ni envp->_ni | |
+#define ul envp->_ul | |
+#define cu envp->_cu | |
+#define ce envp->_ce | |
+#define in envp->_in | |
+#define in1 envp->_in1 | |
+#define un envp->_un | |
+#define wch envp->_wch | |
+#define pendt envp->_pendt | |
+#define pendw envp->_pendw | |
+#define pendnf envp->_pendnf | |
+#define spread envp->_spread | |
+#define it envp->_it | |
+#define itmac envp->_itmac | |
+#define hyptr envp->_hyptr | |
+#define tabtab envp->_tabtab | |
+#define line envp->_line._bufp | |
+#define lnsize envp->_line._size | |
+#define word envp->_word._bufp | |
+#define wdsize envp->_word._size | |
+ | |
+#define oline _oline._bufp | |
+#define olnsize _oline._size | |
+ | |
+/* | |
+ * Note: | |
+ * If this structure changes in ni.c, you must change | |
+ * this as well, and vice versa. | |
+ */ | |
+ | |
+struct Env { | |
+ int _ics; | |
+ int _sps; | |
+ int _spacesz; | |
+ int _lss; | |
+ int _lss1; | |
+ int _ll; | |
+ int _ll1; | |
+ int _lt; | |
+ int _lt1; | |
+ Tchar _ic; | |
+ int _icf; | |
+ Tchar _chbits; | |
+ Tchar _spbits; | |
+ Tchar _nmbits; | |
+ int _apts; | |
+ int _apts1; | |
+ int _pts; | |
+ int _pts1; | |
+ int _font; | |
+ int _font1; | |
+ int _ls; | |
+ int _ls1; | |
+ int _ad; | |
+ int _nms; | |
+ int _ndf; | |
+ int _nmwid; | |
+ int _fi; | |
+ int _cc; | |
+ int _c2; | |
+ int _ohc; | |
+ int _tdelim; | |
+ int _hyf; | |
+ int _hyoff; | |
+ int _hyphalg; | |
+ int _un1; | |
+ int _tabc; | |
+ int _dotc; | |
+ int _adsp; | |
+ int _adrem; | |
+ int _lastl; | |
+ int _nel; | |
+ int _admod; | |
+ Tchar *_wordp; | |
+ int _spflg; | |
+ Tchar *_linep; | |
+ Tchar *_wdend; | |
+ Tchar *_wdstart; | |
+ int _wne; | |
+ int _ne; | |
+ int _nc; | |
+ int _nb; | |
+ int _lnmod; | |
+ int _nwd; | |
+ int _nn; | |
+ int _ni; | |
+ int _ul; | |
+ int _cu; | |
+ int _ce; | |
+ int _in; | |
+ int _in1; | |
+ int _un; | |
+ int _wch; | |
+ int _pendt; | |
+ Tchar *_pendw; | |
+ int _pendnf; | |
+ int _spread; | |
+ int _it; | |
+ int _itmac; | |
+ Tchar *_hyptr[NHYP]; | |
+ long _tabtab[NTAB]; | |
+ Tbuf _line; | |
+ Tbuf _word; | |
+}; | |
+ | |
+extern Env env[]; | |
+extern Env *envp; | |
+ | |
+enum { MBchar = 'U', Troffchar = 'C', Number = 'N', Install = 'i', Look… | |
+ /* U => utf, for instance; C => \(xx, N => \N'...' */ | |
+ | |
+ | |
+ | |
+struct Chwid { /* data on one character */ | |
+ Ushort num; /* character number: | |
+ 0 -> not on this font | |
+ >= ALPHABET -> its number among all Cx… | |
+ Ushort code; /* char code for actual device. us… | |
+ char *str; /* code string for nroff */ | |
+ Uchar wid; /* width */ | |
+ Uchar kern; /* ascender/descender */ | |
+}; | |
+ | |
+struct Font { /* characteristics of a font */ | |
+ int name; /* int name, e.g., BI (2 chars) */ | |
+ char longname[64]; /* long name of this font (e.g., "Bem… | |
+ char *truename; /* path name of table if not in standard… | |
+ int nchars; /* number of width entries for this … | |
+ char specfont; /* 1 == special font */ | |
+ int spacewidth; /* width of space on this font */ | |
+ int defaultwidth; /* default width of characters on this… | |
+ Chwid *wp; /* widths, etc., of the real characte… | |
+ char ligfont; /* 1 == ligatures exist on this font */ | |
+}; | |
+ | |
+/* ligatures, ORed into ligfont */ | |
+ | |
+#define LFF 01 | |
+#define LFI 02 | |
+#define LFL 04 | |
+#define LFFI 010 | |
+#define LFFL 020 | |
+ | |
+/* tracing modes */ | |
+#define TRNARGS 01 /* trace legality of numeric argument… | |
+#define TRREQ 02 /* trace requests */ | |
+#define TRMAC 04 /* trace macros */ | |
+#define RQERR 01 /* processing request/macro */ | |
+ | |
+/* typewriter driving table structure */ | |
+ | |
+ | |
+extern Term t; | |
+struct Term { | |
+ int bset; /* these bits have to be on */ | |
+ int breset; /* these bits have to be off */ | |
+ int Hor; /* #units in minimum horiz motion */ | |
+ int Vert; /* #units in minimum vert motion */ | |
+ int Newline; /* #units in single line space */ | |
+ int Char; /* #units in character width */ | |
+ int Em; /* ditto */ | |
+ int Halfline; /* half line units */ | |
+ int Adj; /* minimum units for horizontal adjustm… | |
+ char *twinit; /* initialize terminal */ | |
+ char *twrest; /* reinitialize terminal */ | |
+ char *twnl; /* terminal sequence for newline */ | |
+ char *hlr; /* half-line reverse */ | |
+ char *hlf; /* half-line forward */ | |
+ char *flr; /* full-line reverse */ | |
+ char *bdon; /* turn bold mode on */ | |
+ char *bdoff; /* turn bold mode off */ | |
+ char *iton; /* turn italic mode on */ | |
+ char *itoff; /* turn italic mode off */ | |
+ char *ploton; /* turn plot mode on */ | |
+ char *plotoff; /* turn plot mode off */ | |
+ char *up; /* sequence to move up in plot mode */ | |
+ char *down; /* ditto */ | |
+ char *right; /* ditto */ | |
+ char *left; /* ditto */ | |
+ | |
+ Font tfont; /* widths and other info, as in a tr… | |
+}; | |
+ | |
+extern Term t; | |
+ | |
+/* | |
+ * for error reporting; keep track of escapes/requests with numeric arguments | |
+ */ | |
+struct Numerr { | |
+ char type; /* request or escape? */ | |
+ char esc; /* was escape sequence named esc */ | |
+ char escarg; /* argument of esc's like \D'l' */ | |
+ unsigned int req; /* was request or macro named req */ | |
+}; | |
diff --git a/troff/troff.1 b/troff/troff.1 | |
@@ -0,0 +1,199 @@ | |
+.TH TROFF 1 | |
+.SH NAME | |
+troff, nroff \- text formatting and typesetting | |
+.SH SYNOPSIS | |
+.B troff | |
+[ | |
+.I option ... | |
+] | |
+[ | |
+.I file ... | |
+] | |
+.PP | |
+.B nroff | |
+[ | |
+.I option ... | |
+] | |
+[ | |
+.I file ... | |
+] | |
+.SH DESCRIPTION | |
+.I Troff | |
+formats text in the named | |
+.I files | |
+for | |
+printing on a typesetter. | |
+.I Nroff | |
+does the same, but produces output suitable | |
+for typewriter-like devices. | |
+.PP | |
+If no | |
+.I file | |
+argument is present, the standard input is read. | |
+An argument consisting of a single minus | |
+.RB ( - ) | |
+is taken to be | |
+a file name corresponding to the standard input. | |
+The options are: | |
+.nr xx \w'\fL-m\f2name\ \ ' | |
+.TP \n(xxu | |
+.BI -o list | |
+Print pages in the comma-separated | |
+.I list | |
+of numbers and ranges. | |
+A range | |
+.IB N - M | |
+means | |
+.I N | |
+through | |
+.IR M ; | |
+initial | |
+.BI - M | |
+means up to | |
+.IR M ; | |
+final | |
+.IB N - | |
+means from | |
+.I N | |
+to the end. | |
+.TP | |
+.BI -n N | |
+Number first generated page | |
+.IR N . | |
+.TP | |
+.BI -m name | |
+Process the macro file | |
+.BI /sys/lib/tmac/tmac. name | |
+before the input | |
+.IR files . | |
+.TP | |
+.BI -r aN | |
+Set register | |
+.I a | |
+(one character name) to | |
+.IR N . | |
+.TP | |
+.B -i | |
+Read standard input after the input files are exhausted. | |
+.TP | |
+.B -q | |
+Invoke the simultaneous input-output mode of the | |
+.B rd | |
+request. | |
+.TP | |
+.B -N | |
+Produce output suitable for typewriter-like devices. | |
+.SS Typesetter devices (not \fL-N\fP) only | |
+.TP \n(xxu | |
+.B -a | |
+Send a printable | |
+textual | |
+approximation | |
+of the results to the standard output. | |
+.TP | |
+.BI -T dest | |
+Prepare output for typesetter | |
+.IR dest : | |
+.br | |
+.ns | |
+.RS | |
+.TP \w'\fL-TLatin1\ 'u | |
+.B -Tutf | |
+(The default.) PostScript printers with | |
+preprocessing to handle Unicode | |
+characters encoded in | |
+.SM UTF | |
+.PD0 | |
+.TP | |
+.B -Tpost | |
+Regular PostScript printers | |
+.PD0 | |
+.TP | |
+.B -T202 | |
+Mergenthaler Linotron 202 | |
+.RE | |
+.PD | |
+.TP "\w'\fL-m\f2name 'u" | |
+.BI -F dir | |
+Take font information from directory | |
+.IR dir . | |
+.SS Typewriter (\fL-N\fP) output only | |
+.TP \n(xxu | |
+.BI -s N | |
+Halt prior to every | |
+.I N | |
+pages (default | |
+.IR N =1) | |
+to allow paper loading or changing. | |
+.TP | |
+.BI -T name | |
+Prepare output for specified terminal. | |
+Known | |
+.I names | |
+include | |
+.B utf | |
+for the normal Plan 9 | |
+.SM UTF | |
+encoding of the Unicode Standard character set (default), | |
+.B 37 | |
+for the | |
+Teletype model 37, | |
+.B lp | |
+(`line-printer') | |
+for any terminal without half-line capability, | |
+.B 450 | |
+for the \s-1DASI\s+1-450 | |
+(Diablo Hyterm), | |
+and | |
+.B think | |
+(HP ThinkJet). | |
+.TP | |
+.B -e | |
+Produce equally-spaced words in adjusted | |
+lines, using full terminal resolution. | |
+.TP | |
+.B -h | |
+Use output tabs during horizontal spacing | |
+to speed output and reduce output character count. | |
+Tab settings are assumed to be every | |
+8 nominal character widths. | |
+.SH FILES | |
+.TF \*9/troff/term/* | |
+.TP | |
+.B /tmp/trtmp* | |
+temporary file | |
+.TP | |
+.B \*9/tmac/tmac.* | |
+standard macro files | |
+.TP | |
+.B \*9/troff/term/* | |
+terminal driving tables for | |
+.I nroff | |
+.TP | |
+.B \*9/troff/font/* | |
+font width tables for | |
+.I troff | |
+.SH SOURCE | |
+.B \*9/src/cmd/troff | |
+.SH "SEE ALSO" | |
+.IR lpr (1), | |
+.IR proof (1), | |
+.IR tr2post (1), | |
+.IR eqn (1), | |
+.IR tbl (1), | |
+.IR pic (1), | |
+.IR grap (1), | |
+.IR doctype (1), | |
+.IR ms (7), | |
+.IR image (7), | |
+.IR tex (1), | |
+.IR deroff (1) | |
+.br | |
+J. F. Ossanna and B. W. Kernighan, | |
+``Troff User's Manual'' | |
+.br | |
+B. W. Kernighan, | |
+``A TROFF Tutorial'', | |
+.I | |
+Unix Research System Programmer's Manual, | |
+Tenth Edition, Volume 2. | |
diff --git a/troff/unansi b/troff/unansi | |
@@ -0,0 +1,49 @@ | |
+# The awk program cvt will convert the relatively sterotyped ansi c | |
+# in this troff distribution into older-style c, by munging function | |
+# declarations. | |
+ | |
+# You will also have to edit fns.h, by | |
+# sed 's/(.*)/()/g' fns.h >foo; mv foo fns.h | |
+# check this before doing the move! | |
+ | |
+# you will also have to make some editing changes in | |
+# tdef.h in the Contab structure: s/(void)/()/ | |
+# you may have to fix up some function declarations | |
+# in n4.c, the ones with (*f)(Tchar). | |
+ | |
+# you will surely also have header files to deal with. | |
+ | |
+# the most obvious cases are dealt with by the following | |
+# commands. make sure you do this stuff on a copy! | |
+ | |
+# function prototypes in n8.c probably belong in fns.h. readpats(void) must | |
+# be readpats() before cvt runs. | |
+ | |
+sed \ | |
+ -e 's/(void)/()/' \ | |
+ -e 's/(Tchar[^)]*);/();/' \ | |
+ -e 's/(char[^)]*);/();/' \ | |
+ -e 's/(int[^)]*);/();/' \ | |
+n8.c >foo | |
+mv foo n8.c | |
+ | |
+for i in *.c | |
+do | |
+ cvt $i >foo | |
+ mv foo $i | |
+done | |
+ | |
+sed 's/(.*)/()/g' fns.h >foo | |
+mv foo fns.h | |
+ | |
+sed -e 's/(void)/()/g' -e '/stdlib/d' tdef.h >foo | |
+mv foo tdef.h | |
+ | |
+# Compliers may not approve of void *setbrk() in fns.h and n3.c. | |
+ | |
+sed 's/^void\*[ ]setbrk/char* setbrk/' fns.h >foo | |
+mv foo fns.h | |
+ | |
+sed 's/^void \*setbrk/char *setbrk/' n3.c >foo | |
+mv foo n3.c | |
+ |