URI:
       thtroff.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       thtroff.c (10511B)
       ---
            1 #include        <u.h>
            2 #include        <libc.h>
            3 #include        <draw.h>
            4 #include        <cursor.h>
            5 #include        <event.h>
            6 #include        <bio.h>
            7 #include        "proof.h"
            8 
            9 int        res;
           10 int        hpos;
           11 int        vpos;
           12 int        DIV = 11;
           13 
           14 Point offset;
           15 Point xyoffset = { 0,0 };
           16 
           17 Rectangle        view[MAXVIEW];
           18 Rectangle        bound[MAXVIEW];                /* extreme points */
           19 int        nview = 1;
           20 
           21 int        lastp;        /* last page number we were on */
           22 
           23 #define        NPAGENUMS        200
           24 struct pagenum {
           25         int        num;
           26         long        adr;
           27 } pagenums[NPAGENUMS];
           28 int        npagenums;
           29 
           30 int        curfont, cursize;
           31 
           32 char        *getcmdstr(void);
           33 
           34 static void        initpage(void);
           35 static void        view_setup(int);
           36 static Point        scale(Point);
           37 static void        clearview(Rectangle);
           38 static int        addpage(int);
           39 static void        spline(Image *, int, Point *);
           40 static int        skipto(int, int);
           41 static void        wiggly(int);
           42 static void        devcntrl(void);
           43 static void        eatline(void);
           44 static int        getn(void);
           45 static int        botpage(int);
           46 static void        getstr(char *);
           47 /*
           48 static void        getutf(char *);
           49 */
           50 
           51 #define Do screen->r.min
           52 #define Dc screen->r.max
           53 
           54 /* declarations and definitions of font stuff are in font.c and main.c */
           55 
           56 static void
           57 initpage(void)
           58 {
           59         int i;
           60 
           61         view_setup(nview);
           62         for (i = 0; i < nview-1; i++)
           63                 draw(screen, view[i], screen, nil, view[i+1].min);
           64         clearview(view[nview-1]);
           65         offset = view[nview-1].min;
           66         vpos = 0;
           67 }
           68 
           69 static void
           70 view_setup(int n)
           71 {
           72         int i, j, v, dx, dy, r, c;
           73 
           74         switch (n) {
           75         case 1: r = 1; c = 1; break;
           76         case 2: r = 1; c = 2; break;
           77         case 3: r = 1; c = 3; break;
           78         case 4: r = 2; c = 2; break;
           79         case 5: case 6: r = 2; c = 3; break;
           80         case 7: case 8: case 9: r = 3; c = 3; break;
           81         default: r = (n+2)/3; c = 3; break; /* finking out */
           82         }
           83         dx = (Dc.x - Do.x) / c;
           84         dy = (Dc.y - Do.y) / r;
           85         v = 0;
           86         for (i = 0; i < r && v < n; i++)
           87                 for (j = 0; j < c && v < n; j++) {
           88                         view[v] = screen->r;
           89                         view[v].min.x = Do.x + j * dx;
           90                         view[v].max.x = Do.x + (j+1) * dx;
           91                         view[v].min.y = Do.y + i * dy;
           92                         view[v].max.y = Do.y + (i+1) * dy;
           93                         v++;
           94                 }
           95 }
           96 
           97 static void
           98 clearview(Rectangle r)
           99 {
          100         draw(screen, r, display->white, nil, r.min);
          101 }
          102 
          103 int resized;
          104 void eresized(int new)
          105 {
          106         /* this is called if we are resized */
          107         if(new && getwindow(display, Refnone) < 0)
          108                 drawerror(display, "can't reattach to window");
          109         initpage();
          110         resized = 1;
          111 }
          112 
          113 static Point
          114 scale(Point p)
          115 {
          116         p.x /= DIV;
          117         p.y /= DIV;
          118         return addpt(xyoffset, addpt(offset,p));
          119 }
          120 
          121 static int
          122 addpage(int n)
          123 {
          124         int i;
          125 
          126         for (i = 0; i < npagenums; i++)
          127                 if (n == pagenums[i].num)
          128                         return i;
          129         if (npagenums < NPAGENUMS-1) {
          130                 pagenums[npagenums].num = n;
          131                 pagenums[npagenums].adr = offsetc();
          132                 npagenums++;
          133         }
          134         return npagenums;
          135 }
          136 
          137 void
          138 readpage(void)
          139 {
          140         int c, i, a, alpha, phi;
          141         static int first = 0;
          142         int m, n, gonow = 1;
          143         Rune r[32], t;
          144         Point p,q,qq;
          145 
          146         offset = screen->clipr.min;
          147         esetcursor(&deadmouse);
          148         while (gonow)
          149         {
          150                 c = getc();
          151                 switch (c)
          152                 {
          153                 case -1:
          154                         esetcursor(0);
          155                         if (botpage(lastp+1)) {
          156                                 initpage();
          157                                 break;
          158                         }
          159                         exits(0);
          160                 case 'p':        /* new page */
          161                         lastp = getn();
          162                         addpage(lastp);
          163                         if (first++ > 0) {
          164                                 esetcursor(0);
          165                                 botpage(lastp);
          166                                 esetcursor(&deadmouse);
          167                         }
          168                         initpage();
          169                         break;
          170                 case '\n':        /* when input is text */
          171                 case ' ':
          172                 case 0:                /* occasional noise creeps in */
          173                         break;
          174                 case '0': case '1': case '2': case '3': case '4':
          175                 case '5': case '6': case '7': case '8': case '9':
          176                         /* two motion digits plus a character */
          177                         hpos += (c-'0')*10 + getc()-'0';
          178 
          179                 /* FALLS THROUGH */
          180                 case 'c':        /* single ascii character */
          181                         r[0] = getrune();
          182                         r[1] = 0;
          183                         dochar(r);
          184                         break;
          185 
          186                 case 'C':
          187                         for(i=0; ; i++){
          188                                 t = getrune();
          189                                 if(isspace(t))
          190                                         break;
          191                                 r[i] = t;
          192                         }
          193                         r[i] = 0;
          194                         dochar(r);
          195                         break;
          196 
          197                 case 'N':
          198                         r[0] = getn();
          199                         r[1] = 0;
          200                         dochar(r);
          201                         break;
          202 
          203                 case 'D':        /* draw function */
          204                         switch (getc())
          205                         {
          206                         case 'l':        /* draw a line */
          207                                 n = getn();
          208                                 m = getn();
          209                                 p = Pt(hpos,vpos);
          210                                 q = addpt(p, Pt(n,m));
          211                                 hpos += n;
          212                                 vpos += m;
          213                                 line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP);
          214                                 break;
          215                         case 'c':        /* circle */
          216                                 /*nop*/
          217                                 m = getn()/2;
          218                                 p = Pt(hpos+m,vpos);
          219                                 hpos += 2*m;
          220                                 ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP);
          221                                 /* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
          222                                 break;
          223                         case 'e':        /* ellipse */
          224                                 /*nop*/
          225                                 m = getn()/2;
          226                                 n = getn()/2;
          227                                 p = Pt(hpos+m,vpos);
          228                                 hpos += 2*m;
          229                                 ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP);
          230                                 break;
          231                         case 'a':        /* arc */
          232                                 p = scale(Pt(hpos,vpos));
          233                                 n = getn();
          234                                 m = getn();
          235                                 hpos += n;
          236                                 vpos += m;
          237                                 q = scale(Pt(hpos,vpos));
          238                                 n = getn();
          239                                 m = getn();
          240                                 hpos += n;
          241                                 vpos += m;
          242                                 qq = scale(Pt(hpos,vpos));
          243                                 /*
          244                                   * tricky: convert from 3-point clockwise to
          245                                   * center, angle1, delta-angle counterclockwise.
          246                                  */
          247                                 a = hypot(qq.x-q.x, qq.y-q.y);
          248                                 phi = atan2(q.y-p.y, p.x-q.x)*180./PI;
          249                                 alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi;
          250                                 if(alpha < 0)
          251                                         alpha += 360;
          252                                 arc(screen, q, a, a, 0, display->black, ZP, phi, alpha);
          253                                 break;
          254                         case '~':        /* wiggly line */
          255                                 wiggly(0);
          256                                 break;
          257                         default:
          258                                 break;
          259                         }
          260                         eatline();
          261                         break;
          262                 case 's':
          263                         n = getn();        /* ignore fractional sizes */
          264                         if (cursize == n)
          265                                 break;
          266                         cursize = n;
          267                         if (cursize >= NFONT)
          268                                 cursize = NFONT-1;
          269                         break;
          270                 case 'f':
          271                         curfont = getn();
          272                         break;
          273                 case 'H':        /* absolute horizontal motion */
          274                         hpos = getn();
          275                         break;
          276                 case 'h':        /* relative horizontal motion */
          277                         hpos += getn();
          278                         break;
          279                 case 'w':        /* word space */
          280                         break;
          281                 case 'V':
          282                         vpos = getn();
          283                         break;
          284                 case 'v':
          285                         vpos += getn();
          286                         break;
          287                 case '#':        /* comment */
          288                 case 'n':        /* end of line */
          289                         eatline();
          290                         break;
          291                 case 'x':        /* device control */
          292                         devcntrl();
          293                         break;
          294                 default:
          295                         fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc());
          296                         exits("bad char");
          297                 }
          298         }
          299         esetcursor(0);
          300 }
          301 
          302 static void
          303 spline(Image *b, int n, Point *pp)
          304 {
          305         long w, t1, t2, t3, fac=1000;
          306         int i, j, steps=10;
          307         Point p, q;
          308 
          309         for (i = n; i > 0; i--)
          310                 pp[i] = pp[i-1];
          311         pp[n+1] = pp[n];
          312         n += 2;
          313         p = pp[0];
          314         for(i = 0; i < n-2; i++)
          315         {
          316                 for(j = 0; j < steps; j++)
          317                 {
          318                         w = fac * j / steps;
          319                         t1 = w * w / (2 * fac);
          320                         w = w - fac/2;
          321                         t2 = 3*fac/4 - w * w / fac;
          322                         w = w - fac/2;
          323                         t3 = w * w / (2*fac);
          324                         q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
          325                                 t3*pp[i].x + fac/2) / fac;
          326                         q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
          327                                 t3*pp[i].y + fac/2) / fac;
          328                         line(b, p, q, 0, 0, 0, display->black, ZP);
          329                         p = q;
          330                 }
          331         }
          332 }
          333 
          334 /* Have to parse skipped pages, to find out what fonts are loaded. */
          335 static int
          336 skipto(int gotop, int curp)
          337 {
          338         char *p;
          339         int i;
          340 
          341         if (gotop == curp)
          342                 return 1;
          343         for (i = 0; i < npagenums; i++)
          344                 if (pagenums[i].num == gotop) {
          345                         if (seekc(pagenums[i].adr) == Beof) {
          346                                 fprint(2, "can't rewind input\n");
          347                                 return 0;
          348                         }
          349                         return 1;
          350                 }
          351         if (gotop <= curp) {
          352             restart:
          353                 if (seekc(0) == Beof) {
          354                         fprint(2, "can't rewind input\n");
          355                         return 0;
          356                 }
          357         }
          358         for(;;){
          359                 p = rdlinec();
          360                 if (p == 0) {
          361                         if(gotop>curp){
          362                                 gotop = curp;
          363                                 goto restart;
          364                         }
          365                         return 0;
          366                 } else if (*p == 'p') {
          367                         lastp = curp = atoi(p+1);
          368                         addpage(lastp);        /* maybe 1 too high */
          369                         if (curp>=gotop)
          370                                 return 1;
          371                 }
          372         }
          373 }
          374 
          375 static void
          376 wiggly(int skip)
          377 {
          378         Point p[300];
          379         int c,i,n;
          380         for (n = 1; (c = getc()) != '\n' && c>=0; n++) {
          381                 ungetc();
          382                 p[n].x = getn();
          383                 p[n].y = getn();
          384         }
          385         p[0] = Pt(hpos, vpos);
          386         for (i = 1; i < n; i++)
          387                 p[i] = addpt(p[i],p[i-1]);
          388         hpos = p[n-1].x;
          389         vpos = p[n-1].y;
          390         for (i = 0; i < n; i++)
          391                 p[i] = scale(p[i]);
          392         if (!skip)
          393                 spline(screen,n,p);
          394 }
          395 
          396 static void
          397 devcntrl(void)        /* interpret device control functions */
          398 {
          399         char str[80];
          400         int n;
          401 
          402         getstr(str);
          403         switch (str[0]) {        /* crude for now */
          404         case 'i':        /* initialize */
          405                 break;
          406         case 'T':        /* device name */
          407                 getstr(devname);
          408                 break;
          409         case 't':        /* trailer */
          410                 break;
          411         case 'p':        /* pause -- can restart */
          412                 break;
          413         case 's':        /* stop */
          414                 break;
          415         case 'r':        /* resolution assumed when prepared */
          416                 res=getn();
          417                 DIV = floor(.5 + res/(100.0*mag));
          418                 if (DIV < 1)
          419                         DIV = 1;
          420                 mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
          421                 break;
          422         case 'f':        /* font used */
          423                 n = getn();
          424                 getstr(str);
          425                 loadfontname(n, str);
          426                 break;
          427         /* these don't belong here... */
          428         case 'H':        /* char height */
          429                 break;
          430         case 'S':        /* slant */
          431                 break;
          432         case 'X':
          433                 break;
          434         }
          435         eatline();
          436 }
          437 
          438 int
          439 isspace(int c)
          440 {
          441         return c==' ' || c=='\t' || c=='\n';
          442 }
          443 
          444 static void
          445 getstr(char *is)
          446 {
          447         uchar *s = (uchar *) is;
          448 
          449         for (*s = getc(); isspace(*s); *s = getc())
          450                 ;
          451         for (; !isspace(*s); *++s = getc())
          452                 ;
          453         ungetc();
          454         *s = 0;
          455 }
          456 
          457 #if 0
          458 static void
          459 getutf(char *s)                /* get next utf char, as bytes */
          460 {
          461         int c, i;
          462 
          463         for (i=0;;) {
          464                 c = getc();
          465                 if (c < 0)
          466                         return;
          467                 s[i++] = c;
          468 
          469                 if (fullrune(s, i)) {
          470                         s[i] = 0;
          471                         return;
          472                 }
          473         }
          474 }
          475 #endif
          476 
          477 static void
          478 eatline(void)
          479 {
          480         int c;
          481 
          482         while ((c=getc()) != '\n' && c >= 0)
          483                 ;
          484 }
          485 
          486 static int
          487 getn(void)
          488 {
          489         int n, c, sign;
          490 
          491         while (c = getc())
          492                 if (!isspace(c))
          493                         break;
          494         if(c == '-'){
          495                 sign = -1;
          496                 c = getc();
          497         }else
          498                 sign = 1;
          499         for (n = 0; '0'<=c && c<='9'; c = getc())
          500                 n = n*10 + c - '0';
          501         while (c == ' ')
          502                 c = getc();
          503         ungetc();
          504         return(n*sign);
          505 }
          506 
          507 static int
          508 botpage(int np)        /* called at bottom of page np-1 == top of page np */
          509 {
          510         char *p;
          511         int n;
          512 
          513         while (p = getcmdstr()) {
          514                 if (*p == '\0')
          515                         return 0;
          516                 if (*p == 'q')
          517                         exits(p);
          518                 if (*p == 'c')                /* nop */
          519                         continue;
          520                 if (*p == 'm') {
          521                         mag = atof(p+1);
          522                         if (mag <= .1 || mag >= 10)
          523                                 mag = DEFMAG;
          524                         allfree();        /* zap fonts */
          525                         DIV = floor(.5 + res/(100.0*mag));
          526                         if (DIV < 1)
          527                                 DIV = 1;
          528                         mag = res/(100.0*DIV);
          529                         return skipto(np-1, np);        /* reprint the page */
          530                 }
          531                 if (*p == 'x') {
          532                         xyoffset.x += atoi(p+1)*100;
          533                         skipto(np-1, np);
          534                         return 1;
          535                 }
          536                 if (*p == 'y') {
          537                         xyoffset.y += atoi(p+1)*100;
          538                         skipto(np-1, np);
          539                         return 1;
          540                 }
          541                 if (*p == '/') {        /* divide into n pieces */
          542                         nview = atoi(p+1);
          543                         if (nview < 1)
          544                                 nview = 1;
          545                         else if (nview > MAXVIEW)
          546                                 nview = MAXVIEW;
          547                         return skipto(np-1, np);
          548                 }
          549                 if (*p == 'p') {
          550                         if (p[1] == '\0'){        /* bare 'p' */
          551                                 if(skipto(np-1, np))
          552                                         return 1;
          553                                 continue;
          554                         }
          555                         p++;
          556                 }
          557                 if ('0'<=*p && *p<='9') {
          558                         n = atoi(p);
          559                         if(skipto(n, np))
          560                                 return 1;
          561                         continue;
          562                 }
          563                 if (*p == '-' || *p == '+') {
          564                         n = atoi(p);
          565                         if (n == 0)
          566                                 n = *p == '-' ? -1 : 1;
          567                         if(skipto(np - 1 + n, np))
          568                                 return 1;
          569                         continue;
          570                 }
          571                 if (*p == 'd') {
          572                         dbg = 1 - dbg;
          573                         continue;
          574                 }
          575 
          576                 fprint(2, "illegal;  try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
          577         }
          578         return 0;
          579 }