void draw(Biobufhdr *Bp) { int r, x1, y1, x2, y2, i; int d1, d2; drawflag = TRUE; r = Bgetrune(Bp); switch(r) { case 'l': if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'r', &i, 0)<=0) error(FATAL, "draw line function, destination coordinates not found.\n"); endstring(); if (pageon()) Bprint(Bstdout, "%d %d %d %d Dl\n", hpos, vpos, hpos+x1, vpos+y1); hpos += x1; vpos += y1; break; case 'c': if (Bgetfield(Bp, 'd', &d1, 0)<=0) error(FATAL, "draw circle function, diameter coordinates not found.\n"); endstring(); if (pageon()) Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d1); hpos += d1; break; case 'e': if (Bgetfield(Bp, 'd', &d1, 0)<=0 || Bgetfield(Bp, 'd', &d2, 0)<=0) error(FATAL, "draw ellipse function, diameter coordinates not found.\n"); endstring(); if (pageon()) Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d2); hpos += d1; break; case 'a': if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'd', &x2, 0)<=0 || Bgetfield(Bp, 'd', &y2, 0)<=0) error(FATAL, "draw arc function, coordinates not found.\n"); endstring(); if (pageon()) Bprint(Bstdout, "%d %d %d %d %d %d Da\n", hpos, vpos, x1, y1, x2, y2); hpos += x1 + x2; vpos += y1 + y2; break; case 'q': drawspline(Bp, 1); break; case '~': drawspline(Bp, 2); break; default: error(FATAL, "unknown draw function <%c>\n", r); break; } }
static char *fm_strbrk(OBJECT *start,WORD maxnum,WORD maxlen,char *alert, WORD *pnum,WORD *plen) { int i, j, len; OBJECT *obj; char *p; *plen = 0; if (*alert == '[') /* ignore a leading [ */ alert++; for (i = 0, obj = start; i < maxnum; i++, obj++, alert++) { p = (char *)obj->ob_spec; for (j = 0; j < maxlen; j++) { if (endsubstring(*alert)) break; *p++ = *alert++; } *p = '\0'; len = p - (char *)obj->ob_spec; if (len > *plen) /* track max substring length */ *plen = len; if (!endsubstring(*alert)) {/* substring was too long */ #if DBG_ALERT kprintf("form_alert(): substring > %d bytes long\n",maxlen); #endif while(1) { /* eat rest of substring */ if (endsubstring(*alert)) break; alert++; } } if (endstring(*alert)) /* end of all substrings */ break; } #if DBG_ALERT if (i >= maxnum) /* too many substrings */ kprintf("form_alert(): more than %d substrings\n",maxnum); #endif while(1) { /* eat any remaining characters */ if (endstring(*alert)) break; alert++; } *pnum = (i<maxnum)?(i+1):maxnum;/* count of substrings found */ if (*alert) /* if not at null byte, */ alert++; /* point to next one */ return alert; }
void beginpath(char *buf, int copy) { /* * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used * to mark the start of a sequence of drawing commands that should be grouped * together and treated as a single path. By default the drawing procedures in * *drawfile treat each drawing command as a separate object, and usually start * with a newpath (just as a precaution) and end with a stroke. The newpath and * stroke isolate individual drawing commands and make it impossible to deal with * composite objects. "x X BeginPath" can be used to mark the start of drawing * commands that should be grouped together and treated as a single object, and * part of what's done here ensures that the PostScript drawing commands defined * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath" * command. At that point the path that's been built up can be manipulated in * various ways (eg. filled and/or stroked with a different line width). * * Color selection is one of the options that's available in parsebuf(), * so if we get here we add *colorfile to the output file before doing * anything important. * */ if (inpath == FALSE) { endstring(); /* getdraw(); */ /* getcolor(); */ Bprint(Bstdout, "gsave\n"); Bprint(Bstdout, "newpath\n"); Bprint(Bstdout, "%d %d m\n", hpos, vpos); Bprint(Bstdout, "/inpath true def\n"); if ( copy == TRUE ) Bprint(Bstdout, "%s\n", buf); inpath = TRUE; } }
void hmot(int x) { int delta; if ((x<expecthmot-1) || (x>expecthmot+1)) { delta = x - expecthmot; if (curtrofffontid <0 || curtrofffontid >= troffontcnt) { fprint(2, "troffontcnt=%d curtrofffontid=%d\n", troffontcnt, curtrofffontid); exits(""); } if (delta == troffontab[curtrofffontid].spacewidth*fontsize/10 && isinstring()) { if (pageon()) runeout(' '); } else { if (pageon()) { endstring(); /* Bprint(Bstdout, " %d 0 rmoveto ", delta); */ /* Bprint(Bstdout, " %d %d m ", hpos+x, vpos); */ if (debug) fprint(2, "x=%d expecthmot=%d\n", x, expecthmot); } } } hpos += x; expecthmot = 0; }
void vgoto(int y) { vpos = y; if (pageon()) { endstring(); /* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */ } }
void hgoto(int x) { hpos = x; if (pageon()) { endstring(); /* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */ } }
static void oput(int ch) /* int ch; / * next output character */ { /* * * Responsible for adding all printing characters from the input file to the * open string on top of the stack. The only other characters that end up in * that string are the quotes required for special characters. Reverse printing * mode hasn't been tested but it should be close. hpos and lastx should disagree * each time (except after startline() does something), and that should force a * call to endstring() for every character. * */ if ( stringcount > 100 ) /* don't put too much on the stack */ endline(); if ( vpos != lasty ) endline(); if ( advance == -1 ) /* for reverse printing - move first */ hmot(hmi); startline(); if ( lastc != ch || hpos != prevx ) { if ( lastx != hpos ) endstring(); if ( isascii(ch) && isprint(ch) ) { if ( ch == '\\' || ch == '(' || ch == ')' ) putc('\\', fp_out); putc(ch, fp_out); } else fprintf(fp_out, "\\%.3o", ch & 0377); lastc = ch; prevx = hpos; lastx += lasthmi; } /* End if */ if ( advance != -1 ) hmot(hmi); markedpage = TRUE; } /* End of oput */
void drawspline(Biobufhdr *Bp, int flag) { /* flag!=1 connect end points */ int x[100], y[100]; int 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 (Bgetfield(Bp, 'd', &x[N], 0)<=0 || Bgetfield(Bp, 'd', &y[N], 0)<=0) 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]; } x[N] = x[N-1]; y[N] = y[N-1]; for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) { endstring(); if (pageon()) Bprint(Bstdout, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]); /* if (dobbox == TRUE) { /* could be better */ /* cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2); /* cover((double)x[i+1], (double)-y[i+1]); /* cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2); /* } */ } hpos = x[N]; /* where troff expects to be */ vpos = y[N]; }
void devcntl(Biobufhdr *inp) { char cmd[50], buf[256], str[MAXTOKENSIZE], *line; int c, n; /* * * Interpret device control commands, ignoring any we don't recognize. The * "x X ..." commands are a device dependent collection generated by troff's * \X'...' request. * */ Bgetfield(inp, 's', cmd, 50); if (debug) Bprint(Bstderr, "devcntl(cmd=%s)\n", cmd); switch (cmd[0]) { case 'f': /* mount font in a position */ Bgetfield(inp, 'd', &n, 0); Bgetfield(inp, 's', str, 100); mountfont(n, str); break; case 'i': /* initialize */ initialize(); break; case 'p': /* pause */ break; case 'r': /* resolution assumed when prepared */ Bgetfield(inp, 'd', &resolution, 0); Bgetfield(inp, 'd', &minx, 0); Bgetfield(inp, 'd', &miny, 0); break; case 's': /* stop */ case 't': /* trailer */ /* flushtext(); */ break; case 'H': /* char height */ Bgetfield(inp, 'd', &n, 0); t_charht(n); break; case 'S': /* slant */ Bgetfield(inp, 'd', &n, 0); t_slant(n); break; case 'T': /* device name */ Bgetfield(inp, 's', devname, 16); if (debug) Bprint(Bstderr, "devname=%s\n", devname); break; case 'E': /* input encoding - not in troff yet */ Bgetfield(inp, 's', str, 100); /* if (strcmp(str, "UTF") == 0) reading = UTFENCODING; else reading = ONEBYTE; */ break; case 'X': /* copy through - from troff */ if (Bgetfield(inp, 's', str, MAXTOKENSIZE-1) <= 0) error(FATAL, "incomplete devcntl line\n"); if ((line = Brdline(inp, '\n')) == 0) error(FATAL, "incomplete devcntl line\n"); strncpy(buf, line, Blinelen(inp)-1); buf[Blinelen(inp)-1] = '\0'; Bungetc(inp); if (strncmp(str, "PI", sizeof("PI")-1) == 0 || strncmp(str, "PictureInclusion", sizeof("PictureInclusion")-1) == 0) { picture(inp, str); } else if (strncmp(str, "InlinePicture", sizeof("InlinePicture")-1) == 0) { error(FATAL, "InlinePicture not implemented yet.\n"); /* inlinepic(inp, buf); */ } else if (strncmp(str, "BeginPath", sizeof("BeginPath")-1) == 0) { beginpath(buf, FALSE); } else if (strncmp(str, "DrawPath", sizeof("DrawPath")-1) == 0) { drawpath(buf, FALSE); } else if (strncmp(str, "BeginObject", sizeof("BeginObject")-1) == 0) { beginpath(buf, TRUE); } else if (strncmp(str, "EndObject", sizeof("EndObject")-1) == 0) { drawpath(buf, TRUE); } else if (strncmp(str, "NewBaseline", sizeof("NewBaseline")-1) == 0) { error(FATAL, "NewBaseline not implemented yet.\n"); /* newbaseline(buf); */ } else if (strncmp(str, "DrawText", sizeof("DrawText")-1) == 0) { error(FATAL, "DrawText not implemented yet.\n"); /* drawtext(buf); */ } else if (strncmp(str, "SetText", sizeof("SetText")-1) == 0) { error(FATAL, "SetText not implemented yet.\n"); /* settext(buf); */ } else if (strncmp(str, "SetColor", sizeof("SetColor")-1) == 0) { error(FATAL, "SetColor not implemented yet.\n"); /* newcolor(buf); */ /* setcolor(); */ } else if (strncmp(str, "INFO", sizeof("INFO")-1) == 0) { error(FATAL, "INFO not implemented yet.\n"); /* flushtext(); */ /* Bprint(outp, "%%INFO%s", buf); */ } else if (strncmp(str, "PS", sizeof("PS")-1) == 0 || strncmp(str, "PostScript", sizeof("PostScript")-1) == 0) { if(pageon()) { endstring(); Bprint(Bstdout, "%s\n", buf); } } else if (strncmp(str, "ExportPS", sizeof("ExportPS")-1) == 0) { /* dangerous!! */ error(FATAL, "ExportPS not implemented yet.\n"); /* if (Bfildes(outp) == 1) { */ /* restore(); */ /* Bprint(outp, "%s", buf); */ /* save(); */ /* } */ } /* else error(WARNING, "Unknown string <%s %s> after x X\n", str, buf); */ break; } while ((c = Bgetc(inp)) != '\n' && c != Beof); inputlineno++; }
/* output glyph. Use first rune to look up character (hash) * then use stoken UTF string to find correct glyph in linked * list of glyphs in bucket. */ void glyphout(Rune rune, char *stoken, BOOLEAN specialflag) { struct charent **cp; struct troffont *tfp; struct psfent *psfp; int i, t, mi, wid; int fontid; /* this is the troff font table index, not the mounted font table index */ Rune r; mi = 0; settrfont(); /* check current font for the character, special or not */ fontid = curtrofffontid; if (debug) fprint(2, "\tlooking through current font: trying %s\n", troffontab[fontid].trfontid); cp = findglyph(fontid, rune, stoken); if (*cp != 0) goto foundit; if (specialflag) { if (expecthmot) hmot(0); /* check special fonts for the special character */ /* cycle through the (troff) mounted fonts starting at the next font */ for (mi=0; mi<fontmnt; mi++) { if (troffontab[fontid].trfontid==0) error(WARNING, "glyphout:troffontab[%d].trfontid=0x%x, botch!\n", fontid, troffontab[fontid].trfontid); if (fontmtab[mi]==0) { if (debug) fprint(2, "fontmtab[%d]=%#p, fontmnt=%d\n", mi, fontmtab[mi], fontmnt); continue; } if (strcmp(troffontab[fontid].trfontid, fontmtab[mi])==0) break; } if (mi==fontmnt) error(FATAL, "current troff font is not mounted, botch!\n"); for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) { if (fontmtab[i]==0) { if (debug) fprint(2, "fontmtab[%d]=%#p, fontmnt=%d\n", i, fontmtab[i], fontmnt); continue; } fontid = findtfn(fontmtab[i], TRUE); if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid); if (troffontab[fontid].special) { cp = findglyph(fontid, rune, stoken); if (*cp != 0) goto foundit; } } /* check font 1 (if current font is not font 1) for the special character */ if (mi != 1) { fontid = findtfn(fontmtab[1], TRUE);; if (debug) fprint(2, " looking through font at position 1: trying %s\n", troffontab[fontid].trfontid); cp = findglyph(fontid, rune, stoken); if (*cp != 0) goto foundit; } } if (*cp == 0) { error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken, troffontab[curtrofffontid].trfontid); expecthmot = 0; } /* use the peter face in lieu of the character that we couldn't find */ rune = 'p'; stoken = "pw"; for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) { if (fontmtab[i]==0) { if (debug) fprint(2, "fontmtab[%d]=%#p\n", i, fontmtab[i]); continue; } fontid = findtfn(fontmtab[i], TRUE); if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid); if (troffontab[fontid].special) { cp = findglyph(fontid, rune, stoken); if (*cp != 0) goto foundit; } } if (*cp == 0) { error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken, troffontab[curtrofffontid].trfontid); expecthmot = 0; return; } foundit: t = (((*cp)->postfontid&0xff)<<8) | ((*cp)->postcharid&0xff); if (debug) fprint(2, "runeout(0x%x)<%C> postfontid=0x%x postcharid=0x%x troffcharwidth=%d\n", rune, rune, (*cp)->postfontid, (*cp)->postcharid, (*cp)->troffcharwidth); tfp = &troffontab[fontid]; psfp = nil; for (i=0; i<tfp->psfmapsize; i++) { psfp = &(tfp->psfmap[i]); if(t>=psfp->start && t<=psfp->end) break; } if (i >= tfp->psfmapsize) error(FATAL, "character <0x%x> does not have a Postscript font defined.\n", rune); setpsfont(psfp->psftid, fontsize); if (t == 0x0001) { /* character is in charlib */ endstring(); if (pageon()) { Bprint(Bstdout, "%d %d m ", hpos, vpos); /* if char is unicode character rather than name, clean up for postscript */ wid = chartorune(&r, (*cp)->name); if(' '<r && r<0x7F) Bprint(Bstdout, "%d build_%s\n", (*cp)->troffcharwidth, (*cp)->name); else{ if((*cp)->name[wid] != 0) error(FATAL, "character <%s> badly named\n", (*cp)->name); Bprint(Bstdout, "%d build_X%.4x\n", (*cp)->troffcharwidth, r); } /* * stash charent pointer in a list so that we can * print these character definitions in the prologue. */ for (i=0; i<build_char_cnt; i++) if (*cp == build_char_list[i]) break; if (i == build_char_cnt) { build_char_list = galloc(build_char_list, sizeof(struct charent *)*++build_char_cnt, "build_char_list"); build_char_list[build_char_cnt-1] = *cp; } } expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth; } else if (isinstring() || rune != ' ') { startstring(); if (pageon()) if (rune == ' ') Bprint(Bstdout, " "); else Bprint(Bstdout, "%s", charcode[RUNEGETCHAR(t)].str); expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth; } }
void vmot(int y) { endstring(); /* Bprint(Bstdout, " 0 %d rmoveto ", -y); */ vpos += y; }