From 5f1cf8e6fb130fd48d6f016d13baf5408b3181f8 Mon Sep 17 00:00:00 2001 From: wkj Date: Sun, 16 May 2004 07:56:41 +0000 Subject: Checkpoint: pull in mpm; merge pic from Taj's version of the world --- src/cmd/mpm/slug.cc | 603 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 603 insertions(+) create mode 100644 src/cmd/mpm/slug.cc (limited to 'src/cmd/mpm/slug.cc') diff --git a/src/cmd/mpm/slug.cc b/src/cmd/mpm/slug.cc new file mode 100644 index 00000000..14378b90 --- /dev/null +++ b/src/cmd/mpm/slug.cc @@ -0,0 +1,603 @@ +#include "misc.h" +#include "slug.h" +//#include +#include + +static char *bufptr(int); + +void slug::coalesce() +{ + (this+1)->dp = dp; // pretty grimy, but meant to ensure + // that all output goes out. + // maybe it has to skip over PT's; + // some stuff is getting pushed inside PT..END +} + +void slug::neutralize() +{ + switch (type) { + case PAGE: + case UF: + case BF: + case PARM: + type = NEUTRAL; + coalesce(); + break; + default: + ERROR "neutralized %d (%s) with %s\n", + type, typename(), headstr() WARNING; + break; + } +} + +void slug::dump() // print contents of a slug +{ + printf("# %d %-4.4s parm %d dv %d base %d s%d f%d H%d\n#\t\t%s\n", + serialno(), typename(), parm, dv, base, + size, font, hpos, headstr()); +} + +char *slug::headstr() +{ + const int HEADLEN = 65; + static char buf[2*HEADLEN]; + int j = 0; + char *s = bufptr(dp); + int n = (this+1)->dp - dp; + if (n >= HEADLEN) + n = HEADLEN; + for (int i = 0; i < n; i++) + switch (s[i]) { + case '\n': + case '\t': + case '\0': + case ' ': + break; + default: + buf[j++] = s[i]; + break; + } + buf[j] = 0; + return buf; +} + +static char *strindex(char s[], char t[]) // index of earliest t[] in s[] +{ + for (int i = 0; s[i] != '\0'; i++) { + int j, k; + for (j = i, k = 0; t[k]!='\0' && s[j] == t[k]; j++, k++) + ; + if (k > 0 && t[k] == '\0') + return s+i; + } + return 0; +} + +void slug::slugout(int col) +{ + static int numout = 0; + if (seen++) + ERROR "%s slug #%d seen %d times [%s]\n", + typename(), serialno(), seen, headstr() WARNING; + if (type == TM) { + char *p; + if ((p = strindex(bufptr(dp), "x X TM ")) != 0) + p += strlen("x X TM "); // skip junk + else + ERROR "strange TM [%s]\n", headstr() FATAL; + fprintf(stderr, "%d\t", userpn); // page # as prefix + for ( ; p < bufptr((this+1)->dp); p++) + putc(*p, stderr); + } else if (type == COORD) { + for (char *p = bufptr(dp); p < bufptr((this+1)->dp) && *p != '\n'; p++) + putc(*p, stdout); + printf(" # P %d X %d", userpn, hpos + col*offset); + return; + } else if (type == VBOX) { + if (numout++ > 0) // BUG??? might miss something + printf("s%d\nf%d\n", size, font); + printf("H%d\n", hpos + col*offset); + } + fwrite(bufptr(dp), sizeof(char), (this+1)->dp - dp, stdout); +} + +char *slug::typename() +{ + static char buf[50]; + char *p = buf; // return value + switch(type) { + case EOF: p = "EOF"; break; + case VBOX: p = "VBOX"; break; + case SP: p = "SP"; break; + case BS: p = "BS"; break; + case US: p = "US"; break; + case BF: p = "BF"; break; + case UF: p = "UF"; break; + case PT: p = "PT"; break; + case BT: p = "BT"; break; + case END: p = "END"; break; + case NEUTRAL: p = "NEUT"; break; + case PAGE: p = "PAGE"; break; + case TM: p = "TM"; break; + case COORD: p = "COORD"; break; + case NE: p = "NE"; break; + case CMD: p = "CMD"; break; + case PARM: p = "PARM"; break; + default: sprintf(buf, "weird type %d", type); + } + return p; +} + +// ================================================================================ + +// troff output-specific functions + +// ================================================================================ + +const int DELTABUF = 500000; // grow the input buffer in chunks + +static char *inbuf = 0; // raw text input collects here +static int ninbuf = 0; // byte count for inbuf +static char *inbp = 0; // next free slot in inbuf +int linenum = 0; // input line number + +static inline void addc(int c) { *inbp++ = c; } + +static void adds(char *s) +{ + for (char *p = s; *p; p++) + addc(*p); +} + +static char *getutf(FILE *fp) // get 1 utf-encoded char (might be multiple bytes) +{ + static char buf[100]; + char *p = buf; + + for (*p = 0; (*p++ = getc(fp)) != EOF; ) { + *p = 0; + if (mblen(buf, sizeof buf) > 0) // found a valid character + break; + } + return buf; +} + +static char *bufptr(int n) { return inbuf + n; } // scope of inbuf is too local + +static inline int wherebuf() { return inbp - inbuf; } + +static char *getstr(char *p, char *temp) +{ // copy next non-blank string from p to temp, update p + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (*p == '\0') { + temp[0] = 0; + return(NULL); + } + while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') + *temp++ = *p++; + *temp = '\0'; + return(p); +} + +/*************************************************************************** + bounding box of a circular arc Eric Grosse 24 May 84 + +Conceptually, this routine generates a list consisting of the start, +end, and whichever north, east, south, and west points lie on the arc. +The bounding box is then the range of this list. + list = {start,end} + j = quadrant(start) + k = quadrant(end) + if( j==k && long way 'round ) append north,west,south,east + else + while( j != k ) + append center+radius*[j-th of north,west,south,east unit vectors] + j += 1 (mod 4) + return( bounding box of list ) +The following code implements this, with simple optimizations. +***********************************************************************/ + +static int quadrant(double x, double y) +{ + if ( x>=0.0 && y> 0.0) return(1); + else if( x< 0.0 && y>=0.0) return(2); + else if( x<=0.0 && y< 0.0) return(3); + else if( x> 0.0 && y<=0.0) return(4); + else return 0; /* shut up lint */ +} + +static double xmin, ymin, xmax, ymax; // used by getDy + +static void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc) + /* start, end, center */ +{ /* assumes center isn't too far out */ + double r; + int j, k; + printf("#start %g,%g, end %g,%g, ctr %g,%g\n", x0,y0, x1,y1, xc,yc); + y0 = -y0; y1 = -y1; yc = -yc; // troff's up is eric's down + x0 -= xc; y0 -= yc; /* move to center */ + x1 -= xc; y1 -= yc; + xmin = (x0x1)?x0:x1; ymax = (y0>y1)?y0:y1; + r = sqrt(x0*x0 + y0*y0); + if (r > 0.0) { + j = quadrant(x0,y0); + k = quadrant(x1,y1); + if (j == k && y1*x0 < x1*y0) { + /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */ + if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r; + if( xmax < r) xmax = r; if( ymax < r) ymax = r; + } else { + while (j != k) { + switch (j) { + case 1: if( ymax < r) ymax = r; break; /* north */ + case 2: if( xmin > -r) xmin = -r; break; /* west */ + case 3: if( ymin > -r) ymin = -r; break; /* south */ + case 4: if( xmax < r) xmax = r; break; /* east */ + } + j = j%4 + 1; + } + } + } + xmin += xc; ymin += yc; ymin = -ymin; + xmax += xc; ymax += yc; ymax = -ymax; +} + + +static int getDy(char *p, int *dx, int *maxv) + // figure out where we are after a D'...' +{ + int x, y, x1, y1; // for input values + char temp[50]; + p++; // get to command letter + switch (*p++) { + case 'l': // line + sscanf(p, "%d %d", dx, &y); + return *maxv = y; + case 'a': // arc + sscanf(p, "%d %d %d %d", &x, &y, &x1, &y1); + *dx = x1 - x; + arc_extreme(0, 0, x+x1, y+y1, x, y); // sets [xy][max|min] + printf("#arc bounds x %g, %g; y %g, %g\n", + xmin, xmax, ymin, ymax); + *maxv = (int) (ymin+0.5); + return y + y1; + case '~': // spline + for (*dx = *maxv = y = 0; (p=getstr(p, temp)) != NULL; ) { + // above getstr() gets x value + *dx += atoi(temp); + p = getstr(p, temp); // this one gets y value + y += atoi(temp); + *maxv = max(*maxv, y); // ok??? + if (*p == '\n' || *p == 0) // input is a single line; + break; // don't walk off end if realloc + } + return y; + case 'c': // circle, ellipse + sscanf(p, "%d", dx); + *maxv = *dx/2; // high water mark is ht/2 + return 0; + case 'e': + sscanf(p, "%d %d", dx, &y); + *maxv = y/2; // high water mark is ht/2 + return 0; + default: // weird stuff + return 0; + } +} + +static int serialnum = 0; + +slug eofslug() +{ + slug ret; + ret.serialnum = serialnum; + ret.type = EOF; + ret.dp = wherebuf(); + return ret; +} + +slug getslug(FILE *fp) +{ + if (inbuf == NULL) { + if ((inbuf = (char *) malloc(ninbuf = DELTABUF)) == NULL) + ERROR "no room for %d character input buffer\n", ninbuf FATAL; + inbp = inbuf; + } + if (wherebuf() > ninbuf-5000) { + // this is still flaky -- lines can be very long + int where = wherebuf(); // where we were + if ((inbuf = (char *) realloc(inbuf, ninbuf += DELTABUF)) == NULL) + ERROR "no room for %d character input buffer\n", ninbuf FATAL; + ERROR "grew input buffer to %d characters\n", ninbuf WARNING; + inbp = inbuf + where; // same offset in new array + } + static int baseV = 0; // first V command of preceding slug + static int curV = 0, curH = 0; + static int font = 0, size = 0; + static int baseadj = 0; + static int ncol = 1, offset = 0; // multi-column stuff + char str[1000], str2[1000], buf[3000], *p; + int firstV = 0, firstH = 0; + int maxV = curV; + int ocurV = curV, mxv = 0, dx = 0; + int sawD = 0; // > 0 if have seen D... + slug ret; + ret.serialnum = serialnum++; + ret.type = VBOX; // use the same as last by default + ret.dv = curV - baseV; + ret.hpos = curH; + ret.base = ret.parm = ret.parm2 = ret.seen = 0; + ret.font = font; + ret.size = size; + ret.dp = wherebuf(); + ret.ncol = ncol; + ret.offset = offset; + ret.linenum = linenum; // might be low + + for (;;) { + int c, m, n; // for input values + int sign; // hoisted from case 'h' below + switch (c = getc(fp)) { + case EOF: + ret.type = EOF; + ret.dv = 0; + if (baseadj) + printf("# adjusted %d bases\n", baseadj); + printf("# %d characters, %d lines\n", wherebuf(), linenum); + return ret; + case 'V': + fscanf(fp, "%d", &n); + if (firstV++ == 0) { + ret.dv = n - baseV; + baseV = n; + } else { + sprintf(buf, "v%d", n - curV); + adds(buf); + } + curV = n; + maxV = max(maxV, curV); + break; + case 'H': // absolute H motion + fscanf(fp, "%d", &n); + if (firstH++ == 0) { + ret.hpos = n; + } else { + sprintf(buf, "h%d", n - curH); + adds(buf); + } + curH = n; + break; + case 'h': // relative H motion + addc(c); + sign = 1; + if ((c = getc(fp)) == '-') { + addc(c); + sign = -1; + c = getc(fp); + } + for (n = 0; isdigit(c); c = getc(fp)) { + addc(c); + n = 10 * n + c - '0'; + } + curH += n * sign; + ungetc(c, fp); + break; + case 'x': // device control: x ... + addc(c); + fgets(buf, (int) sizeof(buf), fp); + linenum++; + adds(buf); + if (buf[0] == ' ' && buf[1] == 'X') { // x X ... + if (2 != sscanf(buf+2, "%s %d", str, &n)) + n = 0; + if (eq(str, "SP")) { // X SP n + ret.type = SP; // paddable SPace + ret.dv = n; // of height n + } else if (eq(str, "BS")) { + ret.type = BS; // Breakable Stream + ret.parm = n; // >=n VBOXES on a page + } else if (eq(str, "BF")) { + ret.type = BF; // Breakable Float + ret.parm = ret.parm2 = n; + // n = pref center (as UF) + } else if (eq(str, "US")) { + ret.type = US; // Unbreakable Stream + ret.parm = n; + } else if (eq(str, "UF")) { + ret.type = UF; // Unbreakable Float + ret.parm = ret.parm2 = n; + // n = preferred center + // to select several, + // use several UF lines + } else if (eq(str, "PT")) { + ret.type = PT; // Page Title + ret.parm = n; + } else if (eq(str, "BT")) { + ret.type = BT; // Bottom Title + ret.parm = n; + } else if (eq(str, "END")) { + ret.type = END; + ret.parm = n; + } else if (eq(str, "TM")) { + ret.type = TM; // Terminal Message + ret.dv = 0; + } else if (eq(str, "COORD")) { + ret.type = COORD;// page COORDinates + ret.dv = 0; + } else if (eq(str, "NE")) { + ret.type = NE; // NEed to break page + ret.dv = n; // if 0) + ERROR "weird x X %s in mid-VBOX\n", + str WARNING; + return ret; + } + break; + case 'n': // end of line + fscanf(fp, "%d %d", &n, &m); + ret.ht = n; + ret.base = m; + getc(fp); // newline + linenum++; + sprintf(buf, "n%d %d\n", ret.ht, ret.base); + adds(buf); + if (!firstV++) + baseV = curV; + // older incarnations of this program used ret.base + // in complicated and unreliable ways; + // example: if ret.ht + ret.base < ret.dv, ret.base = 0 + // this was meant to avoid double-counting the space + // around displayed equations; it didn't work + // Now, we believe ret.base = 0, otherwise we give it + // a value we have computed. + if (ret.base == 0 && sawD == 0) + return ret; // don't fiddle 0-bases + if (ret.base != maxV - baseV) { + ret.base = maxV - baseV; + baseadj++; + } + if (ret.type != VBOX) + ERROR "%s slug (type %d) has base = %d\n", + ret.typename(), ret.type, ret.base WARNING; + return ret; + case 'p': // new page + fscanf(fp, "%d", &n); + ret.type = PAGE; + curV = baseV = ret.dv = 0; + ret.parm = n; // just in case someone needs it + return ret; + case 's': // size change snnn + fscanf(fp, "%d", &size); + sprintf(buf, "s%d\n", size); + adds(buf); + break; + case 'f': // font fnnn + fscanf(fp, "%d", &font); + sprintf(buf, "f%d\n", font); + adds(buf); + break; + case '\n': + linenum++; + /* fall through */ + case ' ': + addc(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 + addc(c); + n = c - '0'; + addc(c = getc(fp)); + curH += 10 * n + c - '0'; + adds(getutf(fp)); + if (!firstV++) + baseV = curV; + break; + case 'c': // single ascii character + addc(c); + adds(getutf(fp)); + if (!firstV++) + baseV = curV; + break; + case 'C': // Cxyz\n + case 'N': // Nnnn\n + addc(c); + while ((c = getc(fp)) != ' ' && c != '\n') + addc(c); + addc(c); + if (!firstV++) + baseV = curV; + linenum++; + break; + case 'D': // draw function: D.*\n + sawD++; + p = bufptr(wherebuf()); // where does the D start + addc(c); + while ((c = getc(fp)) != '\n') + addc(c); + addc(c); + if (!firstV++) + baseV = curV; + ocurV = curV, mxv = 0, dx = 0; + curV += getDy(p, &dx, &mxv); // figure out how big it is + maxV = max(max(maxV, curV), ocurV+mxv); + curH += dx; + linenum++; + break; + case 'v': // relative vertical vnnn + addc(c); + if (!firstV++) + baseV = curV; + sign = 1; + if ((c = getc(fp)) == '-') { + addc(c); + sign = -1; + c = getc(fp); + } + for (n = 0; isdigit(c); c = getc(fp)) { + addc(c); + n = 10 * n + c - '0'; + } + ungetc(c, fp); + curV += n * sign; + maxV = max(maxV, curV); + addc('\n'); + break; + case 'w': // word space + addc(c); + break; + case '#': // comment + addc(c); + while ((c = getc(fp)) != '\n') + addc(c); + addc('\n'); + linenum++; + break; + default: + ERROR "unknown input character %o %c (%50.50s)\n", + c, c, bufptr(wherebuf()-50) WARNING; + abort(); + break; + } + } +} -- cgit v1.2.3