argv@island.uu.net (Dan Heller) (07/19/89)
Submitted-by: Mark Moraes <moraes@ai.toronto.edu> Posting-number: Volume 4, Issue 59 Archive-name: xtroff/part14 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 14 (of 18)." # Contents: xtroff/curves.c xtroff/suntroff.c # Wrapped by moraes@neat.ai on Thu Jul 13 20:55:21 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'xtroff/curves.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xtroff/curves.c'\" else echo shar: Extracting \"'xtroff/curves.c'\" \(28272 characters\) sed "s/^X//" >'xtroff/curves.c' <<'END_OF_FILE' X/* X * SunTroff - A program to display the output of Device Independent X * Troff as a window on a Sun Workstation. X * X * Troff_curves.c - Code to draw the fancy curves needed in the X * ditroff spec. Code written at Berkeley and cleaned up X * just a bit at SPAR. X * X * Authors - The original version of this program was written by X * Richard L. Hyde (Purdue) X * David Slattengren (Berkeley) X * It was nearly all rewritten, cleaned up and a more elegant X * user interface installed by X * Malcolm Slaney (Schlumberger Palo Alto Research) X * X * Legalese - This command was developed as an independent project X * to satisfy a need of the author. This program may contain X * bugs and the user is cautioned to independently verify that X * the program is suitable for the user's intended purpose. X * The program is made available on an ``as is'' basis with X * all faults and without any implied or expressed warranties X * or support from either the author, Malcolm Slaney, or X * Schlumberger Palo Alto Research Laboratory. X * X * I am putting this program in the public domain. You are X * free to use it as you wish. In return I ask two things. X * First, that you do not remove the names of the authors X * from this work. Secondly, if you make changes or X * improvements to this program that you pass these back to X * the author so that everybody can benefit from the X * improvements. X * X * Malcolm Slaney (December 1986) X * Schlumberger Palo Alto Research X * 3340 Hillview Avenue X * Palo Alto, CA 94304 X * (415) 496-4669 X * spar!malcolm@decwrl.dec.com X * malcolm@ecn.purdue.edu X * malcolm@spar.slb.com (Someday) X */ X X/* X * X * This file contains the functions for producing the graphics X * images in the sun driver for ditroff. X */ X X X#include <stdio.h> X#include <ctype.h> X#include <math.h> X#include "fixpoint.h" X X X#define TRUE 1 X#define FALSE 0 X /* imports from dver.c */ X#define hmot(n) HorizontalMove(n) X#define vmot(n) VerticalMove(n) X#define vgoto(n) VerticalGoto(n) X Xextern int HorizontalPosition; Xextern int VerticalPosition; Xextern int DisplayOutput; Xextern point(); Xextern int scale(); X X#define MAXPOINTS 200 /* number of points legal for a curve */ X X#define SOLID -1 /* line styles: these are used as bit masks to */ X#define DOTTED 004 /* create the right style lines. */ X#define DASHED 020 X#define DOTDASHED 024 X#define LONGDASHED 074 X /* constants... */ X#define pi 3.14159265358979324 X X Xint linethickness = 1; /* number of pixels wide to make lines */ Xint linmod = SOLID; /* type of line (SOLID, DOTTED, DASHED...) */ X X Xvoid Xsetstip(n) X int n; X{ X} X X/*---------------------------------------------------------------------------- X * Routine: drawline (horizontal_motion, vertical_motion) X * X * Results: Draws a line of "linethickness" width and "linmod" style X * from current (HorizontalPosition, VerticalPosition) to X * (HorizontalPosition + dh, VerticalPosition + dv). X * X * Side Efct: Resulting position is at end of line (HorizontalPosition + dh, X * VerticalPosition + dv) X *----------------------------------------------------------------------------*/ X Xdrawline(dh, dv) Xregister int dh; Xregister int dv; X{ X if (DisplayOutput) { X HGtline (HorizontalPosition, VerticalPosition, X HorizontalPosition + dh, VerticalPosition + dv); X } X hmot (dh); /* new position is at */ X vmot (dv); /* the end of the line */ X} X X X/*---------------------------------------------------------------------------- X * Routine: DrawCircle (diameter) X * X * Results: Draws a circle with leftmost point at current X * (HorizontalPosition, VerticalPosition) X * with the given diameter d. Does a thick line by calling X * RoundEnd many times with varying radii. X * X * Side Efct: Resulting position is at (HorizontalPosition + diameter, X * VerticalPosition) X *----------------------------------------------------------------------------*/ X XDrawCircle(d) Xint d; X{ X register int delta_rad; X register int limit; X register int radius; X X X if (DisplayOutput) { X radius = Scale(d) / 2; X delta_rad = radius - linethickness / 2; X limit = radius + (linethickness - 1) / 2; X while (delta_rad <= limit) { X RoundEnd (Scale(HorizontalPosition)+radius, X Scale(VerticalPosition), delta_rad, FALSE); X delta_rad++; X } X } X X hmot (d); X} X X X/*---------------------------------------------------------------------------- X * Routine: DrawEllipse(horizontal_diameter, vertical_diameter) X * X * Results: Draws regular ellipses given the major "diameters." It does X * so using a modified circle algorithm (see RoundEnd) that X * increments x and y proportionally to their axes. X * X * Side Efct: Resulting position is at (HorizontalPosition + hd, X * VerticalPosition). X *---------------------------------------------------------------------------*/ X XDrawEllipse(hd, vd) Xint hd; Xint vd; X{ X fixed xs, ys, xepsilon, yepsilon; X int thick; X register int basex; X register int basey; X register int x; X register int y; X X /* bases == coordinates of center */ X basex = Scale(HorizontalPosition + (hd >> 1)); X hmot(hd); /* horizontal motion */ X /* (HorizontalPosition should */ X /* NOT be used after this) */ X basey = Scale(VerticalPosition); X /* hd and vd are radii, not diameters*/ X if ((hd=Scale(hd >> 1)) < 1) hd++; /* neither diameter can be zero. */ X if ((vd=Scale(vd >> 1)) < 1) vd++; /* hd changed!! no hmot after this */ X ys = ffix(vd); /* start at top of the ellipse */ X xs = ffix(0); /* (y = 1/2 diameter, x = 0) */ X X if ((thick = vd) > hd) thick = hd; X xepsilon = ffixd((double) thick / (double) (vd * vd)); X yepsilon = ffixd((double) thick / (double) (hd * hd)); X X /* Calculate trajectory of the ellipse for 1/4 */ X /* the circumference (while ys is non-negative) */ X /* and mirror to get the other three quadrants. */ X X thick = linethickness / 2; X if (thick) { /* more than one pixel thick */ X RoundEnd(basex, fintr(ys) + basey, thick, 0); X RoundEnd(basex, basey - fintr(ys), thick, 0); X while (ys >= 0) { X xs += fmult(xepsilon, ys); /* generate circumference */ X ys -= fmult(yepsilon, xs); X x = fintr(xs); X y = fintr(ys); X RoundEnd(x + basex, y + basey, thick, 0); X RoundEnd(x + basex, basey - y, thick, 0); X RoundEnd(basex - x, y + basey, thick, 0); X RoundEnd(basex - x, basey - y, thick, 0); X } X } else { /* do the perimeter only (no fill) */ X point(basex, fintr(ys) + basey); X point(basex, basey - fintr(ys)); X while (ys >= 0) { X xs += fmult(xepsilon, ys); /* generate circumference */ X ys -= fmult(yepsilon, xs); X x = fintr(xs); X y = fintr(ys); X point(x + basex, y + basey); X point(x + basex, basey - y); X point(basex - x, y + basey); X point(basex - x, basey - y); X } X } X} X X X/*---------------------------------------------------------------------------- X * Routine: DrawArc (xcenter, ycenter, xpoint, ypoint) X * X * Results: Draws an arc starting at current (HorizontalPosition, X * VerticalPosition). Center is at (HorizontalPosition + cdh, X * VerticalPosition + cdv) and the terminating point is X * at <center> + (pdh, pdv). The angle between the lines X * formed by the starting, ending, and center points is figured X * first, then the points and angle are sent to HGArc for the X * drawing. X * X * Side Efct: Resulting position is at the last point of the arc. X *---------------------------------------------------------------------------*/ X XDrawArc(cdh, cdv, pdh, pdv) Xregister int cdh; Xregister int cdv; Xregister int pdh; Xregister int pdv; X{ X register double angle; X /* figure angle from the three points...*/ X /* and convert (and round) to degrees */ X angle = (atan2((double) pdh, (double) pdv) X - atan2 ((double) -cdh, (double) -cdv)) * 180.0 / pi; X /* "normalize" and round */ X angle += (angle < 0.0) ? 360.5 : 0.5; X X if (DisplayOutput) { X HGArc(HorizontalPosition + cdh, VerticalPosition + cdv, X HorizontalPosition, VerticalPosition, (int) angle); X } X hmot(cdh + pdh); X vmot(cdv + pdv); X} X X X/*---------------------------------------------------------------------------- X * Routine: DrawSpline (character_buffer, type_flag) X * X * Results: Given the starting position, the motion list in buf, and any X * extra characters from the file (terminated by a \n), drawwig X * sets up a point list to make a spline from. If "pic" is set X * picurve is called to draw the curve in pic style; else it X * calls HGCurve for the gremlin-style curve. X * X * Side Efct: Resulting position is reached from adding successive motions X * to the current position. X *---------------------------------------------------------------------------*/ X XDrawSpline(buf, pic) Xchar *buf; Xint pic; X{ X register int len = strlen(buf); /* length of the string in "buf" */ X register int npts = 1; /* point list index */ X register char *ptr = buf; /* "walking" pointer into buf */ X int x[MAXPOINTS], y[MAXPOINTS]; /* point list */ X extern char *GetLine(); X X while (*ptr == ' ') ptr++; /* skip any leading spaces */ X x[1] = HorizontalPosition; /* the curve starts at the */ X y[1] = VerticalPosition; /* current position */ X /* curve commands end with a '\n' */ X while (*ptr != '\n' && *ptr != NULL) { X if (npts < (MAXPOINTS - 1)) /* if too many points, forget some */ X npts++; X hmot(atoi(ptr)); /* convert motion to curve points */ X x[npts] = HorizontalPosition; /* and remember them */ X while (isdigit(*++ptr)); /* skip number*/ X while (*++ptr == ' '); /* skip spaces 'tween numbers */ X vmot(atoi(ptr)); X y[npts] = VerticalPosition; X while (isdigit(*++ptr)); X while (*ptr == ' ') ptr++; X /* if the amount we read wasn't the */ X /* whole thing, read some more in */ X if (len - (ptr - buf) < 15 && *(buf + len - 1) != '\n') { X char *cop = buf; X X while (*cop++ = *ptr++); /* copy what's left to the beginning */ X (void) GetLine(cop-1, len-(cop-buf)); X printf("The rest of the line is :\n***%s***\n", cop-1); X ptr = buf; X } X } X /* now, actually DO the curve */ X if (DisplayOutput) { X if (pic > 0) X picurve(x, y, npts); X else if (!pic) X HGCurve(x, y, npts); X else X polygon(x, y, npts); X } X} X X/*ARGSUSED*/ Xpolygon(x,y,npts) Xint *x; Xint *y; Xint npts; X{ X} X X X/*----------------------------------------------------------------------------* X | Routine: drawthick (thickness) X | X | Results: sets the variable "linethickness" to the given size. X | NO motion is involved. X *---------------------------------------------------------------------------*/ X Xdrawthick(s) Xint s; X{ X if ((linethickness = Scale(s)) < 1) linethickness = 1; X} X X X/*----------------------------------------------------------------------------* X | Routine: drawstyle (style_bit_map) X | X | Results: sets the variable "linmod" to the given bit map. X | NO motion is involved. X *---------------------------------------------------------------------------*/ X Xdrawstyle(s) Xint s; X{ X linmod = s; X} X X X/*---------------------------------------------------------------------------- X * Routine: picurve (xpoints, ypoints, num_of_points) X * X * Results: Draws a curve delimited by (not through) the line segments X * traced by (xpoints, ypoints) point list. This is the "Pic" X * style curve. X *---------------------------------------------------------------------------*/ X Xpicurve (x, y, npts) Xint x[MAXPOINTS]; Xint y[MAXPOINTS]; Xint npts; X{ X register int i; /* line segment traverser */ X register fixed nseg; /* effective resolution for each curve */ X register fixed w; /* position factor */ X register int xp; /* current point (and intermediary) */ X register int yp; X int pxp, pyp; /* previous point (to make lines from) */ X fixed t1, t2, t3; /* calculation temps */ X fixed j; /* inner curve segment traverser */ X X X if (x[1] == x[npts] && y[1] == y[npts]) { X x[0] = x[npts - 1]; /* if the lines' ends meet, make */ X y[0] = y[npts - 1]; /* sure the curve meets */ X x[npts + 1] = x[2]; X y[npts + 1] = y[2]; X } else { /* otherwise, make the ends of the */ X x[0] = x[1]; /* curve touch the ending points of */ X y[0] = y[1]; /* the line segments */ X x[npts + 1] = x[npts]; X y[npts + 1] = y[npts]; X } X X pxp = (x[0] + x[1]) / 2; /* make the last point pointers */ X pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line*/ X X for (i = 0; i < npts; i++) { /* traverse the line segments */ X xp = x[i] - x[i+1]; X yp = y[i] - y[i+1]; X nseg = ffixd(sqrt((double)(xp * xp + yp * yp)) / (20.0)); X xp = x[i+1] - x[i+2]; X yp = y[i+1] - y[i+2]; /* "nseg" is the number of line */ X /* segments that will be drawn for */ X /* each curve segment. The division */ X /* is there to get better performace */ X /* by sacrificing resolution */ X nseg += ffixd(sqrt((double)(xp * xp + yp * yp)) / (20.0)); X X for (j = ffix(1); j < nseg; j += ffix(1)) { X w = fdiv(j, nseg); X t1 = fmult(ffixd(0.5), fmult(w, w)); X w -= ffixd(0.5); X t2 = ffixd(0.75) - fmult(w, w); X w -= ffixd(0.5); X t3 = fmult(ffixd(0.5), fmult(w, w)); X xp = fintr(fmult(t1, ffix(x[i+2])) X + fmult(t2, ffix(x[i+1])) + fmult(t3, ffix(x[i]))); X yp = fintr(fmult(t1, ffix(y[i+2])) X + fmult(t2, ffix(y[i+1])) + fmult(t3, ffix(y[i]))); X HGtline(pxp, pyp, xp, yp); X pxp = xp; X pyp = yp; X } X } X} X X X/*---------------------------------------------------------------------------- X * Routine: HGtline(xstart, ystart, xend, yend) X * X * Results: Draws a line of proper thickness (specified in linethickness). X * Scales its points before doing the line - NO scaling should X * be done before calling this routine. X *---------------------------------------------------------------------------*/ X X XHGtline(xs, ys, xe, ye) X{ X register int x0; /* starting point and line-walking registers */ X register int y0; X int dx; /* parameters in the line calculations */ X int dy; X register int res; X int xinc; X int yinc; X int x1; /* end-point of the line */ X int y1; X int radius; X int top; /* how much to bleed line in "up" (left) direction */ X int bottom; /* how much to bleed line in "down" (right) direction */ X int stop1; /* place to stop making circles at start of line */ X int stop2; /* place to start making circles at end of line */ X int halfstop; /* distance tween stop1 and stop3 */ X int stop3; /* midpoint `tween making circles and lines */ X register int i; /* line-bleeding carrier */ X X X x0 = Scale(xs); /* convert endpoints to SUN coordinates */ X y0 = Scale(ys); X x1 = Scale(xe); X y1 = Scale(ye); X X xinc = 1; X yinc = 1; X if ((dx = x1-x0) < 0) { X xinc = -1; X dx = -dx; X } X if ((dy = y1-y0) < 0) { X yinc = -1; X dy = -dy; X } X X radius = (linethickness - 1) / 2; X RoundEnd(x0, y0, radius, TRUE); /* add ends of line */ X RoundEnd(x1, y1, radius, TRUE); /* (nice and curvy) */ X X top = linethickness; /* increase line thickness if at an angle */ X stop1 = halfstop = 0; X if ((i = (int) (sqrt ((double) (dx * dx + dy * dy)) + 0.01)) < 2) X return; /* small lines are done with endpoints */ X if (dx >= dy) { X top = (linethickness * i) / dx; X stop1 = (linethickness * dy) / (i + 1); X halfstop = (radius * dy) / i; X } else { X top = (linethickness * i) / dy; X stop1 = (linethickness * dx) / (i + 1); X halfstop = (radius * dx) / i; X } X bottom = (top - 1) / 2; X top = top / 2; X X if (dx >= dy) { X res = (dy >> 1) - (dx >> 1); X if (linethickness >= i) { X stop1 = stop2 = x0; X halfstop = i + 1; X } else if (xinc == 1) { X stop2 = x1 - stop1; X stop1 = x0 + stop1; X stop3 = x0 + halfstop; X } else { X stop2 = x1 + stop1; X stop1 = x0 - stop1; X stop3 = x0 - halfstop; X } X X while (x0 != stop1) { X RoundEnd(x0, y0, radius, FALSE); X if ((x0&linmod) && (xinc == 1 ? x0 > stop3 : x0 < stop3)) X for (i = y0 - top; i <= y0 + bottom; i++) X point(x0, i); X if (res >= 0) { X res -= dx; X y0 += yinc; X } X res += dy; X x0 += xinc; X } X while (x0 != stop2) { X if (x0&linmod) X for (i = y0 - top; i <= y0 + bottom; i++) X point(x0, i); X if (res >= 0) { X res -= dx; X y0 += yinc; X } X res += dy; X x0 += xinc; X } X stop3 = x1 + (xinc == 1 ? -halfstop : halfstop); X while (x0 != x1) { X RoundEnd(x0, y0, radius, FALSE); X if ((x0&linmod) && (xinc == 1 ? x0 < stop3 : x0 > stop3)) X for (i = y0 - top; i <= y0 + bottom; i++) X point(x0, i); X if (res >= 0) { X res -= dx; X y0 += yinc; X } X res += dy; X x0 += xinc; X } X } else { X res = (dx >> 1) - (dy >> 1); X if (linethickness >= i) { X stop1 = stop2 = y0; X halfstop = i + 1; X } else if (yinc == 1) { X stop2 = y1 - stop1; X stop1 = y0 + stop1; X stop3 = y0 + halfstop; X } else { X stop2 = y1 + stop1; X stop1 = y0 - stop1; X stop3 = y0 - halfstop; X } X X while (y0 != stop1) { X RoundEnd(x0, y0, radius, FALSE); X if ((y0&linmod) && (yinc == 1 ? y0 > stop3 : y0 < stop3)) X for (i = x0 - top; i <= x0 + bottom; i++) X point(i, y0); X if (res >= 0) { X res -= dy; X x0 += xinc; X } X res += dx; X y0 += yinc; X } X while (y0 != stop2) { X if (y0&linmod) X for (i = x0 - top; i <= x0 + bottom; i++) X point(i, y0); X if (res >= 0) { X res -= dy; X x0 += xinc; X } X res += dx; X y0 += yinc; X } X stop3 = y1 + (yinc == 1 ? -halfstop : halfstop); X while (y0 != y1) { X RoundEnd(x0, y0, radius, FALSE); X if ((y0&linmod) && (yinc == 1 ? y0 < stop3 : y0 > stop3)) X for (i = x0 - top; i <= x0 + bottom; i++) X point(i, y0); X if (res >= 0) { X res -= dy; X x0 += xinc; X } X res += dx; X y0 += yinc; X } X } X} X X X/*---------------------------------------------------------------------------- X * Routine: HGArc (xcenter, ycenter, xstart, ystart, angle) X * X * Results: This routine plots an arc centered about (cx, cy) counter X * clockwise starting from the point (px, py) through 'angle' X * degrees. If angle is 0, a full circle is drawn. X * It does so by calling RoundEnd (fat point maker) for points X * along the circle with density depending on the circle's size. X * The points that define the circle are Scaled before doing X * the actual drawing. No scaling should be done before calling X * this routine. X *---------------------------------------------------------------------------*/ X XHGArc(cx,cy,px,py,angle) Xregister int cx; Xregister int cy; Xint px; Xint py; Xint angle; X{ X double resolution, fullcircle; X int extent; X int halfline; X fixed epsilon; X register fixed xs; X register fixed ys; X X X halfline = linethickness / 2; X X cx = Scale(cx); /* set points to sun's res. before drawing */ X cy = Scale(cy); X px = Scale(px); X py = Scale(py); X X px -= cx; /* px, py are equal to change in x and y from */ X py -= cy; /* center to starting point */ X X/* calculate drawing parameters */ X X resolution = sqrt((double)(px * px + py * py)); X fullcircle = ceil(2.0 * pi * resolution); X epsilon = ffixd(1.0 / resolution); X xs = ffix(px); X ys = ffix(py); X X if (angle == 0) /* calculate how long to do the arc */ X extent = (int) fullcircle; X else X extent = (int) (fullcircle * (double) angle / 360.0); X if (extent < 1) extent = 1; X X if (halfline < 1) { X do { X xs += fmult(epsilon, ys); X ys -= fmult(epsilon, xs); X point(fintr(xs) + cx, fintr(ys) + cy); X } while (--extent); X } else { X do { X xs += fmult(epsilon, ys); X ys -= fmult(epsilon, xs); X RoundEnd(cx + fintr(xs), cy + fintr(ys), halfline, FALSE); X } while (--extent); X } X} /* end HGArc */ X X X/*---------------------------------------------------------------------------- X * Routine: RoundEnd (x, y, radius, filled_flag) X * X * Results: Plots a filled (if requested) circle of the specified radius X * centered about (x, y). X *---------------------------------------------------------------------------*/ X XRoundEnd(x, y, radius, filled) Xregister int x; Xregister int y; Xint radius, filled; X{ X fixed xs, ys, epsilon; X register int j; X register int k; X X X point(x, y + radius); /* do the starting point of the circle */ X if (radius < 1) return; /* if circle is tiny, quit now */ X point(x, y - radius); X X /* Calculate trajectory of the circle for 1/4 */ X /* the circumference (while ys is positive) and */ X /* mirror to get the other three quadrants. */ X X xs = ffix(0); X ys = ffix(radius); X epsilon = fdiv(ffix(1), ys); X X while (ys >= 0) { X j = fintr(xs); X k = fintr(ys); X if (filled) { /* fill from center */ X do { X point(j+x, k+y); X point(j+x, y-k); X point(x-j, k+y); X point(x-j, y-k); X } while (--k >= 0); X } else { /* do the perimeter only (no fill) */ X point(j+x, k+y); X point(j+x, y-k); X point(x-j, k+y); X point(x-j, y-k); X } X xs += fmult(epsilon, ys); /* generate circumference */ X ys -= fmult(epsilon, xs); X } X} /* end RoundEnd */; X X X/*---------------------------------------------------------------------------- X * Routine: Paramaterize (xpoints, ypoints, hparams, num_points) X * X * Results: This routine calculates parameteric values for use in X * calculating curves. The parametric values are returned X * in the array h. The values are an approximation of X * cumulative arc lengths of the curve (uses cord length). X * For additional information, see paper cited below. X *---------------------------------------------------------------------------*/ X Xstatic Paramaterize(x, y, h, n) Xint x[MAXPOINTS]; Xint y[MAXPOINTS]; Xfloat h[MAXPOINTS]; Xint n; X{ X register int dx; X register int dy; X register int i; X register int j; X float u[MAXPOINTS]; X X X for (i=1; i<=n; ++i) { X u[i] = 0; X for (j=1; j<i; j++) { X dx = x[j+1] - x[j]; X dy = y[j+1] - y[j]; X u[i] += sqrt ((double) (dx * dx + dy * dy)); X } X } X for (i=1; i<n; ++i) h[i] = u[i+1] - u[i]; X} /* end Paramaterize */ X X X/*---------------------------------------------------------------------------- X * Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints) X * X * Results: This routine solves for the cubic polynomial to fit a X * spline curve to the the points specified by the list X * of values. The Curve generated is periodic. The algorithms X * for this curve are from the "Spline Curve Techniques" paper X * cited below. X *---------------------------------------------------------------------------*/ X Xstatic PeriodicSpline(h, z, dz, d2z, d3z, npoints) Xfloat h[MAXPOINTS]; /* paramaterization */ Xint z[MAXPOINTS]; /* point list */ Xfloat dz[MAXPOINTS]; /* to return the 1st derivative */ Xfloat d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ Xint npoints; /* number of valid points */ X{ X float d[MAXPOINTS]; X float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; X float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS]; X int i; X X /* step 1 */ X for (i=1; i<npoints; ++i) { X deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0; X } X h[0] = h[npoints-1]; X deltaz[0] = deltaz[npoints-1]; X X /* step 2 */ X for (i=1; i<npoints-1; ++i) { X d[i] = deltaz[i+1] - deltaz[i]; X } X d[0] = deltaz[1] - deltaz[0]; X X /* step 3a */ X a[1] = 2 * (h[0] + h[1]); X b[1] = d[0]; X c[1] = h[0]; X for (i=2; i<npoints-1; ++i) { X a[i] = 2*(h[i-1]+h[i]) - pow ((double) h[i-1],(double)2.0) / a[i-1]; X b[i] = d[i-1] - h[i-1] * b[i-1]/a[i-1]; X c[i] = -h[i-1] * c[i-1]/a[i-1]; X } X X /* step 3b */ X r[npoints-1] = 1; X s[npoints-1] = 0; X for (i=npoints-2; i>0; --i) { X r[i] = -(h[i] * r[i+1] + c[i])/a[i]; X s[i] = (6 * b[i] - h[i] * s[i+1])/a[i]; X } X X /* step 4 */ X d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1] X - h[npoints-1] * s[npoints-2]) X / (h[0] * r[1] + h[npoints-1] * r[npoints-2] X + 2 * (h[npoints-2] + h[0])); X for (i=1; i<npoints-1; ++i) { X d2z[i] = r[i] * d2z[npoints-1] + s[i]; X } X d2z[npoints] = d2z[1]; X X /* step 5 */ X for (i=1; i<npoints; ++i) { X dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; X d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0; X } X} /* end PeriodicSpline */ X X X/*---------------------------------------------------------------------------- X * Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints) X * X * Results: This routine solves for the cubic polynomial to fit a X * spline curve the the points specified by the list of X * values. The alogrithms for this curve are from the X * "Spline Curve Techniques" paper cited below. X *---------------------------------------------------------------------------*/ X Xstatic NaturalEndSpline(h, z, dz, d2z, d3z, npoints) Xfloat h[MAXPOINTS]; /* parameterization */ Xint z[MAXPOINTS]; /* Point list */ Xfloat dz[MAXPOINTS]; /* to return the 1st derivative */ Xfloat d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */ Xint npoints; /* number of valid points */ X{ X float d[MAXPOINTS]; X float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; X int i; X X /* step 1 */ X for (i=1; i<npoints; ++i) { X deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0; X } X deltaz[0] = deltaz[npoints-1]; X X /* step 2 */ X for (i=1; i<npoints-1; ++i) { X d[i] = deltaz[i+1] - deltaz[i]; X } X d[0] = deltaz[1] - deltaz[0]; X X /* step 3 */ X a[0] = 2 * (h[2] + h[1]); X b[0] = d[1]; X for (i=1; i<npoints-2; ++i) { X a[i] = 2*(h[i+1]+h[i+2]) - pow((double) h[i+1],(double) 2.0)/a[i-1]; X b[i] = d[i+1] - h[i+1] * b[i-1]/a[i-1]; X } X X /* step 4 */ X d2z[npoints] = d2z[1] = 0; X for (i=npoints-1; i>1; --i) { X d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2]; X } X X /* step 5 */ X for (i=1; i<npoints; ++i) { X dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6; X d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0; X } X} /* end NaturalEndSpline */ X X X/*---------------------------------------------------------------------------- X * Routine: HGCurve(xpoints, ypoints, num_points) X * X * Results: This routine generates a smooth curve through a set of points. X * The method used is the parametric spline curve on unit knot X * mesh described in "Spline Curve Techniques" by Patrick X * Baudelaire, Robert Flegal, and Robert Sproull -- Xerox Parc. X *---------------------------------------------------------------------------*/ X X#define POINTSPERINTERVAL 16 X XHGCurve(x, y, numpoints) Xint x[MAXPOINTS]; Xint y[MAXPOINTS]; Xint numpoints; X{ X float h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS]; X float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS]; X float t, t2, t3; X register int j; X register int k; X register int nx; X register int ny; X int lx, ly; X int PointsPerInterval; X X X lx = x[1]; X ly = y[1]; X PointsPerInterval = POINTSPERINTERVAL / (9999 / Scale(10000) + 1); X X /* Solve for derivatives of the curve at each point X * separately for x and y (parametric). X */ X Paramaterize(x, y, h, numpoints); X /* closed curve */ X if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { X PeriodicSpline(h, x, dx, d2x, d3x, numpoints); X PeriodicSpline(h, y, dy, d2y, d3y, numpoints); X } else { X NaturalEndSpline(h, x, dx, d2x, d3x, numpoints); X NaturalEndSpline(h, y, dy, d2y, d3y, numpoints); X } X X /* generate the curve using the above information and X * PointsPerInterval vectors between each specified knot. X */ X X for (j=1; j<numpoints; ++j) { X if ((x[j] == x[j+1]) && (y[j] == y[j+1])) continue; X for (k=0; k<=PointsPerInterval; ++k) { X t = (float) k * h[j] / (float) PointsPerInterval; X t2 = t * t; X t3 = t * t2; X nx = x[j] + (int)(t * dx[j] + t2 * d2x[j]/2 + t3 * d3x[j]/6); X ny = y[j] + (int)(t * dy[j] + t2 * d2y[j]/2 + t3 * d3y[j]/6); X HGtline(lx, ly, nx, ny); X lx = nx; X ly = ny; X } /* end for k */ X } /* end for j */ X} /* end HGCurve */ END_OF_FILE if test 28272 -ne `wc -c <'xtroff/curves.c'`; then echo shar: \"'xtroff/curves.c'\" unpacked with wrong size! fi # end of 'xtroff/curves.c' fi if test -f 'xtroff/suntroff.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xtroff/suntroff.c'\" else echo shar: Extracting \"'xtroff/suntroff.c'\" \(23976 characters\) sed "s/^X//" >'xtroff/suntroff.c' <<'END_OF_FILE' X/* X * SunTroff - A program to display the output of Device Independent X * Troff as a window on a Sun Workstation. X * X * Suntroff - Code to interface the rather generic user interface X * provided by windows.c and the low level troff parsing X * and drawing routines. X * X * Authors - The original version of this program was written by X * Richard L. Hyde (Purdue) X * David Slattengren (Berkeley) X * It was nearly all rewritten, cleaned up and a more elegant X * user interface installed by X * Malcolm Slaney (Schlumberger Palo Alto Research) X * Write characters as words X * David Cahlander (Cray Research, Inc.) X * X * Legalese - This command was developed as an independent project X * to satisfy a need of the author. This program may contain X * bugs and the user is cautioned to independently verify that X * the program is suitable for the user's intended purpose. X * The program is made available on an ``as is'' basis with X * all faults and without any implied or expressed warranties X * or support from either the author, Malcolm Slaney, or X * Schlumberger Palo Alto Research Laboratory. X * X * I am putting this program in the public domain. You are X * free to use it as you wish. In return I ask two things. X * First, that you do not remove the names of the authors X * from this work. Secondly, if you make changes or X * improvements to this program that you pass these back to X * the author so that everybody can benefit from the X * improvements. X * X * Malcolm Slaney (December 1986) X * Schlumberger Palo Alto Research X * 3340 Hillview Avenue X * Palo Alto, CA 94304 X * (415) 496-4669 X * spar!malcolm@decwrl.dec.com X * malcolm@ecn.purdue.edu X * malcolm@spar.slb.com (Someday) X */ X X#include "suntroff.h" X#ifdef SUNTOOLS X#include <suntool/sunview.h> X#endif SUNTOOLS X#define MAXPAGES 500 /* Pages to remember */ X Xstatic FILE *CurrentFilePointer; /* Current input file. */ Xstatic FILE *RealBufferPointer; /* Buffer file pointer */ Xstatic FILE *RealFilePointer; /* Real File Pointer */ X Xstatic long PagePlace[MAXPAGES]; /* Remembered ftell X positions */ Xstatic int MaxPage = 0; /* Number of remembered positions */ X X X /* TYPESETTER ENVIRONMENT VARIABLES */ Xint size = 1; /* Current Font Size (internal X pstable index) */ Xfloat ditsiz; /* Current Font Scale (special troff X characters) */ Xint font = 1; /* Current Font (internal font X number */ Xint linmod; /* Line Style....unused. */ X Xint linethickness; /* unused */ X Xint HorizontalPosition; /* Horizontal Position (Device X Coordinates) */ Xint VerticalPosition; /* Vertical Position on the page X (Device Coordinates) */ X Xchar DeviceName[11]; /* Output produced for this device */ X Xint DeviceResolution; /* Output produced at this resolution*/ X Xstruct FontBitStruct *CurrentFont = 0; /* Pointer to the current font X information. */ Xint DisplayOutput = 1; /* Don't display output (just parse) X when this flag is zero. */ Xint LineNumber = 0; /* Input file line number */ X Xextern int SUNRES; /* Resolution of display */ X X#ifdef SUNTOOLS Xchar *DefaultTitle = "SUNTROFF (3.0) "; X#else Xchar *DefaultTitle = "XTROFF (4.0) "; X/* X * We use this macro to pack two characters into an int, so we can test for X * troff special characters efficiently. As long as we use PACK_TWO_CHARS for X * both constants that we want to compare against, eg. PACK_TWO_CHARS('c', X * 'i') for 'ci', as well as for variables, it should be portable. Idea from X * Dave Cahlander <dac@cray.com>, portable implementation from Henry Spencer X * <henry@utzoo.uucp>, Jeffrey Lee <jonah@db.toronto.edu> X */ X#define PACK_TWO_CHARS(c1, c2) (((c1)<<8)|(c2)) X#endif X Xint CurrentPage = 0; /* Current Page in Input File */ X Xint LastPage = 0; /* Last Page of input file */ X XShowPage(PageNumber){ X int i; X X if (!CurrentFilePointer){ X warning("No file open for input."); X return(0); X } X X if (PageNumber < 1) X PageNumber = 1; X X if (LastPage && PageNumber > LastPage){ X warning("There are only %d pages in\nthis document.", X LastPage); X return(CurrentPage); X } X X if (PageNumber < MAXPAGES){ X if (PagePlace[PageNumber]){ X FileSeek(PagePlace[PageNumber]); X CurrentPage = PageNumber; X } else { X for (i=PageNumber;i>0 && !PagePlace[i];i--) X ; X FileSeek(PagePlace[i]); X X SetTitleBar("Skipping",i); X DisplayOutput = 0; X while (!feof(CurrentFilePointer) && X ((CurrentPage = ParseInput()) != PageNumber)) X ; X } X DisplayOutput = 1; X ClearPage(); X SetTitleBar("Rasterizing",PageNumber); X CurrentPage = ParseInput(); X RefreshPage(); X } X X if (LastPage && PageNumber > LastPage){ X warning("There are only %d pages in\nthis document.", X LastPage); X SetTitleBar("Displaying",CurrentPage); X return(CurrentPage); X } X X SetTitleBar("Displaying",PageNumber); X return(PageNumber); X} X X XClearPagePositions(){ X int i; X X for (i=0;i<MAXPAGES;i++){ X PagePlace[i] = 0; X } X MaxPage = 0; X} X X#ifdef SUNTOOLS Xstatic short IconImage[] = { X#include "ditroff.icon" X}; XDEFINE_ICON_FROM_IMAGE(DitroffIcon,IconImage); X XInitializeApplication(Frame,Canvas) XWindow Frame, Canvas; X{ X window_set(Frame, X FRAME_ICON,&DitroffIcon, X 0); X SetTitleBar("Initializing",0); X} X#endif SUNTOOLS X X XInitializeFile(RealFile, TempFile) XFILE *RealFile, *TempFile; X{ X CurrentFilePointer = RealFilePointer = RealFile; X RealBufferPointer = TempFile; X FileSeek(0L); X ClearPagePositions(); X CurrentPage = LastPage = 0; X} X XHorizontalMove(delta) Xint delta; X{ X HorizontalPosition += delta; X} X XHorizontalGoto(NewPosition) Xint NewPosition; X{ X HorizontalPosition = NewPosition; X} X XVerticalMove(delta) Xint delta; X{ X VerticalPosition += delta; X} X XVerticalGoto(NewPosition) Xint NewPosition; X{ X VerticalPosition = NewPosition; X} X X/* X * An attempt is made to gather characters up into words. This X * produces a much better display since the individual characters X * in a word are separated by the space allocated for the character X * at this font size. On the average, the position desired and X * the actual screen position will match, since the screen characters X * have the spacing described by the troff description file DESC.out. X * However, if the font has incorrect space or an incorrect discription X * file is used, this scheme will not work. An error term is calculated X * that indicates the difference between where the character actually X * will be placed and the position required by cononical troff position X * file. When this difference exceeds 3 pixels (arbitrary) the X * assembled word is terminated and the next character is placed at X * the position designated by troff. X * Note that the troff position can be a fractional pixel while X * the screen position must always be an integer. X */ XPutCharacterString() X{ X char string[100]; X char strch[100]; X char strpos[100]; X int i, n = 0; X int c, ch, x, w; X float xdelta, xerror; X char **CodeTable, **AsciiTable; X X CodeTable = OutputTypesetter->CodeTable; X AsciiTable = OutputTypesetter->AsciiTable; X X ch = GetChar(); X if (ch < 32 || ch > 128 || X (AsciiTable[font] != NULL && AsciiTable[font][ch-32] == 0)) { X PutCharacter(ch); X return; X } X x = HorizontalPosition; X xerror = 0; X LoadFontBits(); X X/* character translation */ X X strpos[n] = 0; X strch[n] = ch; X ch = CodeTable[font][AsciiTable[font][ch-32]&0xff]; X string[n++] = ch; X X while((c = GetChar()) != EOF) { X switch(c) { X X case '\n': X LineNumber++; X break; X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X HorizontalMove(w = (c-'0')*10 + GetChar()-'0'); X strpos[n] = w; X xdelta = CurrentFont->Bits->per_char[ch].width - X (w * SUNRES) / (float)UserTypesetter->Device.res; X xerror += xdelta; X#ifdef FONTDEBUG X printf("ch=%c d=%g e=%g\n", ch, xdelta, xerror); X#endif /* FONTDEBUG */ X if (xdelta < -5) { X c = 'c'; X } else { X ch = GetChar(); X X/* character translation */ X X strch[n] = ch; X ch = CodeTable[font][AsciiTable[font][ch-32]&0xff]; X string[n++] = ch; X if (ch != 0) X break; X c = 'w'; X } X X default: X/* X * check cumulative error X * The error should be less than .5 space on the wide side or X * about 5 spaces on the narrow side. The canned numbers of X * 5 pixels and 50 pixels may also be O.K. X */ X if (xerror > 5 || xerror < -50) { X HorizontalPosition = x; X for (i = 0; i < n; i++) { X HorizontalPosition += strpos[i]; X PutCharacter(strch[i]&0xff); X } X } else { X string[n] = '\0'; X PutString(x, string); X } X UnGetChar(c); X return; X } X } X} X XPutString(x, string) Xint x; Xchar *string; X{ X if (!DisplayOutput) X return; X DrawString(x, VerticalPosition, string); X} X XPutCharacter(c) Xint c; X{ X int OldFont, i, cwidth; X char **AsciiTable, *SpecialCharacterName, **CodeTable; X short *SpecialCharacterNumber; X struct Font **FontInformation; X struct dev *Device; X X AsciiTable = OutputTypesetter->AsciiTable; X SpecialCharacterNumber = OutputTypesetter->SpecialCharacterNumber; X SpecialCharacterName = OutputTypesetter->SpecialCharacterName; X CodeTable = OutputTypesetter->CodeTable; X FontInformation = OutputTypesetter->FontInformation; X Device = &OutputTypesetter->Device; X X X if (!DisplayOutput){ X return; X } X X if (c == ' ') /* Spaces are easy */ X return; X X c -= 32; X if (c < 0 || c > 128-32+Device->nchtab){ X warning( X "Bad character (%d) passed to PutCharacter at line %d.\n" X ,c+32,LineNumber); X } X X OldFont = font; X X if (AsciiTable[font][c] == 0){ /* If its not in the X table then look for X it in the other X fonts. */ X for (i=0;i<=Device->nfonts;i++){ X if (!FontInformation) X continue; X#ifdef MAYBENOT X if (!FontInformation[i]->specfont) X continue; X#endif MAYBENOT X if (!AsciiTable[i]) X continue; X if (AsciiTable[i][c]) X break; X } X if (i <= Device->nfonts){ X font = i; X VirtualLoadFont(FontInformation[i]->namefont, size); X } else { X char *s = &SpecialCharacterName[SpecialCharacterNumber[c+32-128]]; X switch(PACK_TWO_CHARS(s[0], s[1])) { X X case PACK_TWO_CHARS('F', 'i'): X PutString(HorizontalPosition, "ffi"); X return; X X case PACK_TWO_CHARS('F', 'l'): X PutString(HorizontalPosition, "ffl"); X return; X X case PACK_TWO_CHARS('f', 'i'): X PutString(HorizontalPosition, "fi"); X return; X X case PACK_TWO_CHARS('f', 'f'): X PutString(HorizontalPosition, "ff"); X return; X X case PACK_TWO_CHARS('f', 'l'): X PutString(HorizontalPosition, "fl"); X return; X X default: X warning( X "Can't find (%s)%d in %s character table.\n", X &SpecialCharacterName[SpecialCharacterNumber[ X c+32-128]], X c+32, X OutputTypesetter->Name); X return; X } X } X } X X LoadFontBits(); X X#ifndef NOADJUST X /* X * A hack to help centre the X11 font in the space of the laser X * printer font so it looks much nicer. Taken from David X * Blythe's xproof previewer for X10, at the University of X * Toronto. It might work in Suntools as well - I haven't X * tried. - moraes X */ X cwidth = UserTypesetter->WidthTable[font] X [UserTypesetter->AsciiTable[font][c]&0xff]&0xff; X cwidth = (cwidth * UserTypesetter->PointSizeTable[size - 1] X + UserTypesetter->Device.unitwidth/2) X / UserTypesetter->Device.unitwidth; X#else X cwidth = 0; X#endif X X DrawCharacter(HorizontalPosition,VerticalPosition, X CodeTable[font][AsciiTable[font][c]&0xff], cwidth); X SetFont(OldFont); X} X XPutSpecialCharacter(CharacterName) Xchar *CharacterName; X{ X int i, c; X struct dev *Device; X short *SpecialCharacterNumber; X char *SpecialCharacterName; X X Device = &OutputTypesetter->Device; X SpecialCharacterNumber = OutputTypesetter->SpecialCharacterNumber; X SpecialCharacterName = OutputTypesetter->SpecialCharacterName; X X if (!DisplayOutput){ X return; X } X X#ifndef SUNTOOLS X /* Draw Troff special graphics (non-character) */ X X c = PACK_TWO_CHARS(CharacterName[0], CharacterName[1]); X X switch (c) { X/* X * /bv{0 800 moveto 0 -1000 rls}def X */ X case PACK_TWO_CHARS('b', 'v'): X line(.25, -.8, .25, .2); X return; X/* X * /br{0 750 moveto 0 -1000 rls}def X */ X case PACK_TWO_CHARS('b', 'r'): X line(0., -.75, 0., .25); X return; X/* X * /ru{500 0 rls}def X */ X case PACK_TWO_CHARS('r', 'u'): X line(0., 0., .5, 0.); X return; X/* X * /lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def X */ X case PACK_TWO_CHARS('l', 'f'): X line(.25, -.8, .25, .2); X line(.25, .2, .5, .2); X return; X/* X * /rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def X */ X case PACK_TWO_CHARS('r', 'f'): X line(.25, -.8, .25, .2); X line(.25, .2, 0., .2); X return; X/* X * /lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def X */ X case PACK_TWO_CHARS('l', 'c'): X line(.25, .2, .25, -.8); X line(.25, -.8, .5, -.8); X return; X/* X * /rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def X */ X case PACK_TWO_CHARS('r', 'c'): X line(.25, .2, .25, -.8); X line(.25, -.8, 0., -.8); X return; X/* X * /sq{80 0 rmoveto currentpoint dround newpath moveto X * 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def X */ X case PACK_TWO_CHARS('s', 'q'): X line(.08, 0., .72, 0.); X line(.72, 0., .72, -.64); X line(.72, -.64, .08, -.64); X line(.08, -.64, .08, 0.); X return; X/* X * /bx{80 0 rmoveto currentpoint dround newpath moveto X * 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def X */ X case PACK_TWO_CHARS('b', 'x'): X box(.08, -.64, .72, 0.); X return; X/* X * /ci{500 360 rmoveto currentpoint newpath 333 0 360 arc X * 50 setlinewidth stroke}def X */ X case PACK_TWO_CHARS('c', 'i'): X circle(.5, -.36, .25, 0); X return; X/* X * /lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def X */ X case PACK_TWO_CHARS('l', 't'): X line(.25, .2, .25, -.55); X arc(.5, -.55, .25, 180, -90, 0); X return; X/* X * /rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def X */ X case PACK_TWO_CHARS('r', 't'): X line(.25, .2, .25, -.55); X arc(0., -.55, .25, 0, 90, 0); X return; X/* X * /lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def X */ X case PACK_TWO_CHARS('l', 'b'): X line(.25, -.8, .25, -.05); X arc(.5, -.05, .25, 180, 90, 0); X return; X/* X * /rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def X */ X case PACK_TWO_CHARS('r', 'b'): X line(.25, -.8, .25, -.05); X arc(0., -.05, .25, 0, -90, 0); X return; X/* X * /lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub X * 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def X */ X case PACK_TWO_CHARS('l', 'k'): X line(.25, -.8, .25, -.55); X arc(0., -.55, .25, 0, -90, 0); X arc(0., -.05, .25, 90, -90, 0); X line(.25, -.05, .25, .2); X return; X/* X * /rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub X * 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def X */ X case PACK_TWO_CHARS('r', 'k'): X line(.25, -.8, .25, -.55); X arc(.5, -.55, .25, 180, 90, 0); X arc(.5, -.05, .25, 90, 90, 0); X line(.25, -.05, .25, .2); X return; X/* X * /bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def X */ X case PACK_TWO_CHARS('b', 'u'): X circle(.25, -.36, .25, 1); X return; X/* X * /ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def X */ X case PACK_TWO_CHARS('o', 'b'): X arc(.25, -.36, .25, 0, 360, 0); X return; X/* X * /vr{0 800 moveto 0 -770 rls}def X */ X case PACK_TWO_CHARS('v', 'r'): X line(.25, -.8, .25, -.03); X return; X/* X * /rn{0 840 moveto 500 0 rls}def X */ X case PACK_TWO_CHARS('r', 'n'): X line(.25, -.84, .75, -.84); X return; X/* X * /ul{0 -140 moveto 500 0 rls}def X */ X case PACK_TWO_CHARS('u', 'l'): X line(.25, .14, .75, .14); X return; X/* X * /fractm [.65 0 0 .6 0 0] def X * /fraction X * {/fden exch def /fnum exch def gsave /cf currentfont def X * cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto X * fnum show rmoveto currentfont cf setfont(\244)show setfont fden show X * grestore ditwid 0 rmoveto} def X */ X case PACK_TWO_CHARS('1', '8'): X draw_fraction('1', '8', size); X return; X case PACK_TWO_CHARS('3', '8'): X draw_fraction('3', '8', size); X return; X case PACK_TWO_CHARS('5', '8'): X draw_fraction('5', '8', size); X return; X case PACK_TWO_CHARS('7', '8'): X draw_fraction('7', '8', size); X return; X case PACK_TWO_CHARS('1', '3'): X draw_fraction('1', '3', size); X return; X case PACK_TWO_CHARS('2', '3'): X draw_fraction('2', '3', size); X return; X/* X * space codes X */ X case PACK_TWO_CHARS('\\', '^'): X return; X case PACK_TWO_CHARS('\\', '|'): X return; X } X#endif /* SUNTOOLS */ X X X for (i=0;i<Device->nchtab;i++){ X if (STREQ(&SpecialCharacterName[SpecialCharacterNumber[i]], X CharacterName)) X break; X } X if (i < Device->nchtab){ X PutCharacter(i+128); X return; X } else { X switch(c) { X X case PACK_TWO_CHARS('F', 'i'): X PutString(HorizontalPosition, "ffi"); X return; X X case PACK_TWO_CHARS('F', 'l'): X PutString(HorizontalPosition, "ffl"); X return; X X case PACK_TWO_CHARS('f', 'i'): X PutString(HorizontalPosition, "fi"); X return; X X case PACK_TWO_CHARS('f', 'f'): X PutString(HorizontalPosition, "ff"); X return; X X case PACK_TWO_CHARS('f', 'l'): X PutString(HorizontalPosition, "fl"); X return; X X default: X warning("Couldn't find special character %s in %s character list.\n", X CharacterName, OutputTypesetter->Name); X X X } X } X} X X XPrintDocument(ActualFileName,Printer) Xchar *ActualFileName, *Printer; X{ X char Command[BUFSIZ]; X int i, SavedPageNumber; X X SavedPageNumber = CurrentPage; /* Save this, just in case */ X SaveTitleBar(); X if (!LastPage && RealBufferPointer != RealFilePointer){ X for (i=1; i < MAXPAGES; i++){ X if (PagePlace[i]) X CurrentPage = i; X } X FileSeek(PagePlace[CurrentPage]); X DisplayOutput = 0; /* Now flush the rest of input X */ X while (!LastPage || !feof(RealFilePointer)){ X SetTitleBar("Flushing", CurrentPage); X CurrentPage = ParseInput(); X } X } X X SetTitleBar("Printing Document", -1); X fflush(RealBufferPointer); X X sprintf(Command,"%s%s %s",LPRCOMMAND,Printer, X ActualFileName); X system(Command); X RestoreTitleBar(); X CurrentPage = SavedPageNumber; X} X X XPrintPage(PageNumber,Printer) Xint PageNumber; Xchar *Printer; X{ X char FileName[BUFSIZ], Command[BUFSIZ]; X FILE *fp; X extern char *mktemp(); X X (void) strcpy(FileName,"/tmp/suntroff.XXXXXX"); X (void) mktemp(FileName); X X fp = fopen(FileName,"w"); X if (!fp){ X warning("Can't open %s for writing page image.\n", X FileName); X return; X } X X SaveTitleBar(); X SetTitleBar("Printing Page", PageNumber); X OutputPage(0L, PagePlace[1], CurrentFilePointer, fp); X OutputPage(PagePlace[PageNumber], PagePlace[PageNumber+1], X CurrentFilePointer,fp); X fprintf(fp, "\n"); X fprintf(fp, "x trailer\n"); X fprintf(fp, "x stop\n"); X fclose(fp); X X (void) sprintf(Command,"%s%s -n %s", LPRCOMMAND, Printer, FileName); X (void) system(Command); X unlink(FileName); X RestoreTitleBar(); X} X X/*ARGSUSED*/ XOutputPage(Start,End,Input,Output) Xlong Start, End; XFILE *Input, *Output; X{ X int c; X X if (End != 0 && Start > End){ X fatal("PrintPage: starting offset (%d) is less than\nending offset (%d)\n",Start,End); X return; X } X X FileSeek(Start); X X do { X c = GetChar(); X if (c != EOF){ X putc(c, Output); X } X Start ++; X } while (c != EOF && (End == 0 || Start < End)); X X} X X XSearchFile(String,PageNumber,Direction) Xint PageNumber, Direction; Xchar *String; X{ X PageNumber += Direction; /* Skip Current Page */ X X if (PageNumber <= 0 || (LastPage && PageNumber > PageNumber) || X !String || String[0] == NULL){ X return(0); X } X X if (PagePlace[PageNumber] == 0){ X warning("Can't find the current page while searching."); X return(0); X } X X FileSeek(PagePlace[PageNumber]); X for (;PageNumber>0 ;PageNumber += Direction){ X if (LastPage && PageNumber > LastPage){ X return(0); X } X if (feof(CurrentFilePointer)){ X return(0); X } X if (Direction < 0){ X FileSeek(PagePlace[PageNumber]); X } X X SetTitleBar("Searching",PageNumber); X if (SearchPage(String)) { X return(PageNumber); X } X } X return(0); X} X XSearchPage(String) Xchar *String; X{ X char *StringP = String; X int c; X X while ((c = GetChar()) != EOF){ X switch(c){ X case ' ': X case 0: X case '{': X case '}': X case '\n': X break; X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X GetChar(); X case 'c': X c = GetChar(); X if (c == *StringP){ X StringP++; X if (*StringP == 0){ X return(1); X } X } else { X StringP = String; X } X break; X case 'C': X GetChar(); X GetChar(); X StringP = String; X break; X case 'D': X case 'x': X case '#': X do { X c = GetChar(); X } while (c != '\n' && c != EOF); X StringP = String; X break; X case 'w': X if (*StringP == ' '){ X *StringP++; X if (*StringP == 0){ X return(1); X } X } else { X StringP = String; X } X break; X case 'n': X if (*StringP == ' '){ X *StringP++; X if (*StringP == 0){ X return(1); X } X } else { X StringP = String; X } X GetNumber(); X GetNumber(); X break; X case 's': X case 'f': X case 'H': X case 'V': X case 'h': X case 'v': X GetNumber(); X break; X case 'p': X (void) GetNumber(); X (void) RememberPagePosition(); X return(0); X default: X warning("Unknown input character %c(%d)\n", X c,c); X break; X } X } X return(0); X} X Xstatic UnreadCharacter = 0; X X/* X * Pages are ordered by physical position in the file, because of the weird X * numbers possible with troff pages X */ XRememberPagePosition() X{ X extern long ftell(); X int pageplace = ftell(RealBufferPointer); X int mid; X#ifdef SEEK X char *unread = ""; X#endif X X if (UnreadCharacter) { X pageplace--; X UnreadCharacter = 0; X#ifdef SEEK X unread = " with unread character"; X#endif /* SEEK */ X } X X if (pageplace > PagePlace[MaxPage]) { /* Usual case */ X PagePlace[++MaxPage] = pageplace; X mid = MaxPage; X } else { X /* Binary search for the page - it must be in the table */ X int hi = MaxPage; X int lo = 0; X while (hi >= lo) { X mid = lo + (hi - lo) / 2; X if (PagePlace[mid] == pageplace) X break; X if (pageplace < PagePlace[mid]) X hi = mid - 1; X else X lo = mid + 1; X } X if (PagePlace[mid] != pageplace) X fatal("pageplace 0x%x wasn't in table\n"); X } X#ifdef SEEK X printf("Remembering page %d at 0x%x%s.\n", mid, PagePlace[mid], X unread); X#endif /* SEEK */ X return(mid); X} X XFileSeek(Position) Xlong Position; X{ X UnreadCharacter = 0; X CurrentFilePointer = RealBufferPointer; X fseek(CurrentFilePointer,Position,0); X#ifdef SEEK X printf("Seeking to %x of real buffer.\n", Position); X#endif SEEK X} X XGetChar(){ X int i; X X if (UnreadCharacter){ X i = UnreadCharacter; X UnreadCharacter = 0; X return(i); X } X X i = getc(CurrentFilePointer); X if (CurrentFilePointer != RealBufferPointer){ X putc(i, RealBufferPointer); X } X X if (i == EOF){ X if (RealFilePointer != RealBufferPointer){ X if (CurrentFilePointer == RealBufferPointer){ X CurrentFilePointer = RealFilePointer; X i = GetChar(); X } X } X } X X return(i); X} X XUnGetChar(c) Xint c; X{ X if (UnreadCharacter){ X fatal("Can't UnGetChar more than one character.\n"); X } X X UnreadCharacter = c; X} X Xchar * XGetLine(Buffer, Length) Xchar *Buffer; Xint Length; X{ X int i = 0, c; X char *p = Buffer; X X Length--; /* Save room for final NULL */ X X while (i < Length && (c = GetChar()) != EOF && c != '\n'){ X if (p) X *p++ = c; X } X if (c == '\n' && p){ /* Retain the newline like fgets */ X *p++ = c; X } X if (c == '\n') X UnGetChar(c); X X X if (p) X *p = NULL; X return(Buffer); X} X Xchar * XGetWord(Buffer, Length) Xchar *Buffer; Xint Length; X{ X int i = 0, c; X char *p = Buffer; X X Length--; /* Save room for final NULL */ X X while ((c = GetChar()) != EOF && isspace(c)); X if (c != EOF){ X UnGetChar(c); X } X X while (i < Length && (c = GetChar()) != EOF && !isspace(c)){ X if (p) X *p++ = c; X } X if (c != EOF) X UnGetChar(c); X X if (p) X *p = NULL; X return(Buffer); X} X XGetNumber(){ X int i = 0, c; X X while ((c = GetChar()) != EOF && isspace(c)); X X if (c != EOF){ X UnGetChar(c); X } X X while ((c = GetChar()) != EOF && isdigit(c)){ X i = i*10 + c - '0'; X } X X if (c != EOF) X UnGetChar(c); X return (i); X} X X END_OF_FILE if test 23976 -ne `wc -c <'xtroff/suntroff.c'`; then echo shar: \"'xtroff/suntroff.c'\" unpacked with wrong size! fi # end of 'xtroff/suntroff.c' fi echo shar: End of archive 14 \(of 18\). cp /dev/null ark14isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 18 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0