static void linefeed(void) { int line = 0; /* current line - based on ovmi */ /* * * Adjust our current vertical position. If we've passed the bottom of the page * or exceeded the number of lines per page, print it and go to the upper left * corner of the next page. This routine is also called from carriage() if crislf * is ON. * */ vmot(vmi); if ( lfiscr == ON ) hgoto(leftmargin); if ( linespp > 0 ) /* means something so see where we are */ line = vpos / ovmi + 1; if ( vpos > bottommargin || line > linespp ) formfeed(); } /* End of linefeed */
void drawellip ( int a, int b, /* axes lengths for the ellipse */ int c ) { /* * * Draws an ellipse having axes lengths horizontally and vertically of a and * b. The left side of the ellipse is at the current point. After we're done * drawing the path we move the current position to the right side. * */ if ( a == 0 && b == 0 ) return; fprintf(tf, "%d %d %d %d D%c\n", hpos, vpos, a, b, c); hgoto(hpos + a); /* where troff expects to be */ vgoto(vpos); resetpos(); /* not sure where the printer is */ } /* End of drawellip */
static void htab(void) { int col; /* 'column' we'll be at next */ int i; /* loop index */ /* * * Tries to figure out where the next tab stop is. Wasn't positive about this * one, since hmi can change. I'll assume columns are determined by the original * value of hmi. That fixes them on the page, which seems to make more sense than * letting them float all over the place. * */ endline(); col = hpos/ohmi + 1; for ( i = col; i < ROWS; i++ ) if ( htabstops[i] == ON ) { col = i; break; } /* End if */ hgoto(col * ohmi); lastx = hpos; } /* End of htab */
void drawline ( int dx, int dy /* endpoint is (hpos+dx, vpos+dy) */ ) { /* * * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current * position at the endpoint. * */ if ( dx == 0 && dy == 0 ) drawcirc(1, 'c'); else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos); hgoto(hpos+dx); /* where troff expects to be */ vgoto(vpos+dy); resetpos(); /* not sure where the printer is */ } /* End of drawline */
void drawellip(int a, int b) { int xc, yc; xc = hpos; yc = vpos; conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2); hgoto(xc + a); vgoto(yc); }
void drawcirc(int d) { int xc, yc; xc = hpos; yc = vpos; conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2); hgoto(xc + d); /* circle goes to right side */ vgoto(yc); }
void drawwig(char *s) /* draw wiggly line */ { int x[50], y[50], xp, yp, pxp, pyp; float t1, t2, t3, w; int i, j, numdots, N; int osize; char temp[50], *p; osize = size; setsize(t_size(pstab[osize-1] / drawsize)); p = s; for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]); N++) { x[N] = atoi(temp); p = getstr(p, temp); y[N] = atoi(temp); } x[0] = x[1] = hpos; y[0] = y[1] = vpos; for (i = 1; i < N; i++) { x[i+1] += x[i]; y[i+1] += y[i]; } x[N] = x[N-1]; y[N] = y[N-1]; pxp = pyp = -9999; for (i = 0; i < N-1; i++) { /* interval */ numdots = (dist(x[i],y[i], x[i+1],y[i+1]) + dist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2; numdots /= DX; numdots = min(numdots, maxdots); for (j = 0; j < numdots; j++) { /* points within */ w = (float) j / numdots; t1 = 0.5 * w * w; w = w - 0.5; t2 = 0.75 - w * w; w = w - 0.5; t3 = 0.5 * w * w; xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5; yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5; if (xp != pxp || yp != pyp) { hgoto(xp); vgoto(yp); put1(drawdot); pxp = xp; pyp = yp; } } } setsize(osize); }
static void formfeed(void) { /* * * Called whenever we've finished with the last page and want to get ready for the * next one. Also used at the beginning and end of each input file, so we have to * be careful about what's done. I've added a simple test before the showpage that * should eliminate the extra blank page that was put out at the end of many jobs, * but the PAGES comments may be wrong. * */ if ( fp_out == stdout ) /* count the last page */ printed++; endline(); /* print the last line */ fprintf(fp_out, "cleartomark\n"); if ( feof(fp_in) == 0 || markedpage == TRUE ) fprintf(fp_out, "showpage\n"); fprintf(fp_out, "saveobj restore\n"); fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); if ( ungetc(getc(fp_in), fp_in) == EOF ) redirect(-1); else redirect(++page); fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); fprintf(fp_out, "/saveobj save def\n"); fprintf(fp_out, "mark\n"); writerequest(printed+1, fp_out); fprintf(fp_out, "%d pagesetup\n", printed+1); vgoto(topmargin); hgoto(leftmargin); markedpage = FALSE; } /* End of formfeed */
static void backspace(void) { /* * * Moves backwards a distance equal to the current value of hmi, but don't go * past the left margin. * */ endline(); if ( hpos - leftmargin >= hmi ) hmot(-hmi); else hgoto(leftmargin); /* maybe just ignore the backspace?? */ lastx = hpos; } /* End of backspace */
void drawarc ( int dx1, int dy1, /* vector from current pos to center */ int dx2, int dy2, /* from center to end of the arc */ int c /* clockwise if c is A */ ) { /* * * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed * if we're building a larger path out of pieces that include arcs, and want to * have PostScript manage the path for us. Arguments (for a clockwise arc) are * what would have been supplied if the arc was drawn in a counter-clockwise * direction, and are converted to values suitable for use with PostScript's arcn * operator. * */ if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) ) { fprintf(tf, "%d %d %d %d %d %d D%c\n", hpos, vpos, dx1, dy1, dx2, dy2, c); } hgoto(hpos + dx1 + dx2); /* where troff expects to be */ vgoto(vpos + dy1 + dy2); resetpos(); /* not sure where the printer is */ } /* End of drawarc */
static void carriage(void) { /* * * Handles carriage return character. If crislf is ON we'll generate a line feed * every time we get a carriage return character. * */ if ( shadowprint == ON ) /* back to normal mode */ changefont(fontname); advance = 1; shadowprint = OFF; hgoto(leftmargin); if ( crislf == ON ) linefeed(); } /* End of carriage */
static void escape(void) { int ch; /* control character */ /* * * Handles special codes that are expected to follow an escape character. The * initial escape character is followed by one or two bytes. * */ switch ( ch = getc(fp_in) ) { case 'T': /* top margin */ topmargin = vpos; break; case 'L': /* bottom margin */ bottommargin = vpos; break; case 'C': /* clear top and bottom margins */ bottommargin = BOTTOMMARGIN; topmargin = TOPMARGIN; break; case '9': /* left margin */ leftmargin = hpos; break; case '0': /* right margin */ rightmargin = hpos; break; case '1': /* set horizontal tab */ htabstops[hpos/ohmi] = ON; break; case '8': /* clear horizontal tab at hpos */ htabstops[hpos/ohmi] = OFF; break; case '-': /* set vertical tab */ vtabstops[vpos/ovmi] = ON; break; case '2': /* clear all tabs */ cleartabs(); break; case '\014': /* set lines per page */ linespp = getc(fp_in); break; case '\037': /* set hmi to next byte minus 1 */ hmi = HSCALE * (getc(fp_in) - 1); break; case 'S': /* reset hmi to default */ hmi = ohmi; break; case '\011': /* move to column given by next byte */ hgoto((getc(fp_in)-1) * ohmi); break; case '?': /* do carriage return after line feed */ lfiscr = ON; break; case '!': /* don't generate carriage return */ lfiscr = OFF; break; case '5': /* forward print mode */ advance = 1; break; case '6': /* backward print mode */ advance = -1; break; case '\036': /* set vmi to next byte minus 1 */ vmi = VSCALE * (getc(fp_in) - 1); break; case '\013': /* move to line given by next byte */ vgoto((getc(fp_in)-1) * ovmi); break; case 'U': /* positive half line feed */ vmot(vmi/2); break; case 'D': /* negative half line feed */ vmot(-vmi/2); break; case '\012': /* negative line feed */ vmot(-vmi); break; case '\015': /* clear all margins */ bottommargin = BOTTOMMARGIN; topmargin = TOPMARGIN; leftmargin = BOTTOMMARGIN; rightmargin = RIGHTMARGIN; break; case 'E': /* auto underscore - use italic font */ changefont("/Courier-Oblique"); break; case 'R': /* disable auto underscore */ changefont(fontname); break; case 'O': /* bold/shadow printing */ case 'W': changefont("/Courier-Bold"); shadowprint = ON; break; case '&': /* disable bold printing */ changefont(fontname); shadowprint = OFF; break; case '/': /* ignored 2 byte escapes */ case '\\': case '<': case '>': case '%': case '=': case '.': case '4': case 'A': case 'B': case 'M': case 'N': case 'P': case 'Q': case 'X': case '\010': break; case ',': /* ignored 3 byte escapes */ case '\016': case '\021': getc(fp_in); break; case '3': /* graphics mode - should quit! */ case '7': case 'G': case 'V': case 'Y': case 'Z': error(FATAL, "graphics mode is not implemented"); break; default: error(FATAL, "missing case for escape o%o\n", ch); break; } /* End switch */ } /* End of escape */
void drawspline( FILE *fp, /* input for point list */ int flag /* flag!=1 connect end points */ ) { int x[100], y[100]; size_t i, N; /* * * Spline drawing routine for Postscript printers. The complicated stuff is * handled by procedure Ds, which should be defined in the library file. I've * seen wrong implementations of troff's spline drawing, so fo the record I'll * write down the parametric equations and the necessary conversions to Bezier * cubic splines (as used in Postscript). * * * Parametric equation (x coordinate only): * * * (x2 - 2 * x1 + x0) 2 (x0 + x1) * x = ------------------ * t + (x1 - x0) * t + --------- * 2 2 * * * The coefficients in the Bezier cubic are, * * * A = 0 * B = (x2 - 2 * x1 + x0) / 2 * C = x1 - x0 * * * while the current point is, * * current-point = (x0 + x1) / 2 * * Using the relationships given in the Postscript manual (page 121) it's easy to * see that the control points are given by, * * * x0' = (x0 + 5 * x1) / 6 * x1' = (x2 + 5 * x1) / 6 * x2' = (x1 + x2) / 2 * * * where the primed variables are the ones used by curveto. The calculations * shown above are done in procedure Ds using the coordinates set up in both * the x[] and y[] arrays. * * A simple test of whether your spline drawing is correct would be to use cip * to draw a spline and some tangent lines at appropriate points and then print * the file. * */ for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ ) if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2) break; x[0] = x[1] = hpos; y[0] = y[1] = vpos; for (i = 1; i < N; i++) { x[i+1] += x[i]; y[i+1] += y[i]; } /* End for */ x[N] = x[N-1]; y[N] = y[N-1]; for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]); hgoto(x[N]); /* where troff expects to be */ vgoto(y[N]); resetpos(); /* not sure where the printer is */ } /* End of drawspline */
void movehv(double h, double v) /* go to internal position h, v */ { hgoto(h); vgoto(v); }
void move(double x, double y) /* go to position x, y in external coords */ { hgoto(xconv(x)); vgoto(yconv(y)); }
void drawline(int dx, int dy, char *s) /* draw line from here to dx, dy using s */ { int xd, yd; float val, slope; int i, numdots; int dirmot, perp; int motincr, perpincr; int ohpos, ovpos, osize; float incrway; int itemp; /*temp. storage for value returned byint function sgn*/ osize = size; setsize(t_size(pstab[osize-1] / drawsize)); ohpos = hpos; ovpos = vpos; xd = dx / DX; yd = dy / DX; if (xd == 0) { numdots = abs (yd); numdots = min(numdots, maxdots); motincr = DX * sgn (yd); for (i = 0; i < numdots; i++) { vmot(motincr); put1(drawdot); } vgoto(ovpos + dy); setsize(osize); return; } if (yd == 0) { numdots = abs (xd); motincr = DX * sgn (xd); for (i = 0; i < numdots; i++) { hmot(motincr); put1(drawdot); } hgoto(ohpos + dx); setsize(osize); return; } if (abs (xd) > abs (yd)) { val = slope = (float) xd/yd; numdots = abs (xd); numdots = min(numdots, maxdots); dirmot = 'h'; perp = 'v'; motincr = DX * sgn (xd); perpincr = DX * sgn (yd); } else { val = slope = (float) yd/xd; numdots = abs (yd); numdots = min(numdots, maxdots); dirmot = 'v'; perp = 'h'; motincr = DX * sgn (yd); perpincr = DX * sgn (xd); } incrway = itemp = sgn ((int) slope); for (i = 0; i < numdots; i++) { val -= incrway; if (dirmot == 'h') hmot(motincr); else vmot(motincr); if (val * slope < 0) { if (perp == 'h') hmot(perpincr); else vmot(perpincr); val += slope; } put1(drawdot); } hgoto(ohpos + dx); vgoto(ovpos + dy); setsize(osize); }
void conv(register FILE *fp) { register int c, k; int m, n, n1, m1; char str[4096], buf[4096]; while ((c = getc(fp)) != EOF) { switch (c) { case '\n': /* when input is text */ case ' ': case 0: /* occasional noise creeps in */ break; case '{': /* push down current environment */ t_push(); break; case '}': t_pop(); 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 */ hmot((c-'0')*10 + getc(fp)-'0'); put1(getc(fp)); break; case 'c': /* single ascii character */ put1(getc(fp)); break; case 'C': sget(str, sizeof str, fp); put1s(str); break; case 't': /* straight text */ fgets(buf, sizeof(buf), fp); t_text(buf); break; case 'D': /* draw function */ fgets(buf, sizeof(buf), fp); switch (buf[0]) { case 'l': /* draw a line */ sscanf(buf+1, "%d %d", &n, &m); drawline(n, m, "."); break; case 'c': /* circle */ sscanf(buf+1, "%d", &n); drawcirc(n); break; case 'e': /* ellipse */ sscanf(buf+1, "%d %d", &m, &n); drawellip(m, n); break; case 'a': /* arc */ sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1); drawarc(n, m, n1, m1); break; case '~': /* wiggly line */ drawwig(buf+1); break; default: error(FATAL, "unknown drawing function %s\n", buf); break; } break; case 's': fscanf(fp, "%d", &n); if (n == -23) { float f; fscanf(fp, "%f", &f); setsize(f); } else setsize(t_size(n));/* ignore fractional sizes */ break; case 'f': sget(str, sizeof str, fp); setfont(t_font(str)); break; case 'H': /* absolute horizontal motion */ /* fscanf(fp, "%d", &n); */ while ((c = getc(fp)) == ' ') ; k = 0; do { k = 10 * k + c - '0'; } while (isdigit(c = getc(fp))); ungetc(c, fp); hgoto(k); break; case 'h': /* relative horizontal motion */ /* fscanf(fp, "%d", &n); */ while ((c = getc(fp)) == ' ') ; k = 0; do { k = 10 * k + c - '0'; } while (isdigit(c = getc(fp))); ungetc(c, fp); hmot(k); break; case 'w': /* word space */ putc(' ', stdout); break; case 'V': fscanf(fp, "%d", &n); vgoto(n); break; case 'v': fscanf(fp, "%d", &n); vmot(n); break; case 'p': /* new page */ fscanf(fp, "%d", &n); t_page(n); break; case 'n': /* end of line */ while (getc(fp) != '\n') ; t_newline(); break; case '#': /* comment */ while (getc(fp) != '\n') ; break; case 'x': /* device control */ devcntrl(fp); break; default: error(!FATAL, "unknown input character %o %c\n", c, c); done(); } } }
void conv(Biobuf *Bp) { long n; int r; char special[10]; int save; inputlineno = 1; if (debug) Bprint(Bstderr, "conv(Biobufhdr *Bp=0x%x)\n", Bp); while ((r = Bgetrune(Bp)) >= 0) { /* Bprint(Bstderr, "r=<%c>,0x%x\n", r, r); */ /* Bflush(Bstderr); */ switch (r) { case 's': /* set point size */ Bgetfield(Bp, 'd', &fontsize, 0); break; case 'f': /* set font to postion */ Bgetfield(Bp, 'd', &fontpos, 0); save = inputlineno; settrfont(); inputlineno = save; /* ugh */ break; case 'c': /* print rune */ r = Bgetrune(Bp); runeout(r); break; case 'C': /* print special character */ Bgetfield(Bp, 's', special, 10); specialout(special); break; case 'N': /* print character with numeric value from current font */ Bgetfield(Bp, 'd', &n, 0); break; case 'H': /* go to absolute horizontal position */ Bgetfield(Bp, 'd', &n, 0); hgoto(n); break; case 'V': /* go to absolute vertical position */ Bgetfield(Bp, 'd', &n, 0); vgoto(n); break; case 'h': /* go to relative horizontal position */ Bgetfield(Bp, 'd', &n, 0); hmot(n); break; case 'v': /* go to relative vertical position */ Bgetfield(Bp, 'd', &n, 0); vmot(n); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* move right nn units, then print character c */ n = (r - '0') * 10; r = Bgetrune(Bp); if (r < 0) error(FATAL, "EOF or error reading input\n"); else if (r < '0' || r > '9') error(FATAL, "integer expected\n"); n += r - '0'; r = Bgetrune(Bp); hmot(n); runeout(r); break; case 'p': /* begin page */ Bgetfield(Bp, 'd', &n, 0); endpage(); startpage(); break; case 'n': /* end of line (information only 'b a' follows) */ Brdline(Bp, '\n'); /* toss rest of line */ inputlineno++; break; case 'w': /* paddable word space (information only) */ break; case 'D': /* graphics function */ draw(Bp); break; case 'x': /* device control functions */ devcntl(Bp); break; case '#': /* comment */ Brdline(Bp, '\n'); /* toss rest of line */ case '\n': inputlineno++; break; default: error(WARNING, "unknown troff function <%c>\n", r); break; } } endpage(); if (debug) Bprint(Bstderr, "r=0x%x\n", r); if (debug) Bprint(Bstderr, "leaving conv\n"); }
void main(void) { int c, n; char str[100], *args[10]; int jfont, curfont; if(initdraw(0, fontfile, 0) < 0){ fprint(2, "mnihongo: can't initialize display: %r\n"); exits("open"); } Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); jfont = -1; curfont = 1; while ((c = Bgetc(&bin)) >= 0) { switch (c) { case '\n': /* when input is text */ case ' ': case '\0': /* occasional noise creeps in */ putchar(c); 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 */ putchar(c); /* digit 1 */ n = (c-'0')*10; c = Bgetc(&bin); putchar(c); /* digit 2 */ n += c - '0'; hmot(n); putchar(Bgetc(&bin)); /* char itself */ break; case 'c': /* single character */ c = Bgetrune(&bin); if(c==' ') /* why does this happen? it's troff - bwk */ break; else if(jfont == curfont){ Bungetrune(&bin); Bgetstr(&bin, str); kanji(str); }else{ putchar('c'); putchar(c); } break; case 'C': Bgetstr(&bin, str); Bprint(&bout, "C%s", str); break; case 'f': Bgetstr(&bin, str); curfont = atoi(str); if(curfont < 0 || curfont > 20) curfont = 1; /* sanity */ Bprint(&bout, "%c%s", c, str); break; case 'N': /* absolute character number */ case 's': case 'p': /* new page */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); break; case 'H': /* absolute horizontal motion */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); hgoto(n); break; case 'h': /* relative horizontal motion */ Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); hmot(n); break; case 'V': Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); vgoto(n); break; case 'v': Bgetint(&bin, &n); Bprint(&bout, "%c%d", c, n); vmot(n); break; case 'w': /* word space */ putchar(c); break; case 'x': /* device control */ Bgetline(&bin, str); Bprint(&bout, "%c%s", c, str); if(tokenize(str, args, 10)>2 && args[0][0]=='f' && ('0'<=args[1][0] && args[1][0]<='9')){ if(strncmp(args[2], "Jp", 2) == 0) jfont = atoi(args[1]); else if(atoi(args[1]) == jfont) jfont = -1; } break; case 'D': /* draw function */ case 'n': /* end of line */ case '#': /* comment */ Bgetline(&bin, str); Bprint(&bout, "%c%s", c, str); break; default: fprint(2, "mnihongo: unknown input character %o %c\n", c, c); exits("error"); } } }