diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/proof/htroff.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/proof/htroff.c')
-rwxr-xr-x | sys/src/cmd/proof/htroff.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/sys/src/cmd/proof/htroff.c b/sys/src/cmd/proof/htroff.c new file mode 100755 index 000000000..b7bdec0ed --- /dev/null +++ b/sys/src/cmd/proof/htroff.c @@ -0,0 +1,575 @@ +#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; +} + +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; + } + } +} + +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; +} |