1 /* @(#)dterm.c 1.14 (Berkeley) 02/26/85" 2 * 3 * Converts ditroff output to text on a terminal. It is NOT meant to 4 * produce readable output, but is to show one how one's paper is (in 5 * general) formatted - what will go where on which page. 6 * 7 * options: 8 * 9 * -hn set horizontal resolution to n (in characters per inch; 10 * default is 10.0). 11 * 12 * -vn set vertical resolution (default is 6.0). 13 * 14 * -ln set maximum output line-length to n (default is 79). 15 * 16 * -olist output page list - as in troff. 17 * 18 * -c continue at end of page. Default is to stop at the end 19 * of each page, print "dterm:" and wait for a command. 20 * Type ? to get a list of available commands. 21 * 22 * -m print margins. Default action is to cut printing area down 23 * to only the part of the page with information on it. 24 * 25 * -a make the output readable - i.e. print like a "troff -a" with 26 * no character overlap, and one space 'tween words 27 * 28 * -L put a form feed (^L) at the end of each page 29 * 30 * -w sets h = 20, v = 12, l = 131, also sets -c, -m and -L to allow 31 * for extra-wide printouts on the printer. 32 * 33 * -fxxx get special character definition file "xxx". Default is 34 * FONTDIR/devter/specfile. 35 */ 36 37 38 #include <stdio.h> 39 #include <ctype.h> 40 #include <math.h> 41 42 43 #define FATAL 1 44 #define PGWIDTH 266 /* WAY too big - for good measure */ 45 #define PGHEIGHT 220 46 #define LINELEN 78 47 #define SPECFILE "devter/specfile" 48 #ifndef FONTDIR 49 #define FONTDIR "/usr/lib/font" 50 #endif 51 52 #define hgoto(n) hpos = n 53 #define vgoto(n) vpos = n 54 #define hmot(n) hpos += n 55 #define vmot(n) vpos += n 56 57 #define sgn(n) ((n > 0) ? 1 : ((n < 0) ? -1 : 0)) 58 #define abs(n) ((n) >= 0 ? (n) : -(n)) 59 #define max(x,y) ((x) > (y) ? (x) : (y)) 60 #define min(x,y) ((x) < (y) ? (x) : (y)) 61 #define sqr(x) (long int)(x)*(x) 62 63 64 char SccsId [] = "@(#)dterm.c 1.14 (Berkeley) 02/26/85"; 65 66 char **spectab; /* here go the special characters */ 67 char specfile[100] = FONTDIR;/* place to look up special characters */ 68 char *malloc(); 69 char *operand(); 70 71 int keepon = 0; /* flags: Don't stop at the end of each page? */ 72 int clearsc = 0; /* Put out form feed at each page? */ 73 int output = 0; /* Do we do output at all? */ 74 int nolist = 0; /* Output page list if > 0 */ 75 int margin = 0; /* Print blank margins? */ 76 int ascii = 0; /* make the output "readable"? */ 77 int olist[20]; /* pairs of page numbers */ 78 79 float hscale = 10.0; /* characters and lines per inch for output */ 80 float vscale = 6.0; /* device (defaults are for printer) */ 81 FILE *fp = stdin; /* input file pointer */ 82 83 char pagebuf[PGHEIGHT][PGWIDTH]; 84 int minh = PGWIDTH; 85 int maxh = 0; 86 int minv = PGHEIGHT; 87 int maxv = 0; 88 int linelen = LINELEN; 89 90 int hpos; /* horizontal position to be next (left = 0) */ 91 int vpos; /* current vertical position (down positive) */ 92 93 int np; /* number of pages seen */ 94 int npmax; /* high-water mark of np */ 95 int pgnum[40]; /* their actual numbers */ 96 long pgadr[40]; /* their seek addresses */ 97 98 int DP; /* step size for drawing */ 99 int maxdots = 3200; /* maximum number of dots in an object */ 100 101 102 103 main(argc, argv) 104 int argc; 105 char **argv; 106 { 107 strcat(specfile, "/"); 108 strcat(specfile, SPECFILE); 109 while (--argc > 0 && **++argv == '-') { 110 switch ((*argv)[1]) { 111 case 'f': /* special character filepath */ 112 strncpy(specfile, operand(&argc, &argv), 100); 113 break; 114 case 'l': /* output line length */ 115 linelen = atoi(operand(&argc, &argv)) - 1; 116 break; 117 case 'h': /* horizontal scale (char/inch) */ 118 hscale = atof(operand(&argc, &argv)); 119 break; 120 case 'v': /* vertical scale (char/inch) */ 121 vscale = atof(operand(&argc, &argv)); 122 break; 123 case 'o': /* output list */ 124 outlist(operand(&argc, &argv)); 125 break; 126 case 'c': /* continue at endofpage */ 127 keepon = !keepon; 128 break; 129 case 'm': /* print margins */ 130 margin = !margin; 131 break; 132 case 'a': /* readable mode */ 133 ascii = !ascii; 134 break; 135 case 'L': /* form feed after each page */ 136 clearsc = !clearsc; 137 break; 138 case 'w': /* "wide" printer format */ 139 hscale = 16.0; 140 vscale = 9.6; 141 linelen = 131; 142 keepon = 1; 143 clearsc = 1; 144 break; 145 } 146 } 147 148 if (argc < 1) 149 conv(stdin); 150 else 151 while (argc--) { 152 if (strcmp(*argv, "-") == 0) 153 fp = stdin; 154 else if ((fp = fopen(*argv, "r")) == NULL) 155 error(FATAL, "can't open %s", *argv); 156 conv(fp); 157 fclose(fp); 158 argv++; 159 } 160 done(); 161 } 162 163 164 /*----------------------------------------------------------------------------* 165 | Routine: char * operand (& argc, & argv) 166 | 167 | Results: returns address of the operand given with a command-line 168 | option. It uses either "-Xoperand" or "-X operand", whichever 169 | is present. The program is terminated if no option is present. 170 | 171 | Side Efct: argc and argv are updated as necessary. 172 *----------------------------------------------------------------------------*/ 173 174 char *operand(argcp, argvp) 175 int * argcp; 176 char ***argvp; 177 { 178 if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */ 179 if ((--*argcp) <= 0) { /* operand next word */ 180 fprintf (stderr, "command-line option operand missing.\n"); 181 exit(1); 182 } 183 return(*(++(*argvp))); /* no operand */ 184 } 185 186 187 outlist(s) /* process list of page numbers to be printed */ 188 char *s; 189 { 190 int n1, n2, i; 191 192 nolist = 0; 193 while (*s) { 194 n1 = 0; 195 if (isdigit(*s)) 196 do 197 n1 = 10 * n1 + *s++ - '0'; 198 while (isdigit(*s)); 199 else 200 n1 = -9999; 201 n2 = n1; 202 if (*s == '-') { 203 s++; 204 n2 = 0; 205 if (isdigit(*s)) 206 do 207 n2 = 10 * n2 + *s++ - '0'; 208 while (isdigit(*s)); 209 else 210 n2 = 9999; 211 } 212 olist[nolist++] = n1; 213 olist[nolist++] = n2; 214 if (*s != '\0') 215 s++; 216 } 217 olist[nolist] = 0; 218 } 219 220 221 in_olist(n) /* is n in olist? */ 222 int n; 223 { 224 int i; 225 226 if (nolist == 0) 227 return(1); /* everything is included */ 228 for (i = 0; i < nolist; i += 2) 229 if (n >= olist[i] && n <= olist[i+1]) 230 return(1); 231 return(0); 232 } 233 234 235 conv(fp) 236 register FILE *fp; 237 { 238 register int c; 239 int m, n, i, n1, m1; 240 char str[100], buf[300]; 241 242 while ((c = getc(fp)) != EOF) { 243 switch (c) { 244 case '\n': /* when input is text */ 245 case '\t': 246 case ' ': 247 case 0: 248 break; 249 250 case '0': case '1': case '2': case '3': case '4': 251 case '5': case '6': case '7': case '8': case '9': 252 /* two motion digits plus a character */ 253 if (ascii) { 254 hmot((int)hscale); 255 getc(fp); 256 } else { 257 hmot((c-'0')*10 + getc(fp)-'0'); 258 } 259 put1(getc(fp)); 260 break; 261 262 case 'c': /* single ascii character */ 263 put1(getc(fp)); 264 break; 265 266 case 'C': /* funny character */ 267 fscanf(fp, "%s", str); 268 put1s(str); 269 break; 270 271 case 't': /* straight text */ 272 fgets(buf, sizeof(buf), fp); 273 t_text(buf); 274 break; 275 276 case 'D': /* draw function */ 277 fgets(buf, sizeof(buf), fp); 278 switch (buf[0]) { 279 case 'l': /* draw a line */ 280 sscanf(buf+1, "%d %d", &n, &m); 281 drawline(n, m); 282 break; 283 case 'c': /* circle */ 284 sscanf(buf+1, "%d", &n); 285 drawcirc(n); 286 break; 287 case 'e': /* ellipse */ 288 sscanf(buf+1, "%d %d", &m, &n); 289 drawellip(m, n); 290 break; 291 case 'a': /* arc */ 292 sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1); 293 drawarc(n, m, n1, m1); 294 break; 295 case 'q': /* versatec polygon - ignore */ 296 while (buf[strlen(buf) - 1] != '\n') 297 if (fgets(buf, sizeof(buf), fp) == NULL) 298 error(FATAL,"unexpected end of input"); 299 break; 300 case 'P': /* unbordered */ 301 case 'p': /* polygon */ 302 sscanf(buf+1, "%d", &n); 303 n = 1; 304 while(buf[n++] == ' '); 305 while(isdigit(buf[n])) n++; 306 drawwig(buf+n, 1); 307 break; 308 case 'g': /* "gremlin" curve */ 309 case '~': /* wiggly line */ 310 drawwig(buf+1, 0); 311 break; 312 case 't': /* thickness - not important */ 313 case 's': /* style - not important */ 314 break; 315 default: 316 error(FATAL,"unknown drawing command %s\n",buf); 317 break; 318 } 319 break; 320 case 'i': /* stipple pattern request - ignored */ 321 case 's': /* point size - ignored */ 322 fscanf(fp, "%d", &n); 323 break; 324 325 case 'f': /* font request - ignored */ 326 fscanf(fp, "%s", str); 327 break; 328 329 case 'H': /* absolute horizontal motion */ 330 fscanf(fp, "%d", &n); 331 hgoto(n); 332 break; 333 334 case 'h': /* relative horizontal motion */ 335 fscanf(fp, "%d", &n); 336 hmot(n); 337 break; 338 339 case 'w': /* word space */ 340 if (ascii) { 341 hmot((int)hscale); 342 } 343 break; 344 345 case 'V': /* absolute vertical motion */ 346 fscanf(fp, "%d", &n); 347 vgoto(n); 348 break; 349 350 case 'v': /* relative vertical motion */ 351 fscanf(fp, "%d", &n); 352 vmot(n); 353 break; 354 355 case 'p': /* new page */ 356 fscanf(fp, "%d", &n); 357 t_page(n); 358 break; 359 360 case 'P': /* new span (ignored) */ 361 fscanf(fp, "%d", &n); 362 break; 363 364 case 'n': /* end of line */ 365 hpos = 0; 366 case '#': /* comment */ 367 while (getc(fp) != '\n') 368 ; 369 break; 370 371 case 'x': /* device control */ 372 devcntrl(fp); 373 break; 374 375 default: 376 error(!FATAL, "unknown input character %o %c\n", c, c); 377 done(); 378 } 379 } 380 } 381 382 383 devcntrl(fp) /* interpret device control functions */ 384 FILE *fp; 385 { 386 int c, n; 387 char str[20]; 388 389 fscanf(fp, "%s", str); 390 switch (str[0]) { /* crude for now */ 391 case 'i': /* initialize */ 392 t_init(0); 393 break; 394 case 'r': /* resolution assumed when prepared */ 395 fscanf(fp, "%d", &n); 396 hscale = (float) n / hscale; 397 vscale = (float) n / vscale; 398 DP = min (hscale, vscale); /* guess the drawing */ 399 DP = max (DP, 1); /* resolution */ 400 break; 401 case 'f': /* font used */ 402 case 'T': /* device name */ 403 case 't': /* trailer */ 404 case 'p': /* pause -- can restart */ 405 case 's': /* stop */ 406 break; 407 } 408 while (getc(fp) != '\n') /* skip rest of input line */ 409 ; 410 } 411 412 /* error printing routine - first argument is a "fatal" flag */ 413 error(f, s, a1, a2, a3, a4, a5, a6, a7) { 414 fprintf(stderr, "dterm: "); 415 fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7); 416 fprintf(stderr, "\n"); 417 if (f) exit(1); 418 } 419 420 421 t_init(reinit) /* initialize device */ 422 int reinit; 423 { 424 register int i; 425 register int j; 426 register FILE *fp; /* file to look up special characters */ 427 register char *charptr; /* string pointer to step through specials */ 428 register char *tabptr; /* string pointer for spectab setting */ 429 char specials[5000]; /* intermediate input buffer (made bigger */ 430 /* than we'll EVER use... */ 431 432 433 fflush(stdout); 434 hpos = vpos = 0; 435 for (i = 0; i < PGHEIGHT; i++) 436 for (j = 0; j < PGWIDTH; j++) 437 pagebuf[i][j] = ' '; 438 minh = PGWIDTH; 439 maxh = 0; 440 minv = PGHEIGHT; 441 maxv = 0; 442 443 if (reinit) return; /* if this is the first time, read */ 444 /* special character table file. */ 445 if ((fp = fopen (specfile, "r")) != NULL) { 446 charptr = &specials[0]; 447 for (i = 2; fscanf(fp, "%s", charptr) != EOF; i++) { 448 charptr += strlen(charptr) + 1; 449 } 450 fclose(fp); 451 *charptr++ = '\0'; /* ending strings */ 452 *charptr++ = '\0'; 453 /* allocate table */ 454 spectab = (char **) malloc(i * sizeof(char*)); 455 spectab[0] = tabptr = malloc(j = (int) (charptr - &specials[0])); 456 457 /* copy whole table */ 458 for (charptr = &specials[0]; j--; *tabptr++ = *charptr++); 459 460 tabptr = spectab[0]; /* set up pointers to table */ 461 for (j = 0; i--; j++) { 462 spectab[j] = tabptr; 463 tabptr += strlen(tabptr) + 1; 464 } 465 466 } else { /* didn't find table - allocate a null one */ 467 468 error (!FATAL, "Can't open special character file: %s", specfile); 469 spectab = (char **) malloc(2 * sizeof(char*)); 470 spectab[0] = malloc (2); 471 spectab[1] = spectab[0] + 1; 472 *spectab[0] = '\0'; 473 *spectab[1] = '\0'; 474 } 475 } 476 477 478 /* just got "p#" command. print the current page and */ 479 t_page(n) /* do whatever new page functions */ 480 { 481 long ftell(); 482 int c, m, i; 483 char buf[100], *bp; 484 485 pgnum[np++] = n; 486 pgadr[np] = ftell(fp); 487 if (np > npmax) 488 npmax = np; 489 if (output == 0) { 490 output = in_olist(n); 491 t_init(1); 492 return; 493 } 494 495 putpage(); 496 fflush(stdout); 497 498 if (clearsc) putchar(''); 499 if (keepon) { 500 t_init(1); 501 return; 502 } 503 next: 504 for (bp = buf; (*bp = readch()); ) 505 if (*bp++ == '\n') 506 break; 507 *bp = 0; 508 switch (buf[0]) { 509 case 0: 510 done(); 511 break; 512 case '\n': 513 output = in_olist(n); 514 t_init(1); 515 return; 516 case '-': 517 case 'p': 518 m = atoi(&buf[1]) + 1; 519 if (fp == stdin) { 520 fputs("you can't; it's not a file\n", stderr); 521 break; 522 } 523 if (np - m <= 0) { 524 fputs("too far back\n", stderr); 525 break; 526 } 527 np -= m; 528 fseek(fp, pgadr[np], 0); 529 output = 1; 530 t_init(1); 531 return; 532 case '0': case '1': case '2': case '3': case '4': 533 case '5': case '6': case '7': case '8': case '9': 534 m = atoi(&buf[0]); 535 for (i = 0; i < npmax; i++) 536 if (m == pgnum[i]) 537 break; 538 if (i >= npmax || fp == stdin) { 539 fputs("you can't\n", stderr); 540 break; 541 } 542 np = i + 1; 543 fseek(fp, pgadr[np], 0); 544 output = 1; 545 t_init(1); 546 return; 547 case 'o': 548 outlist(&buf[1]); 549 output = 0; 550 t_init(1); 551 return; 552 case '?': 553 fputs("p print this page again\n", stderr); 554 fputs("-n go back n pages\n", stderr); 555 fputs("n print page n (previously printed)\n", stderr); 556 fputs("o... set the -o output list to ...\n", stderr); 557 break; 558 default: 559 fputs("?\n", stderr); 560 break; 561 } 562 goto next; 563 } 564 565 /* print the contents of the current page. puts out */ 566 putpage() /* only the part of the page that's been written on */ 567 { /* unless "margin" is set. */ 568 int i, j, k; 569 570 fflush(stdout); 571 if (margin) minv = minh = 0; 572 for (i = minv; i <= maxv; i++) { 573 for (k = maxh; pagebuf[i][k] == ' '; k--) 574 ; 575 if (k > minh + linelen) 576 k = minh + linelen; 577 for (j = minh; j <= k; j++) 578 putchar(pagebuf[i][j]); 579 putchar('\n'); 580 } 581 fflush(stdout); 582 } 583 584 585 t_text(s) /* print string s as text */ 586 char *s; 587 { 588 int c; 589 char str[100]; 590 591 if (!output) 592 return; 593 while ((c = *s++) != '\n') { 594 if (c == '\\') { 595 switch (c = *s++) { 596 case '\\': 597 case 'e': 598 put1('\\'); 599 break; 600 case '(': 601 str[0] = *s++; 602 str[1] = *s++; 603 str[2] = '\0'; 604 put1s(str); 605 break; 606 } 607 } else { 608 put1(c); 609 } 610 hmot((int)hscale); 611 } 612 } 613 614 615 put1s(s) /* s is a funny char name */ 616 char *s; 617 { 618 int i; 619 char *p; 620 static char prev[10] = ""; 621 static int previ; 622 623 if (!output) 624 return; 625 if (strcmp(s, prev) != 0) { 626 previ = -1; 627 for (i = 0; *spectab[i] != '\0'; i += 2) 628 if (strcmp(spectab[i], s) == 0) { 629 strcpy(prev, s); 630 previ = i; 631 break; 632 } 633 } 634 if (previ >= 0) { 635 for (hmot((int)-hscale), p = spectab[previ+1]; *p; p++) { 636 hmot((int)hscale); 637 store(*p); 638 } 639 } else 640 prev[0] = '\0'; 641 } 642 643 644 put1(c) /* output char c */ 645 int c; 646 { 647 if (!output) 648 return; 649 store(c); 650 } 651 652 653 done() 654 { 655 output = 1; 656 putpage(); 657 fflush(stdout); 658 exit(0); 659 } 660 661 662 readch () 663 { 664 int c; 665 static FILE *rcf; 666 static nbol; /* 0 if at beginning of a line */ 667 668 if (rcf == NULL) { 669 rcf = fopen ("/dev/tty", "r"); 670 setbuf (rcf, NULL); 671 } 672 673 if (!nbol) 674 fprintf (stderr, "dterm: "); /* issue prompt */ 675 if ((c = getc (rcf)) == EOF) 676 return 0; 677 nbol = (c != '\n'); 678 return c; 679 } 680 681 682 store(c) /* put 'c' in the page at (hpos, vpos) */ 683 { 684 register int i; 685 register int j; 686 687 688 i = hpos / hscale; /* scale the position to page coordinates */ 689 j = vpos / vscale; 690 691 if (i >= PGWIDTH) i = PGWIDTH - 1; /* don't go over the edge */ 692 else if (i < 0) i = 0; 693 if (j >= PGHEIGHT) j = PGHEIGHT - 1; 694 else if (j < 0) j = 0; 695 696 pagebuf[j][i] = c; /* write the character */ 697 698 if (i > maxh) maxh = i; /* update the page bounds */ 699 if (i < minh) minh = i; 700 if (j > maxv) maxv = j; 701 if (j < minv) minv = j; 702 } 703 704 705 drawline(dx, dy) /* draw line from here to dx, dy using s */ 706 int dx, dy; 707 { 708 register int xd; 709 register int yd; 710 register int i; 711 register int numdots; 712 int dirmot, perp; 713 int motincr, perpincr; 714 int ohpos, ovpos; 715 float val, slope; 716 float incrway; 717 718 ohpos = hpos; 719 ovpos = vpos; 720 xd = dx / DP; 721 yd = dy / DP; 722 if (xd == 0) { 723 numdots = abs (yd); 724 numdots = min(numdots, maxdots); 725 motincr = DP * sgn (yd); 726 put1('|'); 727 for (i = 0; i < numdots; i++) { 728 vmot(motincr); 729 put1('|'); 730 } 731 } else 732 if (yd == 0) { 733 numdots = abs (xd); 734 numdots = min(numdots, maxdots); 735 motincr = DP * sgn (xd); 736 put1('-'); 737 for (i = 0; i < numdots; i++) { 738 hmot(motincr); 739 put1('-'); 740 } 741 } else { 742 if (abs (xd) > abs (yd)) { 743 val = slope = (float) xd/yd; 744 numdots = abs (xd); 745 dirmot = 'h'; 746 perp = 'v'; 747 motincr = DP * sgn (xd); 748 perpincr = DP * sgn (yd); 749 } else { 750 val = slope = (float) yd/xd; 751 numdots = abs (yd); 752 dirmot = 'v'; 753 perp = 'h'; 754 motincr = DP * sgn (yd); 755 perpincr = DP * sgn (xd); 756 } 757 numdots = min(numdots, maxdots); 758 incrway = sgn ((int) slope); 759 put1('*'); 760 for (i = 0; i < numdots; i++) { 761 val -= incrway; 762 if (dirmot == 'h') 763 hmot(motincr); 764 else 765 vmot(motincr); 766 if (val * slope < 0) { 767 if (perp == 'h') 768 hmot(perpincr); 769 else 770 vmot(perpincr); 771 val += slope; 772 } 773 put1('*'); 774 } 775 } 776 hgoto(ohpos + dx); 777 vgoto(ovpos + dy); 778 } 779 780 781 drawwig(s, poly) /* draw wiggly line or polygon, if "poly" set */ 782 char *s; 783 int poly; 784 { 785 int x[50], y[50], xp, yp, pxp, pyp; 786 float t1, t2, t3, w; 787 int i, j, numdots, N; 788 char temp[50], *p, *getstr(); 789 790 p = s; 791 for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]);) { 792 x[N] = atoi(temp); 793 p = getstr(p, temp); 794 y[N++] = atoi(temp); 795 } 796 if (poly) { 797 for (i = 2; i < N; i++) 798 drawline(x[i], y[i]); 799 return; 800 } 801 x[0] = x[1] = hpos; 802 y[0] = y[1] = vpos; 803 for (i = 1; i < N; i++) { 804 x[i+1] += x[i]; 805 y[i+1] += y[i]; 806 } 807 x[N] = x[N-1]; 808 y[N] = y[N-1]; 809 pxp = pyp = -9999; 810 for (i = 0; i < N-1; i++) { /* interval */ 811 numdots = (dist(x[i], y[i], x[i+1], y[i+1]) 812 + dist(x[i+1], y[i+1], x[i+2], y[i+2])) / 2; 813 numdots /= DP; 814 numdots = min(numdots, maxdots); 815 for (j = 0; j < numdots; j++) { /* points within */ 816 w = (float) j / numdots; 817 t1 = 0.5 * w * w; 818 w = w - 0.5; 819 t2 = 0.75 - w * w; 820 w = w - 0.5; 821 t3 = 0.5 * w * w; 822 xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5; 823 yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5; 824 if (xp != pxp || yp != pyp) { 825 hgoto(xp); 826 vgoto(yp); 827 put1('*'); 828 pxp = xp; 829 pyp = yp; 830 } 831 } 832 } 833 } 834 835 836 /* copy next non-blank string from p to temp, update p */ 837 838 char *getstr(p, temp) 839 char *p, *temp; 840 { 841 while (*p == ' ' || *p == '\t' || *p == '\n') 842 p++; 843 if (*p == '\0') { 844 temp[0] = 0; 845 return(NULL); 846 } 847 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 848 *temp++ = *p++; 849 *temp = '\0'; 850 return(p); 851 } 852 853 854 drawcirc(d) 855 { 856 int xc, yc; 857 858 xc = hpos; 859 yc = vpos; 860 conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2); 861 hgoto(xc + d); /* circle goes to right side */ 862 vgoto(yc); 863 } 864 865 866 dist(x1, y1, x2, y2) /* integer distance from x1,y1 to x2,y2 */ 867 { 868 float dx, dy; 869 870 dx = x2 - x1; 871 dy = y2 - y1; 872 return sqrt(dx*dx + dy*dy) + 0.5; 873 } 874 875 876 drawarc(dx1, dy1, dx2, dy2) 877 { 878 int x0, y0, x2, y2, r; 879 880 x0 = hpos + dx1; /* center */ 881 y0 = vpos + dy1; 882 x2 = x0 + dx2; /* "to" */ 883 y2 = y0 + dy2; 884 r = sqrt((float) dx1 * dx1 + (float) dy1 * dy1) + 0.5; 885 conicarc(x0, -y0, hpos, -vpos, x2, -y2, r, r); 886 } 887 888 889 drawellip(a, b) 890 { 891 int xc, yc; 892 893 xc = hpos; 894 yc = vpos; 895 conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2); 896 hgoto(xc + a); 897 vgoto(yc); 898 } 899 900 901 conicarc(x, y, x0, y0, x1, y1, a, b) 902 { 903 /* based on Bresenham, CACM Feb 77, pp 102-3 by Chris Van Wyk */ 904 /* capitalized vars are an internal reference frame */ 905 long dotcount = 0; 906 int xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt, 907 M1x, M1y, M2x, M2y, M3x, M3y, 908 Q, move, Xc, Yc; 909 int ox1, oy1; 910 long delta; 911 float xc, yc; 912 float radius, slope; 913 float xstep, ystep; 914 915 ox1 = x1; 916 oy1 = y1; 917 if (a != b) /* an arc of an ellipse; internally, think of circle */ 918 if (a > b) { 919 xstep = (float)a / b; 920 ystep = 1; 921 radius = b; 922 } else { 923 xstep = 1; 924 ystep = (float)b / a; 925 radius = a; 926 } 927 else { 928 /* a circular arc; radius computed from center and first point */ 929 xstep = ystep = 1; 930 radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y))); 931 } 932 933 xc = x0; 934 yc = y0; 935 /* now, use start and end point locations to figure out 936 the angle at which start and end happen; use these 937 angles with known radius to figure out where start 938 and end should be 939 */ 940 slope = atan2((double)(y0 - y), (double)(x0 - x) ); 941 if (slope == 0.0 && x0 < x) 942 slope = 3.14159265; 943 x0 = x + radius * cos(slope) + 0.5; 944 y0 = y + radius * sin(slope) + 0.5; 945 slope = atan2((double)(y1 - y), (double)(x1 - x)); 946 if (slope == 0.0 && x1 < x) 947 slope = 3.14159265; 948 x1 = x + radius * cos(slope) + 0.5; 949 y1 = y + radius * sin(slope) + 0.5; 950 /* step 2: translate to zero-centered circle */ 951 xs = x0 - x; 952 ys = y0 - y; 953 xt = x1 - x; 954 yt = y1 - y; 955 /* step 3: normalize to first quadrant */ 956 if (xs < 0) 957 if (ys < 0) { 958 Xs = abs(ys); 959 Ys = abs(xs); 960 qs = 3; 961 M1x = 0; 962 M1y = -1; 963 M2x = 1; 964 M2y = -1; 965 M3x = 1; 966 M3y = 0; 967 } else { 968 Xs = abs(xs); 969 Ys = abs(ys); 970 qs = 2; 971 M1x = -1; 972 M1y = 0; 973 M2x = -1; 974 M2y = -1; 975 M3x = 0; 976 M3y = -1; 977 } 978 else if (ys < 0) { 979 Xs = abs(xs); 980 Ys = abs(ys); 981 qs = 0; 982 M1x = 1; 983 M1y = 0; 984 M2x = 1; 985 M2y = 1; 986 M3x = 0; 987 M3y = 1; 988 } else { 989 Xs = abs(ys); 990 Ys = abs(xs); 991 qs = 1; 992 M1x = 0; 993 M1y = 1; 994 M2x = -1; 995 M2y = 1; 996 M3x = -1; 997 M3y = 0; 998 } 999 1000 Xc = Xs; 1001 Yc = Ys; 1002 if (xt < 0) 1003 if (yt < 0) { 1004 Xt = abs(yt); 1005 Yt = abs(xt); 1006 qt = 3; 1007 } else { 1008 Xt = abs(xt); 1009 Yt = abs(yt); 1010 qt = 2; 1011 } 1012 else if (yt < 0) { 1013 Xt = abs(xt); 1014 Yt = abs(yt); 1015 qt = 0; 1016 } else { 1017 Xt = abs(yt); 1018 Yt = abs(xt); 1019 qt = 1; 1020 } 1021 1022 /* step 4: calculate number of quadrant crossings */ 1023 if (((4 + qt - qs) % 4 == 0) && (Xt <= Xs) && (Yt >= Ys)) 1024 Q = 3; 1025 else 1026 Q = (4 + qt - qs) % 4 - 1; 1027 /* step 5: calculate initial decision difference */ 1028 delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys); 1029 /* here begins the work of drawing. */ 1030 while ((Q >= 0) || ((Q > -2) && ((Xt > Xc) && (Yt < Yc)))) { 1031 if (dotcount++ % DP == 0) { 1032 hgoto((int)xc); 1033 vmot(-vpos-((int)yc)); 1034 put1('*'); 1035 } 1036 if (Yc < 0.5) { 1037 /* reinitialize */ 1038 Xs = Xc = 0; 1039 Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys))); 1040 delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys); 1041 Q--; 1042 M1x = M3x; 1043 M1y = M3y; 1044 { 1045 int T; 1046 T = M2y; 1047 M2y = M2x; 1048 M2x = -T; 1049 T = M3y; 1050 M3y = M3x; 1051 M3x = -T; 1052 } 1053 } else { 1054 if (delta <= 0) 1055 if (2 * delta + 2 * Yc - 1 <= 0) 1056 move = 1; 1057 else 1058 move = 2; 1059 else if (2 * delta - 2 * Xc - 1 <= 0) 1060 move = 2; 1061 else 1062 move = 3; 1063 switch (move) { 1064 case 1: 1065 Xc++; 1066 delta += 2 * Xc + 1; 1067 xc += M1x * xstep; 1068 yc += M1y * ystep; 1069 break; 1070 case 2: 1071 Xc++; 1072 Yc--; 1073 delta += 2 * Xc - 2 * Yc + 2; 1074 xc += M2x * xstep; 1075 yc += M2y * ystep; 1076 break; 1077 case 3: 1078 Yc--; 1079 delta -= 2 * Yc + 1; 1080 xc += M3x * xstep; 1081 yc += M3y * ystep; 1082 break; 1083 } 1084 } 1085 } 1086 drawline((int)xc-ox1,(int)yc-oy1); 1087 } 1088