/*****************************************************************************/ /* */ /* dvimfj --- generates an MFJOB program from a .dvi file. */ /* */ /*****************************************************************************/ #include #include #include "commands.h" #if defined(MSDOS) #include #include #include #include #endif #define LASTCHAR 127 /* max dvi character, above are commands */ #define get1() num(1) #define get2() num(2) #define get3() num(3) #define get4() num(4) #define sget1() snum(1) #define sget2() snum(2) #define sget3() snum(3) #define sget4() snum(4) typedef struct{ char *name; char *mag; int base; int mode; } FONTDEF; typedef struct{ char *pattern; int base; int mode; } FONTPAT; #define MaxBAidx 10 /* maximum number of bases (plain, cm, etc.) */ #define MaxMOidx 10 /* maximum number of modes (lj, fx, etc.) */ int FDsize, FDidx; FONTDEF **Fontdefs; int FPsize, FPidx; FONTPAT **FPatterns; int BAidx; char *BAses[MaxBAidx]; int MOidx; char *MOdes[MaxMOidx]; int Nomfj; char *Inputmodes, *MFjobcmd, *Outname="dvimfj.mfj"; FILE * dvifp; char * dvi_name; long pc; long Numerator, Denominator, Magnification; double Scale = 1; char * realloc (); void main (); void read_dvi_file (); void bop (); void preamble (); void postamble (); void postpostamble (); void fontdef (); void special (); unsigned long num (); long snum (); void addfontdef (); void * Realloc (); char * Strdup (); void read_config_file (); void read_config_80 (); void addpatterndef (); void write_mfj (); void run_mfjob (); /*---------------------------------------------------------------------------*/ void main(argc, argv) int argc; char **argv; { register int i, jx; long scale; if (argc < 2) { usage: printf("\nUsage: %s dvifile [magstep] [no]\n", *argv); printf("\tFonts scaled (1.2^magstep) or (magstep/1000).\n" "\tNo MFjob spawn.\n"); exit(1); } else{ if ((i = strlen(argv[1])) == 0) { printf("Illegal empty filename\n"); exit(2); } if ((i >= 5) && !strcmpi(argv[1]+i-4, ".dvi")) dvi_name = argv[1]; else { dvi_name = Realloc(0, (i+5) * sizeof(char)); strcpy(dvi_name, argv[1]); strcat(dvi_name, ".dvi"); } if ((dvifp = fopen(dvi_name, "rb")) == NULL) { printf("Cant open %s\n", dvi_name); exit(3); } if (argc > 2){ for (jx = 2; jx < argc; jx++){ if ('N' == toupper(argv[jx][0])){ Nomfj = 1; continue; } scale = 0; if (1 > sscanf(argv[jx], " %ld", &scale)) goto usage; if (scale > 30) Scale = scale/1000.f; else Scale = pow((double)1.2, (double)scale); } } } read_config_file(argv[0]); read_dvi_file(); write_mfj(); run_mfjob(); exit(0); } /* main */ void read_dvi_file() { int opcode; while ((opcode = (int) get1()) != EOF) { /* process until end of file */ if ((opcode <= LASTCHAR) && isprint(opcode)) { while ((opcode <= LASTCHAR) && isprint(opcode)) { opcode = (int) get1(); } } if (opcode <= LASTCHAR) ; else if ((opcode >= FONT_00) && (opcode <= FONT_63)) ; else switch (opcode) { case SET1 : case SET2 : case SET3 : case SET4 : num(opcode - SET1 + 1); break; case SET_RULE : sget4(); sget4(); break; case PUT1 : case PUT2 : case PUT3 : case PUT4 : num(opcode - PUT1 + 1); break; case PUT_RULE : sget4(); sget4(); case NOP : break; case BOP : bop(); break; case EOP : case PUSH : case POP : break; case RIGHT1 : case RIGHT2 : case RIGHT3 : case RIGHT4 : snum(opcode - RIGHT1 + 1); case W0 : break; case W1 : case W2 : case W3 : case W4 : snum(opcode - W0); case X0 : break; case X1 : case X2 : case X3 : case X4 : snum(opcode - X0); break; case DOWN1 : case DOWN2 : case DOWN3 : case DOWN4 : snum(opcode - DOWN1 + 1); case Y0 : break; case Y1 : case Y2 : case Y3 : case Y4 : snum(opcode - Y0); case Z0 : break; case Z1 : case Z2 : case Z3 : case Z4 : snum(opcode - Z0); break; case FNT1 : case FNT2 : case FNT3 : case FNT4 : num(opcode - FNT1 + 1); break; case XXX1 : case XXX2 : case XXX3 : case XXX4 : special(opcode - XXX1 + 1); break; case FNT_DEF1 : case FNT_DEF2 : case FNT_DEF3 : case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break; case PRE : preamble(); break; case POST : postamble(); break; case POST_POST: postpostamble(); break; } } } /* read_dvi_file */ /*----------------------------------------------------------------------------*/ void bop() { int i; for (i=0; i < 11; i++) get4(); } /* bop */ /*---------------------------------------------------------------------------*/ void postamble() { sget4(); if (Numerator != get4() || Denominator != get4() || Magnification != get4()){ printf("Postamble does not match preamble\n"); exit(3); } get4(); get4(); get2(); get2(); } /* postamble */ void preamble() { long ix; get1(); Numerator = get4(); Denominator = get4(); Magnification = get4(); ix = (long)(Scale*1000); /* truncate at third decimal place */ Scale = ((double)ix)/1000; printf("\nmagnification: %ld scale: %05.3f\n\n", Magnification, Scale); get1(); } /* preamble */ void postpostamble() { register int i; get4(); get1(); while ((i = (int) get1()) == TRAILER) ; while (i != EOF) { printf("%06ld: ", pc - 1); printf("BAD DVI FILE END: 0x%02X\n", i); i = (int) get1(); } } /* postpostamble */ void special(x) register int x; { register long len; register long i; len = num(x); for (i = 0; i < len; i++) get1(); } /* special */ void fontdef(x) register int x; { register int ix, jx; long scale, design; double mag; char fontname[10], fontmag[10]; num(x); get4(); scale = get4(); design = get4(); if (0==design) mag = -1; else{ mag = (double)scale/(double)design; mag = Scale*Magnification*mag/1000; } sprintf(fontmag, "%07.3f", mag); ix = (int) get1() + (int) get1(); #if defined(MSDOS) #define LIMIT8 && jx < 8 #else #define LIMIT8 #endif for (jx=0; jx < ix LIMIT8; jx++) fontname[jx] = (char) get1(); fontname[jx] = 0; for (; jx < ix; jx++) get1(); addfontdef(fontname, fontmag); } /* fontdef */ unsigned long num(size) register int size; { register int i; register long x = 0; pc += size; for (i = 0; i < size; i++) x = (x << 8) + (unsigned) getc(dvifp); return x; } /* num */ long snum(size) register int size; { register int i; register long x = 0; pc += size; x = getc(dvifp); if (x & 0x80) x -= 0x100; for (i = 1; i < size; i++) x = (x << 8) + (unsigned) getc(dvifp); return x; } /* snum */ void addfontdef(name, mag) char *name, *mag; { int ix, jx, found, base, mode; char *pat; if (FDsize < 2+FDidx){ FDsize = 30+FDidx; Fontdefs = Realloc(Fontdefs, FDsize * sizeof Fontdefs[0]); } for (ix=0; ix < FDidx; ix++){ if (!strcmp(Fontdefs[ix]->name, name) && !strcmp(Fontdefs[ix]->mag, mag)){ return; } } for (found=ix=0; ix < FPidx; ix++){ pat = FPatterns[ix]->pattern; for (jx=0; pat[jx] && pat[jx]==name[jx]; jx++); if (pat[jx]=='*' || !strcmp(pat, name)){ base = FPatterns[ix]->base; mode = FPatterns[ix]->mode; found = 1; break; } } if (!found){ printf("Font %s not found in .CFG file\n", name); exit(3); } Fontdefs[FDidx] = Realloc(NULL, sizeof(FONTDEF)); Fontdefs[FDidx]->name = Strdup(name); Fontdefs[FDidx]->mag = Strdup(mag); Fontdefs[FDidx]->base = base; Fontdefs[FDidx]->mode = mode; FDidx++; printf("font: %-8s mag: %s base: %-8s mode: %s\n", name, mag, BAses[base], MOdes[mode]); } /* addfontdef */ void *Realloc(ptr, size) void *ptr; int size; { void *outpntr; if (size < 0) exit(11); outpntr = realloc(ptr, size); if (0==outpntr){ printf("Memory error\n"); exit(4); } return outpntr; } /* Realloc */ char *Strdup(str) char *str; { char *newstr; newstr = strdup(str); if (0==newstr){ printf("Strdup error\n"); exit(4); } return newstr; } /* Strdup */ char Buf80[81]; FILE *Cfp; void read_config_file(name) char *name; { int ix, sl; sl = strlen(name); if (sl >= (80-5)) exit(10); strcpy(Buf80, name); for (ix = sl-1; ix > 0 && ix > sl-5; ix--){ if (Buf80[ix]=='.'){ strcpy(Buf80+ix+1, "CFG"); Cfp = fopen(Buf80, "r"); if (0==Cfp){ printf("Can't open %s\n", Buf80); exit(3); } read_config_80(); MFjobcmd = Strdup(Buf80); read_config_80(); Inputmodes = Strdup(Buf80); for (;;){ read_config_80(); if (!strcmp(Buf80, "*end")){ fclose(Cfp); return; } if (!strcmp(Buf80, "*base")){ read_config_80(); BAses[BAidx++] = Strdup(Buf80); if (BAidx >= MaxBAidx){ printf("Too many bases\n"); exit(3); } continue; } if (!strcmp(Buf80, "*mode")){ read_config_80(); MOdes[MOidx++] = Strdup(Buf80); if (MOidx >= MaxMOidx){ printf("Too many modes\n"); exit(3); } continue; } if (!BAidx){ printf("Missing *base command\n"); exit(3); } if (!MOidx){ printf("Missing *mode command\n"); exit(3); } addpatterndef(Buf80, BAidx-1, MOidx-1); } } } printf("Missing *end command\n"); exit(3); } /* read_config_file */ void read_config_80() { if (1==fscanf(Cfp, " %80s", Buf80)) return; printf("Can't read config file\n"); exit(3); } void addpatterndef(pattern, base, mode) char *pattern; int base, mode; { if (FPsize < 2+FPidx){ FPsize = 10+FPidx; FPatterns = Realloc(FPatterns, FPsize * sizeof FPatterns[0]); } FPatterns[FPidx] = Realloc(NULL, sizeof(FONTDEF)); FPatterns[FPidx]->pattern = Strdup(pattern); FPatterns[FPidx]->base = base; FPatterns[FPidx]->mode = mode; FPidx++; } /* addpatterndef */ void write_mfj() { int ix, jx, mx, nx, flag; FILE *fp; fp = fopen(Outname, "w"); if (0==fp){ printf("Can't create %s\n", Outname); exit(3); } fprintf(fp, "%s\n", Inputmodes); for (mx=0; mx < MOidx; mx++){ for (jx=0; jx < BAidx; jx++){ flag = 0; for (ix=0; ix < FDidx; ix++){ if (mx != Fontdefs[ix]->mode) continue; if (jx != Fontdefs[ix]->base) continue; if (!flag){ fprintf(fp, "{\n base=%s;\n %s;\n", BAses[jx], MOdes[mx]); flag = 1; } nx = fprintf(fp, " { font=%s;", Fontdefs[ix]->name); fprintf(fp, "%*smag=%s; }\n", 21-nx, " ", Fontdefs[ix]->mag); } if (flag) fprintf(fp, "}\n"); } } fclose(fp); } /* write_mfj */ void run_mfjob() { int retcode; if (Nomfj) return; printf("\nSpawning %s %s\n\n", MFjobcmd, Outname); retcode = spawnl(P_WAIT, MFjobcmd, MFjobcmd, Outname, NULL); if (0==retcode){ printf("\nDeleting %s\n", Outname); unlink(Outname); } } /* run_mfjob */ /* ================================================================================ == DVI file format == ================================================================================ no_ops >= 0 bytes (NOP, nops before the preamble) preamble_marker 1 ubyte (PRE) version_id 1 ubyte (should be version 2) numerator 4 ubytes (numerater must equal the one in postamble) denominator 4 ubytes (denominator must equal the one in postamble) magnification 4 ubytes (magnification must equal the one in postamble) id_len 1 ubyte (lenght of identification string) id_string id_len ubytes (identification string) no_ops >= 0 bytes (NOP, nops before a page) begin_of_page 1 ubyte (BOP) page_nr 4 sbytes (page number) do_be_do 36 bytes (filler ????) prev_page_offset 4 sbytes (offset in file where previous page starts, -1 for none) ... PAGE DATA ... end_of_page 1 ubyte (EOP) no_ops ??? >= 0 bytes (NOPS, I think they are allowed here...) postamble_marker 1 ubyte (POST) last_page_offset 4 sbytes (offset in file where last page starts) numerator 4 ubytes (numerater must equal the one in preamble) denominator 4 ubytes (denominator must equal the one in preamble) magnification 4 ubytes (magnification must equal the one in preamble) max_page_height 4 ubytes (maximum page height) max_page_width 4 ubytes (maximum page width) max_stack 2 ubytes (maximum stack depth needed) total_pages 2 ubytes (number of pages in file) ... FONT DEFINITIONS ... postamble_offset 4 sbytes (offset in file where postamble starts) version_id 1 ubyte (should be version 2) trailer >= 4 ubytes (TRAILER) FONT DEFINITIONS: do { switch (c = getc(dvi_fp) { case FNTDEF1 : case FNTDEF2 : case FNTDEF3 : case FNTDEF4 : define_font(c); case POSTPOST : break; default : error; } } while (c != POSTPOST); ===== A font def looks like: 1,2,3 or 4 ubytes TeXfontnumber for FNTDEF1 .. FNTDEF4 4 ubytes checksum 4 ubytes scale 4 ubytes design size 1 byte deflen1 1 byte deflen2 deflen1 + deflen2 bytes fontname. ===== A special looks like: 1,2,3 or 4 ubytes telling length of special command for XXX1 .. XXX4 all bytes in the special command are used as defined in the dvi driver. */