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