Back to index

tetex-bin  3.0
dmp.c
Go to the documentation of this file.
00001 /****************************************************************
00002 Copyright 1990 - 1995 by AT&T Bell Laboratories.
00003 
00004 Permission to use, copy, modify, and distribute this software
00005 and its documentation for any purpose and without fee is hereby
00006 granted, provided that the above copyright notice appear in all
00007 copies and that both that the copyright notice and this
00008 permission notice and warranty disclaimer appear in supporting
00009 documentation, and that the names of AT&T Bell Laboratories or
00010 any of its entities not be used in advertising or publicity
00011 pertaining to distribution of the software without specific,
00012 written prior permission.
00013 
00014 AT&T disclaims all warranties with regard to this software,
00015 including all implied warranties of merchantability and fitness.
00016 In no event shall AT&T be liable for any special, indirect or
00017 consequential damages or any damages whatsoever resulting from
00018 loss of use, data or profits, whether in an action of contract,
00019 negligence or other tortious action, arising out of or in
00020 connection with the use or performance of this software.
00021 ****************************************************************/
00022 
00023 /* This program reads device-independent troff output files,
00024    and converts them into a symbolic form understood by MetaPost.  Some
00025    of the code was borrowed from DVItoMP.  It understands all the D? graphics
00026    functions that dpost does but it ignores `x X' device control functions
00027    such as `x X SetColor:...', `x X BeginPath:', and `x X DrawPath:...'.
00028 
00029    The output file is a sequence of MetaPost picture expressions, one for every
00030    page in the input file.  It makes no difference where the input file comes
00031    from, but it is intended to process the result of running eqn and troff on
00032    the output of MPtoTR.  Such a file contains one page for every btex...etex
00033    block in the original input.  This program then creates a corresponding
00034    sequence of MetaPost picture expressions for use as an auxiliary input file.
00035    Since MetPost expects such files to have the extension .mpx, the output
00036    is sometimes called an `mpx' file.
00037 
00038    The |banner| string defined here should be changed whenever this program
00039    gets modified.
00040 */
00041 char *banner="% Written by DMP, Version 0.64";   /* first line of output */
00042 char *term_banner="This is DMP, Version 0.64";
00043 
00044 #include "config.h"
00045 #include <kpathsea/c-proto.h>
00046 #include <kpathsea/tex-file.h>
00047 #include <kpathsea/c-ctype.h>
00048 #include <kpathsea/c-pathch.h>
00049 #include <math.h>
00050 
00051 /* From ../cpascal.h */
00052 extern void printversionandexit P3H(const_string, const_string, const_string);
00053 
00054 #ifndef PI
00055 #define PI  3.14159265358979323846
00056 #endif
00057 
00058 #define POOLMAX      65000  /* total characters in all font and char names */
00059 #define FCOUNT       100    /* maximum number of fonts */
00060 #define SHIFTS       100    /* maximum number of characters with special shifts */
00061 #define line_length 79      /* maximum output line length (must be at least 60) */
00062 #define Hprime       2459   /* much bigger than max(chars/font,fonts/job) */
00063 #define MAXCHARS 2048       /* character codes fall in the range 0..MAXCHARS-1 */
00064 #define LLENGTH 1024 /* one more than maximum line length for troff output */
00065 
00066 #define is_specchar(c)      (c<=2) /* does charcode c identify a special char? */
00067 #define LWscale      0.03   /* line width for graphics as a fraction of pointsize */
00068 #define YCORR 12.0   /* V coordinate of reference point in (big) points */
00069 
00070 char strpool[POOLMAX];             /* text for font names and char names */
00071 int poolsize = 0;           /* chars used so far in strpool */
00072 
00073 char *texname[FCOUNT];             /* TeX names (null-terminated strings) */
00074 int font_num[FCOUNT];              /* external font numbers */
00075 float font_design_size[FCOUNT];    /* design size in TeX points */
00076 struct hcell *charcodes[FCOUNT];/* hash tables for translating char names */
00077 int next_specfnt[FCOUNT];   /* used to link special fonts together */
00078 float charwd[FCOUNT][MAXCHARS];    /* width/ptsize indexed [font num][char code] */
00079 int nfonts;                 /* no. of internal font nums (texname indices)*/
00080 int shiftchar[SHIFTS];             /* charcode of character to shift, else -1 */
00081 float shifth[SHIFTS],shiftv[SHIFTS];      /* shift vals/fontsize (y is upward) */
00082 int shiftptr = 0;           /* number of entries in shift tables */
00083 int shiftbase[FCOUNT];             /* initial index into shifth,shiftv,shiftchar */
00084 int specfnt = FCOUNT;              /* int. num. of first special font (or FCOUNT)*/
00085 int *specf_tail = &specfnt; /* tail of specfnt list (*specf_tail==FCOUNT) */
00086 FILE *trf;                  /* the input file (troff output) */
00087 FILE *mpxf;                 /* the output file */
00088 struct hcell *trfonts;             /* hash tab for internal nums of troff fonts */
00089 float unit = 0.0;           /* (big) points per troff unit (0 when unset)*/
00090 int h,v;                    /* current position in tr. units (v downward)*/
00091 float cursize;                     /* current type size in (big) points */
00092 int curfont;                /* internal number for current font */
00093 float Xslant;               /* degrees additional slant for all fonts */
00094 float Xheight;                     /* yscale fonts to this height if nonzero */
00095 char *dbname = "trfonts.map";      /* file for table of troff & TFM font names */
00096 char *adjname = "trchars.adj";     /* file for character shift amounts */
00097 #define tfmpath kpse_tfm_format
00098 #define dbpath kpse_mpsupport_format
00099 #define trpath kpse_troff_font_format
00100 int lnno = 0;               /* line num. in troff output file (our input) */
00101 
00102 
00103 void quit P3C(char*,msg1,char*,msg2,char*,msg3)
00104 {
00105     fprintf(stderr,"DMP abort at troff output line %d:\n%s%s%s\n",
00106        lnno, msg1, msg2, msg3);
00107     exit(1);
00108 }
00109 
00110 void warn P3C(char*,msg1,char*,msg2,char*,msg3)
00111 {
00112     fprintf(stderr,"DMP warning at troff output line %d:\n%s%s%s\n",
00113        lnno, msg1, msg2, msg3);
00114 }
00115 
00116 void add_to_pool P1C(char,c)
00117 {
00118     if (poolsize==POOLMAX) quit("Need to increase POOLMAX","","");
00119     else strpool[poolsize++] = c;
00120 }
00121 
00122 
00123 
00124 
00125 /**************************************************************
00126                      Hash tables
00127 ***************************************************************/
00128 
00129 typedef struct hcell {
00130     char* lab;
00131     int datum;
00132 } Hcell;
00133 
00134 #define new_htab   (Hcell*) calloc((unsigned)Hprime, (unsigned)sizeof(Hcell))
00135 
00136 
00137 int hash P1C(char*,s)
00138 {
00139     register int r;
00140     for(r=0; *s!=0; s++) {
00141         /* GROFF - in font metrics file the character name may be 8bit
00142            groff_font(5): Groff supports eight bit characters;
00143            groff_out(5): Note that single characters can have the
00144                eighth  bit  set, as can the names of fonts and special
00145                characters.
00146         */
00147        r = (r<<1) + *(unsigned char*)s;
00148        while (r>=Hprime) r-=Hprime;
00149     }
00150     return r;
00151 }
00152 
00153 
00154 /* Find or insert the given string in the hash table and return the address
00155    of the datum.
00156 */
00157 Hcell *failure;                    /* null unless last hfind failed (used below) */
00158 
00159 int *hfind P2C(char*,s,Hcell*,htab)
00160 {
00161     register Hcell *p;
00162     register int cnt = Hprime;
00163     failure = (Hcell *) 0;
00164     p = &htab[hash(s)];
00165     do {
00166        if (p->lab==NULL) {
00167            failure = p;
00168            if (s<&strpool[0] || s>=&strpool[POOLMAX]) {
00169               p->lab = &strpool[poolsize];
00170               do add_to_pool(*s); while (*s++!='\0');
00171            } else p->lab = s;
00172            return &p->datum;
00173        }
00174        if (strcmp(s, p->lab)==0) return &p->datum;
00175        if (p==htab) p= &htab[Hprime-1];
00176        else p--;
00177     } while (--cnt >= 0);
00178     quit("Need to increase Hprime","","");
00179     return (int*)0;         /* keep lint happy */
00180 }
00181 
00182 
00183 /* If the last hfind() failed, undo the insertion and return zero (FALSE).
00184 */
00185 int hfound()
00186 {
00187     if (failure==(Hcell *)0) return 1;
00188     failure->lab = NULL;
00189     return 0;
00190 }
00191 
00192 
00193 
00194 /**************************************************************
00195                      Search Paths
00196 ***************************************************************/
00197 
00198 FILE *fsearch P3C(char*,nam, char*,ext, kpse_file_format_type,format)
00199 {
00200     FILE *f = NULL;
00201     
00202     string fname = kpse_find_file (nam, format, true);
00203     const_string mode = kpse_format_info[format].binmode
00204                         ? FOPEN_RBIN_MODE
00205                         : FOPEN_R_MODE;
00206     if (fname) {
00207       f = xfopen (fname, mode);
00208     }
00209     if (f==NULL) quit("Cannot find ",nam,ext);
00210     return f;
00211 }
00212 
00213 
00214 
00215 /**************************************************************
00216                      Scanning Numbers
00217 ***************************************************************/
00218 
00219 /* The standard functions atoi(), atof(), and sscanf() provide ways of reading
00220    numbers from strings but they give no indication of how much of the string
00221    is consumed.  These homemade versions don't parse scientific notation.
00222 */
00223 char *arg_tail;        /* char after the number just gotten; NULL on failure */
00224 
00225 
00226 int get_int P1C(char *,s)
00227 {
00228     register int i, d, neg;
00229     if (s==NULL) goto bad;
00230     for (neg=0;; s++)
00231        if (*s=='-') neg=!neg;
00232        else if (*s!=' ' && *s!='\t') break;
00233     if (i= *s-'0', 0>i||i>9) goto bad;
00234     while (d= *++s-'0', 0<=d&&d<=9)
00235        i = 10*i + d;
00236     arg_tail = s;
00237     return neg ? -i : i;
00238 bad:arg_tail = NULL;
00239     return 0;
00240 }
00241 
00242 /* GROFF font description files use octal character codes
00243    groff_font(5): The code can be any integer.  If it starts with
00244        a 0 it will be interpreted as octal; if it starts with  0x
00245        or 0X it will be intepreted as hexadecimal.
00246 */
00247 int get_int_map P1C(char *,s)
00248 {
00249     register int i;
00250     if (s==NULL) goto bad;
00251     i=strtol(s,&arg_tail,0);
00252     if (s==arg_tail) goto bad;
00253     return i;
00254 bad:arg_tail = NULL;
00255     return 0;
00256 }
00257 
00258 /* Troff output files contain few if any non-integers, but this program is
00259    prepared to read floats whenever they seem reasonable; i.e., when the
00260    number is not being used for character positioning.  (For non-PostScript
00261    applications h and v are usually in pixels and should be integers.)
00262 */
00263 float get_float P1C(char *,s)
00264 {
00265     register int d, neg, digits;
00266     register float x, y;
00267 
00268     digits = 0;
00269     if (s!=NULL) {
00270        for (neg=0;; s++)
00271            if (*s=='-') neg=!neg;
00272            else if (*s!=' ' && *s!='\t') break;
00273        x = 0.0;
00274        while (d= *s-'0', 0<=d&&d<=9) {
00275            x = 10.0*x + d;
00276            digits++; s++;
00277        }
00278        if (*s=='.') {
00279            y = 1.0;
00280            while (d= *++s-'0', 0<=d&&d<=9) {
00281               y /= 10.0;
00282               x += y*d;
00283               digits++;
00284            }
00285        }
00286     }
00287     if (digits==0) {
00288        arg_tail = NULL;
00289        return 0.0;
00290     }
00291     arg_tail = s;
00292     return neg ? -x : x;
00293 }
00294 
00295 /* GROFF font description files have metrics field
00296    of comma-separated integers. Traditional troff
00297    have a float in this position. The value is not
00298    used anyway - thus just skip the value,
00299    eat all non-space chars.
00300 */
00301 float get_float_map P1C(char *,s)
00302 {
00303     if (s!=NULL) {
00304         while (isspace(*s))
00305             s++;
00306         while (!isspace(*s) && *s)
00307             s++;
00308     }
00309     arg_tail = s;
00310     return 0;
00311 }
00312 
00313 /**************************************************************
00314               Reading Initialization Files
00315 ***************************************************************/
00316 
00317 /* Read the database file, reserve internal font numbers and set
00318    the texname[] entries.  Each line in the database file contains
00319    <troff-name>\t,PostScript-name>\t<TeX-name>
00320    or just <troff-name>\t,PostScript-name> if the TeX name matches the
00321    PostScript name. ("\t" means one or more tabs.)
00322 */
00323 
00324 void read_fmap P1C(char*,dbase)
00325 {
00326     FILE *fin;
00327     int c;                  /* last character read */
00328     char *nam;                     /* a font name being read */
00329 
00330     nfonts = 0;
00331     fin = fsearch(dbase,"",dbpath);
00332     trfonts = new_htab;
00333     while ((c=getc(fin))!=EOF) {
00334        if (nfonts==FCOUNT) quit("Need to increase FCOUNT","","");
00335        nam = &strpool[poolsize];
00336        for (;c!='\t'; c=getc(fin)) add_to_pool(c);
00337        add_to_pool(0);
00338        *hfind(nam, trfonts) = nfonts;
00339        texname[nfonts] = &strpool[poolsize];
00340        do {
00341            poolsize = texname[nfonts] - strpool;
00342            do c=getc(fin); while (c=='\t');
00343            for (;c!='\t' && c!='\n'; c=getc(fin))
00344               add_to_pool(c);
00345            add_to_pool(0);
00346        } while (c=='\t');
00347        font_num[nfonts] = -1;             /* indicate font is not mounted */
00348        nfonts++;
00349     }
00350     fclose(fin);
00351 }
00352 
00353 
00354 /* Some characters need their coordinates shifted in order to agree with
00355    troff's view of the world.  Logically, this information belongs in the
00356    font description files but it actually resides in a PostScript prolog
00357    that the troff output processor dpost reads.  Since that file is in
00358    PostScript and subject to change, we read the same information from
00359    a small auxiliary file that gives shift amounts relative to the font
00360    size with y upward.
00361 */
00362 /* GROFF NOTE:
00363    The PostScript prologue in GNU groff's font directory does not
00364    contain any character shift information, so the following function
00365    becomes redundant.  Simply keeping an empty "trchars.adj" file
00366    around will do fine without requiring any changes to this program.
00367 */
00368 void read_char_adj P1C(char*,adjfile)
00369 {
00370     FILE* fin;
00371     char buf[200];
00372     int i;
00373 
00374     fin = fsearch(adjfile, "", dbpath);
00375     for (i=0; i<nfonts; i++)
00376        shiftbase[i] = 0;
00377     while (fgets(buf,200,fin)!=NULL) {
00378        if (shiftptr==SHIFTS-1) quit("Need to increase SHIFTS","","");
00379        if (buf[0]!=' ' && buf[0]!='\t') {
00380            for (i=0; buf[i]!='\0'; i++)
00381               if (buf[i]=='\n') buf[i]='\0';
00382            shiftchar[shiftptr++] = -1;
00383            shiftbase[*hfind(buf,trfonts)] = shiftptr;
00384            if (!hfound()) quit(adjfile," refers to unknown font ",buf);
00385        } else {
00386            shiftchar[shiftptr] = get_int(buf);
00387            shifth[shiftptr] = get_float(arg_tail);
00388            shiftv[shiftptr] = -get_float(arg_tail);
00389            if (arg_tail==NULL) quit("Bad shift entry : \"",buf,"\"");
00390            shiftptr++;
00391        }
00392     }
00393     shiftchar[shiftptr++] = -1;
00394     fclose(fin);
00395 }
00396 
00397 
00398 /**************************************************************
00399                      Reading Font Files
00400 ***************************************************************/
00401 
00402 
00403 /* Read the TFM file for the font with internal number f, updating the
00404    data structures appropriately.  We get the character widths out of the
00405    tfm file instead of the troff font description file because they don't
00406    because the latter source reflects alterations made only by dpost (the
00407    troff output driver that is bypassed when using MetaPost).
00408 */
00409 void read_tfm P1C(int, f)
00410 {
00411     FILE* tf;
00412     long a = 0;
00413     int sizes[5];    /* file & header lengths, bc, ec, words in wd table */
00414     long wd[256];    /* the width table (font size relative, scaled 2^20) */
00415     int i, j;
00416     long wtmp;              /* needed to a floating exception on certain machines */
00417 
00418     tf = fsearch(texname[f], ".tfm", tfmpath);
00419     for (i=0; i<5; i++) {
00420        sizes[i] = getc(tf);
00421        sizes[i] = (sizes[i]<<8) | (getc(tf) & 0377);
00422     }
00423     if (sizes[1]<2 || sizes[2]<0 || sizes[3]<sizes[2]-1 || sizes[3]>255
00424            || sizes[0]<sizes[1]+sizes[3]-sizes[2]+sizes[4]+7)
00425        quit("Bad tfm file: ",texname[f],".tfm");
00426     for (i=2*5; i<28; i++)
00427        (void) getc(tf);
00428     for (i=0; i<4; i++)
00429        a = (a<<8) | (long) (getc(tf) & 0377);
00430     font_design_size[f] = ((float) a)/1048576.0;
00431     fseek(tf, (long)(28+4*(sizes[1]+sizes[3]-sizes[2])), 0);
00432     for (i=0; i<sizes[4]; i++) {
00433        wd[i] = 0L;
00434        for (j=0; j<4; j++)
00435            wd[i] = (wd[i]<<8) | (long) (getc(tf) & 0377);
00436     }
00437     fseek(tf, (long)(24+4*sizes[1]), 0);
00438     for (i=sizes[2]; i<=sizes[3]; i++) {
00439        wtmp = wd[getc(tf) & 0377];
00440        charwd[f][i] = ((double) wtmp)/1048576.0/unit;
00441        for (j=3; --j>=0;)  (void) getc(tf);
00442     }
00443     fclose(tf);
00444 }
00445 
00446 
00447 /* Given one line from the character description file for the font with
00448    internal number f, save the appropriate data in the charcodes[f] table.
00449    A return value of zero indicates a syntax error.
00450 */
00451 /* GROFF NOTE:
00452    GNU groff uses an extended font description file format documented
00453    in groff_font(5).  In order to allow parsing of groff's font files,
00454    this function needs to be rewritten as follows:
00455 
00456    1. The `metrics' field parsed by "get_float(lin);" may include
00457       a comma-separated list of up to six decimal integers rather
00458       than just a single floating-point number.
00459 
00460    2. The `charcode' field parsed by "lastcode = get_int(arg_tail);"
00461       may be given either in decimal, octal, or hexadecimal format.
00462 */
00463 int scan_desc_line P2C(int,f, char*,lin)
00464 {
00465     static int lastcode;
00466     char *s;
00467 
00468     s = &strpool[poolsize];
00469     while (*lin!=' ' && *lin!='\t' && *lin!='\0')
00470        add_to_pool(*lin++);
00471     add_to_pool('\0');
00472     while (*lin==' ' || *lin=='\t') lin++;
00473     if (*lin=='"')
00474        *hfind(s,charcodes[f]) = lastcode;
00475     else {
00476        (void) get_float_map(lin);
00477        (void) get_int(arg_tail);
00478        lastcode = get_int_map(arg_tail);
00479        if (arg_tail==NULL) return 0;
00480        *hfind(s,charcodes[f]) = lastcode;
00481        if (lastcode<0 || lastcode>=MAXCHARS) return 0;
00482     }
00483     return 1;
00484 }
00485 
00486 /* Read the font description file for the font with the given troff name
00487    and update the data structures.  The result is the internal font number.
00488 */
00489 int read_fontdesc P1C(char*,nam)
00490 {
00491     char buf[200];
00492     FILE* fin;                     /* input file */
00493     int f;                  /* internal font number */
00494 
00495     if (unit==0.0) quit("Resolution is not set soon enough","","");
00496     f = *hfind(nam, trfonts);
00497     if (!hfound())
00498        quit("Font was not in map file","","");
00499     fin = fsearch(nam, "", trpath);
00500     for (;;) {
00501        if (fgets(buf,200,fin)==NULL)
00502            quit("Description file for ",nam," ends unexpectedly");
00503        if (strncmp(buf,"special",7)==0) {
00504            *specf_tail = f;
00505            next_specfnt[f] = FCOUNT;
00506            specf_tail = &next_specfnt[f];
00507        } else if (strncmp(buf,"charset",7)==0)
00508            break;
00509     }
00510     charcodes[f] = new_htab;
00511     while (fgets(buf,200,fin)!=NULL)
00512        if (scan_desc_line(f, buf) == 0)
00513            quit(nam," has a bad line in its description file: ",buf);
00514     fclose(fin);
00515     return f;
00516 }
00517 
00518 
00519 
00520 /**************************************************************
00521               Low Level Output Routines
00522 ***************************************************************/
00523 
00524 /* One of the basic output operations is to write a \MP\ string expression for
00525    a sequence of characters to be typeset.  The main difficulties are that such
00526    strings can contain arbitrary eight-bit bytes and there is no fixed limit on
00527    the length of the string that needs to be produced.  In extreme cases this
00528    can lead to expressions such as
00529        char7&char15\&char31&"?FWayzz"
00530        &"zzaF"&char15&char3&char31
00531        &"Nxzzzzzzzwvtsqo"
00532 
00533    A global variable state keeps track of the output process.
00534    When state=normal we have begun a quoted string and the next character
00535    should be a printable character or a closing quote.  When state=special
00536    the last thing printed was a `char' construction or a closing quote
00537    and an ampersand should come next.  The starting condition state=initial
00538    is a lot like state=special, except no ampersand is required.
00539 */
00540 #define special      0      /* the state after printing a `char' expression */
00541 #define normal       1      /* the state value in a quoted string */
00542 #define initial      2      /* initial state */
00543 
00544 int state = initial;
00545 int print_col = 0;   /* there are at most this many characters on the current line */
00546 
00547 
00548 /* To print a string on the MPX file, initialize print_col, ensure that
00549    state=initial, and pass the characters one-at-a-time to print_char.
00550 */
00551 void print_char P1C(char,cc)
00552 {
00553     int printable;   /* nonzero if it is safe to print c */
00554     int l;           /* number of chars in c or the `char' expression */
00555     int c;           /* equal to cc mod 256, but always positive */
00556 
00557     c = cc&0377;
00558     printable = isprint(c) && c<128;      /* avoid high-bit-on Latin-1 chars */
00559     if (printable) l=1;
00560     else if (c<10) l=5;
00561     else if (c<100) l=6;
00562     else l=7;
00563     if (print_col+l>line_length-2) {
00564        if (state==normal) {
00565            putc('"',mpxf);
00566            state = special;
00567        }
00568        putc('\n',mpxf);
00569        print_col = 0;
00570     }
00571     if (state==normal)
00572        if (printable) putc(c,mpxf);
00573        else {
00574            fprintf(mpxf,"\"&char%d",c);
00575            print_col += 2;
00576        }
00577     else {
00578        if (state==special) {
00579            putc('&',mpxf);
00580            print_col++;
00581        }
00582        if (printable) {
00583            fprintf(mpxf,"\"%c",c);
00584            print_col++;
00585        } else
00586            fprintf(mpxf,"char%d",c);
00587     }
00588     print_col += l;
00589     state = printable ? normal : special;
00590 }
00591 
00592 
00593 /* The end_char_string procedure gets the string ended properly and ensures
00594    that there is room for |l| more characters on the output line.
00595 */
00596 void end_char_string P1C(int, l)
00597 {
00598     while (state>special) {
00599        putc('"',mpxf);
00600        print_col++;
00601        state--;
00602     }
00603     if (print_col+l>line_length) {
00604        putc('\n',mpxf);
00605        print_col = 0;
00606     }
00607     state = initial;        /* get ready to print the next string */
00608 }
00609 
00610 
00611 
00612 /**************************************************************
00613               Page and Character Output
00614 ***************************************************************/
00615 
00616 char font_used[FCOUNT];            /* nonzero for fonts used on this page */
00617 int fonts_used;                    /* nonzero if any font been used on this page */
00618 int graphics_used;          /* nonzero if any graphics seen on this page */
00619 float str_h1,str_v;         /* corrected start pos for current out string */
00620 float str_h2;               /* where the current output string ends */
00621 int str_f;                  /* internal font num for cur. output string */
00622 float str_size;                    /* point size for this text string */
00623 
00624 
00625 /* Before using any fonts we need to define a MetaPost macro for typesetting
00626    character strings.
00627 */
00628 void prepare_font_use()
00629 {
00630     int k;
00631 
00632     for (k=0;k<nfonts;k++) font_used[k]=0;
00633     fonts_used = 1;
00634     fprintf(mpxf,"string n[];\n");
00635     fprintf(mpxf,"vardef s(expr t,m,x,y) =\n");
00636     fprintf(mpxf,"  addto p also t scaled(m*1.00375) shifted(x,y); enddef;\n");
00637 }
00638 
00639 
00640 /* Do what is necessary when the font with internal number f is used for the
00641    first time on a page.
00642 */
00643 void first_use P1C(int,f)
00644 {
00645     font_used[f] = 1;
00646     fprintf(mpxf, "n%d=\"%s\";\n", font_num[f], texname[f]);
00647 }
00648 
00649 
00650 /* Print any transformations required by the current Xslant and Xheight
00651    settings.
00652 */
00653 void slant_and_ht()
00654 {
00655     int i = 0;
00656 
00657     if (Xslant!=0.0) {
00658        fprintf(mpxf," slanted%.5f",Xslant);
00659        i++;
00660     }
00661     if (Xheight!=cursize && Xheight!=0.0 && cursize!=0.0) {
00662        fprintf(mpxf," yscaled%.4f", Xheight/cursize);
00663        i++;
00664     }
00665     if (i>0) fprintf(mpxf, "\n ");
00666 }
00667 
00668 
00669 /* We maintain the invariant that str_f is -1 when there is no output string
00670    under construction.
00671 */
00672 void finish_last_char()
00673 {
00674     float m,x,y;     /* font scale, MetaPost coords of reference point */
00675 
00676     if (str_f>=0) {
00677        m = str_size/font_design_size[str_f];
00678        x = str_h1*unit;
00679        y = YCORR-str_v*unit;
00680        if (fabs(x)>=4096.0 || fabs(y)>=4096.0 || m>=4096.0 || m<0) {
00681            warn("text out of range ignored","","");
00682            end_char_string(67);
00683        }
00684        else end_char_string(47);
00685        fprintf(mpxf,")infont n%d", font_num[str_f]);
00686        slant_and_ht();
00687        fprintf(mpxf,",%.5f,%.4f,%.4f);\n", m, x,y);
00688        str_f = -1;
00689     }
00690 }
00691 
00692 
00693 /* Output character number c in the font with internal number f.
00694 */
00695 void set_num_char P2C(int,f,int,c)
00696 {
00697     float hh, vv;           /* corrected versions of h, v */
00698     int i;
00699 
00700     hh = h;
00701     vv = v;
00702     for (i=shiftbase[f]; shiftchar[i]>=0; i++)
00703        if (shiftchar[i]==c) {
00704            hh += (cursize/unit)*shifth[i];
00705            vv += (cursize/unit)*shiftv[i];
00706            break;
00707        }
00708     if (c==0) quit("attempt to typeset an invalid character","","");
00709     if (hh-str_h2>=1.0 || str_h2-hh>=1.0 || vv-str_v>=1.0 || str_v-vv>=1.0
00710            || f!=str_f || cursize!=str_size) {
00711        if (str_f>=0) finish_last_char();
00712        else if (!fonts_used)
00713            prepare_font_use();     /* first font usage on this page */
00714        if (!font_used[f])
00715            first_use(f);    /* first use of font f on this page */
00716        fprintf(mpxf,"s((");
00717        print_col = 3;
00718        str_f=f; str_v=vv; str_h1=hh;
00719        str_size = cursize;
00720     }
00721     print_char(c);
00722     str_h2 = hh + cursize*charwd[f][c];
00723 }
00724 
00725 /* Output a string. */
00726 void set_string P1C(char*,cname)
00727 {
00728     float hh;  /* corrected version of h, current horisontal position */
00729 
00730     if (!*cname) return;
00731     hh = h;
00732     set_num_char(curfont,*cname);
00733     hh+= cursize*charwd[curfont][*cname];
00734     while (*++cname){
00735        print_char(*cname);
00736        hh += cursize*charwd[curfont][*cname];
00737     }
00738     h = rint(hh);
00739     finish_last_char();
00740 }
00741 
00742 /* The following initialization and clean-up is required.
00743 */
00744 void start_picture()
00745 {
00746     fonts_used = graphics_used = 0;
00747     str_f = -1;
00748     str_v = 0.0;
00749     str_h2 = 0.0;
00750     str_size = 0.0;
00751     fprintf(mpxf,"begingroup save C,D,p,s,n; picture p; p=nullpicture;\n");
00752 }
00753 
00754 void stop_picture()
00755 {
00756     if (str_f>=0) finish_last_char();
00757     fprintf(mpxf,"p endgroup\n");
00758 }
00759 
00760 
00761 
00762 /**************************************************************
00763                      Special Characters
00764 ***************************************************************/
00765 
00766 /* Given the troff name of a special character, this routine finds its
00767    definition and copies it to the MPX file.  It also finds the name of
00768    the vardef macro, puts it in the string pool, and index where the
00769    string starts.  The name should be C.<something>.
00770 */
00771 char specintro[] = "vardef ";             /* MetaPost name follows this */
00772 #define speci 7                           /* length of the above string */
00773 
00774 int copy_spec_char P1C(char*,cname)
00775 {
00776     int k = 0;                            /* how much of specintro so far */
00777     FILE *deff;
00778     int c, s;
00779 
00780     deff = fsearch(concat3("charlib",DIR_SEP_STRING,cname), "", dbpath);
00781     while (k<speci) {
00782        if ((c=getc(deff))==EOF)
00783            quit("No vardef in ",concat3("charlib",DIR_SEP_STRING,cname),"");
00784        putc(c, mpxf);
00785        if (c==specintro[k]) k++; else k=0;
00786     }
00787     s = poolsize;
00788     while ((c=getc(deff))!='(') {
00789        if (c==EOF) quit("vardef in ",concat3("charlib",DIR_SEP_STRING,cname),
00790                       " has no arguments");
00791        putc(c, mpxf);
00792        add_to_pool(c);
00793     }
00794     putc(c, mpxf);
00795     add_to_pool('\0');
00796     while ((c=getc(deff))!=EOF)
00797        putc(c, mpxf);
00798     return s;
00799 }
00800 
00801 
00802 /* When given a character name instead of a number, we need to check if
00803    it is a special character and download the definition if necessary.
00804    If the character is not in the current font we have to search the special
00805    fonts.
00806 */
00807 Hcell *spec_tab = (Hcell*)0;
00808 
00809 void set_char P1C(char*,cname)
00810 {
00811     int f, c, *flagp;
00812 
00813     if (*cname==' '||*cname=='\t') return;
00814     f = curfont;
00815     c = *hfind(cname, charcodes[f]);
00816     if (!hfound()) {
00817        for (f=specfnt; f!=FCOUNT; f=next_specfnt[f]) {
00818            c = *hfind(cname, charcodes[f]);
00819            if (hfound()) goto out;
00820        }
00821        quit("There is no character ",cname,"");
00822     }
00823 out:if (!is_specchar(c)) set_num_char(f,c);
00824     else {
00825        if (str_f>=0) finish_last_char();
00826        if (!fonts_used) prepare_font_use();
00827        if (!font_used[f]) first_use(f);
00828        if (spec_tab==(Hcell*)0)
00829            spec_tab = new_htab;
00830        flagp = hfind(cname, spec_tab);
00831        if (*flagp==0)
00832            *flagp = copy_spec_char(cname);       /* this won't be zero */
00833        fprintf(mpxf, "s(%s(n%d)", &strpool[*flagp], font_num[f]);
00834        slant_and_ht();
00835        fprintf(mpxf, ",%.5f,%.4f,%.4f);\n",
00836            cursize/font_design_size[f], h*unit, YCORR-v*unit);
00837     }
00838 }
00839 
00840 
00841 
00842 /**************************************************************
00843                      Font Definitions
00844 ***************************************************************/
00845 
00846 /* Mount the font with troff name nam at external font number n and read any
00847    necessary font files.
00848 */
00849 void do_font_def P2C(int,n, char*,nam)
00850 {
00851     int f, k;
00852 
00853     f = *hfind(nam, trfonts);
00854     if (!hfound())
00855        quit("Font ",nam," was not in map file");
00856     if (font_design_size[f]==0) {
00857        read_fontdesc(nam);
00858        read_tfm(f);
00859     }
00860     for (k=0; k<nfonts; k++)
00861        if (font_num[k]==n) font_num[k]= -1;
00862     font_num[f] = n;
00863 }
00864 
00865 
00866 
00867 /**************************************************************
00868               Time on `makepath pencircle'
00869 ***************************************************************/
00870 
00871 #define Speed ((float) (PI/4.0))
00872 
00873 /* Given the control points of a cubic Bernstein polynomial, evaluate
00874    it at t.
00875 */
00876 float Beval P2C(float*,xx, float, t)
00877 {
00878     float zz[4];
00879     register int i, j;
00880     for (i=0; i<=3; i++) zz[i]=xx[i];
00881     for (i=3; i>0; i--)
00882        for (j=0; j<i; j++)
00883            zz[j] += t*(zz[j+1]-zz[j]);
00884     return zz[0];
00885 }
00886 
00887 
00888 /* Find the direction angle at time t on the path `makepath pencircle'.
00889    The tables below give the Bezier control points for MetaPost's cubic
00890    approximation to the first octant of a unit circle.
00891 */
00892 float xx[4] = {1.0, 1.0, 0.8946431597, 0.7071067812};
00893 float yy[4] = {0.0, 0.2652164899, 0.5195704026, 0.7071067812};
00894 
00895 float circangle P1C(float,t)
00896 {
00897     float ti;
00898 
00899     ti = floor(t);
00900     t -= ti;
00901     return (float) atan(Beval(yy,t)/Beval(xx,t)) + ti*Speed;
00902 }
00903 
00904 
00905 /* Find the spline parameter where `makepath pencircle' comes closest to
00906    (cos(a)/2,sin(a)/2).
00907 */
00908 float circtime P1C(float,a)
00909 {
00910     int i;
00911     float t;
00912     t = a/Speed;
00913     for (i=2; --i>=0;)
00914        t += (a - circangle(t))/Speed;
00915     return t;
00916 }
00917 
00918 
00919 
00920 /**************************************************************
00921                      Troff Graphics
00922 ***************************************************************/
00923 
00924 float gx, gy;        /* current point for graphics (init. (h,YCORR/unit-v) */
00925 
00926 void prepare_graphics()
00927 {
00928     fprintf(mpxf,"vardef D(expr d)expr q =\n");
00929     fprintf(mpxf," addto p doublepath q withpen pencircle scaled d; enddef;\n");
00930     graphics_used = 1;
00931 }
00932 
00933 
00934 /* This function prints the current position (gx,gy).  Then if it can read dh dv
00935    from string s, it increments (gx,gy) and prints "--".  By returning the rest
00936    of the string s or NULL if nothing could be read from s, it provides the
00937    argument for the next iteration.
00938 */
00939 char *do_line P1C(char*,s)
00940 {
00941     float dh, dv;
00942 
00943     fprintf(mpxf, "(%.3f,%.3f)", gx*unit, gy*unit);
00944     dh = get_float(s);
00945     dv = get_float(arg_tail);
00946     if (arg_tail==NULL) return NULL;
00947     gx += dh;
00948     gy -= dv;
00949     fprintf(mpxf,"--\n");
00950     return arg_tail;
00951 }
00952 
00953 
00954 /* Function spline_seg() reads two pairs of (dh,dv) increments and prints the
00955    corresponding quadratic B-spline segment, leaving the ending point to be
00956    printed next time.  The return value is the string with the first (dh,dv)
00957    pair lopped off.  If only one pair of increments is found, we prepare to
00958    terminate the iteration by printing last time's ending point and returning
00959    NULL.
00960 */
00961 char * spline_seg P1C(char*,s)
00962 {
00963     float dh1, dv1, dh2, dv2;
00964 
00965     dh1 = get_float(s);
00966     dv1 = get_float(arg_tail);
00967     if (arg_tail==NULL) quit("Missing spline increments","","");
00968     s = arg_tail;
00969     fprintf(mpxf, "(%.3f,%.3f)", (gx+.5*dh1)*unit, (gy-.5*dv1)*unit);
00970     gx += dh1;
00971     gy -= dv1;
00972     dh2 = get_float(s);
00973     dv2 = get_float(arg_tail);
00974     if (arg_tail==NULL) return NULL;
00975     fprintf(mpxf, "..\ncontrols (%.3f,%.3f) and (%.3f,%.3f)..\n",
00976        (gx-dh1/6.0)*unit, (gy+dv1/6.0)*unit, (gx+dh2/6.0)*unit,
00977        (gy-dv2/6.0)*unit);
00978     return s;
00979 }
00980 
00981 
00982 /* Draw an ellipse with the given major and minor axes.
00983 */
00984 void do_ellipse P2C(float,a, float,b)
00985 {
00986     fprintf(mpxf, "makepath(pencircle xscaled %.3f\n yscaled %.3f",
00987        a*unit, b*unit);
00988     fprintf(mpxf, " shifted (%.3f,%.3f));\n", (gx+.5*a)*unit, gy*unit);
00989     gx += a;
00990 }
00991 
00992 
00993 /* Draw a counter-clockwise arc centered at (cx,cy) with initial and final radii
00994    (ax,ay) and (bx,by) respectively.
00995 */
00996 void do_arc P6C(float,cx, float,cy, float,ax, float,ay, float,bx, float,by)
00997 {
00998     float t1, t2;
00999 
01000     t1 = circtime(atan2(ay, ax));
01001     t2 = circtime(atan2(by, bx));
01002     if (t2 < t1) t2 += 8.0;
01003     fprintf(mpxf, "subpath (%.5f,%.5f) of\n", t1, t2);
01004     fprintf(mpxf, " makepath(pencircle scaled %.3f shifted (%.3f,%.3f));\n",
01005        2.0*sqrt(ax*ax+ay*ay)*unit, cx*unit, cy*unit);
01006     gx = cx + bx;
01007     gy = cy + by;
01008 }
01009 
01010 
01011 
01012 /* string s is everything following the initial `D' in a troff graphics command.
01013 */
01014 void do_graphic P1C(char*,s)
01015 {
01016     float h1, v1, h2, v2;
01017     finish_last_char();
01018     /* GROFF uses Fd to set fill color for solid drawing objects to the
01019        default, so just ignore that.
01020     */
01021     if (s[0] == 'F' && s[1] == 'd') return;
01022     gx = (float) h;
01023     gy = YCORR/unit - ((float) v);
01024     if (!graphics_used) prepare_graphics();
01025     fprintf(mpxf,"D(%.4f) ", LWscale*cursize);
01026     switch (*s++) {
01027     case 'c':
01028        h1 = get_float(s);
01029        if (arg_tail==NULL) quit("Bad argument in ",s-2,"");
01030        do_ellipse(h1,h1);
01031        break;
01032     case 'e':
01033        h1 = get_float(s);
01034        v1 = get_float(arg_tail);
01035        if (arg_tail==NULL) quit("Bad argument in ",s-2,"");
01036        do_ellipse(h1,v1);
01037        break;
01038     case 'A':
01039        fprintf(mpxf, "reverse ");
01040        /* fall through */
01041     case 'a':
01042        h1 = get_float(s);
01043        v1 = get_float(arg_tail);
01044        h2 = get_float(arg_tail);
01045        v2 = get_float(arg_tail);
01046        if (arg_tail==NULL) quit("Bad argument in ",s-2,"");
01047        do_arc(gx+h1, gy-v1, -h1, v1, h2, -v2);
01048        break;
01049     case 'l': case 'p':
01050        while (s!=NULL)
01051            s = do_line(s);
01052        fprintf(mpxf, ";\n");
01053        break;
01054     case 'q':
01055        do s = spline_seg(s); while (s!=NULL);
01056        fprintf(mpxf, ";\n");
01057        break;
01058     case '~':
01059        fprintf(mpxf, "(%.3f,%.3f)--", gx*unit, gy*unit);
01060        do s = spline_seg(s); while (s!=NULL);
01061        fprintf(mpxf, "--(%.3f,%.3f);\n", gx*unit, gy*unit);
01062        break;
01063     default:
01064        quit("Unknown drawing function",s-2,"");
01065     }
01066     h = (int) floor(gx+.5);
01067     v = (int) floor(YCORR/unit+.5-gy);
01068 }
01069 
01070 
01071 
01072 /**************************************************************
01073               Interpreting Troff Output
01074 ***************************************************************/
01075 
01076 void change_font P1C(int,f)
01077 {
01078     for (curfont=0; curfont<nfonts; curfont++)
01079        if (font_num[curfont]==f) return;
01080     quit("Bad font setting","","");
01081 }
01082 
01083 
01084 /* String s0 is everything following the initial `x' in a troff device control
01085    command.  A zero result indicates a stop command.
01086 */
01087 int do_x_cmd P1C(char *,s0)
01088 {
01089     float x;
01090     int n;
01091     char *s;
01092 
01093     s = s0;
01094     while (*s==' ' || *s=='\t') s++;
01095     switch (*s++) {
01096     case 'r':
01097        if (unit!=0.0) quit("Attempt to reset resolution","","");
01098        while (*s!=' ' && *s!='\t') s++;
01099        unit = get_float(s);
01100        if (unit<=0.0) quit("Bad resolution: x",s0,"");
01101        unit = 72.0/unit;
01102        break;
01103     case 'f':
01104        while (*s!=' ' && *s!='\t') s++;
01105        n = get_int(s);
01106        if (arg_tail==NULL) quit("Bad font def: x",s0,"");
01107        s = arg_tail;
01108        while (*s==' ' || *s=='\t') s++;
01109        do_font_def(n, s);
01110        break;
01111     case 's':
01112        return 0;
01113     case 'H':
01114        while (*s!=' ' && *s!='\t') s++;
01115        Xheight = get_float(s);
01116        /* GROFF troff output is scaled
01117           groff_out(5): The argument to the s command is in scaled
01118                points (units of points/n, where n is the argument
01119                to the sizescale command  in the DESC file.)  The
01120                argument to the x Height command is also in scaled points.
01121                sizescale for groff devps is 1000
01122         */
01123        if(unit != 0.0) Xheight *= unit;
01124        else Xheight /= 1000.0;
01125        if (Xheight==cursize) Xheight=0.0;
01126        break;
01127     case 'S':
01128        while (*s!=' ' && *s!='\t') s++;
01129        Xslant = get_float(s)*(PI/180.0);
01130        x = cos(Xslant);
01131        if (-1e-4<x && x<1e-4) quit("Excessive slant","","");
01132        Xslant = sin(Xslant)/x;
01133        break;
01134     default:
01135        /* do nothing */;
01136     }
01137     return 1;
01138 }
01139 
01140 
01141 /* This routine reads commands from the troff output file up to and including
01142    the next `p' or `x s' command.  It also calls set_num_char() and set_char()
01143    to generate output when appropriate.  A zero result indicates that there
01144    are no more pages to do.
01145 */
01146 /* GROFF NOTE:
01147    GNU groff uses an extended device-independent output file format
01148    documented in groff_out(5). In order to allow parsing of groff's
01149    output files, this function either needs to be extended to support
01150    the new command codes, or else the use of the "t" and "u" commands
01151    must be disabled by removing the line "tcommand" from the DESC file
01152    in the $(prefix)/lib/groff/devps directory.
01153 */
01154 int do_page()
01155 {
01156     char buf[LLENGTH];
01157     char a, *c, *cc;
01158 
01159     h = v = 0;
01160     while (fgets(buf,LLENGTH,trf)!=NULL) {
01161        for (c=buf; *c!='\n'; c++)
01162            if (*c=='\0') quit("Need to increase LLENGTH","","");
01163        *c = '\0';
01164        lnno++;
01165        c = buf;
01166        while (*c!='\0') {
01167            switch(*c) {
01168            case ' ': case '\t': case 'w':
01169               c++;
01170               break;
01171            case 's':
01172               cursize = get_float(c+1);
01173               /* GROFF troff output is scaled
01174                  groff_out(5): The argument to the s command is in scaled
01175                        points (units of points/n, where n is the argument
01176                        to the sizescale command  in the DESC file.)  The
01177                        argument to the x Height command is also in scaled
01178                        points.
01179                    sizescale for groff devps is 1000
01180               */
01181               if (unit != 0.0) cursize *= unit;
01182               else cursize /= 1000.0;
01183               goto iarg;
01184            case 'f':
01185               change_font(get_int(c+1));
01186               goto iarg;
01187            case 'c':
01188               if (c[1]=='\0') quit("Bad c command in troff output","","");
01189               cc = c+2;
01190               goto set;
01191            case 'C':
01192               cc=c; do cc++; while (*cc!=' ' && *cc!='\t' && *cc!='\0');
01193               goto set;
01194            case 'N':
01195               set_num_char(curfont, get_int(c+1));
01196               goto iarg;
01197            case 'H':
01198               h = get_int(c+1);
01199               goto iarg;
01200            case 'V':
01201               v = get_int(c+1);
01202               goto iarg;
01203            case 'h':
01204               h += get_int(c+1);
01205               goto iarg;
01206            case 'v':
01207               v += get_int(c+1);
01208               goto iarg;
01209            case '0': case '1': case '2': case '3': case '4':
01210            case '5': case '6': case '7': case '8': case '9':
01211               if (c[1]<'0' || c[1]>'9' || c[2]=='\0')
01212                   quit("Bad nnc command in troff output","","");
01213               h += 10*(c[0]-'0') + c[1]-'0';
01214               c++;
01215               cc = c+2;
01216               goto set;
01217            case 'p':
01218               return 1;
01219            case 'n':
01220               (void) get_int(c+1);
01221               (void) get_int(arg_tail);
01222               goto iarg;
01223            case 'D':
01224               do_graphic(c+1);
01225               goto eoln;
01226            case 'x':
01227               if (!do_x_cmd(c+1)) return 0;
01228               goto eoln;
01229            case '#':
01230               goto eoln;
01231            case 'F':
01232                 /* GROFF uses this command to report filename */
01233                 goto eoln;
01234            case 'm':
01235                 /* GROFF uses this command to control color */
01236               goto eoln;
01237            case 'u':
01238                 /* GROFF uses this command to output a word with additional
01239                    white space between characters, not implemented
01240                 */
01241               quit("Bad command in troff output\n",
01242                      "change the DESC file for your GROFF PostScript device, ",
01243                      "remove tcommand");
01244            case 't':
01245                 /* GROFF uses this command to output a word */
01246               cc=c; do cc++; while (*cc!=' ' && *cc!='\t' && *cc!='\0');
01247               a= *cc; *cc='\0';
01248               set_string(++c);
01249               c = cc;
01250               *c = a;
01251               continue;
01252            default:
01253               quit("Bad command in troff output","","");
01254            }
01255            continue;
01256        set:a= *cc; *cc='\0';
01257            set_char(++c);
01258            c = cc;
01259            *c = a;
01260            continue;
01261        iarg:c = arg_tail;
01262        }
01263     eoln:/* do nothing */;
01264     }
01265     return 0;
01266 }
01267 
01268 
01269 /**************************************************************
01270                      Main Program
01271 ***************************************************************/
01272 
01273 void dmp_usage P2C(char*,name, int,status)
01274 {
01275     extern KPSEDLL char *kpse_bug_address;
01276     FILE *f = status == 0 ? stdout : stderr;
01277     fputs ("Usage: dmp [OPTION]... DITROFFFILE [MPXFILE]\n\
01278   Translate DITROFFFILE to the MetaPost MPXFILE or standard output.\n\
01279 \n\
01280 --help      display this help and exit\n\
01281 --version   output version information and exit\n", f);
01282     putc ('\n', f);
01283     fputs (kpse_bug_address, f);
01284     exit(status);
01285 }
01286 
01287 int main P2C(int, argc, char**, argv)
01288 {
01289     int more;
01290 
01291     trf = stdin;
01292     mpxf = stdout;
01293 
01294     kpse_set_progname (argv[0]);
01295 
01296     if (argc == 1) {
01297       fputs ("dmp: Need one or two file arguments.\n", stderr);
01298       fputs ("Try `dmp --help' for more information.\n", stderr);
01299       exit(1);
01300     } else if (argc > 1 && strcmp (argv[1], "--help") == 0) {
01301       dmp_usage (argv[0], 0);
01302     } else if (argc > 1 && strcmp (argv[1], "--version") == 0) {
01303       printversionandexit (term_banner,
01304                            "AT&T Bell Laboratories", "John Hobby");
01305     }
01306     if (argc>3) dmp_usage(argv[0], 1);
01307     if (argc>1) {
01308        trf = fopen(argv[1], "r");
01309        if (trf==(FILE*)0) {
01310          fprintf (stderr, "%s: ", argv[0]);
01311          perror (argv[1]);
01312          exit(1);
01313        }
01314        if (argc>2) {
01315            mpxf = fopen(argv[2], "w");
01316            if (mpxf==(FILE*)0) {
01317              fprintf (stderr, "%s: ", argv[0]);
01318              perror (argv[2]);
01319              exit(1);
01320            }
01321        }
01322     }
01323     fprintf(mpxf, "%s\n", banner);
01324     read_fmap(dbname);
01325     read_char_adj(adjname);
01326     if (do_page()) {
01327        do {
01328            h=0; v=0;
01329            Xslant = Xheight = 0.0;
01330            start_picture();
01331            more = do_page();
01332            stop_picture();
01333            fprintf(mpxf,"mpxbreak\n");
01334        } while (more);
01335     }
01336     return 0;
01337 }