tan old saddle - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 020c80587a21a72ca8f9a503640c4234c289a19a | |
parent 24c02865d8fcc97d1fb5cb9281810d8074aa5eb1 | |
Author: rsc <devnull@localhost> | |
Date: Tue, 4 Jan 2005 21:24:19 +0000 | |
an old saddle | |
Diffstat: | |
A src/cmd/proof/font.c | 372 +++++++++++++++++++++++++++++… | |
A src/cmd/proof/htroff.c | 579 +++++++++++++++++++++++++++++… | |
A src/cmd/proof/main.c | 226 +++++++++++++++++++++++++++++… | |
A src/cmd/proof/mkfile | 14 ++++++++++++++ | |
A src/cmd/proof/portdate | 5 +++++ | |
A src/cmd/proof/proof.h | 48 +++++++++++++++++++++++++++++… | |
A 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 | |
t@@ -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 quic… | |
+#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 he… | |
+}; | |
+ | |
+Fontmap fontmap[100]; | |
+int pos2fontmap[NFONT]; /* indexed by troff font position, gives… | |
+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]].trof… | |
+ 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, fontn… | |
+ 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… | |
+ 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… | |
+ 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,… | |
+ 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… | |
+ exits("rdsubfont"); | |
+ } | |
+ close(fd); | |
+ ff = mkfont(f, 0); | |
+ if(ff == 0){ | |
+ fprint(2, "can't mkfont %s: %r… | |
+ exits("rdsubfont"); | |
+ } | |
+ fonttab[n][s] = ff; | |
+ dprint(2, "using %s for font %d %d\n",… | |
+ return; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n],… | |
+ 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 v… | |
+{ | |
+ 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 *… | |
+{ | |
+ 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, va… | |
+ chartorune(&r, (char*)ch); | |
+ if(utflen((char*)ch)==1 && r<QUICK) | |
+ charmap[curmap].quick[r] = val; | |
+ else | |
+ addmap(curmap, strdup((char *) ch), val); /* pu… | |
+ } | |
+} | |
+ | |
+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"… | |
+ 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 | |
t@@ -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, disp… | |
+ 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, dis… | |
+ /* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,O… | |
+ 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, dis… | |
+ 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 counterclockwi… | |
+ */ | |
+ 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 - ph… | |
+ if(alpha < 0) | |
+ alpha += 360; | |
+ arc(screen, q, a, a, 0, display->black, ZP, ph… | |
+ 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 %lu… | |
+ 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 coarsene… | |
+ 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 o… | |
+ } | |
+ return 0; | |
+} | |
diff --git a/src/cmd/proof/main.c b/src/cmd/proof/main.c | |
t@@ -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 ma… | |
+ 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 | |
t@@ -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 | |
t@@ -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 | |
t@@ -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 bi… | |
+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 | |
t@@ -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 … | |
+ 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 != V… | |
+ 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", … | |
+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.ma… | |
+ display->white, nil, ZP); | |
+ else /* moved right, clear left*/ | |
+ draw(screen, Rect(screen->r.min.x, screen->r.min.y, mi… | |
+ 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.ma… | |
+ display->white, nil, ZP); | |
+ else /* moved down, clear up */ | |
+ draw(screen, Rect(screen->r.min.x, screen->r.min.y, sc… | |
+ 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]; | |
+} |