diff options
author | rsc <devnull@localhost> | 2005-01-04 21:24:19 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-01-04 21:24:19 +0000 |
commit | 020c80587a21a72ca8f9a503640c4234c289a19a (patch) | |
tree | c59a014d358fe04e413aa6963a21e3ec87f33ad7 /src/cmd/proof | |
parent | 24c02865d8fcc97d1fb5cb9281810d8074aa5eb1 (diff) | |
download | plan9port-020c80587a21a72ca8f9a503640c4234c289a19a.tar.gz plan9port-020c80587a21a72ca8f9a503640c4234c289a19a.tar.bz2 plan9port-020c80587a21a72ca8f9a503640c4234c289a19a.zip |
an old saddle
Diffstat (limited to 'src/cmd/proof')
-rw-r--r-- | src/cmd/proof/font.c | 372 | ||||
-rw-r--r-- | src/cmd/proof/htroff.c | 579 | ||||
-rw-r--r-- | src/cmd/proof/main.c | 226 | ||||
-rw-r--r-- | src/cmd/proof/mkfile | 14 | ||||
-rw-r--r-- | src/cmd/proof/portdate | 5 | ||||
-rw-r--r-- | src/cmd/proof/proof.h | 48 | ||||
-rw-r--r-- | src/cmd/proof/screen.c | 315 |
7 files changed, 1559 insertions, 0 deletions
diff --git a/src/cmd/proof/font.c b/src/cmd/proof/font.c new file mode 100644 index 00000000..d930f34c --- /dev/null +++ b/src/cmd/proof/font.c @@ -0,0 +1,372 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <event.h> +#include <bio.h> +#include "proof.h" + +char fname[NFONT][20]; /* font names */ +char lastload[NFONT][20]; /* last file name prefix loaded for this font */ +Font *fonttab[NFONT][NSIZE]; /* pointers to fonts */ +int fmap[NFONT]; /* what map to use with this font */ + +static void loadfont(int, int); +static void fontlookup(int, char *); +static void buildxheight(Biobuf*); +static void buildmap(Biobuf*); +static void buildtroff(char *); +static void addmap(int, char *, int); +static char *map(Rune*, int); +static void scanstr(char *, char *, char **); + +int specfont; /* somehow, number of special font */ + +#define NMAP 5 +#define QUICK 2048 /* char values less than this are quick to look up */ +#define eq(s,t) strcmp((char *) s, (char *) t) == 0 + +int curmap = -1; /* what map are we working on */ + +typedef struct Link Link; +struct Link /* link names together */ +{ + uchar *name; + int val; + Link *next; +}; + +typedef struct Map Map; +struct Map /* holds a mapping from uchar name to index */ +{ + double xheight; + Rune quick[QUICK]; /* low values get special treatment */ + Link *slow; /* other stuff goes into a link list */ +}; + +Map charmap[5]; + +typedef struct Fontmap Fontmap; +struct Fontmap /* mapping from troff name to filename */ +{ + char *troffname; + char *prefix; + int map; /* which charmap to use for this font */ + char *fallback; /* font to look in if can't find char here */ +}; + +Fontmap fontmap[100]; +int pos2fontmap[NFONT]; /* indexed by troff font position, gives Fontmap */ +int nfontmap = 0; /* how many are there */ + + +void +dochar(Rune r[]) +{ + char *s, *fb; + Font *f; + Point p; + int fontno, fm, i; + char buf[10]; + + fontno = curfont; + if((s = map(r, curfont)) == 0){ /* not on current font */ + if ((s = map(r, specfont)) != 0) /* on special font */ + fontno = specfont; + else{ + /* look for fallback */ + fm = pos2fontmap[curfont]; + fb = fontmap[fm].fallback; + if(fb){ + /* see if fallback is mounted */ + for(i = 0; i < NFONT; i++){ + if(eq(fb, fontmap[pos2fontmap[i]].troffname)){ + s = map(r, i); + if(s){ + fontno = i; + goto found; + } + } + } + } + /* no such char; use name itself on defont */ + /* this is not a general solution */ + p.x = hpos/DIV + xyoffset.x + offset.x; + p.y = vpos/DIV + xyoffset.y + offset.y; + p.y -= font->ascent; + sprint(buf, "%S", r); + string(screen, p, display->black, ZP, font, buf); + return; + } + } + found: + p.x = hpos/DIV + xyoffset.x + offset.x; + p.y = vpos/DIV + xyoffset.y + offset.y; + while ((f = fonttab[fontno][cursize]) == 0) + loadfont(fontno, cursize); + p.y -= f->ascent; + dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize); + string(screen, p, display->black, ZP, f, s); +} + +static int drawlog2[] = { + 0, 0, + 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5 +}; + +static void +loadfont(int n, int s) +{ + char file[100]; + int i, fd, t, deep; + static char *try[3] = {"", "times/R.", "pelm/"}; + Subfont *f; + Font *ff; + + try[0] = fname[n]; + dprint(2, "loadfont %d %d\n", n, s); + for (t = 0; t < 3; t++){ + i = s * mag * charmap[fmap[n]].xheight/0.72; /* a pixel is 0.72 points */ + if (i < MINSIZE) + i = MINSIZE; + dprint(2, "size %d, i %d, mag %g\n", s, i, mag); + for(; i >= MINSIZE; i--){ + /* if .font file exists, take that */ + sprint(file, "%s/%s%d.font", libfont, try[t], i); + ff = openfont(display, file); + if(ff != 0){ + fonttab[n][s] = ff; + dprint(2, "using %s for font %d %d\n", file, n, s); + return; + } + /* else look for a subfont file */ + for (deep = drawlog2[screen->depth]; deep >= 0; deep--){ + sprint(file, "%s/%s%d.%d", libfont, try[t], i, deep); + dprint(2, "trying %s for %d\n", file, i); + if ((fd = open(file, 0)) >= 0){ + f = readsubfont(display, file, fd, 0); + if (f == 0) { + fprint(2, "can't rdsubfontfile %s: %r\n", file); + exits("rdsubfont"); + } + close(fd); + ff = mkfont(f, 0); + if(ff == 0){ + fprint(2, "can't mkfont %s: %r\n", file); + exits("rdsubfont"); + } + fonttab[n][s] = ff; + dprint(2, "using %s for font %d %d\n", file, n, s); + return; + } + } + } + } + fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s); + exits("no font"); +} + +void +loadfontname(int n, char *s) +{ + int i; + Font *f, *g = 0; + + if (strcmp(s, fname[n]) == 0) + return; + if(fname[n] && fname[n][0]){ + if(lastload[n] && strcmp(lastload[n], fname[n]) == 0) + return; + strcpy(lastload[n], fname[n]); + } + fontlookup(n, s); + for (i = 0; i < NSIZE; i++) + if (f = fonttab[n][i]){ + if (f != g) { + freefont(f); + g = f; + } + fonttab[n][i] = 0; + } +} + +void +allfree(void) +{ + int i; + + for (i=0; i<NFONT; i++) + loadfontname(i, "??"); +} + + +void +readmapfile(char *file) +{ + Biobuf *fp; + char *p, cmd[100]; + + if ((fp=Bopen(file, OREAD)) == 0){ + fprint(2, "proof: can't open map file %s\n", file); + exits("urk"); + } + while((p=Brdline(fp, '\n')) != 0) { + p[Blinelen(fp)-1] = 0; + scanstr(p, cmd, 0); + if(p[0]=='\0' || eq(cmd, "#")) /* skip comments, empty */ + continue; + else if(eq(cmd, "xheight")) + buildxheight(fp); + else if(eq(cmd, "map")) + buildmap(fp); + else if(eq(cmd, "special")) + buildtroff(p); + else if(eq(cmd, "troff")) + buildtroff(p); + else + fprint(2, "weird map line %s\n", p); + } + Bterm(fp); +} + +static void +buildxheight(Biobuf *fp) /* map goes from char name to value to print via *string() */ +{ + char *line; + + line = Brdline(fp, '\n'); + if(line == 0){ + fprint(2, "proof: bad map file\n"); + exits("map"); + } + charmap[curmap].xheight = atof(line); +} + +static void +buildmap(Biobuf *fp) /* map goes from char name to value to print via *string() */ +{ + uchar *p, *line, ch[100]; + int val; + Rune r; + + curmap++; + if(curmap >= NMAP){ + fprint(2, "proof: out of char maps; recompile\n"); + exits("charmap"); + } + while ((line = Brdline(fp, '\n'))!= 0){ + if (line[0] == '\n') + return; + line[Blinelen(fp)-1] = 0; + scanstr((char *) line, (char *) ch, (char **)(void*)&p); + if (ch[0] == '\0') { + fprint(2, "bad map file line '%s'\n", (char*)line); + continue; + } + val = strtol((char *) p, 0, 10); +dprint(2, "buildmap %s (%x %x) %s %d\n", (char*)ch, ch[0], ch[1], (char*)p, val); + chartorune(&r, (char*)ch); + if(utflen((char*)ch)==1 && r<QUICK) + charmap[curmap].quick[r] = val; + else + addmap(curmap, strdup((char *) ch), val); /* put somewhere else */ + } +} + +static void +addmap(int n, char *s, int val) /* stick a new link on */ +{ + Link *p = (Link *) malloc(sizeof(Link)); + Link *prev = charmap[n].slow; + + if(p == 0) + exits("out of memory in addmap"); + p->name = (uchar *) s; + p->val = val; + p->next = prev; + charmap[n].slow = p; +} + +static void +buildtroff(char *buf) /* map troff names into bitmap filenames */ +{ /* e.g., R -> times/R., I -> times/I., etc. */ + char *p, cmd[100], name[200], prefix[400], fallback[100]; + + scanstr(buf, cmd, &p); + scanstr(p, name, &p); + scanstr(p, prefix, &p); + while(*p!=0 && isspace(*p)) + p++; + if(*p != 0){ + scanstr(p, fallback, &p); + fontmap[nfontmap].fallback = strdup(fallback); + }else + fontmap[nfontmap].fallback = 0; + fontmap[nfontmap].troffname = strdup(name); + fontmap[nfontmap].prefix = strdup(prefix); + fontmap[nfontmap].map = curmap; + dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n", name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback? fontmap[nfontmap].fallback : "<null>"); + nfontmap++; +} + +static void +fontlookup(int n, char *s) /* map troff name of s into position n */ +{ + int i; + + for(i = 0; i < nfontmap; i++) + if (eq(s, fontmap[i].troffname)) { + strcpy(fname[n], fontmap[i].prefix); + fmap[n] = fontmap[i].map; + pos2fontmap[n] = i; + if (eq(s, "S")) + specfont = n; + dprint(2, "font %d %s is %s\n", n, s, fname[n]); + return; + } + /* god help us if this font isn't there */ +} + + +static char * +map(Rune rp[], int font) /* figure out mapping for char in this font */ +{ + static char s[100]; + char c[10]; + Link *p; + Rune r; + + if(rp[1]==0 && rp[0]<QUICK) /* fast lookup */ + r = charmap[fmap[font]].quick[rp[0]]; + else { /* high-valued or compound character name */ + sprint(c, "%S", rp); + r = 0; + for (p = charmap[fmap[font]].slow; p; p = p->next) + if(eq(c, p->name)){ + r = p->val; + break; + } + } + if(r == 0){ /* not there */ + dprint(2, "didn't find %S font# %d\n", rp, font); + return 0; + } + dprint(2, "map %S to %s font# %d\n", rp, s, font); + s[runetochar(s, &r)] = 0; + return s; +} + +static void +scanstr(char *s, char *ans, char **ep) +{ + for (; isspace((uchar) *s); s++) + ; + for (; *s!=0 && !isspace((uchar) *s); ) + *ans++ = *s++; + *ans = 0; + if (ep) + *ep = s; +} diff --git a/src/cmd/proof/htroff.c b/src/cmd/proof/htroff.c new file mode 100644 index 00000000..d591d384 --- /dev/null +++ b/src/cmd/proof/htroff.c @@ -0,0 +1,579 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <cursor.h> +#include <event.h> +#include <bio.h> +#include "proof.h" + +int res; +int hpos; +int vpos; +int DIV = 11; + +Point offset; +Point xyoffset = { 0,0 }; + +Rectangle view[MAXVIEW]; +Rectangle bound[MAXVIEW]; /* extreme points */ +int nview = 1; + +int lastp; /* last page number we were on */ + +#define NPAGENUMS 200 +struct pagenum { + int num; + long adr; +} pagenums[NPAGENUMS]; +int npagenums; + +int curfont, cursize; + +char *getcmdstr(void); + +static void initpage(void); +static void view_setup(int); +static Point scale(Point); +static void clearview(Rectangle); +static int addpage(int); +static void spline(Image *, int, Point *); +static int skipto(int, int); +static void wiggly(int); +static void devcntrl(void); +static void eatline(void); +static int getn(void); +static int botpage(int); +static void getstr(char *); +/* +static void getutf(char *); +*/ + +#define Do screen->r.min +#define Dc screen->r.max + +/* declarations and definitions of font stuff are in font.c and main.c */ + +static void +initpage(void) +{ + int i; + + view_setup(nview); + for (i = 0; i < nview-1; i++) + draw(screen, view[i], screen, nil, view[i+1].min); + clearview(view[nview-1]); + offset = view[nview-1].min; + vpos = 0; +} + +static void +view_setup(int n) +{ + int i, j, v, dx, dy, r, c; + + switch (n) { + case 1: r = 1; c = 1; break; + case 2: r = 1; c = 2; break; + case 3: r = 1; c = 3; break; + case 4: r = 2; c = 2; break; + case 5: case 6: r = 2; c = 3; break; + case 7: case 8: case 9: r = 3; c = 3; break; + default: r = (n+2)/3; c = 3; break; /* finking out */ + } + dx = (Dc.x - Do.x) / c; + dy = (Dc.y - Do.y) / r; + v = 0; + for (i = 0; i < r && v < n; i++) + for (j = 0; j < c && v < n; j++) { + view[v] = screen->r; + view[v].min.x = Do.x + j * dx; + view[v].max.x = Do.x + (j+1) * dx; + view[v].min.y = Do.y + i * dy; + view[v].max.y = Do.y + (i+1) * dy; + v++; + } +} + +static void +clearview(Rectangle r) +{ + draw(screen, r, display->white, nil, r.min); +} + +int resized; +void eresized(int new) +{ + /* this is called if we are resized */ + if(new && getwindow(display, Refnone) < 0) + drawerror(display, "can't reattach to window"); + initpage(); + resized = 1; +} + +static Point +scale(Point p) +{ + p.x /= DIV; + p.y /= DIV; + return addpt(xyoffset, addpt(offset,p)); +} + +static int +addpage(int n) +{ + int i; + + for (i = 0; i < npagenums; i++) + if (n == pagenums[i].num) + return i; + if (npagenums < NPAGENUMS-1) { + pagenums[npagenums].num = n; + pagenums[npagenums].adr = offsetc(); + npagenums++; + } + return npagenums; +} + +void +readpage(void) +{ + int c, i, a, alpha, phi; + static int first = 0; + int m, n, gonow = 1; + Rune r[32], t; + Point p,q,qq; + + offset = screen->clipr.min; + esetcursor(&deadmouse); + while (gonow) + { + c = getc(); + switch (c) + { + case -1: + esetcursor(0); + if (botpage(lastp+1)) { + initpage(); + break; + } + exits(0); + case 'p': /* new page */ + lastp = getn(); + addpage(lastp); + if (first++ > 0) { + esetcursor(0); + botpage(lastp); + esetcursor(&deadmouse); + } + initpage(); + break; + case '\n': /* when input is text */ + case ' ': + case 0: /* occasional noise creeps in */ + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* two motion digits plus a character */ + hpos += (c-'0')*10 + getc()-'0'; + + /* FALLS THROUGH */ + case 'c': /* single ascii character */ + r[0] = getrune(); + r[1] = 0; + dochar(r); + break; + + case 'C': + for(i=0; ; i++){ + t = getrune(); + if(isspace(t)) + break; + r[i] = t; + } + r[i] = 0; + dochar(r); + break; + + case 'N': + r[0] = getn(); + r[1] = 0; + dochar(r); + break; + + case 'D': /* draw function */ + switch (getc()) + { + case 'l': /* draw a line */ + n = getn(); + m = getn(); + p = Pt(hpos,vpos); + q = addpt(p, Pt(n,m)); + hpos += n; + vpos += m; + line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP); + break; + case 'c': /* circle */ + /*nop*/ + m = getn()/2; + p = Pt(hpos+m,vpos); + hpos += 2*m; + ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP); + /* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/ + break; + case 'e': /* ellipse */ + /*nop*/ + m = getn()/2; + n = getn()/2; + p = Pt(hpos+m,vpos); + hpos += 2*m; + ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP); + break; + case 'a': /* arc */ + p = scale(Pt(hpos,vpos)); + n = getn(); + m = getn(); + hpos += n; + vpos += m; + q = scale(Pt(hpos,vpos)); + n = getn(); + m = getn(); + hpos += n; + vpos += m; + qq = scale(Pt(hpos,vpos)); + /* + * tricky: convert from 3-point clockwise to + * center, angle1, delta-angle counterclockwise. + */ + a = hypot(qq.x-q.x, qq.y-q.y); + phi = atan2(q.y-p.y, p.x-q.x)*180./PI; + alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi; + if(alpha < 0) + alpha += 360; + arc(screen, q, a, a, 0, display->black, ZP, phi, alpha); + break; + case '~': /* wiggly line */ + wiggly(0); + break; + default: + break; + } + eatline(); + break; + case 's': + n = getn(); /* ignore fractional sizes */ + if (cursize == n) + break; + cursize = n; + if (cursize >= NFONT) + cursize = NFONT-1; + break; + case 'f': + curfont = getn(); + break; + case 'H': /* absolute horizontal motion */ + hpos = getn(); + break; + case 'h': /* relative horizontal motion */ + hpos += getn(); + break; + case 'w': /* word space */ + break; + case 'V': + vpos = getn(); + break; + case 'v': + vpos += getn(); + break; + case '#': /* comment */ + case 'n': /* end of line */ + eatline(); + break; + case 'x': /* device control */ + devcntrl(); + break; + default: + fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc()); + exits("bad char"); + } + } + esetcursor(0); +} + +static void +spline(Image *b, int n, Point *pp) +{ + long w, t1, t2, t3, fac=1000; + int i, j, steps=10; + Point p, q; + + for (i = n; i > 0; i--) + pp[i] = pp[i-1]; + pp[n+1] = pp[n]; + n += 2; + p = pp[0]; + for(i = 0; i < n-2; i++) + { + for(j = 0; j < steps; j++) + { + w = fac * j / steps; + t1 = w * w / (2 * fac); + w = w - fac/2; + t2 = 3*fac/4 - w * w / fac; + w = w - fac/2; + t3 = w * w / (2*fac); + q.x = (t1*pp[i+2].x + t2*pp[i+1].x + + t3*pp[i].x + fac/2) / fac; + q.y = (t1*pp[i+2].y + t2*pp[i+1].y + + t3*pp[i].y + fac/2) / fac; + line(b, p, q, 0, 0, 0, display->black, ZP); + p = q; + } + } +} + +/* Have to parse skipped pages, to find out what fonts are loaded. */ +static int +skipto(int gotop, int curp) +{ + char *p; + int i; + + if (gotop == curp) + return 1; + for (i = 0; i < npagenums; i++) + if (pagenums[i].num == gotop) { + if (seekc(pagenums[i].adr) == Beof) { + fprint(2, "can't rewind input\n"); + return 0; + } + return 1; + } + if (gotop <= curp) { + restart: + if (seekc(0) == Beof) { + fprint(2, "can't rewind input\n"); + return 0; + } + } + for(;;){ + p = rdlinec(); + if (p == 0) { + if(gotop>curp){ + gotop = curp; + goto restart; + } + return 0; + } else if (*p == 'p') { + lastp = curp = atoi(p+1); + addpage(lastp); /* maybe 1 too high */ + if (curp>=gotop) + return 1; + } + } +} + +static void +wiggly(int skip) +{ + Point p[300]; + int c,i,n; + for (n = 1; (c = getc()) != '\n' && c>=0; n++) { + ungetc(); + p[n].x = getn(); + p[n].y = getn(); + } + p[0] = Pt(hpos, vpos); + for (i = 1; i < n; i++) + p[i] = addpt(p[i],p[i-1]); + hpos = p[n-1].x; + vpos = p[n-1].y; + for (i = 0; i < n; i++) + p[i] = scale(p[i]); + if (!skip) + spline(screen,n,p); +} + +static void +devcntrl(void) /* interpret device control functions */ +{ + char str[80]; + int n; + + getstr(str); + switch (str[0]) { /* crude for now */ + case 'i': /* initialize */ + break; + case 'T': /* device name */ + getstr(devname); + break; + case 't': /* trailer */ + break; + case 'p': /* pause -- can restart */ + break; + case 's': /* stop */ + break; + case 'r': /* resolution assumed when prepared */ + res=getn(); + DIV = floor(.5 + res/(100.0*mag)); + if (DIV < 1) + DIV = 1; + mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */ + break; + case 'f': /* font used */ + n = getn(); + getstr(str); + loadfontname(n, str); + break; + /* these don't belong here... */ + case 'H': /* char height */ + break; + case 'S': /* slant */ + break; + case 'X': + break; + } + eatline(); +} + +int +isspace(int c) +{ + return c==' ' || c=='\t' || c=='\n'; +} + +static void +getstr(char *is) +{ + uchar *s = (uchar *) is; + + for (*s = getc(); isspace(*s); *s = getc()) + ; + for (; !isspace(*s); *++s = getc()) + ; + ungetc(); + *s = 0; +} + +#if 0 +static void +getutf(char *s) /* get next utf char, as bytes */ +{ + int c, i; + + for (i=0;;) { + c = getc(); + if (c < 0) + return; + s[i++] = c; + + if (fullrune(s, i)) { + s[i] = 0; + return; + } + } +} +#endif + +static void +eatline(void) +{ + int c; + + while ((c=getc()) != '\n' && c >= 0) + ; +} + +static int +getn(void) +{ + int n, c, sign; + + while (c = getc()) + if (!isspace(c)) + break; + if(c == '-'){ + sign = -1; + c = getc(); + }else + sign = 1; + for (n = 0; '0'<=c && c<='9'; c = getc()) + n = n*10 + c - '0'; + while (c == ' ') + c = getc(); + ungetc(); + return(n*sign); +} + +static int +botpage(int np) /* called at bottom of page np-1 == top of page np */ +{ + char *p; + int n; + + while (p = getcmdstr()) { + if (*p == '\0') + return 0; + if (*p == 'q') + exits(p); + if (*p == 'c') /* nop */ + continue; + if (*p == 'm') { + mag = atof(p+1); + if (mag <= .1 || mag >= 10) + mag = DEFMAG; + allfree(); /* zap fonts */ + DIV = floor(.5 + res/(100.0*mag)); + if (DIV < 1) + DIV = 1; + mag = res/(100.0*DIV); + return skipto(np-1, np); /* reprint the page */ + } + if (*p == 'x') { + xyoffset.x += atoi(p+1)*100; + skipto(np-1, np); + return 1; + } + if (*p == 'y') { + xyoffset.y += atoi(p+1)*100; + skipto(np-1, np); + return 1; + } + if (*p == '/') { /* divide into n pieces */ + nview = atoi(p+1); + if (nview < 1) + nview = 1; + else if (nview > MAXVIEW) + nview = MAXVIEW; + return skipto(np-1, np); + } + if (*p == 'p') { + if (p[1] == '\0'){ /* bare 'p' */ + if(skipto(np-1, np)) + return 1; + continue; + } + p++; + } + if ('0'<=*p && *p<='9') { + n = atoi(p); + if(skipto(n, np)) + return 1; + continue; + } + if (*p == '-' || *p == '+') { + n = atoi(p); + if (n == 0) + n = *p == '-' ? -1 : 1; + if(skipto(np - 1 + n, np)) + return 1; + continue; + } + if (*p == 'd') { + dbg = 1 - dbg; + continue; + } + + fprint(2, "illegal; try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n"); + } + return 0; +} diff --git a/src/cmd/proof/main.c b/src/cmd/proof/main.c new file mode 100644 index 00000000..5e0c804c --- /dev/null +++ b/src/cmd/proof/main.c @@ -0,0 +1,226 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <event.h> +#include <bio.h> +#include "proof.h" + +Rectangle rpage = { 0, 0, 850, 1150 }; +char devname[64]; +double mag = DEFMAG; +int dbg = 0; +char *track = 0; +Biobuf bin; +char *libfont = "#9/font"; +char *mapfile = "MAP"; +char *mapname = "MAP"; + +void +usage(void) +{ + fprint(2, "usage: proof [-m mag] [-/ nview] [-x xoff] [-y yoff] [-M mapfile] [-F fontdir] [-dt] file...\n"); + exits("usage"); +} + +double +getnum(char *s) +{ + if(s == nil) + usage(); + return atof(s); +} + +char* +getstr(char *s) +{ + if(s == nil) + usage(); + return s; +} + +void +main(int argc, char *argv[]) +{ + char c; + int dotrack = 0; + + libfont = unsharp(libfont); + ARGBEGIN{ + case 'm': /* magnification */ + mag = getnum(ARGF()); + if (mag < 0.1 || mag > 10){ + fprint(2, "ridiculous mag argument ignored\n"); + mag = DEFMAG; + } + break; + case '/': + nview = getnum(ARGF()); + if (nview < 1 || nview > MAXVIEW) + nview = 1; + break; + case 'x': + xyoffset.x += getnum(ARGF()) * 100; + break; + case 'y': + xyoffset.y += getnum(ARGF()) * 100; + break; + case 'M': /* change MAP file */ + mapname = EARGF(usage()); + break; + case 'F': /* change /lib/font/bit directory */ + libfont = EARGF(usage()); + break; + case 'd': + dbg = 1; + break; + case 't': + dotrack = 1; + break; + default: + usage(); + }ARGEND + + if (argc > 0) { + close(0); + if (open(argv[0], 0) != 0) { + sysfatal("can't open %s: %r\n", argv[0]); + exits("open failure"); + } + if(dotrack) + track = argv[0]; + } + Binit(&bin, 0, OREAD); + mapfile = smprint("%s/%s", libfont, mapname); + readmapfile(mapfile); + for (c = 0; c < NFONT; c++) + loadfontname(c, "??"); + mapscreen(); + clearscreen(); + readpage(); +} + +/* + * Input buffer to allow us to back up + */ +#define SIZE 100000 /* 8-10 pages, typically */ + +char bufc[SIZE]; +char *inc = bufc; /* where next input character goes */ +char *outc = bufc; /* next character to be read from buffer */ +int off; /* position of outc in total input stream */ + +void +addc(int c) +{ + *inc++ = c; + if(inc == &bufc[SIZE]) + inc = &bufc[0]; +} + +int +getc(void) +{ + int c; + + if(outc == inc){ + c = Bgetc(&bin); + if(c == Beof) + return Beof; + addc(c); + } + off++; + c = *outc++; + if(outc == &bufc[SIZE]) + outc = &bufc[0]; + return c; +} + +int +getrune(void) +{ + int c, n; + Rune r; + char buf[UTFmax]; + + for(n=0; !fullrune(buf, n); n++){ + c = getc(); + if(c == Beof) + return Beof; + buf[n] = c; + } + chartorune(&r, buf); + return r; +} + +int +nbuf(void) /* return number of buffered characters */ +{ + int ini, outi; + + ini = inc-bufc; + outi = outc-bufc; + if(ini < outi) + ini += SIZE; + return ini-outi; +} + +ulong +seekc(ulong o) +{ + ulong avail; + long delta; + + delta = off-o; + if(delta < 0) + return Beof; + avail = SIZE-nbuf(); + if(delta < avail){ + off = o; + outc -= delta; + if(outc < &bufc[0]) + outc += SIZE; + return off; + } + return Beof; +} + +void +ungetc(void) +{ + if(off == 0) + return; + if(nbuf() == SIZE){ + fprint(2, "backup buffer overflow\n"); + return; + } + if(outc == &bufc[0]) + outc = &bufc[SIZE]; + --outc; + --off; +} + +ulong +offsetc(void) +{ + return off; +} + +char* +rdlinec(void) +{ + static char buf[2048]; + int c, i; + + for(i=0; i<sizeof buf; ){ + c = getc(); + if(c == Beof) + break; + buf[i++] = c; + if(c == '\n') + break; + } + + if(i == 0) + return nil; + return buf; +} diff --git a/src/cmd/proof/mkfile b/src/cmd/proof/mkfile new file mode 100644 index 00000000..c0e877be --- /dev/null +++ b/src/cmd/proof/mkfile @@ -0,0 +1,14 @@ +<$PLAN9/src/mkhdr + +TARG=proof +OFILES=main.$O\ + font.$O\ + htroff.$O\ + screen.$O\ + +HFILES=proof.h + +<$PLAN9/src/mkone + +$O.pout: $OFILES + $LD -o $O.pout -p $OFILES diff --git a/src/cmd/proof/portdate b/src/cmd/proof/portdate new file mode 100644 index 00000000..e0762007 --- /dev/null +++ b/src/cmd/proof/portdate @@ -0,0 +1,5 @@ +font.c 2004/1225 +htroff.c 2004/1225 +main.c 2004/1225 +proof.h 2004/1225 +screen.c 2004/1225 diff --git a/src/cmd/proof/proof.h b/src/cmd/proof/proof.h new file mode 100644 index 00000000..73f39b8c --- /dev/null +++ b/src/cmd/proof/proof.h @@ -0,0 +1,48 @@ +#include <cursor.h> +#undef isspace +#define NPAGES 500 +#define NFONT 33 +#define NSIZE 40 +#define MINSIZE 4 +#define DEFMAG (10.0/11.0) /* was (10.0/11.0), then 1 */ +#define MAXVIEW 40 + +#define ONES ~0 + +extern char devname[]; +extern double mag; +extern int nview; +extern int hpos, vpos, curfont, cursize; +extern int DIV, res; +extern int Mode; + +extern Point offset; /* for small pages within big page */ +extern Point xyoffset; /* for explicit x,y move */ +extern Cursor deadmouse; + +extern char *libfont; + +void mapscreen(void); +void clearscreen(void); +char *getcmdstr(void); + +void readmapfile(char *); +void dochar(Rune*); +void bufput(void); +void loadfontname(int, char *); +void allfree(void); +void readpage(void); +int isspace(int); + +extern int getc(void); +extern int getrune(void); +extern void ungetc(void); +extern ulong offsetc(void); +extern ulong seekc(ulong); +extern char* rdlinec(void); + + +#define dprint if (dbg) fprint + +extern int dbg; +extern int resized; diff --git a/src/cmd/proof/screen.c b/src/cmd/proof/screen.c new file mode 100644 index 00000000..dccfe01d --- /dev/null +++ b/src/cmd/proof/screen.c @@ -0,0 +1,315 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <cursor.h> +#include <event.h> +#include <bio.h> +#include "proof.h" + +static int checkmouse(void); +/* static int buttondown(void); */ +static char *getmousestr(void); +static char *getkbdstr(int); + +extern Cursor blot; +extern char *track; + +Mouse mouse; + +void +mapscreen(void) +{ + if(initdraw(0, 0, "proof") < 0){ + fprint(2, "proof: initdraw failed: %r\n"); + exits("initdraw"); + } + einit(Ekeyboard|Emouse); +} + +void +clearscreen(void) +{ + draw(screen, screen->r, display->black, nil, ZP); +} + +void +screenprint(char *fmt, ...) +{ + char buf[100]; + Point p; + va_list args; + + va_start(args, fmt); + vseprint(buf, &buf[sizeof buf], fmt, args); + va_end(args); + p = Pt(screen->clipr.min.x+40, screen->clipr.max.y-40); + string(screen, p, display->black, ZP, font, buf); +} + +#define Viewkey 0xb2 +#define etimer(x, y) 0 + +char * +getcmdstr(void) +{ + Event ev; + int e; + static ulong timekey = 0; + ulong tracktm = 0; + Dir *dir; + + if(track){ + if(timekey == 0) + timekey = etimer(0, 5000); + dir = dirstat(track); + if(dir != nil){ + tracktm = dir->mtime; + free(dir); + } + } + for (;;) { + e = event(&ev); + if(resized){ + resized = 0; + return "p"; + } + if ((e & Emouse) && ev.mouse.buttons) { + mouse = ev.mouse; + return getmousestr(); + } else if (e & Ekeyboard) + return getkbdstr(ev.kbdc); /* sadly, no way to unget */ + else if (e & timekey) { + if((dir = dirstat(track)) != nil){ + if(tracktm < dir->mtime){ + free(dir); + return "q"; + } + free(dir); + } + } + } + return nil; +} + +static char * +getkbdstr(int c0) +{ + static char buf[100]; + char *p; + int c; + + if (c0 == '\n') + return ""; + buf[0] = c0; + buf[1] = 0; + screenprint("%s", buf); + for (p = buf+1; (c = ekbd()) != '\n' && c != '\r' && c != -1 && c != Viewkey; ) { + if (c == '\b' && p > buf) { + *--p = ' '; + } else { + *p++ = c; + *p = 0; + } + screenprint("%s", buf); + } + *p = 0; + return buf; +} + + +#define button3(b) ((b) & 4) +#define button2(b) ((b) & 2) +#define button1(b) ((b) & 1) +#define button23(b) ((b) & 6) +#define button123(b) ((b) & 7) + +#define butcvt(b) (1 << ((b) - 1)) + +#if 0 +static int buttondown(void) /* report state of buttons, if any */ +{ + if (!ecanmouse()) /* no event pending */ + return 0; + mouse = emouse(); /* something, but it could be motion */ + return mouse.buttons & 7; +} +#endif + +int waitdown(void) /* wait until some button is down */ +{ + while (!(mouse.buttons & 7)) + mouse = emouse(); + return mouse.buttons & 7; +} + +int waitup(void) +{ + while (mouse.buttons & 7) + mouse = emouse(); + return mouse.buttons & 7; +} + +char *m3[] = { "next", "prev", "page n", "again", "bigger", "smaller", "pan", "quit?", 0 }; +char *m2[] = { 0 }; + +enum { Next = 0, Prev, Page, Again, Bigger, Smaller, Pan, Quit }; + +Menu mbut3 = { m3, 0, 0 }; +Menu mbut2 = { m2, 0, 0 }; + +int last_hit; +int last_but; + +char *pan(void) +{ + Point dd, xy, lastxy, min, max; + + esetcursor(&blot); + waitdown(); + xy = mouse.xy; + do{ + lastxy = mouse.xy; + mouse = emouse(); + dd = subpt(mouse.xy, lastxy); + min = addpt(screen->clipr.min, dd); + max = addpt(screen->clipr.max, dd); + draw(screen, rectaddpt(screen->r, subpt(mouse.xy, lastxy)), + screen, nil, screen->r.min); + if(mouse.xy.x < lastxy.x) /* moved left, clear right */ + draw(screen, Rect(max.x, screen->r.min.y, screen->r.max.x, screen->r.max.y), + display->white, nil, ZP); + else /* moved right, clear left*/ + draw(screen, Rect(screen->r.min.x, screen->r.min.y, min.x, screen->r.max.y), + display->white, nil, ZP); + if(mouse.xy.y < lastxy.y) /* moved up, clear down */ + draw(screen, Rect(screen->r.min.x, max.y, screen->r.max.x, screen->r.max.y), + display->white, nil, ZP); + else /* moved down, clear up */ + draw(screen, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, min.y), + display->white, nil, ZP); + flushimage(display, 1); + }while(mouse.buttons); + + xyoffset = addpt(xyoffset, subpt(mouse.xy, xy)); + + esetcursor(0); + return "p"; +} + +static char *getmousestr(void) +{ + static char buf[20]; + + checkmouse(); + if (last_but == 1) + return "p"; /* repaint after panning */ + if (last_but == 2) { + return "c"; + } else if (last_but == 3) { + switch (last_hit) { + case Next: + return ""; + case Prev: + return "-1"; + case Page: + screenprint("page? "); + return "c"; + case Again: + return "p"; + case Bigger: + sprint(buf, "m%g", mag * 1.1); + return buf; + case Smaller: + sprint(buf, "m%g", mag / 1.1); + return buf; + case Pan: + return pan(); + case Quit: + return "q"; + default: + return "c"; + } + } else { /* button 1 or bail out */ + return "c"; + } +} + +static int +checkmouse(void) /* return button touched if any */ +{ + int c, b; + char *p; + extern int confirm(int); + + b = waitdown(); + last_but = 0; + last_hit = -1; + c = 0; + if (button3(b)) { + last_hit = emenuhit(3, &mouse, &mbut3); + last_but = 3; + } else if (button2(b)) { + last_hit = emenuhit(2, &mouse, &mbut2); + last_but = 2; + } else { /* button1() */ + pan(); + last_but = 1; + } + waitup(); + if (last_but == 3 && last_hit >= 0) { + p = m3[last_hit]; + c = p[strlen(p) - 1]; + } + if (c == '?' && !confirm(last_but)) + last_hit = -1; + return last_but; +} + +Cursor deadmouse = { + { 0, 0}, /* offset */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41, + 0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0, + 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41, + 0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0, + 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } +}; + +Cursor blot ={ + { 0, 0 }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } +}; + +Cursor skull ={ + { 0, 0 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, + 0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0, + 0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27, + 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, + 0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0, + 0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27, + 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } +}; + +int +confirm(int but) /* ask for confirmation if menu item ends with '?' */ +{ + int c; + static int but_cvt[8] = { 0, 1, 2, 0, 3, 0, 0, 0 }; + + esetcursor(&skull); + c = waitdown(); + waitup(); + esetcursor(0); + return but == but_cvt[c]; +} |