diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/ivd2dvi |
Initial commit
Diffstat (limited to 'dviware/ivd2dvi')
-rw-r--r-- | dviware/ivd2dvi/Makefile | 22 | ||||
-rw-r--r-- | dviware/ivd2dvi/auxiliary.c | 591 | ||||
-rw-r--r-- | dviware/ivd2dvi/commands.h | 79 | ||||
-rw-r--r-- | dviware/ivd2dvi/doc | 60 | ||||
-rw-r--r-- | dviware/ivd2dvi/global.h | 65 | ||||
-rw-r--r-- | dviware/ivd2dvi/io.c | 520 | ||||
-rw-r--r-- | dviware/ivd2dvi/ivd2dvi.1 | 89 | ||||
-rw-r--r-- | dviware/ivd2dvi/ivd2dvi.c | 957 | ||||
-rw-r--r-- | dviware/ivd2dvi/ivd2dvi.readme | 9 | ||||
-rw-r--r-- | dviware/ivd2dvi/makefile | 22 |
10 files changed, 2414 insertions, 0 deletions
diff --git a/dviware/ivd2dvi/Makefile b/dviware/ivd2dvi/Makefile new file mode 100644 index 0000000000..6d64761254 --- /dev/null +++ b/dviware/ivd2dvi/Makefile @@ -0,0 +1,22 @@ +BINAREA=/usr/local/bin + +CC = gcc +CFLAGS = -O + +OBJS = ivd2dvi.o auxiliary.o io.o +SRCS = ivd2dvi.c auxiliary.c io.c +INCLUDES = global.h commands.h + +all: ivd2dvi + +ivd2dvi: ${OBJS} + ${CC} ${CFLAGS} -o ivd2dvi ${OBJS} + +${OBJS}: ${INCLUDES} + +install: all + install -s -m 755 ivd2dvi ${BINAREA} + +bugs: ${SRCS} ${INCLUDES} + rm -f bugs + lint -hbxac ${SRCS} > bugs diff --git a/dviware/ivd2dvi/auxiliary.c b/dviware/ivd2dvi/auxiliary.c new file mode 100644 index 0000000000..c6fa51a3e1 --- /dev/null +++ b/dviware/ivd2dvi/auxiliary.c @@ -0,0 +1,591 @@ +/* + * Auxiliary routines for ivd2dvi. Copyright 1988 by Larry Denenberg. + * May be freely distributed as long as this notice is retained. + */ + + +#include <stdio.h> +#include "commands.h" +#include "global.h" + +/* Procedures and global variables defined in io.c */ +extern unsigned BufSize; +extern unsigned_byte CopyByte(), ReadByte(), FReadByte(); +extern long FReadUnsigned(), FReadSigned(), ReadUnsigned(), ReadSigned(); +extern long CopyWord(); +extern void WriteByte(), CopyNBytes(), SkipNBytes(), FSkipNBytes(); +extern void InitIOBuffers(), BufOverflow(), WriteNumber(); + +/* Global variables defined in ivd2dvi.c */ +extern char *ProgramName; +extern long XInput, XOutput, WInput, WOutput, DeltaH; +extern int State; +extern boolean ExactOutput; + + +/* Global variables defined here */ +int FilePushLevel; /* current excess of PUSH over POP */ +int MaxFilePushLevel; /* maximum FilePushLevel seen so far */ +char *TeXFontDirs; /* directories to search for TFM files */ +int NTeXFontDirs; /* number of directories in TeXFontDirs */ +FILE *tfmfp; /* fp for currently open TFM file */ +font *CurFont; /* font from which we're typesetting */ +font *FirstFont; /* head of linked list of all fonts */ +long *AuxStackPointer; /* first unused spot on the aux stack */ +long *AuxBeginStack; /* first usable spot on the aux stack */ +long *AuxEndStack; /* first location beyond the aux stack */ + + +/* Procedures defined in this file, in order of definition */ +void Initializations(); +void PushWX(), PopXW(), PushDeltaH(), PopDeltaH(), AuxPush(); +long AuxPop(); +void PushWrite(), PopWrite(), MaxPushLevelOutput(); +font *FindFont(); +void FontDefine(), NewFont(); +long WordMaybeRead(); +unsigned_byte ByteMaybeRead(); +void CopyFontDefinition(), SkipFontDefinition(); +long CharWidth(); +void ReadTFMFile(); +boolean TFMOpen(), TFMTrialOpen(); +void TFMHeaderLoad(), TFMWidthsLoad(), FontMemoryOverflow(); +void BadDVIAbort(); + + + +/* + * Global initializations. At this point, the command line has been + * processed, so we know /BufSize/ and /ProgramName/. After trivial + * initializations, we change /TeXFontDirs/ from a colon-separated list + * to a sequence of null-terminated strings by simply changing each + * colon to a null and keeping a count in /NTeXFontDirs/. Finally, we + * set up the /AuxStack/ along with its pointer and end; giving it + * four times the size of a small stack since /PushWX/ puts four things + * on it at a time. + */ +void +Initializations() +{ + char *pchar; + + State = LTYPESETTING; + CurFont = FirstFont = NULL; + MaxFilePushLevel = FilePushLevel = 0; + InitIOBuffers(); + + TeXFontDirs = getenv("TEXFONTS"); + if (TeXFontDirs == NULL) TeXFontDirs = TFMAREADEFAULT; + if (*TeXFontDirs == ':') TeXFontDirs++; + for (NTeXFontDirs = 0, pchar = TeXFontDirs; *pchar; NTeXFontDirs++) { + while (*pchar && (*pchar != ':')) pchar++; + if (*pchar == ':') *pchar++ = '\0'; + } + + AuxBeginStack = SEQALLOC(4*(BufSize/SMALLBUFDIVISOR), long); + AuxEndStack = AuxBeginStack + 4*(BufSize/SMALLBUFDIVISOR); + AuxStackPointer = AuxBeginStack; + if (AuxBeginStack == NULL) { + fprintf(stderr, "\n%s fatal error: can't allocate buffers\n", + ProgramName); + exit(3); + } +} + + + +/* + * Save the horizontal motion parameters on the aux stack. + */ +void +PushWX() +{ + AuxPush(WInput); + AuxPush(WOutput); + AuxPush(XInput); + AuxPush(XOutput); +} + + + +/* + * Restore the horizontal motion parameters from the aux stack. + */ +void +PopXW() +{ + XOutput = AuxPop(); + XInput = AuxPop(); + WOutput = AuxPop(); + WInput = AuxPop(); +} + + + +/* + * Save /DeltaH/. We use the same stack as /PushWX/; only /EndReflect/ + * has to worry about the necessary stack discipline. + */ +void +PushDeltaH() +{ + AuxPush(DeltaH); +} + + + +/* + * Restore /DeltaH/. + */ +void +PopDeltaH() +{ + DeltaH = AuxPop(); +} + + + +/* + * Push /value/ onto the auxiliary stack. + */ +void +AuxPush(value) +long value; +{ + *AuxStackPointer++ = value; + if (AuxStackPointer >= AuxEndStack) BufOverflow(); +} + + + +/* + * Pop a value from the auxiliary stack. Underflow means that + * something is seriously wrong; even bad input shouldn't do it. + */ +long +AuxPop() +{ + if (--AuxStackPointer < AuxBeginStack) { + fprintf(stderr, "\n%s internal error: simulation stack underflow\n", + ProgramName); + exit(4); + } + return *AuxStackPointer; +} + + + +/* + * Write a PUSH command to the output DVI file. All such commands must + * be written by this routine so we can keep an accurate count of how + * deep we are. /FilePushLevel/ keeps this count and /MaxFilePushLevel/ + * keeps track of the deepest we've ever been. (This routine should be + * called WritePush, but then its name would conflict with WritePop.) + */ +void +PushWrite() +{ + WriteByte(PUSH); + if (++FilePushLevel > MaxFilePushLevel) + MaxFilePushLevel = FilePushLevel; +} + + + +/* + * Write a POP command to the output DVI file. All such commands must + * be written by this routine, so we can keep an accurate count of how + * deep we are. The error here shouldn't occur no matter what garbage + * is in the DVI file since this stuff is checked at an even lower + * level; see /NestingValidate/ in io.c. + */ +void +PopWrite() { + WriteByte(POP); + if (--FilePushLevel < 0) { + fprintf(stderr, "\n%s internal error: more pops than pushes!\n", + ProgramName); + exit(4); + } +} + + + +/* + * Write out the maximum stack depth necessary to process this file. + * That number is exactly /MaxFilePushLevel/, as computed by the two + * routines immediately preceding. However, we start by reading the + * old value, and use it instead if it's big enough and the -X flag + * was used. Here's the reason: TeX doesn't always put the correct + * value in this field! If TeX is writing out a POP that immediately + * follows a PUSH, they are both dropped and nothing goes to the DVI + * file. But the variable that's worrying about the maximum stack + * depth is not informed of this optimization. So if TeX tries to + * write "PUSH PUSH PUSH POP POP POP" it thinks that the max stack + * depth is 3, but in fact nothing is written. Thus TeX's behavior + * is always conservative. See paragraphs 601, 619, and 629 of + * Volume B of {\it Computers and Typesetting}. + */ +void +MaxPushLevelOutput() +{ + long inputlevel; + + inputlevel = ReadUnsigned(2); + if (ExactOutput && (inputlevel > MaxFilePushLevel)) + WriteNumber(inputlevel, 2); + else + WriteNumber((long) MaxFilePushLevel, 2); +} + + + + +/* + * Find the font associated with /fontnumber/ by searching the list. + * If it's not there, return NULL and let the caller worry. + */ +font * +FindFont(fontnumber) +long fontnumber; +{ + font *f; + + f = FirstFont; + while ((f != NULL) && (f->number != fontnumber)) f = f->nextfont; + return f; +} + + + + +/* + * Define a new font as required by a FNT_DEFn command. If the font is + * already known, we must have seen this FNT_DEFn before---skip it if + * simulating, otherwise copy it over. (A given FNT_DEFn command may be + * seen any number of times because we must process them whether we're + * simulating or typesetting.) Call /NewFont/ on never-yet-seen fonts. + */ +void +FontDefine(bytes) +unsigned bytes; +{ + long fontnumber; + + fontnumber = ReadUnsigned(bytes); + if (FindFont(fontnumber) == NULL) + NewFont(fontnumber, bytes); + else if (State >= SIMULATING) + SkipFontDefinition(); + else + CopyFontDefinition(fontnumber, bytes); +} + + + +/* + * Process a font for the first time. If we're not simulating, we must + * copy the FNT_DEFn command and parameters into the output file as we + * read them. Allocate the new font object and link it into the list. + * Fill in the /number/, /checksum/, /scalefactor/, /area/, and /name/ + * fields from the arguments (skip the design size; we don't need it). + * Set /loaded/ to FALSE to indicate that we haven't read the TFM file. + * Only when we need the width of a character in the font---when + * /CharWidth/ is called---do we load the TFM file and fill in the rest + * of the fields. That is, we never read the TFM files of fonts that + * aren't used in reflected text. + */ +void +NewFont(fontnumber, bytes) +long fontnumber; +unsigned bytes; +{ + font *newfont; + unsigned areasize, namesize; + char *p; + + if (State < SIMULATING) { + WriteByte(FNT_DEF1 + bytes - 1); + WriteNumber(fontnumber, bytes); + } + newfont = OBJALLOC(font); + if (newfont == NULL) FontMemoryOverflow(); + newfont->nextfont = FirstFont; + FirstFont = newfont; + newfont->number = fontnumber; + newfont->checksum = WordMaybeRead(); + newfont->scalefactor = WordMaybeRead(); + WordMaybeRead(); + areasize = ByteMaybeRead(); + namesize = ByteMaybeRead(); + newfont->area = (char *) calloc(areasize+1, sizeof(char)); + if (newfont->area == NULL) FontMemoryOverflow(); + for (p = newfont->area; areasize != 0; areasize--) *p++ = ByteMaybeRead(); + *p = '\0'; + newfont->name = (char *) calloc(namesize+1, sizeof(char)); + if (newfont->name == NULL) FontMemoryOverflow(); + for (p = newfont->name; namesize != 0; namesize--) *p++ = ByteMaybeRead(); + *p = '\0'; + newfont->loaded = FALSE; +} + + + +/* + * Either read or copy a word, depending on whether we're simulating. + * This routine and the next are useful because the definition of a + * font might be seen for the first time during a simulation or + * during normal left-to-right typesetting. Thus /NewFont/ might or + * might not want to copy out parameters as they're read. + */ +long +WordMaybeRead() +{ + if (State >= SIMULATING) return ReadSigned(4); else return CopyWord(); +} + + + +/* + * Either read or copy a byte, depending on whether we're simulating. + */ +unsigned_byte +ByteMaybeRead() +{ + if (State >= SIMULATING) return ReadUnsigned(1); else return CopyByte(); +} + + + +/* + * Copy a font definition from the input DVI file to the output file. + */ +void +CopyFontDefinition(fontnumber, bytes) +long fontnumber; +unsigned bytes; +{ + WriteByte(FNT_DEF1 + bytes - 1); + WriteNumber(fontnumber, bytes); + CopyNBytes(12L); + CopyNBytes((long) (CopyByte() + CopyByte())); +} + + + +/* + * Skip by a font definition. The FNT_DEFn command and the first + * parameter have already been skipped. + */ +void +SkipFontDefinition() +{ + SkipNBytes(12L); + SkipNBytes((long) (ReadUnsigned(1) + ReadUnsigned(1))); +} + + + + +/* + * Find the width of character /c/ in /CurFont/. If the TFM file hasn't + * been read, read it. The /widths/ field is NULL in fonts whose TFM + * files we couldn't find; we just return 0 as the width of any character + * in such a font. Carefully reduce /c/ modulo 256 if necessary. If /c/ + * is now between /bc/ and /ec/, it's a character in the font. Get its + * value from the /charwidths/ table (whose indices run from 0 to + * /ec/-/bc/) and use that number to index the /widths/ table. If /c/ + * isn't in the font, issue a warning and return 0. + */ +long +CharWidth(c) +long c; +{ + if (CurFont->loaded == FALSE) ReadTFMFile(CurFont); + if (CurFont->widths == NULL) return 0L; + if (c < 0) c = 255 - ((-1 - c) % 256); + else if (c >= 256) c = c % 256; + if ((c >= CurFont->bc) && (c <= CurFont->ec) && + (CurFont->charwidths[c - CurFont->bc] != 0)) + return CurFont->widths[CurFont->charwidths[c - CurFont->bc]]; + fprintf(stderr, "\n%s warning: character %d undefined in font %s\n", + ProgramName, c, CurFont->name); + return 0L; +} + + + + +/* + * Read in the width information for a font. This data isn't read until + * we actually need it, viz., the first time /CharWidth/ is called with + * /f/ in /CurFont/. If we can't find the TFM file, we set /f->widths/ + * to NULL as a flag meaning "assume all widths are zero." In any case, + * we mark /f/ as "loaded" so we don't do this again. + */ +void +ReadTFMFile(f) +font *f; +{ + if (TFMOpen(f)) { + TFMHeaderLoad(f); + TFMWidthsLoad(f); + (void) fclose(tfmfp); + } else + f->widths = NULL; + f->loaded = TRUE; +} + + + +/* + * Open the TFM file for a font, returning TRUE if we did so and FALSE + * otherwise. If the name of the font starts with a slash, we only + * try to open the exact file. Otherwise we try prepending each of + * the possible TFM directories until we get a hit or run out. Recall + * that at this point /TeXFontDirs/ is a null-separated list of names. + */ +boolean +TFMOpen(f) +font *f; +{ + char *pchar; + int ndir; + + if ((*f->area == '/') || ((!*f->area) && (*f->name == '/'))) { + if (TFMTrialOpen("", f->area, f->name)) return TRUE; + } else { + for (pchar = TeXFontDirs, ndir = NTeXFontDirs; ndir > 0; ndir--) { + if (TFMTrialOpen(pchar, f->area, f->name)) return TRUE; + while (*pchar++); + } + } + fprintf(stderr, "\n%s warning: Can't find TFM file for font %s; ", + ProgramName, f->name); + fprintf(stderr, "assuming zero width\n"); + return FALSE; +} + + + +/* + * Try to open a font file. The "area" is mostly empty for TeX, but + * you never can tell. On success, leave the file descriptor in the + * global variable /tfmfp/ and return TRUE, otherwise return FALSE. + */ +boolean +TFMTrialOpen(path,area,name) +char *path, *area, *name; +{ + static char buffer[MAXFILENAMESIZE]; + + (void) sprintf(buffer, "%s/%s/%s.tfm", path, area, name); + tfmfp = fopen(buffer, "r"); + if (tfmfp == NULL) return FALSE; else return TRUE; +} + + + +/* + * Set up the remaining fields of the font structure. Get and store + * the first and last character codes and the number of distinct widths + * in the font. Allocate the tables /charwidths/ and /widths/. Check + * the checksum, but skip by the rest of the header. Finally, read the + * values into the /charwidths/ table. + */ +void +TFMHeaderLoad(f) +font *f; +{ + int nchars; + long lh; + unsigned_byte *pbyte; + + FSkipNBytes(tfmfp,2L); + lh = FReadUnsigned(tfmfp,2); + f->bc = FReadUnsigned(tfmfp,2); + f->ec = FReadUnsigned(tfmfp,2); + nchars = f->ec - f->bc + 1; + if (nchars < 0) nchars = 0; + if (nchars > 0) { + f->charwidths = SEQALLOC(nchars, unsigned_byte); + if (f->charwidths == NULL) FontMemoryOverflow(); + } + f->nw = FReadUnsigned(tfmfp,2); + if (f->nw > 0) { + f->widths = SEQALLOC(nchars, long); + if (f->widths == NULL) FontMemoryOverflow(); + } + FSkipNBytes(tfmfp,14L); + if (f->checksum != FReadSigned(tfmfp,4)) + fprintf(stderr, "\n%s warning: checksum mismatch on font %s\n", + ProgramName, f->name); + FSkipNBytes(tfmfp, 4*lh - 4); + for (pbyte = f->charwidths; nchars > 0; nchars--) { + *pbyte++ = FReadByte(tfmfp); + FSkipNBytes(tfmfp,3L); + } +} + + + +/* + * Read the character widths of a font from the TFM file and convert + * to DVI units, a calculation that must be done with extreme care. + * Further explanation is punted to section 571 of volume B of the + * Encyclop\ae dia TeXnica. The results go into the /widths/ table. + */ +void +TFMWidthsLoad(f) +font *f; +{ + int nwidths; + unsigned_byte a,b,c,d; + long *pwidth,z,alpha,beta; + + z = f->scalefactor; + alpha = 16; + while (z >= 040000000L) { z = z/2; alpha = alpha+alpha; } + beta = 256/alpha; + alpha *= z; + nwidths = f->nw; + for (pwidth = f->widths; nwidths > 0; nwidths--) { + a = FReadByte(tfmfp); b = FReadByte(tfmfp); + c = FReadByte(tfmfp); d = FReadByte(tfmfp); + *pwidth = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; + if (a != 0) { + if (a != 255) { + fprintf(stderr, "\n%s fatal error: Bad TFM file for font %s\n", + ProgramName, f->name); + exit(2); + } else *pwidth -= alpha; + } + pwidth++; + } +} + + + +/* + * Do you need comments for this one? + */ +void +FontMemoryOverflow() +{ + fprintf(stderr, "\n%s: Insufficient memory for font definitions\n", + ProgramName); + exit(3); +} + + + +/* + * Abort the run due to junk in the input. + */ +void +BadDVIAbort(message) +char *message; +{ + fprintf(stderr, "\n%s: Malformed DVI file (%s)\n", ProgramName, message); + exit(2); +} diff --git a/dviware/ivd2dvi/commands.h b/dviware/ivd2dvi/commands.h new file mode 100644 index 0000000000..f7a30ffab2 --- /dev/null +++ b/dviware/ivd2dvi/commands.h @@ -0,0 +1,79 @@ +/* + * Commands and values found in DVI files. + */ + +#define SETC_000 0 +/* . . . + * . . . + * . . . + */ +#define SETC_127 127 +#define SET1 128 +#define SET2 129 +#define SET3 130 +#define SET4 131 +#define SET_RULE 132 +#define PUT1 133 +#define PUT2 134 +#define PUT3 135 +#define PUT4 136 +#define PUT_RULE 137 +#define NOP 138 +#define BOP 139 +#define EOP 140 +#define PUSH 141 +#define POP 142 +#define RIGHT1 143 +#define RIGHT2 144 +#define RIGHT3 145 +#define RIGHT4 146 +#define W0 147 +#define W1 148 +#define W2 149 +#define W3 150 +#define W4 151 +#define X0 152 +#define X1 153 +#define X2 154 +#define X3 155 +#define X4 156 +#define DOWN1 157 +#define DOWN2 158 +#define DOWN3 159 +#define DOWN4 160 +#define Y0 161 +#define Y1 162 +#define Y2 163 +#define Y3 164 +#define Y4 165 +#define Z0 166 +#define Z1 167 +#define Z2 168 +#define Z3 169 +#define Z4 170 +#define FONT_00 171 +/* . . . + * . . . + * . . . + */ +#define FONT_63 234 +#define FNT1 235 +#define FNT2 236 +#define FNT3 237 +#define FNT4 238 +#define XXX1 239 +#define XXX2 240 +#define XXX3 241 +#define XXX4 242 +#define FNT_DEF1 243 +#define FNT_DEF2 244 +#define FNT_DEF3 245 +#define FNT_DEF4 246 +#define PRE 247 +#define POST 248 +#define POST_POST 249 +#define BEG_REFLECT 250 +#define END_REFLECT 251 + +#define DVIVERSION 2 +#define DVIPADCHAR 223 diff --git a/dviware/ivd2dvi/doc b/dviware/ivd2dvi/doc new file mode 100644 index 0000000000..dd23d74471 --- /dev/null +++ b/dviware/ivd2dvi/doc @@ -0,0 +1,60 @@ +NAME + ivd2dvi - convert a dvi-ivd file to a normal dvi file + +SYNOPSIS + ivd2dvi [-Xv] [-b buffersize] [filename] + +DESCRIPTION + An extension to TeX called TeX-XeT produces "dvi-ivd" files, which + are similar to dvi files but include nonstandard commands calling + for the "reflection" (horizontal reversal) of text. In general, + dvi-ivd files cannot be processed by standard dvi drivers because + the reflection commands are not recognized. ivd2dvi converts a + dvi-ivd file to an equivalent dvi file, that is, to a file in which + the necessary reflections are carried out using only standard dvi + commands. The resulting file can be processed by any dvi driver. + + The dvi-ivd file to be processed is specified on the command line; + if the named file cannot be found and contains no period following + its rightmost slash, ".dvi" is appended and ivd2dvi tries again. + Unlike most dvi processors, ivd2dvi is a true filter and reads its + standard input if no file is specified. The dvi file produced by + ivd2dvi is written to standard output. + + Since dvitype says only "unrecognized command!" about the reflection + commands found in dvi-ivd files, ivd2dvi also performs careful error + checking for proper use of these commands. + +OPTIONS + -v Verbose mode. The number of each page is printed as it is + processed. + + -b newbuffersize + Change the size of ivd2dvi's buffers. ivd2dvi uses several + internal buffers and cannot proceed if any overflows. When this + happens, you should try again using -b to increase the buffer + size. The default buffer size is 1024. + + -X Exact mode. In this mode, ivd2dvi attempts to process the input + file without modification. The comment string is not updated, + NOP commands are retained, and the maximum stack depth is copied + from the input file if possible (this number is conservatively + but imprecisely computed by TeX; normally ivd2dvi will substitute + the exact value). As a result, dvi files with no reflection + commands are more likely to emerge totally unchanged. Use of + this flag is discouraged except for debugging. + +ENVIRONMENT + TEXFONTS + Colon-separated list of directories to be searched for font + metric files. The default is /usr/lib/tex/fonts. + +FILES + /usr/lib/tex/fonts/*.tfm Font metric files. + +SEE ALSO + "Mixing right-to-left texts with left-to-right texts," Donald Knuth + and Pierre MacKay, TUGboat volume 8 (1987), number 1, pp. 14--25. + +AUTHOR + Larry Denenberg, larry@bbn.com or larry@harvard.edu. diff --git a/dviware/ivd2dvi/global.h b/dviware/ivd2dvi/global.h new file mode 100644 index 0000000000..27bcb67367 --- /dev/null +++ b/dviware/ivd2dvi/global.h @@ -0,0 +1,65 @@ +/* + * Global definitions for ivd2dvi. Copyright 1988 by Larry Denenberg. + * May be freely distributed as long as this notice is retained. + */ + +#define TRUE 1 +#define FALSE 0 + + +/* + * Buffer sizing and allocation is explained in io.c. + */ +#define BUFDEFAULTSIZE 1024 +#define SMALLBUFDIVISOR 16 +#define MAXFILENAMESIZE 256 +#define TFMAREADEFAULT "/usr/local/lib/tex/fonts" + + +/* + * Values of /State/; see the overview in ivd2dvi.c. + */ +#define LTYPESETTING 0 +#define RTYPESETTING 1 +#define SIMULATING 2 + + +/* + * Allocate an object of type T or a sequence of N such objects. + */ +#define OBJALLOC(T) ((T *) malloc(sizeof(T))) +#define SEQALLOC(N,T) ((T *) calloc((unsigned) N, sizeof(T))) + + +/* + * Library routines declared to avoid lint errors. + */ +extern char *calloc(), *malloc(), *rindex(), *index(), *getenv(); +extern void exit(); + + +/* + * Useful types. If your compiler doesn't recognize unsigned char, + * you'll have to find another one-byte unsigned integer. + */ +typedef unsigned char unsigned_byte; +typedef short boolean; + + +/* + * Structure for font information. Note that /charwidths/ is a table + * of length ec-bc+1 giving the width of each character; each entry + * in this table is an index into the /widths/ table where the widths + * really reside. Further information is in the file auxiliary.c. + */ +typedef struct font { + long number; /* font number in the DVI file */ + char *area, *name; /* strings naming the associated file */ + long checksum, scalefactor; /* you figure this one out */ + boolean loaded; /* TRUE iff we've read the TFM file */ + int nw; /* number of distinct widths */ + long *widths; /* the distinct widths */ + int bc, ec; /* beginning and ending char numbers */ + unsigned_byte *charwidths; /* widths of the individual characters */ + struct font *nextfont; /* pointer to the next font */ +} font; diff --git a/dviware/ivd2dvi/io.c b/dviware/ivd2dvi/io.c new file mode 100644 index 0000000000..c461920d4a --- /dev/null +++ b/dviware/ivd2dvi/io.c @@ -0,0 +1,520 @@ +/* + * Input/output routines for ivd2dvi. Copyright 1988 by Larry Denenberg. + * May be freely distributed as long as this notice is retained. + * + * Here are the naming conventions for input routines: A routine is named + * "Read..." if it merely reads something from standard input, e.g. + * /ReadByte/, /ReadSigned/. Recall that the input DVI file always + * comes via standard input. As in C, there are routines "FRead..." + * whose first argument is of type FILE*; these read from an arbitrary + * file and are used to read TFM files. We also have the "Copy..." + * routines; these are just like their "Read..." counterparts but also + * copy every byte read to the output DVI file. There are no "FCopy..." + * routines for obvious reasons. The routine /CopyNBytes/ has no "Read" + * analogue because it returns no value. + */ + + +#include <stdio.h> +#include "global.h" +#include "commands.h" + +/* Procedure and global variable defined in auxiliary.c */ +extern void BadDVIAbort(); +extern font *CurFont; + +/* Global variables defined in ivd2dvi.c */ +extern int State; +extern char *ProgramName; + +/* Global variables defined here */ +unsigned BufSize = BUFDEFAULTSIZE; /* buffer size, mutable with -b */ +unsigned_byte *Buffer; /* first char of input buffer */ +unsigned_byte *BufEnd; /* pointer just beyond buffer area */ +unsigned_byte *BufFirstNonchar; /* first unused spot; save input here */ +unsigned_byte *BufPointer; /* pointer into buffer; read from here */ +boolean ReadingCommand = FALSE; /* true iff reading a DVI main command */ +unsigned_byte *VStack; /* start of nesting validation stack */ +unsigned_byte *VEnd; /* pointer just beyond vstack area */ +unsigned_byte *VPointer; /* vstack pointer to first unused slot */ +long BytesOutput = 0L; /* number of bytes written to output */ + + +/* Procedures defined in this file, in order of definition */ +void InitIOBuffers(); +unsigned_byte ReadByte(); +void NestingValidate(), BufOverflow(); +unsigned_byte ReadCommand(), CopyByte(), FReadByte(); +void SkipNBytes(), FSkipNBytes(), CopyNBytes(); +long ReadUnsigned(), FReadUnsigned(), ReadSigned(), FReadSigned(); +long CopyWord(), CopyUnsigned(); +unsigned_byte *ReadFilePosition(); +void ResetFilePosition(), RereadLastByte(); +void WriteByte(), WriteWord(), WriteNumber(), WriteString(); +unsigned SignedBytes(); + + + +/* + * Initialize two of the three main memory areas in ivd2dvi. The + * size of each is a function of the value /BufSize/ which can be + * changed by the user with the -b flag. So the user doesn't need to + * know that there are lots of buffers with different sizes; if there's + * not enough room, using the -b flag will make them all bigger. + */ +void +InitIOBuffers() +{ + Buffer = SEQALLOC(BufSize, unsigned_byte); + BufPointer = NULL; + BufFirstNonchar = Buffer; + BufEnd = Buffer + BufSize; + + VStack = SEQALLOC(BufSize/SMALLBUFDIVISOR, unsigned_byte); + VPointer = VStack; + VEnd = VStack + BufSize/SMALLBUFDIVISOR; + + if ((Buffer == NULL) || (VStack = NULL)) { + fprintf(stderr, "\n%s fatal error: can't allocate buffers\n", + ProgramName); + exit(3); + } +} + + + + +/* + * Read a byte from the input DVI file. All input routines that read + * standard input must come through here. + * + * The problem to worry about is that ivd2dvi frequently needs to reread + * input. Rather than doing seeks, we've (perhaps foolishly) decided to + * buffer input so we can see it again later. This means that ivd2dvi is + * a true filter, which is a useless advantage since TeX doesn't write + * its standard output and since most dvi drivers (dvi2ps in particular) + * need real files and can't read standard input. + * + * Now, we don't buffer *all* input, since we know that only if we're + * simulating will we need to reread the input. So anytime we're + * reading from the real input file and we're simulating, we save the + * character in the buffer. + * + * /BufPointer/ is the place in the buffer from which we're reading + * saved input. It also serves as a flag; if it's NULL, then we're not + * reading saved input at all. So the basic idea is: if /BufPointer/ + * is pointing, return the character it points to and advance it. + * Otherwise, do a real read, and save if simulating. + * + * What if /BufPointer/ points, but there's no more input? Then we want + * to go back to reading real input: set /BufPointer/ to NULL and call + * ourselves recursively to force real input. We also take this + * opportunity to clear out the buffer and start over, a step which is + * justified only because we start rereading input only when we stop + * simulating (thus nobody can need the saved input anymore). + * + * Note that it's an error if standard input ever comes to EOF; we + * should have seen the postamble and quit. Finally, /ReadingCommand/ + * is TRUE iff the byte is a command and not a parameter; in this case + * we check it with /NestingValidate/. + */ +unsigned_byte +ReadByte() +{ + int nextchar; + + if (BufPointer) { + if (BufPointer < BufFirstNonchar) return *BufPointer++; + else { + BufPointer = NULL; + BufFirstNonchar = Buffer; + return ReadByte(); + } + } else { + nextchar = getchar(); + if (nextchar == EOF) BadDVIAbort("unexpected EOF"); + if (ReadingCommand) NestingValidate((unsigned_byte) nextchar); + if (State >= SIMULATING) { + *BufFirstNonchar++ = (unsigned_byte) nextchar; + if (BufFirstNonchar > BufEnd) BufOverflow(); + } + return nextchar; + } +} + + + +/* + * Test a character for nesting. Since dvitype doesn't check DVI-IVD + * files for validity, it's important to do careful checking here--- + * ivd2dvi will get horribly confused if reflections and pushes don't + * nest properly. This routine gets called to validate every single + * command read from the input file. The method is simple: if the + * command is PUSH, BEG_REFLECT, or BOP, just push it on the stack (the + * stack is the tiny /VStack/, not used for anything else). If the + * command is POP, END_REFLECT, or EOP, pop a command from the stack and + * be sure it matches. Ignore all other commands. + */ +void +NestingValidate(nextchar) +unsigned_byte nextchar; +{ + switch (nextchar) { + case PUSH: case BEG_REFLECT: case BOP: + if (VPointer >= VEnd) BufOverflow(); else *VPointer++ = nextchar; + break; + case POP: + if ((VPointer <= VStack) || (*--VPointer != PUSH)) + BadDVIAbort("reflection commands incorrectly nested"); + break; + case EOP: + if ((VPointer <= VStack) || (*--VPointer != BOP)) + BadDVIAbort("reflection commands incorrectly nested"); + break; + case END_REFLECT: + if ((VPointer <= VStack) || (*--VPointer != BEG_REFLECT)) + BadDVIAbort("reflection commands incorrectly nested"); + break; + } +} + + + +/* + * As Knuth would say, ``Exit due to finiteness.'' We can become less + * finite, but we have to know in advance! + */ +void +BufOverflow() +{ + fprintf(stderr, "\n%s: Buffer size %d was inadequate\n", + ProgramName, BufSize); + fprintf(stderr, "(Use the -b flag to increase the buffer size)\n"); + exit(3); +} + + + + +/* + * Read a command. Just read a byte with /ReadingCommand/ turned on + * (and then turn it off!). See the discussion of /VStack/ above. + */ +unsigned_byte +ReadCommand() +{ + unsigned_byte result; + + ReadingCommand = TRUE; + result = ReadByte(); + ReadingCommand = FALSE; + return result; +} + + + + +/* + * Copy a single byte from the input DVI file to the output file and + * return it. + */ +unsigned_byte +CopyByte() +{ + unsigned result = ReadByte(); + + WriteByte(result); + return result; +} + + + +/* + * Read a byte from the input file /fp/. We don't have to worry about + * buffering or special checks, just about EOF. The error message is + * justified because we do input only from the TFM file of the current + * font (except for the main input DVI file, of course). + */ +unsigned_byte +FReadByte(fp) +FILE *fp; +{ + int nextchar; + + nextchar = getc(fp); + if (nextchar == EOF) { + fprintf(stderr, "\n%s: unexpected EOF in TFM file for font %s\n", + ProgramName, CurFont->name); + exit(2); + } + return nextchar; +} + + + + +/* + * Discard /n/ bytes from the input DVI file. + */ +void +SkipNBytes(n) +long n; +{ + while (n--) (void) ReadByte(); +} + + + +/* + * Discard /n/ bytes from the input file /fp/. + */ +void +FSkipNBytes(fp,n) +FILE *fp; +long n; +{ + while (n--) (void) FReadByte(fp); +} + + + +/* + * Copy /n/ bytes from the input DVI file to the output file. + */ +void +CopyNBytes(n) +long n; +{ + while (n--) WriteByte(ReadByte()); +} + + + + +/* + * Read an unsigned integer of length /bytes/ from the input DVI file. + */ +long +ReadUnsigned(bytes) +unsigned bytes; +{ + long result = 0; + + while (bytes-- != 0) { + result <<= 8; + result |= ReadByte(); + } + return result; +} + + + +/* + * Read an unsigned integer of length /bytes/ from the input file /fp/. + */ +long +FReadUnsigned(fp,bytes) +FILE *fp; +unsigned bytes; +{ + long result = 0; + + while (bytes--) { + result <<= 8; + result |= FReadByte(fp); + } + return result; +} + + + +/* + * Read a signed integer of length /bytes/ from the input DVI file. + * This must be done with no assumptions about the length of long ints + * on the machine and without using sign-extending right shifts. + */ +long +ReadSigned(bytes) +unsigned bytes; +{ + long result; + + result = ReadByte(); + if (result >= 128) result -= 256; + while (--bytes) { + result <<= 8; + result |= ReadByte(); + } + return result; +} + + + +/* + * Read a signed integer of length /bytes/ from the input file /fp/. + */ +long +FReadSigned(fp,bytes) +FILE *fp; +int bytes; +{ + long result; + + result = FReadByte(fp); + if (result >= 128) result -= 256; + while (--bytes) { + result <<= 8; + result |= FReadByte(fp); + } + return result; +} + + + + +/* + * Copy a 32-bit word from the input DVI file to the output file, and + * return it. + */ +long +CopyWord() +{ + long result = ReadSigned(4); + + WriteWord(result); + return result; +} + + + +/* + * Copy an unsigned integer of length /bytes/ from the input DVI file + * to the output file, and return it. + */ +long +CopyUnsigned(bytes) +unsigned bytes; +{ + long result = ReadUnsigned(bytes); + + WriteNumber(result,bytes); + return result; +} + + + + +/* + * Get a file position from which we can take input later. If we're + * currently taking input from the buffer, the result is just the buffer + * pointer. If not, the saved position is the place inside the buffer + * where we're storing the input as it comes in. Details at /ReadByte/. + */ +unsigned_byte * +ReadFilePosition() +{ + if (BufPointer) return BufPointer; else return BufFirstNonchar; +} + + + +/* + * Reset to take input starting from a saved file position. Easy. + */ +void +ResetFilePosition(position) +unsigned_byte *position; +{ + BufPointer = position; +} + + + +/* + * Arrange to see the last character of the input again. Possible only + * when we're reading buffered input, in which case it's simple. In + * fact, this routine is used only by /SetString/ while RTYPESETTING. + */ +void RereadLastByte() { + if (!BufPointer || (BufPointer == Buffer)) { + fprintf(stderr, "\n%s internal error: illegal attempt to backup input\n", + ProgramName); + exit(4); + } + BufPointer--; +} + + + + +/* + * Write a single byte to the output DVI file. All non-diagnostic output + * ***MUST*** go through this routine so that the number of bytes output + * is counted accurately. + */ +void +WriteByte(value) +unsigned value; +{ + putchar(value); + BytesOutput++; +} + + + +/* + * Write a 32-bit word to the output file. + */ +void +WriteWord(value) +long value; +{ + WriteNumber(value, 4); +} + + + +/* + * Write /value/ to the output file as an integer of length /bytes/. + */ +void +WriteNumber(value,bytes) +long value; +unsigned bytes; +{ + if (bytes > 1) WriteNumber(value >> 8, bytes - 1); + WriteByte((unsigned_byte) value & 0377); +} + + + +/* + * Write a string to the output DVI file. + */ +void +WriteString(string) +char *string; +{ + char *pchar; + + for (pchar = string; *pchar; pchar++) + WriteByte((unsigned_byte) *pchar); +} + + + + +/* + * Calculate how many bytes are required to represent /number/. Don't + * say /number = -(number+1)/ because of the possibility of overflow. + */ +unsigned +SignedBytes(number) +long number; +{ + if (number > 0) { number = -number; number -= 1; } + if (number >= -128) return 1; + else if (number >= -(128*256)) return 2; + else if (number >= -(128*256*256)) return 3; + else return 4; +} diff --git a/dviware/ivd2dvi/ivd2dvi.1 b/dviware/ivd2dvi/ivd2dvi.1 new file mode 100644 index 0000000000..d8231be19c --- /dev/null +++ b/dviware/ivd2dvi/ivd2dvi.1 @@ -0,0 +1,89 @@ +.TH IVD2DVI 1 "31 August 1988" +.SH NAME +ivd2dvi \- convert a dvi-ivd file to a standard dvi file + +.SH SYNOPSIS +.B ivd2dvi +[\-Xvcb] +.RI [ filename ] + +.SH DESCRIPTION +An extension to TeX called TeX-XeT produces ``dvi-ivd'' files, which +are similar to dvi files but include nonstandard commands calling +for the ``reflection'' (horizontal reversal) of text. In general, +dvi-ivd files cannot be processed by standard dvi drivers because +the reflection commands are not recognized. +.I ivd2dvi +converts a +dvi-ivd file to an equivalent dvi file, that is, to a file in which +the necessary reflections are carried out using only standard dvi +commands. The resulting file can be processed by any dvi driver. + +The dvi-ivd file to be translated is specified on the command line; +if the file cannot be found and its name contains no period following +the rightmost slash, ``.dvi'' is appended and +.I ivd2dvi +tries again. +Unlike most dvi processors, +.I ivd2dvi +is a true filter and reads its +standard input if no file is specified. The dvi file produced by +.I ivd2dvi +is written to standard output. + +.I ivd2dvi +also performs careful error checking for proper placement +of the reflection commands since +dvitype(1), the dvi-file validation program, +does not understand them. + +.SH OPTIONS +.IP \-v +Verbose mode. +.IP \-c +Error checking only. Report if reflection commands are misused +in the input file (or if the input file is malformed in some other +way detectable by +.I ivd2dvi) +but produce no other output. +.IP \-b +Double the size of +.IR ivd2dvi 's +buffers. +.I ivd2dvi +uses several +internal buffers and cannot proceed if any overflows. When this +happens, you should try again using \-b to increase the buffer +size. This flag can be used more than once, but probably +will never be needed +(since the default buffers are plenty big). +.IP \-X +Exact mode. In this mode, +.I ivd2dvi +attempts to process the input +file without modification. The comment string is not updated, +NOP commands are retained, and the maximum stack depth is copied +from the input file if possible (this number is conservatively +but imprecisely computed by TeX; normally +.I ivd2dvi +will substitute +the exact value). As a result, dvi files with no reflection +commands will typically emerge unchanged. Unnecessary except when debugging. + +.SH ENVIRONMENT +.IP TEXFONTS +Colon-separated list of directories to be searched for font +metric files. The default is /usr/lib/tex/fonts. + +.SH FILES +.ta 32 +/usr/lib/tex/fonts/*.tfm Font metric files. + +.SH SEE ALSO +``Mixing right-to-left texts with left-to-right texts,'' Donald Knuth +and Pierre MacKay, TUGboat volume 8 (1987), number 1, pp. 14\-\-25. + +dvitype(1) + +.SH AUTHOR +Larry Denenberg, larry@bbn.com or larry@harvard.edu. diff --git a/dviware/ivd2dvi/ivd2dvi.c b/dviware/ivd2dvi/ivd2dvi.c new file mode 100644 index 0000000000..d2f68397b0 --- /dev/null +++ b/dviware/ivd2dvi/ivd2dvi.c @@ -0,0 +1,957 @@ +/* + * ivd2dvi. + * Copyright 1988 by Larry Denenberg. May be freely distributed as long + * as this notice is retained. + * + * This is a general discussion of ivd2dvi, assuming familiarity with + * the format of DVI files and with the semantics of the reflection + * commands (see Knuth and Mackay, "Mixing right-to-left text with + * left-to-right text" in TUGboat volume 8 number 1). Notation: let + * "BR" stand for the BEGIN_REFLECT command, let "ER" stand for + * END_REFLECT, let "a" stand for SET_097 (i.e. "typeset character 97," + * usually lowercase a), and similarly for the other lowercase letters. + * + * The simplest idea would be to rearrange reflected text somehow so + * that the right thing happens. Is it enough to reverse the commands? + * Certainly if we see "BR a b c ER" we can replace it with "c b a". + * But this works only so long as the reflected segment sticks to a + * small subset of DVI commands; "BR a FONT_00 b ER" can't in general be + * changed to "b FONT_00 a". We also get in trouble with commands that + * change the DVI registers (not to mention PUSH and POP!). + * + * Some of these difficulties could be overcome with more clever + * rearrangement. Unfortunately, there are situations that can't be + * handled by any such scheme: for example, you can't typeset the + * sequence "BR PUSH i POP w ER" without knowing about the widths of + * "i" and "w". The PUTn commands also lead to unsolvable problems. + * So we abandon this approach and resign ourselves to reading width + * data from TFM files. + * + * Here's the method we use: we read through the input DVI file, + * copying DVI commands to the output file. When we see a BR we stop + * copying and simply read the input looking for the matching ER. + * During this scan we keep track of the total width of the commands + * between the BR and ER. (Each character contributes its width as + * revealed by the TFM file, horizontal motions contribute their + * width, vertical motions are ignored, etc.) This procedure is + * called *simulating*; at its end we've just read an ER and we know + * the width of the segment between the BR and the ER. Call this + * width T. Note that nothing at all is output during simulation. + * + * Now we move right (in the output file) by T; of course we do so by + * shipping out a RIGHTn command. Next, we make a second pass over the + * commands between the BR and the ER; this time, we typeset them + * "backwards." For example, to SET an "a" we first move left by the + * width of an "a", and lay down the "a" without moving---this is the + * inverse of laying down the "a" and then moving right. If the command + * is any sort of horizontal motion we negate the distance before moving. + * Reflection applies only to horizontal motion, however; vertical + * motion commands, font changes, font definitions, and so forth, are + * copied unchanged. (For the precise way in which we reverse, see the + * documentation for the individual DVI commands below, especially + * /SetChar/ and /SetString/.) + * + * When we see the ER for the second time, the horizontal location in + * the output file should be the same as it was when we first saw the BR + * (since we've processed all the same commands, only backwards). So we + * once again output a command to move right by T, thus moving to the + * place where we typeset the first command after the BR. We're now + * done translating this reflected segment and we continue normally. + * + * What happens when reflections are nested? Well, it's easy. If we + * encounter a BR during a simulation, we basically ignore it! We're + * trying to find the total width of the reflected segment; the fact + * that part of the segment is further reflected doesn't matter. (We do + * have to be certain to skip over the inner ER so that we match only + * the ER we're looking for.) Later, when we're no longer simulating + * but "typesetting backwards," we'll encounter the BR of the inner + * reflection. At that point it gets its own simulation set up, and we + * do the whole two-pass business again on the inner segment; of course, + * the second pass is now a "forwards" pass, at the end of which we + * continue the "backwards" pass over the outer segment. + * + * All of this can be nested to any depth. We keep track of what we're + * doing with the variable /State/ which takes on the following values: + * LTYPESETTING Typesetting normally, left-to-right + * RTYPESETTING Typesetting "backwards," right-to-left + * SIMULATING First pass over text to be reflected + * >SIMULATING Inside nested begin_reflect/end_reflect pairs + * Values of /State/ greater than SIMULATING are used to keep track of + * the nesting depth of BR/ER pairs. While we're simulating, we simply + * increment /State/ when we see BR and decrement it when we see ER. + * We switch from simulating to typesetting only when we see ER while + * /State/ is exactly equal to SIMULATING. Note carefully that we're + * never simulating on behalf of more than one BR/ER pair; there's never + * more than one segment whose width we're measuring. + * + * So the procedure upon hitting a BR in the general case is as follows: + * if /State/ equals or exceeds SIMULATING, just increment /State/. + * Otherwise set /State/ to SIMULATING and start the first pass. The + * actions necessary at ER are a bit more complex: if /State/ is + * *greater* than SIMULATING, just decrement it. If /State/ is equal to + * SIMULATING, we've just finished a simulation: output the motion + * command as above, switch to the direction opposite to the one we were + * in when we hit the BR, and reset the input file to the point just + * after the BR, thus beginning the second pass. If /State/ is + * LTYPESETTING or RTYPESETTING, we've just finished the second pass + * over a reflection: invert /State/, and output the second long motion + * command as described above. Of course, there's lots of things to + * save and restore here; details are in the code below. + * + * Even when we're not simulating we have to keep track of certain + * values. The current font is an obvious example: we have to remember + * what it is, because if we start a simulation we'll have to measure + * its characters. We also keep track of the horizontal motion + * parameters: if a W0 appears in reflected text we must know the + * current value of W, which may have been set before the simulation + * began. Therefore we keep variables in which we store the values, and + * a stack to model all pushes and pops in the input file. The same + * stack is used to store values over a simulation; no conflict can + * occur. On the other hand, the values of the vertical motion + * parameters never concern us. + * + * One final twist. Suppose we encounter the following sequence: "BR + * <set W to d> a W0 b W0 c W0 ER" Now if we weren't clever, each W0 + * would have to be replaced by a longer RIGHTn command, because when + * we're typesetting backwards a W0 translates to a rightward motion by + * -d, not d. It's better to set W to -d to begin with; then we can use + * W0 inside the reflection and save considerable space. So we negate + * the parameter of Wn commands encountered while RTYPESETTING. But as + * a consequence, the input file may disagree with the output file over + * the current value of W. So we must keep two separate variables, + * /WInput/ and /WOutput/, that record the two values. These two + * variables always are equal in absolute value, but we can't compute + * from the state whether they're equal or not (because reflections may + * start and end independently of changes to W). More details are given + * at /SetWandMoveForward/. All of this applies to X as well. With + * more work we could do further optimization, catching (e.g.) cases + * like "<set W to d> BR a W0 b W0 ER" in which W0 will not be used as + * our scheme stands. + * + * Jacques Goldberg first suggested the possibility of a dvi-ivd to dvi + * processor. Please send comments, suggestions, and bug reports to + * larry@bbn.com or larry@harvard.edu. + * + */ + + +#include <stdio.h> +#include "global.h" +#include "commands.h" + +/* Global variables and procedures defined in auxiliary.c. */ +extern font *CurFont, *FindFont(); +extern void Initializations(), BadDVIAbort(), MaxPushLevelOutput(); +extern void PushWrite(), PopWrite(); +extern void PushWX(), PopXW(), PushDeltaH(), PopDeltaH(); +extern void FontDefine(), CopyFontDefinition(); + +/* Global variables and procedures defined in io.c. */ +extern unsigned BufSize, SignedBytes(); +extern long BytesOutput, CopyWord(); +extern long ReadSigned(), ReadUnsigned(), CharWidth(), CopyUnsigned(); +extern void WriteByte(), WriteString(), WriteNumber(), WriteWord(); +extern void CopyNBytes(), SkipNBytes(); +extern void RereadLastByte(), ResetFilePosition(); +extern unsigned_byte CopyByte(), ReadByte(), ReadCommand(); +extern unsigned_byte *ReadFilePosition(); + + +/* Global variables defined here */ +char *ProgramName; /* argv[0], used in error messages */ +boolean VerboseOutput = FALSE; /* v flag: report page progress */ +boolean ExactOutput = FALSE; /* X flag: try not to change input file */ +long PrevPagePointer = -1; /* output file location of previous BOP */ +int State; /* current direction or simulation depth*/ +long WInput, WOutput; /* value of W in input and output files */ +long XInput, XOutput; /* value of X in input and output files */ +long DeltaH; /* total size of reflected segment */ +int SavedState; /* state at start of current simulation */ +font *SavedFont; /* font at start of current simulation */ +unsigned_byte *SavedPosition; /* file position at start of simulation */ +unsigned_byte CurCommand; /* DVI command under consideration */ + +#define REVERSE(STATE) (LTYPESETTING + RTYPESETTING - STATE) + + +/* Procedures defined in this file, in order of definition */ +void main(),Arguments(),FileArgument(),Preliminaries(),MainLoop(); +void SetChar(),SetRule(),SetString(),SetFont(); +void BeginPage(),EndPage(),BegReflect(),EndReflect(); +void MoveForward(),SetWandMoveForward(),SetXandMoveForward(); +void Postliminaries(),CopyParametrizedCommand(); + + + + +/* + * Main procedure, whose function is self-documenting. The only way + * ivd2dvi can terminate normally is through the /exit/ here. + */ +void +main(ignore, argv) +int ignore; +char *argv[]; +{ + Arguments(argv); + Initializations(); + Preliminaries(); + MainLoop(); + Postliminaries(); + exit(0); +} + + + +/* + * Standard argument processing. Don't worry if a flag is given more + * than once, but allow at most one filename. We also allow forms like + * "-Xv", or even "-Xbv 1024" since the argument following any -b is + * taken as the new buffer size. + */ +void +Arguments(argv) +char *argv[]; +{ + char *arg; + boolean seenfile = FALSE; + int newbufsize; + + ProgramName = argv[0]; + for (arg = *++argv; arg; arg = *++argv) + if (*arg == '-') + while (*++arg) + switch(*arg) { + case 'X': + ExactOutput = TRUE; + break; + case 'v': + VerboseOutput = TRUE; + break; + case 'b': + if (!*++argv) { + fprintf(stderr, "%s: missing buffer size, -b ignored\n", + ProgramName); + return; + } else { + newbufsize = atoi(*argv); + if (newbufsize == 0) + fprintf(stderr, "%s: illegal buffer size %s ignored\n", + ProgramName, *argv); + else + BufSize = newbufsize; + } + break; + default: + fprintf(stderr, "%s: illegal flag %c ignored\n", + ProgramName, *arg); + } + else if (seenfile) + fprintf(stderr, "%s: superflous filename %s ignored\n", + ProgramName, arg); + else { + seenfile = TRUE; + FileArgument(arg); + } +} + + + +/* + * Process a file argument. Try to open the file. If we can't, and if + * the name has no period after its rightmost slash, append ".dvi" and + * try again. In either case we're reopening standard input, so that + * we can read the input DVI file from /stdin/ whether or not there's a + * filename on the command line. + */ +void +FileArgument(filename) +char *filename; +{ + char buf[MAXFILENAMESIZE], *p; + + if (freopen(filename, "r", stdin) != NULL) return; + p = rindex(filename, '/'); + if (*p == '\0') p = filename; + p = index(p, '.'); + if (*p != '\0') { + fprintf(stderr, "%s: Can't open %s\n", ProgramName, filename); + exit(1); + } else { + (void) sprintf(buf, "%s.dvi", filename); + if (freopen(buf, "r", stdin) != NULL) return; + fprintf(stderr, "%s: Can't open %s nor %s\n", + ProgramName, filename, buf); + exit(1); + } +} + + + +/* + * Process the preamble. We mostly just copy it through untouched, + * except that we check the first two bytes for correctness and update + * the comment string to say ivd2dvi was here. (Don't update the + * comment string if the -X flag was used nor when the new comment + * wouldn't fit.) + */ +void +Preliminaries() +{ + static char *comment = "; postprocessed by ivd2dvi"; + unsigned comlength; + + if (CopyByte() != PRE) BadDVIAbort("no preamble"); + if (CopyByte() != DVIVERSION) + BadDVIAbort("wrong DVI version in preamble"); + CopyNBytes(12L); + comlength = ReadByte(); + if (!ExactOutput && (comlength < 256 - strlen(comment))) { + WriteByte(comlength + strlen(comment)); + CopyNBytes((long) comlength); + WriteString(comment); + } else { + WriteByte(comlength); + CopyNBytes((long) comlength); + } +} + + + + +/* + * The main loop. Read a command, switch on it, and continue doing so + * forever. The only way out of this routine is when /CurCommand/ is + * POST. Most cases of the main switch are simply procedure calls; the + * rest are documented case-by-case. We first handle the most common + * case, for top speed: if /CurCommand/ is SET_000 through SET_127 and + * we're typesetting normally, we need do nothing but write it into the + * output. If we're simulating or typesetting backwards, /SetString/ + * will handle it. Other commands are handled inside the switch. Note: + * the first test relies on the assumption that SET_000 is 0, which we + * really shouldn't do, but then again it *is* the test for the most + * common case! Expressions like "CurCommand - W1 + 1" return the + * number of bytes in the first parameter of commands with four forms. + */ + +#define SETTING TRUE + +void +MainLoop() +{ + while (TRUE) { + + CurCommand = ReadCommand(); + + if (CurCommand <= SETC_127) { + if (State == LTYPESETTING) WriteByte(CurCommand); else SetString(); + continue; + } + + switch (CurCommand) { + + case SET1: case SET2: case SET3: case SET4: + SetChar(CurCommand - SET1 + 1, SETTING); + break; + + case PUT1: case PUT2: case PUT3: case PUT4: + SetChar(CurCommand - PUT1 + 1, !SETTING); + break; + + case SET_RULE: case PUT_RULE: + SetRule(); + break; + + case NOP: + if (ExactOutput) WriteByte(NOP); + break; + + case BOP: + BeginPage(); + break; + + case EOP: + EndPage(); + break; + + +/* + * When we see a PUSH/POP we save/restore the horizontal parameters. + * If we're simulating, we also have to save/restore /DeltaH/, since + * stuff that happens between the PUSH and the POP has no effect on + * the size of the reflected segment. (If we're not simulating, we + * don't care at all about /DeltaH/ and there's no sense saving it.) + * Note that the stack discipline works out as long as we restore + * in the opposite order that we save, since PUSH/POP must nest with + * respect to reflection---so we can't have a PUSH while simulating + * that matches a POP while not simulating. Oh yeah, I almost forgot: + * if we're *not* simulating, we must write the command to the output! + */ + case PUSH: + PushWX(); + if (State < SIMULATING) PushWrite(); else PushDeltaH(); + break; + + case POP: + if (State < SIMULATING) PopWrite(); else PopDeltaH(); + PopXW(); + break; + + case RIGHT1: case RIGHT2: case RIGHT3: case RIGHT4: + MoveForward(ReadSigned(CurCommand - RIGHT1 + 1)); + break; + + +/* + * Move forward by W. It's up to /MoveForward/ whether "forward" means + * left or right (or neither, if we're just simulating). The amount to + * move is of course the *input* file's idea of the current W. + */ + case W0: + MoveForward(WInput); + break; + + case W1: case W2: case W3: case W4: + SetWandMoveForward(ReadSigned(CurCommand - W1 + 1)); + break; + + +/* + * Move forward by X. Please see the comments for W0, above. + */ + case X0: + MoveForward(XInput); + break; + + case X1: case X2: case X3: case X4: + SetXandMoveForward(ReadSigned(CurCommand - X1 + 1)); + break; + + +/* + * We don't especially care about vertical motion, so if we're only + * simulating there's nothing to do. Otherwise, copy the command and + * its parameters to the output file. + */ + case DOWN1: case DOWN2: case DOWN3: case DOWN4: + if (State < SIMULATING) + CopyParametrizedCommand(CurCommand - DOWN1 + 1); + break; + + case Y0: case Y1: case Y2: case Y3: case Y4: + if (State < SIMULATING) CopyParametrizedCommand(CurCommand - Y0); + break; + + case Z0: case Z1: case Z2: case Z3: case Z4: + if (State < SIMULATING) CopyParametrizedCommand(CurCommand - Z0); + break; + + +/* + * We must keep track of all font changes, simulating or not. So call + * /SetFont/ on the selected font number, and if we're not simulating + * copy the whole command to the output file. + */ + case FNT1: case FNT2: case FNT3: case FNT4: + if (State >= SIMULATING) + SetFont(ReadUnsigned(CurCommand - FNT1 + 1)); + else { + WriteByte(CurCommand); + SetFont(CopyUnsigned(CurCommand - FNT1 + 1)); + } + break; + + +/* + * Skip past if simulating, otherwise copy out the whole command. + */ + case XXX1: case XXX2: case XXX3: case XXX4: + if (State >= SIMULATING) + SkipNBytes(ReadUnsigned(CurCommand - XXX1 + 1)); + else { + WriteByte(CurCommand); + CopyNBytes(CopyUnsigned(CurCommand - XXX1 + 1)); + } + break; + + case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4: + FontDefine(CurCommand - FNT_DEF1 + 1); + break; + + case PRE: + BadDVIAbort("unexpected PRE"); + break; + + +/* + * Shouldn't see the postamble while simulating or reversing; otherwise + * it's time to quit. This is the only normal way out of /MainLoop/. + */ + case POST: + if (State != LTYPESETTING) BadDVIAbort("unexpected POST"); + return; + + case POST_POST: + BadDVIAbort("unexpected POST_POST"); + break; + + case BEG_REFLECT: + BegReflect(); + break; + + case END_REFLECT: + EndReflect(); + break; + + +/* + * The only commands left, besides illegal ones, are the one-byte font + * selection commands. Copy them to the output file unless simulating. + * Then call /SetFont/ to note the change of font. + */ + default: + if (CurCommand >= FONT_00 && CurCommand <= FONT_63) { + if (State < SIMULATING) WriteByte(CurCommand); + SetFont((long) CurCommand - FONT_00); + } else + BadDVIAbort("unrecognized command"); + + } /* end of "switch (CurCommand) { ... }" */ + } /* end of "while (TRUE) { ... }" */ +} /* end of procedure MainLoop */ + + + + +/* + * Set a single character as specified by a SETn or PUTn command. + * (SET_nnn commands don't come here; they go to /SetString/.) + * /setting/ tells whether it was a SET or a PUT, and /bytes/ gives the + * parameter length. If we're typesetting normally we just copy out the + * command and parameter, and if we're simulating it's enough to add the + * width of the desired character to the running total. If we're + * typesetting in reverse there's more to do: first move "forward" + * (left, in this case) by the width of the character. Only then do we + * typeset the character. Moreover, if the original command was a SET, + * we PUT the character since we've already moved. And if the original + * command was a PUT, we SET the character---which has the effect of + * moving back to the right, for a net motion of zero. + */ +void +SetChar(bytes, setting) +unsigned bytes; +boolean setting; +{ + long charnumber; + + switch (State) { + case LTYPESETTING: + CopyParametrizedCommand(bytes); + break; + case RTYPESETTING: + charnumber = ReadUnsigned(bytes); + MoveForward(CharWidth(charnumber)); + if (setting) + WriteByte(PUT1 + bytes - 1); + else + WriteByte(SET1 + bytes - 1); + WriteNumber(charnumber, bytes); + break; + default: /* State >= SIMULATING */ + DeltaH += CharWidth(ReadUnsigned(bytes)); + } +} + + + +/* + * Same idea as /SetChar/, just above. If LTYPESETTING just copy, if + * simulating just accumulate the width. If RTYPESETTING first move + * left and then interchange SET and PUT. + */ +void +SetRule() +{ + long height, width; + + switch (State) { + case LTYPESETTING: + CopyParametrizedCommand(8); + break; + case RTYPESETTING: + height = ReadSigned(4); + width = ReadSigned(4); + MoveForward(width); + if (CurCommand == SET_RULE) WriteByte(PUT_RULE); + else WriteByte(SET_RULE); + WriteWord(height); + WriteWord(width); + break; + default: /* State >= SIMULATING */ + SkipNBytes(4L); + width = ReadSigned(4); + if (CurCommand == SET_RULE) DeltaH += width; + } +} + + + +/* + * Handle a SET_nnn command. This routine is called only while + * simulating or typesetting in reverse (the normal case is handled + * directly in /MainLoop/ for speed). + * + * If we're just simulating there's nothing to do except add the width + * of the character to the running total. The RTYPESETTING case is the + * interesting one. Here's the story: We could typeset backwards + * as we do in /SetChar/ above: move left, then PUT (since all these + * commands are variants of SET). But that would mean that every one + * of these common one-byte commands would translate into around five + * bytes. So instead of handling a single command, this routine handles + * /CurCommand/ and all subsequent SET_nnn commands at once. We first + * continue to read the input until we hit a command that is *not* a + * SET_nnn. As we do so, we accumulate the total width (call it T) of + * all the SET_nnn commands that we've read. Finally, we write the + * following instructions into the output file: (a) move forward---that + * is, left---by T, (b) PUSH, to save the new value of H, (c) typeset + * all the characters we've seen *backwards*, (d) POP to get back to + * the place where we started emitting characters. This does the trick. + * + * A few notes: We must back up the input after we're done since that + * first non-SET_nnn command must be reconsidered by /MainLoop/. We + * rely on the fact that /ReadFilePosition/ gives us a pointer into a + * buffer from which we can rattle off /count/ characters; this is true + * since we must be rescanning input after a simulation. Finally, if + * there's only a single SET_nnn character to typeset we save a byte by + * replacing steps (b), (c) and (d) with a simple PUT1. + * + * This routine relies on the fact that SET_nnn in fact has value nnn, + * which, stylistically, is absolutely indefensible. + */ +void +SetString() +{ + unsigned_byte *p; + unsigned_byte nextcommand; + long totalwidth; + int count; + + if (State >= SIMULATING) + DeltaH += CharWidth((long) CurCommand); + else { /* State == RTYPESETTING */ + totalwidth = count = 0; + nextcommand = CurCommand; + do { + count++; + totalwidth += CharWidth((long) nextcommand); + nextcommand = ReadByte(); + } while (nextcommand <= SETC_127); + RereadLastByte(); + MoveForward(totalwidth); + if (count == 1) { + WriteByte(PUT1); + WriteByte(CurCommand); + } else { + PushWrite(); + p = ReadFilePosition(); + while (count--) WriteByte(*--p); + PopWrite(); + } + } +} + + + +/* + * Record the current font number, which must be done no matter what + * state we're in. The work is done by /FindFont/; we just put the + * result into /CurFont/ and complain if the font is unknown. + */ +void +SetFont(fontnumber) +long fontnumber; +{ + CurFont = FindFont(fontnumber); + if (CurFont == NULL) BadDVIAbort("font used but not defined"); +} + + + +/* + * Pages should end only in normal left-to-right mode. We write the + * BOP, copy the ten \count registers printing the first if in verbose + * mode, and write out the pointer to the previous page. (We can't copy + * the old one since page lengths may change.) We also update this + * pointer; it must point to the newly written BOP. Finally, we start + * out the font, W, and X registers correctly. + */ +void +BeginPage() +{ + long pagenumber; + + if (State != LTYPESETTING) BadDVIAbort("unexpected BOP"); + WriteByte(BOP); + pagenumber = CopyWord(); + if (VerboseOutput) fprintf(stderr, "[%ld", pagenumber); + CopyNBytes(36L); + SkipNBytes(4L); + WriteWord(PrevPagePointer); + PrevPagePointer = BytesOutput - 45; + WInput = WOutput = XInput = XOutput = 0; + CurFont = NULL; +} + + + +/* + * End a page. Must happen in "normal" LTYPESETTING mode, but otherwise + * there's nothing to do but write the EOP and chatter if requested. + */ +void +EndPage() +{ + static int pages = 0; + + if (State != LTYPESETTING) BadDVIAbort("unexpected EOP"); + WriteByte(EOP); + if (VerboseOutput) fprintf(stderr, "]%c", (++pages % 10) ? ' ' : '\n'); +} + + + +/* + * Start of a reflected segment, which may happen in any state. If + * we're already simulating just increment /State/ to indicate nested + * reflections (see the overview above). Otherwise start simulating: + * save the horizontal motion parameters, the current file location, the + * current font, and the current state. Start the running total of the + * size of this segment at zero. Change state to SIMULATING to start + * the first pass over the segment; the rest of the work is done at + * /EndReflect/. One subtlety: it's OK to save the font, the state, and + * the file position in variables since there's never more than one + * simulation at a time. We could do the same with the horizontal + * motion parameters, but we might as well use the extant stack. + */ +void +BegReflect() +{ + if (State >= SIMULATING) ++State; + else { + PushWX(); + SavedPosition = ReadFilePosition(); + SavedFont = CurFont; + SavedState = State; + State = SIMULATING; + DeltaH = 0; + } +} + + + + +/* + * Come here at the end of a reflected segment. We first comment the + * easy case, which happens to be coded last: If /State/ is greater + * than SIMULATING we're inside nested reflections that don't concern + * us yet, so just decrement /State/ to show that we're up a level. + * + * If /State/ says we're at the outermost simulation, we must wrap up + * the simulation and start the second pass. The direction will be the + * inverse of the direction just before the simulation started. We + * also reset the font and the horizontal parameters to their saved + * values, and set things up so we're rescanning the input just *after* + * the BEG_REFLECT that started the simulation. Finally, we move + * "forward" by the total width of the reflected segment; we'll now + * typeset everything "backward" from that point. (Note that we move + * "forward" by the *negative* of /DeltaH/; this is because we've + * already turned the state around. Exercise: why must the /PopXW/ + * precede the /MoveForward/?) But we're not quite done with /DeltaH/; + * we need it at the *end* of the second pass to move forward over + * the reflected segment again. Since the variable /DeltaH/ is used + * by any nested simulations, we must save its value on the stack. + * + * If /State/ says we're typesetting (either direction) then we've + * just finished the second pass over a reflected segment: grab the + * saved value of /DeltaH/, use it to move back over the reflected + * segment, then revert to the previous direction of typesetting + * (which is the opposite of the direction just finished). Be sure + * to see the overview if you don't understand this move by /DeltaH/. + * + * Harder exercise: When we've finished typesetting a simulation as + * just described, we repeat the move that we started with to get back + * to the right place to continue. Why don't we use PUSH and POP *in + * the output file* to remember the place? That is, why not add a call + * to /PushWrite/ just after /MoveForward(-DeltaH)/ in the SIMULATING + * case, and *replace* the /MoveForward/ in the typesetting cases with + * a call to /PopWrite/? We'd save a couple of bytes in the output, + * and wouldn't have to worry about the value of /DeltaH/ during the + * second pass (thus we could skip pushing and popping /DeltaH/). + * What's the disadvantage that vitiates this clever idea? + */ +void +EndReflect() +{ + switch(State) { + case SIMULATING: + CurFont = SavedFont; + ResetFilePosition(SavedPosition); + State = REVERSE(SavedState); /* must precede MoveForward */ + PopXW(); /* must precede MoveForward */ + MoveForward(-DeltaH); + PushDeltaH(); + break; + case LTYPESETTING: case RTYPESETTING: + PopDeltaH(); + MoveForward(-DeltaH); + State = REVERSE(State); + break; + default: /* State >SIMULATING */ + State--; + } +} + + + +/* + * Move "forward" by /distance/. If we're simulating it's enough to + * accumulate /distance/ into the running total, otherwise we need a + * motion command in the output file. Now "forward" means "right" if + * typesetting normally, but "left" if typesetting right-to-left, so + * first we negate distance if we're in the latter mode. If we can + * accomplish this move with a simple W0 or X0 we do so. Otherwise, + * we use a RIGHTn with the smallest possible n. Notice that we + * test /distance/ against the *output* file's idea of W and X when + * trying for the short versions. These may not agree with W and X + * in the input file; see the two routines immediately following. + */ +void +MoveForward(distance) +long distance; +{ + unsigned bytes; + + if (State >= SIMULATING) { DeltaH += distance; return; } + if (State == RTYPESETTING) distance = -distance; + if (distance == WOutput) WriteByte(W0); + else if (distance == XOutput) WriteByte(X0); + else { + bytes = SignedBytes(distance); + WriteByte(RIGHT1 - 1 + bytes); + WriteNumber(distance, bytes); + } +} + + + +/* + * Process a command in the range W1..W4. The parameter has been + * already been read. We always need to set this distance into WInput, + * the input file's idea of W. If we're just simulating, just + * accumulate /distance/ into the current total and quit (the value of + * WOutput is irrelevant during simulation). If typesetting left-to- + * right, output a Wn command to move and set W in the output file. If + * typesetting right-to-left, the same, except we first negate + * /distance/. This means two things: first of all, we'll move the + * opposite direction in the output file as desired. Secondly, the + * value of W in the output file (recorded in /WOutput/) is the negative + * of its value in the input file. That way, upcoming W0 commands will + * be directly usable as long as we're typesetting backwards. + */ +void +SetWandMoveForward(distance) +long distance; +{ + unsigned bytes; + + WInput = WOutput = distance; + if (State >= SIMULATING) { DeltaH += distance; return; } + if (State == RTYPESETTING) WOutput = distance = -distance; + bytes = SignedBytes(distance); + WriteByte(W1 - 1 + bytes); + WriteNumber(distance, bytes); +} + + + +/* + * Don't even think of finding comments for this routine. Just look up + * at /SetWandMoveForward/, OK? + */ +void +SetXandMoveForward(distance) +long distance; +{ + unsigned bytes; + + XInput = XOutput = distance; + if (State >= SIMULATING) { DeltaH += distance; return; } + if (State == RTYPESETTING) XOutput = distance = -distance; + bytes = SignedBytes(distance); + WriteByte(X1 - 1 + bytes); + WriteNumber(distance, bytes); +} + + + +/* + * Process the postamble, having just read a POST command from the input + * file. Mostly we just copy the postamble into the output file, with a + * few exceptions: The previous page pointers and maximum stack depth may + * be different, and NOP commands are suppressed unless the -X flag was + * used. When we hit POST_POST, we finish off the file with four 223's + * and enough more so that the total file length is divisible by four. + * Note that ivd2dvi stops reading its input file after seeing the dvi + * version character here. As a consequence, it's always an error for + * the input file to come to EOF. + */ +void +Postliminaries() +{ + long i; + + if (VerboseOutput) fprintf(stderr, "[post]\n"); + WriteByte(POST); + SkipNBytes(4L); + WriteWord(PrevPagePointer); + PrevPagePointer = BytesOutput - 5; + CopyNBytes(20L); + MaxPushLevelOutput(); + CopyNBytes(2L); + while (CurCommand != POST_POST) { + CurCommand = ReadByte(); + switch (CurCommand) { + case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4: + CopyFontDefinition(ReadSigned(CurCommand - FNT_DEF1 + 1), + CurCommand - FNT_DEF1 + 1); + break; + case NOP: + if (ExactOutput) WriteByte(CurCommand); + break; + case POST_POST: + break; + default: + BadDVIAbort("unrecognized command in postamble"); + } + } + WriteByte(POST_POST); + SkipNBytes(4L); + WriteWord(PrevPagePointer); + if (CopyByte() != DVIVERSION) + BadDVIAbort("wrong DVI version in postamble"); + for (i = 7 - ((BytesOutput-1) % 4); i > 0; i--) WriteByte(DVIPADCHAR); +} + + + +/* + * Output the current command, then copy /bytes/ more bytes from the + * input file to the output file. Surprisingly useful. + */ +void +CopyParametrizedCommand(bytes) +unsigned bytes; +{ + WriteByte(CurCommand); + CopyNBytes((long) bytes); +} diff --git a/dviware/ivd2dvi/ivd2dvi.readme b/dviware/ivd2dvi/ivd2dvi.readme new file mode 100644 index 0000000000..82d286aa59 --- /dev/null +++ b/dviware/ivd2dvi/ivd2dvi.readme @@ -0,0 +1,9 @@ +Nothing very complicated here. Edit the Makefile to pick your C compiler +and flags, and fix the installation directory if you use "make install". +If your TFMs are not in /usr/lib/tex/fonts edit global.h to say where. +Thanks to Justin Bur of U de Montreal for converting the man page to the +right format. Send bugs and improvements. Good luck! + +/Larry Denenberg +larry@bbn.com, larry@harvard.edu + diff --git a/dviware/ivd2dvi/makefile b/dviware/ivd2dvi/makefile new file mode 100644 index 0000000000..cdaec45f31 --- /dev/null +++ b/dviware/ivd2dvi/makefile @@ -0,0 +1,22 @@ +# Set this variable to the ultimate location of the software. +BINAREA=/usr/local/bin + +CFLAGS = -O + +OBJS = ivd2dvi.o auxiliary.o io.o +SRCS = ivd2dvi.c auxiliary.c io.c +INCLUDES = global.h commands.h + +all: ivd2dvi + +ivd2dvi: ${OBJS} + cc ${CFLAGS} -o ivd2dvi ${OBJS} + +${OBJS}: ${INCLUDES} + +install: all + install -s -m 755 ivd2dvi ${BINAREA} + +bugs: ${SRCS} ${INCLUDES} + rm -f bugs + lint -hbxac ${SRCS} > bugs |