/*----------------------------------------------------------------------------- * ipress - most of the code directly dependent on interpress used by dipress * to produce an interpress file from device independent troff * intermediate code. * * William LeFebvre * * Copyright (c) 1984, 1985 Xerox Corp. * * History: * John Mellor-Crummey 28-aug-1985 restructuring and minor modifications * * ed flint 10-may-1985 coerce device.num_char_wid to unsigned char, change * ch argument in outputChar to unsigned int * since we now have > 128 special characters *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include "deviceinfo.h" /* typesetter characteristics */ #include "iptokens.h" /* \ */ #include "literal.h" /* > interface levels for interpress */ #include "operator.h" /* / */ #include "defs.h" /* constant and macro definitions */ #include "externs.h" /* declarations for global variables */ /* initialize device */ initDevice() { int lines = 0; int timapf; int ret; register char *ptr; register char **ipp; register char **trp; char temp[60]; struct stat stbuf; if (dbg) printf("initDevice called\n"); /* start the preamble */ ip_select(outputfile); /* special master instructions go here... */ Op(beginBlock); Op(beginBody); /* save scaling transform that uses a mica co-ordinate system */ AppendRational(1L, 100000); Op(scale); AppendInteger((long) F_transform); Op(fset); /* select file that holds page bodies */ ip_select(pagebodyfile); /* open file that maps troff names to interpress names */ (void) sprintf(temp, "%s/dev%s/interpress-fonts", fontdirectory, devicename); if ((timapf = open(temp, O_RDONLY,0)) == -1) reportError(QUIT, "can't open %s (%s)", temp, sys_errlist[errno]); /* read in the whole thing */ ret = fstat(timapf, &stbuf); if (dbg) printf("stat returned %d, errno %d\n", ret, errno); timap = malloc((unsigned)(stbuf.st_size + 1)); if (dbg) printf("reading %d bytes from timapf\n", stbuf.st_size); ret = read(timapf, timap, (int)stbuf.st_size); if (dbg) printf("read returned %d, errno %d, timapf %d\n", ret, errno, timapf); timap[(int)stbuf.st_size] = '\0'; (void) close(timapf); /* count the newlines */ if (dbg) printf("pointer starts at %08x ... ", timap); for (ptr = timap; *ptr != '\0'; ptr++) if (*ptr == '\n') lines++; if (dbg) printf("ends at %08x\n", ptr); if (dbg) printf("found %d lines\n", lines); /* allocate the mapping arrays */ trp = trname = (char **)malloc((unsigned)(lines * 2 * sizeof(char *))); ipp = ipname = trname + lines; /* break out the strings and store pointers in the arrays */ ptr = timap; mapcnt = 0; while (*ptr) { if (dbg) printf("loop: ptr = %08x, *ptr = %c\n", ptr, *ptr); *trp++ = ptr; while (!white(*ptr)) ptr++; *ptr++ = '\0'; while (white(*ptr)) ptr++; *ipp++ = ptr; while (*++ptr != '\n') /* nothing */; *ptr++ = '\0'; mapcnt++; } if (dbg) { int i; for (i = 0; i < lines; i++) printf("%s\t%s\n", trname[i], ipname[i]); } /* reset vertical and horizontal positions */ hor_pos = ver_pos = old_hor = old_ver = 0; /* reset the font information */ bzero((char *) currfonts, sizeof(currfonts)); } setScale(spi) /* set resolution */ int spi; { /* set the scaling variable used in all x and y calculations */ scale = floor(2540.0 / (double)spi + 0.5); if (dbg) printf("setScale(%d) sets scale to %e\n", spi, scale); /* * Set the drawing scale based on the scale. This factor is applied to * all points drawn in the bitmap for graphical objects. It is scaled * down from micas to 508 dpi so that the bitmaps aren't of unwieldy * size, but still retain enough information to look decent on a good * device. 508/2540 == 0.2 */ drawscale = scale * .2; if (dbg) printf("setScale(%d) sets drawscale to %e\n", spi, drawscale); } pushCurrentEnv() /* begin a new block */ { statep->ssize = size; statep->sfont = font; statep->shorig = hor_orig; statep->svorig = ver_orig; statep->shpos = hor_pos; statep->svpos = ver_pos; hor_orig = hor_pos; ver_orig = ver_pos; hor_pos = ver_pos = 0; if (statep++ >= state + MAXSTATE) { reportError(QUIT, "{ nested too deep"); } hor_pos = ver_pos = 0; } popSavedEnv() /* pop to previous state */ { if (--statep < state) { reportError(QUIT, "extra }"); } size = statep->ssize; font = statep->sfont; hor_pos = statep->shpos; ver_pos = statep->svpos; hor_orig = statep->shorig; ver_orig = statep->svorig; } newpage(n) /* new page */ int n; { int i; char buff[15]; /* print any pending bitmap */ /* terminate previous page if outputting */ if (outputflag) { print_bitmap(); Op(endBody); } else flush_bitmap(); /* reset vertical positions */ ver_pos = old_ver = 0; /* check new page number against those found in the nPageRanges */ if (nPageRanges == 0) { /* no -o specified -- do all pages */ outputflag = 1; } else { /* see if new page has been selected for output */ outputflag = 0; for (i = 0; i < nPageRanges; i++) { if ((n >= pagerange[i][0]) && (n <= pagerange[i][1])) { outputflag = 1; break; } } } /* start new page */ if (outputflag) { Op(beginBody); (void) sprintf(buff, "Page %d", n); AppendComment(buff); Fget(F_transform); Op(concatt); AppendInteger(2L); AppendInteger((long) I_strokeEnd); Op(iset); } /* font/size no longer valid -- force a new assignment */ oldftsz = -1; } newLine() /* new line (no vertical motion implied) */ { if (dbg == 3) putchar('\n'); flushbuff(); endcorrect(); hor_pos = 0; virgin_line = 1; } internalSize(number) /* convert integer to internal size number */ int number; { int index; if (number >= pointsizeTab[device.num_sizes - 1]) { /* larger than largest -- use largest */ return(device.num_sizes-1); } else if (number <= pointsizeTab[0]) { /* smaller than smallest -- use smallest */ return(0); } /* else find the size in pointsizeTab and return index */ for (index = 0; number > pointsizeTab[index]; index++); return(index); } /* handle device stop command */ resetDevice() { int amt; static int is_reset = 0; char bigbuff[1024]; if (is_reset) return; /* ignore multiple resets */ print_bitmap(); /* this is the absolute last thing that we do */ /* wrap up the preamble and the body */ ip_select(outputfile); Op(endBody); ip_select(pagebodyfile); Op(endBody); Op(endBlock); ip_close(); /* close the body */ /* * Reopen the body and copy it onto the end of the real file (which is * where we have been building the preamble). We don't need to ip_flush * the preamble since that is done everytime we ip_select the body. * Conveniently enough, "tempfilename" still holds the name of the body * temporary. */ pagebodyfile = open(tempfilename, O_RDONLY,0); while ((amt = read(pagebodyfile, bigbuff, sizeof(bigbuff))) != 0) { (void) write(outputfile, bigbuff, amt); } /* close and unlink the body temporary file */ (void) close(pagebodyfile); (void) unlink(tempfilename); /* send the file off to the printer */ tempfilename[strlen(tempfilename) - 1] = '\0'; if (outputfile != 1) { IPprint(tempfilename); } /* we are now reset */ is_reset = 1; } outputString(character) /* print a "funny" character */ char *character; { int i; if (!outputflag) return; if (dbg > 2) printf("\\(%s", character); if (dbg > 3) putchar(' '); for (i = 0; i < device.spec_char_num; i++) if (strcmp(&specCharStrTab[specCharTab[i]], character) == 0) break; if (i < device.spec_char_num) { /* printf(" i = %d so i+128 = %d\n", i, i+128); */ outputChar((unsigned int) i + 128); } else { if (dbg > 3) printf("-- character not found"); } if (dbg > 2) putchar('\n'); } outputChar(character) /* put a character */ unsigned int character; { unsigned char *widp; /* pointer to appropriate width table */ register char *codep; /* pointer to appropriate table of codes */ register int i, old_font, fnt_index; int j, value; if (!outputflag) return; if (character <= 32) { if (dbg) printf("non-existent character 0%o\n", character); charw = charWidthTab[font][0] * pointsizeTab[size-1] / device.width_units; return; } character -= 32; old_font= font; i = fontIndexTab[font][character] & 255; if (i != 0) /* it's on this font */ { codep = charCodeTab[font]; widp = charWidthTab[font]; } else if (specFontPos > 0) /* on special (we hope) */ { /* assertion: i == 0 */ fnt_index= specFontPos; for (j=0; j <= device.num_fonts; j++) { struct font_entry *fb; fnt_index= (fnt_index+1) % (device.num_fonts+1); if ((fb = fontPtr[fnt_index]) != NULL) { if (fb->special_flag && (i = fontIndexTab[fnt_index][character] & 255) != 0) { codep = charCodeTab[fnt_index]; widp = charWidthTab[fnt_index]; setFont(fnt_index); break; } } } /* assertion: if j > device.num_fonts then i == 0 and character was not found */ } value= codep[i] & 255; if (i == 0 || value == 0) { if (dbg) printf("character not found 0%o\n", character+32); return; } /* remember this character's width */ /* This MUST be done before calling showchar */ charw = (widp[i] * pointsizeTab[size-1] + device.width_units/2) / device.width_units; if (dbg == 3) { if (isprint(character+32)) putchar(character+32); } if (dbg > 3) { if (isprint(character+32)) printf("character %c %d\n", character+32, value); else printf("character %03o %d\n", character+32, value); } if (value == 0377) { /* special escape to an extended code */ value = getexcode(i); } if (dbg < 6) showchar(value); if (font != old_font) { setFont(old_font); } } setPointSize(n) /* set point size to n */ int n; /* internal value: index into pointsizeTab */ { size = n; ftsz = ((long)font << 16) | ((long)size); } setFont(n) /* set font to n */ int n; /* internal index */ { font = n; ftsz = ((long)font << 16) | ((long)size); } /* * reportError an error reporting hack that uses dummy parameters * as place holders for arguments that may or may not * exist, fprintf will sort out how many should be there */ /*VARARGS 2*/ reportError(f, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) char *s, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8; { fprintf(stderr, "dipress: "); fprintf(stderr, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); fprintf(stderr, "\nerror encountered near line %d\n", linenumber); if (f == QUIT) goodbye(); } /* * Graphics drawing primitives. These use the vector drawing capabilities of * interpress to draw straight lines. All other primitive objects (circle, * ellipse, etc.) are built in a bitmap and printed with a pixel vector. */ drawline(dh, dv) int dh,dv; { if(!outputflag) return; AppendInteger((long) curr_strokewidth); AppendInteger((long) I_strokeWidth); Op(iset); Moveto(xloc(hor_pos), yloc(ver_pos)); hor_pos += dh; ver_pos += dv; Lineto(xloc(hor_pos), yloc(ver_pos)); Op(maskstroke); } /* routines used by interpress dependent routines */ char showbuff[Showbuff_size + 1]; char *showp = showbuff; int showcnt = 0; showchar(ch) /* buffer "ch" for use in a "show" command */ int ch; { char *framep; register int hdiff, vdiff; /* set correct position */ vdiff = ver_pos - old_ver; hdiff = hor_pos - old_hor; if (dbg > 4) { printf("old_hor %d, hor_pos %d, hdiff %d; old_ver %d, ver_pos %d, vdiff %d %s\n", old_hor, hor_pos, hdiff, old_ver, ver_pos, vdiff, virgin_line ? "(virgin)" : ""); } /* NOTE: this expression depends on boolean true being 1! */ /* See K&R, Appendix A, section 7.7, page 190 */ if (ch == '_') goto underbar; switch (((vdiff != 0) << 1) | (hdiff != 0)) { case 0: /* no change */ break; default: underbar: flushbuff(); Setxy(xloc(hor_pos), yloc(ver_pos)); break; } /* * Update old_hor and old_ver. Account for character width in old_hor but not in * hor_pos. If the next hInc call is for the width of the character, the * next time showchar gets called, old_hor will equal hor_pos. */ old_ver = ver_pos; old_hor = hor_pos + charw; /* line is no longer virgin */ virgin_line = 0; /* font and point still the same? */ if (ftsz != oldftsz) { flushbuff(); if ((framep = currfonts[font]->frames) == NULL) { /* previously unused -- give it a frame table */ framep = currfonts[font]->frames = malloc((unsigned)(device.num_sizes * sizeof(char))); bzero(framep, device.num_sizes * sizeof(char)); } if (framep[size] == 0) { /* make a new font */ ip_select(outputfile); SetupFont(currfonts[font]->uname, floor(pointsizeTab[size-1] * 35.28 + .5), frameindex); ip_select(pagebodyfile); framep[size] = frameindex++; } /* switch to new font/size combo */ Setfont(framep[size]); oldftsz = ftsz; } /* adjust for character codes > 0377 */ if (ch > 0377) { if (dbg > 4) { printf("processing large code: 0%o (%d)\n", ch, ch); } if (showcnt + 5 > Showbuff_size) { flushbuff(); } *showp++ = '\377'; *showp++ = (ch & 0177400) >> 8; *showp++ = ch & 255; *showp++ = '\377'; *showp++ = '\0'; showcnt += 5; } else { *showp++ = ch; if (++showcnt > Showbuff_size) { flushbuff(); } } } /* * getexcode(findex) - get the extended code for the character "findex" */ getexcode(findex) int findex; { register int extfd; register int i; register unsigned short *tab; char temp[132]; if (dbg > 4) { printf("getexcode(%d)\n", findex); } if ((tab = currfonts[font]->extab) == NULL) { /* load in the extended code table */ (void) sprintf(temp, "%s/dev%s/%s.out.ext", fontdirectory, devicename, currfonts[font]->name); if (dbg > 4) { printf("opening and reading %s\n", temp); } if ((extfd = open(temp, O_RDONLY,0)) == -1) { reportError(CONTINUE, "can't open %s (%s)", temp, sys_errlist[errno]); return(0); } currfonts[font]->extab = tab = (unsigned short *) malloc( (unsigned)(i = (device.spec_char_num + 128-32) * sizeof(short)) ); (void) read(extfd, (char *)tab, i); /* should test result! */ (void) close(extfd); } if (dbg > 4) { printf("getexcode returning %.7o\n", tab[findex]); } return(tab[findex]); } flushbuff() /* flush and reset "showbuff" */ { if (showcnt == 0) return; if (!in_correct) { startcorrect(); } /* we must do the append_Sequence explicitly, */ /* because showbuff might have nulls in it. */ append_Sequence(sequenceString, showcnt, (unsigned char *)showbuff); Op(show); showp = showbuff; showcnt = 0; } int hstart; startcorrect() { #ifdef CORRECT_BLOCKS Op(correct); Op(beginBody); #endif in_correct = 1; hstart = hor_pos; } endcorrect() { /* append a Setcorrectmeasure operation */ /* "hor_pos" or "old_hor"??? Make it "old_hor" for now */ #ifdef CORRECT_BLOCKS Setcorrectmeasure(xloc(old_hor), 0.0); Op(endBody); #endif in_correct = 0; } /* * IPprint(filename) - send the file "filename" to the interpress printer. * This routine is *very* dependent on local * environments. */ IPprint(filename) char *filename; { if (dbg) { printf("interpress file saved in %s.\n", filename); return; } if (vfork() == 0) { /* is child */ execl("/usr/local/bin/qip", "qip", "-nc", "-nk", filename, 0); exit(1); } } /* bitmap graphics object sizing functions */ g_sizearc(x1, y1, xc, yc, x2, y2) int x1, y1, xc, yc, x2, y2; { int minx; int miny; int maxx; int maxy; int quad1; int quad2; int radius; int axc; int ayc; int i; /* the center and the second point are offsets from the first */ /* calculate actual center and radius */ axc = x1 + xc; ayc = y1 + yc; radius = (int)(hypot((double)xc, (double)yc) + .5); if (dbg > 1) { printf("g_sizearc(%d, %d, %d, %d, %d, %d): radius is %d\n", x1, y1, xc, yc, x2, y2, radius); } /* preset the minmal and maximal points -- this is our first guess */ if ((minx = x1 + xc + x2) > x1) { maxx = minx; minx = x1; } else { maxx = x1; } if ((miny = y1 + yc + y2) > y1) { maxy = miny; miny = y1; } else { maxy = y1; } /* calculate the offset from the center to the first point */ x1 = -xc; y1 = -yc; /* now all three arguments are offsets */ /* calculate the quadrant of each endpoint */ quad1 = quadrant(x1, y1); quad2 = quadrant(x2, y2); if (dbg > 1) { printf("(%d, %d) in quadrant %d ... ", x1, y1, quad1); printf("(%d, %d) in quadrant %d\n", x2, y2, quad2); } /* insure that quad1 < quad2 */ if (quad2 < quad1) { quad2 += 4; } /* compensate for arc at each quadrant boundary */ for (i = quad1 + 1; i <= quad2; i++) { switch (i & 3) { case 0: /* 1st quadrant */ maxx = axc + radius; break; case 1: /* 2nd quadrant */ miny = ayc - radius; break; case 2: /* 3rd quadrant */ minx = axc - radius; break; case 3: /* 4th quadrant */ maxy = ayc + radius; break; } } /* now set the extremes */ if (dbg > 1) { printf("extremes are %d, %d, %d, %d\n", minx, miny, maxx, maxy); } gobj_size(minx, miny, maxx, maxy); } quadrant(dx, dy) int dx,dy; { register int yplus; yplus = dy > 0; if (dx > 0) { return(yplus ? 3 : 0); } else { return(yplus ? 2 : 1); } } g_sizeWigglyLine(str) char *str; { int minx; int miny; int maxx; int maxy; int currx; int curry; int incx; int incy; currx = minx = maxx = hor_pos; curry = miny = maxy = ver_pos; while(white(*str)) str++; /* trim leading white space */ while (*str) { (void) readNumber(&str,&incx); (void) readNumber(&str,&incy); currx += incx; curry += incy; if (currx > maxx) maxx = currx; else if (currx < minx) minx = currx; if (curry > maxy) maxy = curry; else if (curry < miny) miny = curry; } gobj_size(minx, miny, maxx, maxy); }