summaryrefslogtreecommitdiff
path: root/sys/src/cmd/proof/htroff.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/proof/htroff.c575
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;
+}