]> git.lyx.org Git - lyx.git/blob - development/Win32/packaging/dtl/dt2dv.c
* Enable man2ps to work without hard-coding the locations of groff or dpost.
[lyx.git] / development / Win32 / packaging / dtl / dt2dv.c
1 /* dt2dv - convert human-readable "DTL" file to DVI format
2          - this is intended to invert dv2dt version 0.6.0
3    - version 0.6.2 - 27 July 2005
4    - Geoffrey Tobin    G.Tobin@ee.latrobe.edu.au
5    - fixes:  Michal Tomczak-Jaegermann    ntomczak@vm.ucs.ualberta.ca
6              Nelson H. F. Beebe    beebe@math.utah.edu
7              Angus Leeming leeming@lyx.org: Enable dt2dv to handle
8              .dvi files containing strings longer than 1024 chars.
9    - Reference:  "The DVI Driver Standard, Level 0",
10                  by  The TUG DVI Driver Standards Committee.
11                  Appendix A, "Device-Independent File Format".
12 */
13
14 /* unix version; read from stdin, write to stdout, by default. */
15
16 #include <ctype.h>
17 #include <errno.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "dtl.h"
24
25 /* by default, read and write regular files */
26 int rd_stdin = 0;
27 int wr_stdout = 0;
28
29 /* maximum number of characters in a DTL input line */
30 #define MAXLINE  1024
31
32 /* input line */
33 typedef struct
34 {
35   COUNT num;    /* current line number */
36   size_t max;   /* capacity of buf */
37   S4 wrote;     /* number of characters written into buf */
38   size_t read;  /* position in buf of next character to read from buf */
39   char * buf;   /* line buffer */
40 } Line;
41
42 char linebuf[MAXLINE+1];
43
44 Line dtl_line = {0, 0, 0, MAXLINE, linebuf};
45
46 /* a DTL token either is:
47      a quoted string (admitting an escape character),
48      or BCOM (if that is a nonempty string),
49      or ECOM (if that is a nonempty string),
50      or a string _not_ including ECOM_CHAR or space.
51 */
52
53 /* maximum expected length of a DTL token */
54 #define MAXTOKLEN 255
55 typedef char Token[MAXTOKLEN+1];
56
57 typedef unsigned char Byte;
58 typedef char Boolean;
59
60 #define true  1
61 #define false 0
62
63 /* command prefixes */
64 typedef struct
65 {
66     Byte first_code;
67     char * name;
68     Boolean has_suffix;
69     Byte first_suffix, last_suffix;
70 } CmdPrefix;
71
72 CmdPrefix  cmd_prefixes [] =
73 {
74   {0,   SETCHAR, true, 0, 127},
75   {128, SET, true, 1, 4},
76   {132, SETRULE, false, 0, 0},
77   {133, PUT, true, 1, 4},
78   {137, PUTRULE, false, 0, 0},
79   {138, NOP, false, 0, 0},
80   {139, BOP, false, 0, 0},
81   {140, EOP, false, 0, 0},
82   {141, PUSH, false, 0, 0},
83   {142, POP, false, 0, 0},
84   {143, RIGHT, true, 1, 4},
85   {147, W, true, 0, 4},
86   {152, X, true, 0, 4},
87   {157, DOWN, true, 1, 4},
88   {161, Y, true, 0, 4},
89   {166, Z, true, 0, 4},
90   {171, FONTNUM, true, 0, 63},
91   {235, FONT, true, 1, 4},
92   {239, SPECIAL, true, 1, 4},
93   {243, FONTDEF, true, 1, 4},
94   {247, PRE, false, 0, 0},
95   {248, POST, false, 0, 0},
96   {249, POSTPOST, false, 0, 0},
97   {250, OPCODE, true, 250, 255}
98 };
99 /* cmd_prefixes[] */
100
101 /* Number of DVI commands, including those officially undefined */
102 #define NCMDS 256
103
104 /* table of command name (string) pointers */
105 typedef char * CmdTable [NCMDS];
106
107 /* initially all command name pointers are NULL */
108 CmdTable cmd_table;
109
110 /* operation's opcode, name, number of args, string of arguments. */
111 typedef struct
112 {
113   int code;
114   char * name;
115   int nargs;
116   char * args;
117 } op_info;
118
119 /* name of table, first opcode, last opcode, pointer to opcode info. */
120 typedef struct
121 {
122   char * name;
123   int first;
124   int last;
125   op_info * list;
126 } op_table;
127
128 /* Table for opcodes 128 to 170 inclusive. */
129
130 op_info  op_info_128_170 [] =
131 {
132   {128, SET1, 1, "1"},
133   {129, SET2, 1, "2"},
134   {130, SET3, 1, "3"},
135   {131, SET4, 1, "-4"},
136   {132, SETRULE, 2, "-4 -4"},
137   {133, PUT1, 1, "1"},
138   {134, PUT2, 1, "2"},
139   {135, PUT3, 1, "3"},
140   {136, PUT4, 1, "-4"},
141   {137, PUTRULE, 2, "-4 -4"},
142   {138, NOP, 0, ""},
143   /* bop:  not counting last argument, a signed address: */
144   {139, BOP, 10, "-4 -4 -4 -4 -4 -4 -4 -4 -4 -4"},
145   {140, EOP, 0, ""},
146   {141, PUSH, 0, ""},
147   {142, POP, 0, ""},
148   {143, RIGHT1, 1, "-1"},
149   {144, RIGHT2, 1, "-2"},
150   {145, RIGHT3, 1, "-3"},
151   {146, RIGHT4, 1, "-4"},
152   {147, W0, 0, ""},
153   {148, W1, 1, "-1"},
154   {149, W2, 1, "-2"},
155   {150, W3, 1, "-3"},
156   {151, W4, 1, "-4"},
157   {152, X0, 0, ""},
158   {153, X1, 1, "-1"},
159   {154, X2, 1, "-2"},
160   {155, X3, 1, "-3"},
161   {156, X4, 1, "-4"},
162   {157, DOWN1, 1, "-1"},
163   {158, DOWN2, 1, "-2"},
164   {159, DOWN3, 1, "-3"},
165   {160, DOWN4, 1, "-4"},
166   {161, Y0, 0, ""},
167   {162, Y1, 1, "-1"},
168   {163, Y2, 1, "-2"},
169   {164, Y3, 1, "-3"},
170   {165, Y4, 1, "-4"},
171   {166, Z0, 0, ""},
172   {167, Z1, 1, "-1"},
173   {168, Z2, 1, "-2"},
174   {169, Z3, 1, "-3"},
175   {170, Z4, 1, "-4"}
176 };
177 /* op_info  op_info_128_170 [] */
178
179 op_table  op_128_170  =  {"op_128_170", 128, 170, op_info_128_170};
180
181 /* Table for fnt1 to fnt4 (opcodes 235 to 238) inclusive. */
182
183 op_info  fnt_n [] =
184 {
185   {235, FONT1, 1, "1"},
186   {236, FONT2, 1, "2"},
187   {237, FONT3, 1, "3"},
188   {238, FONT4, 1, "-4"}
189 };
190 /* op_info  fnt_n [] */
191
192 op_table  fnt  =  {FONT, 235, 238, fnt_n};
193
194
195 /* Function prototypes */
196
197 Void mem_viol ARGS((int sig));
198 Void give_help (VOID);
199 int parse ARGS((char * s));
200 Void process ARGS((char * s));
201
202 Void no_op (VOID);
203 Void dtl_stdin (VOID);
204 Void dvi_stdout (VOID);
205
206 int open_dtl ARGS((char * dtl_file, FILE ** pdtl));
207 int open_dvi ARGS((char * dvi_file, FILE ** pdvi));
208
209 int dt2dv ARGS((FILE * dtl, FILE * dvi));
210
211 Void * gmalloc ARGS((long int size));
212
213 Void dinfo (VOID);
214 Void dexit ARGS((int n));
215
216 int cons_cmds ARGS((int nprefixes, CmdPrefix * prefix, CmdTable cmds));
217 Void free_cmds ARGS((CmdTable cmd_table));
218
219 int get_line ARGS((FILE * fp, Line * line, int max));
220 int read_line_char ARGS((FILE * fp, int * ch));
221 int read_char ARGS((FILE * fp, int * ch));
222 int unread_char (VOID);
223 int read_string_char ARGS((FILE * fp, int * ch));
224
225 COUNT read_variety ARGS((FILE * dtl));
226 COUNT read_token ARGS((FILE * dtl, char * token));
227 COUNT skip_space ARGS((FILE * fp, int * ch));
228 COUNT read_misc ARGS((FILE * fp, Token token));
229 COUNT read_mes ARGS((FILE * fp, char * token));
230
231 int find_command ARGS((char * command, int * opcode));
232 int xfer_args ARGS((FILE * dtl, FILE * dvi, int opcode));
233
234 int set_seq ARGS((FILE * dtl, FILE * dvi));
235
236 int check_byte ARGS((int byte));
237 int put_byte ARGS((int onebyte, FILE * dvi));
238
239 U4 xfer_hex ARGS((int n,  FILE * dtl,  FILE * dvi));
240 U4 xfer_oct ARGS((int n,  FILE * dtl,  FILE * dvi));
241 U4 xfer_unsigned ARGS((int n,  FILE * dtl,  FILE * dvi));
242 S4 xfer_signed   ARGS((int n,  FILE * dtl,  FILE * dvi));
243
244 int check_bmes ARGS((FILE * dtl));
245 int check_emes ARGS((FILE * dtl));
246
247 Void init_Lstring ARGS((Lstring * lsp, long int n));
248 Void de_init_Lstring ARGS((Lstring * lsp));
249 Lstring * alloc_Lstring ARGS((long int n));
250 Void free_Lstring ARGS((Lstring * lstr));
251 Void ls_putb ARGS((int ch, Lstring * lstr));
252
253 S4 get_Lstring ARGS((FILE * dtl, Lstring * lstr));
254 Void put_Lstring ARGS((const Lstring * lstr, FILE * dvi));
255 U4 xfer_len_string ARGS((int n, FILE * dtl, FILE * dvi));
256
257 U4 get_unsigned ARGS((FILE * dtl));
258 S4 get_signed   ARGS((FILE * dtl));
259
260 int put_unsigned ARGS((int n, U4 unum, FILE * dvi));
261 int put_signed   ARGS((int n, S4 snum, FILE * dvi));
262
263 S4 xfer_bop_address ARGS((FILE * dtl,  FILE * dvi));
264 S4 xfer_postamble_address ARGS((FILE * dtl,  FILE * dvi));
265
266 int put_table ARGS((op_table table, int opcode, FILE * dtl, FILE * dvi));
267
268 U4 special ARGS((FILE * dtl,  FILE * dvi,  int n));
269 int fontdef ARGS((FILE * dtl,  FILE * dvi,  int n));
270
271 U4 preamble ARGS((FILE * dtl,  FILE * dvi));
272 int postamble ARGS((FILE * dtl,  FILE * dvi));
273 int post_post ARGS((FILE * dtl,  FILE * dvi));
274
275
276 typedef struct
277 {
278   char * keyword;  /* command line option keyword */
279   int * p_var;     /* pointer to option variable */
280   char * desc;     /* description of keyword and value */
281   Void (* p_fn) (VOID);  /* pointer to function called when option is set */
282 } Options;
283
284 Options opts[] =
285 {
286   {"-debug", &debug, "detailed debugging", no_op},
287   {"-group", &group, "each DTL command is in parentheses", no_op},
288   {"-si", &rd_stdin, "read all DTL commands from standard input", dtl_stdin},
289   {"-so", &wr_stdout, "write all DVI commands to standard output", dvi_stdout},
290   {NULL, NULL, NULL, NULL}
291 };
292 /* opts[] */
293
294 char * progname = "";  /* intended for name of this program */
295 int nfile = 0;  /* number of filename arguments on the command line */
296
297 #define PRINT_PROGNAME  fprintf (stderr, "%s ", progname)
298
299 /* Harbison & Steele (1991) warn that some C implementations */
300 /* of free() do not treat NULL pointers correctly. */
301 #define gfree(p) {if (p) free (p);}
302
303
304 FILE * dtl_fp = NULL;
305 FILE * dvi_fp = NULL;
306
307 char * dtl_filename = "";
308 char * dvi_filename = "";
309
310
311 int
312 main
313 #ifdef STDC
314   (int argc,  char * argv[])
315 #else
316   (argc,  argv)
317   int argc;
318   char * argv[];
319 #endif
320 {
321   Void (*handler) ARGS((int));  /* Previous signal handler */
322   int i;
323
324   progname = argv[0];  /* name of this program */
325
326   /* memory violation signal handler */
327
328   handler = (Void (*) ARGS((int))) signal (SIGSEGV, mem_viol);
329
330 #ifndef __DATE__
331 #define __DATE__ ""
332 #endif
333
334 #ifndef __TIME__
335 #define __TIME__ ""
336 #endif
337
338 #if STDC
339 #define C_LEVEL ""
340 #else /* NOT STDC */
341 #define C_LEVEL "non-"
342 #endif /* NOT STDC */
343
344   /* message about program and compiler */
345   /* NB:  LTU EE's Sun/OS library is BSD, even though gcc 2.2.2 is ANSI */
346
347   fprintf (stderr, "\n");
348   fprintf (stderr,
349     "Program \"%s\" version %s compiled %s %s in %sstandard C.\n",
350     progname, VERSION, __DATE__, __TIME__, C_LEVEL);
351
352   /* interpret command line arguments */
353
354   nfile = 0;
355   dtl_fp = dvi_fp = NULL;
356   dtl_filename = dvi_filename = "";
357
358   for (i=1; i < argc; i++)
359   {
360     /* parse options, followed by any explicit filenames */
361     parse (argv[i]);
362   }
363
364   if (nfile != 2)  /* not exactly two files specified, so give help */
365     give_help();
366   else
367     /* the real works */
368     dt2dv (dtl_fp, dvi_fp);
369
370   return 0;  /* OK */
371 }
372 /* end main */
373
374
375 Void
376 mem_viol
377 #ifdef STDC
378   (int sig)
379 #else
380   (sig)
381   int sig;
382 #endif
383 {
384   Void (* handler) ARGS((int));
385   handler = (Void (*) ARGS((int))) signal (SIGSEGV, mem_viol);
386   if (sig != SIGSEGV)
387   {
388     PRINT_PROGNAME;
389     fprintf (stderr,
390       "(mem_viol) : called with wrong signal!\n");
391   }
392   PRINT_PROGNAME;
393   fprintf (stderr, "(mem_viol) : RUNTIME MEMORY ERROR : memory violation, ");
394   fprintf (stderr, "dtl line >= ");
395   fprintf (stderr, WF, dtl_line.num);
396   fprintf (stderr, "\n");
397   dexit (1);
398 }
399 /* mem_viol */
400
401
402 Void
403 give_help (VOID)
404 {
405   int i;
406   char * keyword;
407   fprintf (stderr, "usage:   ");
408   PRINT_PROGNAME;
409   fprintf (stderr, "[options]  dtl_file  dvi_file");
410   fprintf (stderr, "\n");
411   for (i=0; (keyword = opts[i].keyword) != NULL; i++)
412   {
413     fprintf (stderr, "    ");
414     fprintf (stderr, "[%s]", keyword);
415     fprintf (stderr, "    ");
416     fprintf (stderr, "%s", opts[i].desc);
417     fprintf (stderr, "\n");
418   }
419   fprintf (stderr, "Messages, like this one, go to stderr.\n");
420 }
421 /* give_help */
422
423
424 Void no_op (VOID)
425 /* do nothing */
426 {
427 }
428
429 Void dtl_stdin (VOID)
430 {
431   extern FILE * dtl_fp;
432   extern int nfile;
433
434   dtl_fp = stdin;
435   dtl_filename = "Standard Input";
436   ++ nfile;
437 }
438
439 Void dvi_stdout (VOID)
440 {
441   extern FILE * dvi_fp;
442   extern int nfile;
443
444   /* ! Perilous to monitors! */
445   dvi_fp = stdout;
446   dvi_filename = "Standard Output";
447   ++ nfile;
448 }
449
450
451 int
452 parse
453 #ifdef STDC
454   (char * s)
455 #else
456   (s)
457   char * s;
458 #endif
459 /* parse one command-line argument, `s' */
460 {
461   int i;
462   char * keyword;
463   for (i=0; (keyword = opts[i].keyword) != NULL; i++)
464   {
465     if (strncmp (s, keyword, strlen (keyword)) == 0)
466     {
467       Void (*pfn) (VOID);
468       (*(opts[i].p_var)) = 1;  /* turn option on */
469       if ((pfn = opts[i].p_fn) != NULL)
470         (*pfn) ();    /* call option function */
471       return i;
472     }
473   }
474   /* reached here, so not an option: assume it's a filename */
475   process (s);
476   return i;
477 }
478 /* parse */
479
480
481 int
482 open_dtl
483 #ifdef STDC
484   (char * dtl_file, FILE ** pdtl)
485 #else
486   (dtl_file, pdtl)
487   char * dtl_file;
488   FILE ** pdtl;
489 #endif
490 /* I:  dtl_file;  I:  pdtl;  O:  *pdtl. */
491 {
492   extern char * dtl_filename;
493
494   dtl_filename = dtl_file;
495
496   if (dtl_filename == NULL)
497   {
498     PRINT_PROGNAME;
499     fprintf (stderr,
500       "(open_dtl) : INTERNAL ERROR : dtl file's name is NULL.\n");
501     dexit (1);
502   }
503
504   if (pdtl == NULL)
505   {
506     PRINT_PROGNAME;
507     fprintf (stderr,
508       "(open_dtl) : INTERNAL ERROR : address of dtl variable is NULL.\n");
509     dexit (1);
510   }
511
512   *pdtl = fopen (dtl_file, "r");
513
514   if (*pdtl == NULL)
515   {
516     PRINT_PROGNAME;
517     fprintf (stderr,
518       "(open_dtl) : DTL FILE ERROR : Cannot open \"%s\" for text reading.\n",
519       dtl_file);
520     dexit (1);
521   }
522
523   return 1;  /* OK */
524 }
525 /* open_dtl */
526
527
528 int
529 open_dvi
530 #ifdef STDC
531   (char * dvi_file, FILE ** pdvi)
532 #else
533   (dvi_file, pdvi)
534   char * dvi_file;
535   FILE ** pdvi;
536 #endif
537 /* I:  dvi_file;  I:  pdvi;  O:  *pdvi. */
538 {
539   extern char * dvi_filename;
540
541   dvi_filename = dvi_file;
542
543   if (dvi_filename == NULL)
544   {
545     PRINT_PROGNAME;
546     fprintf (stderr,
547     "(open_dvi) : INTERNAL ERROR : dvi file's name is NULL.\n");
548     dexit (1);
549   }
550
551   if (pdvi == NULL)
552   {
553     PRINT_PROGNAME;
554     fprintf (stderr,
555     "(open_dvi) : INTERNAL ERROR : address of dvi variable is NULL.\n");
556     dexit (1);
557   }
558
559   *pdvi = fopen (dvi_file, "wb");
560
561   if (*pdvi == NULL)
562   {
563     PRINT_PROGNAME;
564     fprintf (stderr,
565       "(open_dvi) : DVI FILE ERROR : Cannot open \"%s\" for binary writing.\n",
566       dvi_file);
567     dexit (1);
568   }
569
570   return 1;  /* OK */
571 }
572 /* open_dvi */
573
574
575 Void
576 process
577 #ifdef STDC
578   (char * s)
579 #else
580   (s)
581   char * s;
582 #endif
583 {
584   extern FILE * dtl_fp, * dvi_fp;
585   extern int nfile;
586   if (dtl_fp == NULL)  /* first filename assumed to be DTL input */
587   {
588     open_dtl (s, &dtl_fp);
589   }
590   else if (dvi_fp == NULL)  /* second filename assumed to be DVI output */
591   {
592     open_dvi (s, &dvi_fp);
593   }
594   else
595   {
596     PRINT_PROGNAME;
597     fprintf (stderr, "(process) : at most two filenames allowed.\n");
598     exit (1);
599   }
600   ++ nfile;
601 }
602 /* process */
603
604
605 COUNT dtl_read = 0;  /* bytes read from dtl file */
606 COUNT dvi_written = 0;  /* bytes written to dvi file */
607 word_t last_bop_address = -1;  /* byte address of last bop; first bop uses -1 */
608 word_t postamble_address = -1;  /* byte address of postamble */
609 COUNT ncom = 0;  /* commands successfully read and interpreted from dtl file */
610 COUNT com_read = 0;  /* bytes read in current (command and arguments), */
611                       /* since and including the opening BCOM_CHAR, if any */
612
613
614 int
615 put_byte
616 #ifdef STDC
617   (int byte, FILE * dvi)
618 #else
619   (byte, dvi)
620   int byte;
621   FILE * dvi;
622 #endif
623 /* write byte into dvi file */
624 {
625   check_byte (byte);
626 /*  if (fprintf (dvi, "%c", byte) != 1) */
627   if (fprintf (dvi, "%c", byte) < 0)
628   {
629     PRINT_PROGNAME;
630     fprintf (stderr,
631       "(put_byte) : DVI FILE ERROR (%s) : cannot write to dvi file.\n",
632       dtl_filename);
633     dexit (1);
634   }
635   ++ dvi_written;
636   return 1;  /* OK */
637 }
638 /* put_byte */
639
640
641 int
642 dt2dv
643 #ifdef STDC
644   (FILE * dtl, FILE * dvi)
645 #else
646   (dtl, dvi)
647   FILE * dtl;
648   FILE * dvi;
649 #endif
650 {
651   int nprefixes = 0;  /* number of prefixes in cmd_prefixes[] list. */
652   static Token dtl_cmd = "";  /* DTL command name */
653   COUNT nread = 0;  /* number of bytes read by a function from dtl file. */
654
655   nprefixes = sizeof (cmd_prefixes) / sizeof (CmdPrefix);
656
657   /* Construct array of all NCMDS == 256 DTL commands */
658
659   (Void) cons_cmds (nprefixes, cmd_prefixes, cmd_table);
660
661   /* DTL commands have the form "[ ]*command arg ... arg[ ]*", */
662   /* possibly enclosed in a BCOM, ECOM pair, */
663   /* and are separated by optional whitespace, typically newlines. */
664   /* That is, each command and its arguments are parenthesised, */
665   /* with optional spaces after the BCOM and before the ECOM, if any. */
666
667   /* dt2dv is now at the very start of the DTL file */
668
669   dtl_line.num = 0;
670   dtl_read = 0;
671
672   /* The very first thing should be the "variety" signature */
673
674   nread = read_variety (dtl);
675
676   /* while not end of dtl file or reading error, */
677   /*   read, interpret, and write commands */
678
679   while (!feof (dtl))
680   {
681     int opcode;
682
683     com_read = 0;
684
685     if (group)
686     {
687       /* BCOM check */
688       static Token token = "";  /* DTL token */
689       nread = read_token (dtl, token);
690       /* test for end of input, or reading error */
691       if (strlen (token) == 0)
692       {
693         if (debug)
694         {
695           PRINT_PROGNAME;
696           fprintf (stderr, "(dt2dv) : end of input, or reading error.\n");
697         }
698         break;
699       }
700       /* test whether this command begins correctly */
701       else if (strcmp (token, BCOM) != 0)
702       {
703         PRINT_PROGNAME;
704         fprintf (stderr, "(dt2dv) : DTL FILE ERROR (%s) : ", dtl_filename);
705         fprintf (stderr, "command must begin with \"%s\", ", BCOM);
706         fprintf (stderr, "not `%c' (char %d).\n", token[0], token[0]);
707         dexit (1);
708       }
709       /* end BCOM check */
710     }
711
712     /* read the command name */
713     nread = read_token (dtl, dtl_cmd);
714     /* test for end of input, or reading error */
715     if (strlen (dtl_cmd) == 0)
716     {
717       if (debug)
718       {
719         PRINT_PROGNAME;
720         fprintf (stderr,
721           "(dt2dv) : end of input, or reading error.\n");
722       }
723       break;
724     }
725     else
726     {
727       if (debug)
728       {
729         PRINT_PROGNAME;
730         fprintf (stderr, "(dt2dv) : command ");
731         fprintf (stderr, WF, ncom);
732         fprintf (stderr, " = \"%s\".\n", dtl_cmd);
733       }
734
735       /* find opcode for this command */
736       if (find_command (dtl_cmd, &opcode) == 1)
737       {
738         /* write the opcode, if we can */
739         put_byte (opcode, dvi);
740
741         /* treat the arguments, if any */
742         xfer_args (dtl, dvi, opcode);
743       }
744       else if (dtl_cmd[0] == BSEQ_CHAR)
745       {
746         /* sequence of font characters for SETCHAR */
747         set_seq (dtl, dvi);
748       }
749       else
750       {
751         PRINT_PROGNAME;
752         fprintf (stderr,
753           "(dt2dv) : DTL FILE ERROR (%s) : unknown command \"%s\".\n",
754           dtl_filename, dtl_cmd);
755         dexit (1);
756       }
757     }
758
759     if (group)
760     {
761       /* seek ECOM after command's last argument and optional whitespace */
762       static Token token = "";  /* DTL token */
763       nread = read_token (dtl, token);
764       /* test for end of input, or reading error */
765       if (strlen (token) == 0)
766       {
767         if (debug)
768         {
769           PRINT_PROGNAME;
770           fprintf (stderr,
771             "(dt2dv) : end of input, or reading error.\n");
772         }
773         break;
774       }
775       if (strcmp (token, ECOM) != 0)
776       {
777         PRINT_PROGNAME;
778         fprintf (stderr, "(dt2dv) : DTL FILE ERROR (%s) : ", dtl_filename);
779         fprintf (stderr, "ECOM (\"%s\") expected, not `%c' (char %d).\n",
780           ECOM, token[0], token[0]);
781         dexit (1);
782       }
783       /* end ECOM check */
784     }
785
786     ++ ncom;  /* one more command successfully read and interpreted */
787   }
788   /* end while */
789
790   PRINT_PROGNAME;
791   fprintf (stderr, "(dt2dv) :\n");
792   fprintf (stderr, "Read (from file \"%s\") ", dtl_filename);
793   fprintf (stderr, WF, dtl_read);
794   fprintf (stderr, " DTL bytes (");
795   fprintf (stderr, UF4, dtl_line.num);
796   fprintf (stderr, " lines);\n");
797   fprintf (stderr, "wrote (to file \"%s\") ", dvi_filename);
798   fprintf (stderr, WF, dvi_written);
799   fprintf (stderr, " DVI bytes;\n");
800   fprintf (stderr, "completely interpreted ");
801   fprintf (stderr, WF, ncom);
802   fprintf (stderr, " DVI command%s.\n", (ncom == 1 ? "" : "s"));
803   fprintf (stderr, "\n");
804
805   (Void) free_cmds (cmd_table);
806
807   return 1;  /* OK */
808 }
809 /* dt2dv */
810
811
812 Void *
813 gmalloc
814 #ifdef STDC
815   (long int size)
816 #else
817   (size)
818   long int size;
819 #endif
820 {
821   Void * p = NULL;
822   if (size < 1)
823   {
824     PRINT_PROGNAME;
825     fprintf (stderr, "(gmalloc) : INTERNAL ERROR : ");
826     fprintf (stderr,
827       "unreasonable request to malloc %ld bytes\n",
828       size);
829     dexit (1);
830   }
831   p = (Void *) malloc ((size_t) size);
832   if (p == NULL)
833   {
834     PRINT_PROGNAME;
835     fprintf (stderr, "(gmalloc) : MEMORY ALLOCATION ERROR : ");
836     fprintf (stderr,
837       "operating system failed to malloc %ld bytes\n",
838       size);
839     dexit (1);
840   }
841   return (p);
842 }
843 /* gmalloc */
844
845
846 Void
847 dinfo (VOID)
848 {
849   PRINT_PROGNAME;
850   fprintf (stderr, "(dinfo) : ");
851   fprintf (stderr, "Current DTL input line ");
852   fprintf (stderr, UF4, dtl_line.num);
853   fprintf (stderr, " :\n");
854   fprintf (stderr, "\"%s\"\n", dtl_line.buf);
855   fprintf (stderr, "Read ");
856   fprintf (stderr, WF, dtl_read);
857   fprintf (stderr, " DTL bytes (");
858   fprintf (stderr, WF, com_read);
859   fprintf (stderr, " in current command), wrote ");
860   fprintf (stderr, WF, dvi_written);
861   fprintf (stderr, " DVI bytes.\n");
862   fprintf (stderr, "Successfully interpreted ");
863   fprintf (stderr, WF, ncom);
864   fprintf (stderr, " DVI command%s.\n", (ncom == 1 ? "" : "s"));
865 }
866 /* dinfo */
867
868
869 Void
870 dexit
871 #ifdef STDC
872   (int n)
873 #else
874   (n)
875   int n;
876 #endif
877 {
878   dinfo();
879   PRINT_PROGNAME;
880   fprintf (stderr, "(dexit) : exiting with status %d.\n", n);
881   exit (n);
882 }
883 /* dexit */
884
885
886 int
887 cons_cmds
888 #ifdef STDC
889   (int nprefixes, CmdPrefix * prefix, CmdTable cmds)
890 #else
891   (nprefixes, prefix, cmds)
892   int nprefixes;
893   CmdPrefix * prefix;
894   CmdTable cmds;
895 #endif
896 {
897   int code;  /* first opcode for a given command prefix */
898   int opcode;  /* command's opcode */
899   int nsuffixes;  /* number of commands with a given prefix */
900   int isuffix;  /**** integer suffix, of at most three digits ****/
901   String suffix;  /* suffix string generated from integer suffix */
902   size_t plen = 0;  /* prefix length */
903   size_t slen;  /* suffix length */
904   size_t clen;  /* whole command name length */
905   int i, j;  /* loop indices */
906
907   for (i=0; i < nprefixes; prefix++, i++)
908   {
909     code = prefix->first_code;
910     if (code < 0 || code > 255)
911     {
912       PRINT_PROGNAME;
913       fprintf (stderr, "(cons_cmds) : INTERNAL ERROR : ");
914       fprintf (stderr,
915         "prefix listed internally with code = %d, must be 0 to 255\n",
916         code);
917       dexit (1);
918     }
919     if (prefix->has_suffix)
920     {
921       plen = strlen (prefix->name);
922       /**** Suffixes in DTL are Integers, in Sequence */
923       if (prefix->last_suffix < prefix->first_suffix)
924       {
925         PRINT_PROGNAME;
926         fprintf (stderr, "(cons_cmds) : INTERNAL ERROR : ");
927         fprintf (stderr,
928           "prefix's last suffix %d < first suffix (%d)\n",
929           prefix->last_suffix, prefix->first_suffix);
930         dexit (1);
931       }
932       nsuffixes = prefix->last_suffix - prefix->first_suffix + 1;
933       opcode = prefix->first_code;
934       for (j=0; j < nsuffixes; j++, opcode++)
935       {
936         isuffix = prefix->first_suffix + j;
937         if (0 <= code && code <= 127)  /* SETCHAR */
938         {
939           /* SETCHAR's suffix is written in uppercase hexadecimal */
940           sprintf (suffix, "%02X", isuffix);
941         }
942         else  /* 128 <= code && code <= 255 */  /* other DTL commands */
943         {
944           /* other commands' suffices are written in decimal */
945           sprintf (suffix, "%d", isuffix);
946         }
947         slen = strlen (suffix);
948         clen = plen + slen;
949         cmds[opcode] = (char *) gmalloc (clen+1);
950         strcpy (cmds[opcode], prefix->name);
951         strcat (cmds[opcode], suffix);
952       }
953     }
954     else /* command name = prefix */
955     {
956       plen = strlen (prefix->name);
957       clen = plen;
958       opcode = prefix->first_code;
959       cmds[opcode] = (char *) gmalloc (clen+1);
960       strcpy (cmds[opcode], prefix->name);
961     }
962   }
963
964   return 1;  /* OK */
965 }
966 /* cons_cmds */
967
968
969 Void
970 free_cmds
971 #ifdef STDC
972   (CmdTable cmd_table)
973 #else
974   (cmd_table)
975   CmdTable cmd_table;
976 #endif
977 {
978   int i;
979   for (i=0; i < NCMDS; i++)
980     gfree (cmd_table[i]);
981 }
982 /* free_cmds */
983
984
985 int
986 get_line
987 #ifdef STDC
988   (FILE * fp, Line * line, int max)
989 #else
990   (fp, line, max)
991   FILE * fp;
992   Line * line;
993   int max;
994 #endif
995 /* read a (Line *) line from fp, return length */
996 /* adapted from K&R (second, alias ANSI C, edition, 1988), page 165 */
997 {
998   if (fgets (line->buf, max, fp) == NULL)
999     return 0;
1000   else
1001   {
1002     ++ line->num;
1003     line->wrote = strlen (line->buf);
1004     line->read = 0;
1005     return 1;
1006   }
1007 }
1008 /* get_line */
1009
1010
1011 int
1012 read_line_char
1013 #ifdef STDC
1014   (FILE * fp, int * ch)
1015 #else
1016   (fp, ch)
1017   FILE * fp;
1018   int * ch;
1019 #endif
1020 /* read one character from dtl_line if possible, */
1021 /* otherwise read another dtl_line from fp */
1022 /* return 1 if a character is read, 0 if at end of fp file */
1023 {
1024   extern Line dtl_line;
1025   if (dtl_line.wrote == 0 || dtl_line.read >= dtl_line.wrote)
1026   {
1027     int line_status;
1028     /* refill line buffer */
1029     line_status = get_line (fp, &dtl_line, MAXLINE);
1030     if (line_status == 0)
1031     {
1032       /* at end of DTL file */
1033       if (debug)
1034       {
1035         PRINT_PROGNAME;
1036         fprintf (stderr, "(read_line_char) : end of DTL file\n");
1037         dinfo();
1038       }
1039       return 0;
1040     }
1041     else
1042     {
1043       /* new DTL line was read */
1044       if (debug)
1045       {
1046         PRINT_PROGNAME;
1047         fprintf (stderr, "(read_line_char) : new DTL input line:\n");
1048         fprintf (stderr, "\"%s\"\n", dtl_line.buf);
1049       }
1050     }
1051   }
1052   *ch = dtl_line.buf [dtl_line.read ++];
1053   ++ dtl_read;
1054   ++ com_read;  /* count another DTL command character */
1055   return 1;
1056 }
1057 /* read_line_char */
1058
1059
1060 int
1061 read_char
1062 #ifdef STDC
1063   (FILE * fp, int * ch)
1064 #else
1065   (fp, ch)
1066   FILE * fp;
1067   int * ch;
1068 #endif
1069 /* Read next character, if any, from file fp. */
1070 /* Write it into *ch. */
1071 /* If no character is read, then *ch value < 0. */
1072 /* Return 1 if OK, 0 if EOF or error. */
1073 {
1074   int status = 1;
1075   int c;  /* in case ch points awry, we still have something in c. */
1076
1077   c = EOF;
1078   if (read_line_char (fp, &c) == 0)
1079   {
1080     /* end of fp file, or error reading it */
1081     status = 0;
1082   }
1083   else
1084   {
1085     if (c > 255)
1086     {
1087       PRINT_PROGNAME;
1088       fprintf (stderr,
1089         "(read_char) : character %d not in range 0 to 255\n",
1090         c);
1091       dinfo();
1092       status = 0;
1093     }
1094     else if ( ! isprint (c) && ! isspace (c))
1095     {
1096       PRINT_PROGNAME;
1097       fprintf (stderr,
1098         "(read_char) : character %d %s.\n",
1099         c,
1100         "not printable and not white space");
1101       dinfo();
1102       status = 0;
1103     }
1104   }
1105   *ch = c;
1106
1107   return status;
1108 }
1109 /* read_char */
1110
1111
1112 COUNT
1113 read_variety
1114 #ifdef STDC
1115   (FILE * dtl)
1116 #else
1117   (dtl)
1118   FILE * dtl;
1119 #endif
1120 /* read and check DTL variety signature */
1121 /* return number of DTL bytes written */
1122 /* DTL variety is _NEVER_ grouped by BCOM and ECOM. */
1123 /* Uniformity here enables the program easily to modify its behavior. */
1124 {
1125   COUNT vread = 0;  /* number of DTL bytes read by read_variety */
1126   COUNT nread = 0;  /* number of DTL bytes read by read_token */
1127   static Token token = "";
1128
1129   /* read the DTL VARIETY keyword */
1130   nread = read_token (dtl, token);
1131   vread += nread;
1132   /* test whether signature begins correctly */
1133   if (strcmp (token, "variety") != 0)
1134   {
1135     PRINT_PROGNAME;
1136     fprintf (stderr, "(read_variety) : DTL FILE ERROR (%s) : ", dtl_filename);
1137     fprintf (stderr, "DTL signature must begin with \"%s\", not \"%s\".\n",
1138       "variety", token);
1139     dexit (1);
1140   }
1141
1142   /* read the DTL variety */
1143   nread = read_token (dtl, token);
1144   vread += nread;
1145   /* test whether variety is correct */
1146   if (strcmp (token, VARIETY) != 0)
1147   {
1148     PRINT_PROGNAME;
1149     fprintf (stderr, "(read_variety) : DTL FILE ERROR (%s) : ", dtl_filename);
1150     fprintf (stderr, "DTL variety must be \"%s\", not \"%s\".\n",
1151       VARIETY, token);
1152     dexit (1);
1153   }
1154
1155   PRINT_PROGNAME;
1156   fprintf (stderr, "(read_variety) : DTL variety %s is OK.\n", VARIETY);
1157
1158   return vread;  /* OK */
1159 }
1160 /* read_variety */
1161
1162
1163 COUNT
1164 skip_space
1165 #ifdef STDC
1166   (FILE * fp, int * ch)
1167 #else
1168   (fp, ch)
1169   FILE * fp;
1170   int * ch;
1171 #endif
1172 /* Skip whitespace characters in file fp. */
1173 /* Write in *ch the last character read from fp, */
1174 /*   or < 0 if fp could not be read. */
1175 /* Return number of characters read from fp. */
1176 {
1177   int c;  /* character read (if any) */
1178   COUNT count;  /* number (0 or more) of whitespace characters read */
1179   int nchar;  /* number (0 or 1) of characters read by read_char */
1180
1181   /* loop ends at:  end of fp file, or reading error, or not a white space */
1182   for (count=0;  ((nchar = read_char (fp, &c)) == 1 && isspace (c));  ++count)
1183   {
1184     /* otherwise, more white spaces to skip */
1185     if (debug)
1186     {
1187       /* report when each DTL end of line is reached */
1188       if (c == '\n')
1189       {
1190         PRINT_PROGNAME;
1191         fprintf (stderr, "(skip_space) : ");
1192         fprintf (stderr, "end of DTL line (at least) ");
1193         fprintf (stderr, WF, dtl_line.num);
1194         fprintf (stderr, "\n");
1195       }
1196     }
1197   }
1198
1199   if (nchar == 0)
1200   {
1201     c = -1;
1202   }
1203
1204   *ch = c;  /* c will be < 0 if read_char could not read fp */
1205   return (count + nchar);
1206 }
1207 /* skip_space */
1208
1209
1210 COUNT
1211 read_token
1212 #ifdef STDC
1213   (FILE * dtl, char * token)
1214 #else
1215   (dtl, token)
1216   FILE * dtl;
1217   char * token;
1218 #endif
1219 /* read next token from dtl file. */
1220 /* return number of DTL bytes read. */
1221 /* A token is one of:
1222      a string from BMES_CHAR to the next unescaped EMES_CHAR, inclusive;
1223      BCOM or ECOM, unless these are empty strings;
1224      BSEQ or ESEQ;
1225      any other sequence of non-whitespace characters.
1226 */
1227 {
1228   COUNT nread;  /* number of DTL bytes read by read_token */
1229   int ch;  /* most recent character read */
1230
1231   nread = 0;
1232
1233   /* obtain first non-space character */
1234   /* add to nread the number of characters read from dtl by skip_space */
1235   nread += skip_space (dtl, &ch);
1236
1237   if (ch < 0)
1238   {
1239     /* end of dtl file */
1240     /* write an empty token */
1241     strcpy (token, "");
1242     if (debug)
1243     {
1244       PRINT_PROGNAME;
1245       fprintf (stderr, "(read_token) : end of dtl file.\n");
1246     }
1247   }
1248   else if (group && ch == BCOM_CHAR)
1249   {
1250     strcpy (token, BCOM);
1251   }
1252   else if (group && ch == ECOM_CHAR)
1253   {
1254     strcpy (token, ECOM);
1255   }
1256   else
1257   {
1258     token[0] = ch;
1259     token[1] = '\0';
1260     if (ch == BMES_CHAR)  /* string token; read until unescaped EMES_CHAR */
1261     {
1262       nread += read_mes (dtl, token+1);
1263     }
1264     else if (ch == BSEQ_CHAR || ch == ESEQ_CHAR)
1265     {
1266       /* token is complete */
1267     }
1268     else  /* any other string not containing (ECOM_CHAR or) whitespace */
1269     {
1270       nread += read_misc (dtl, token+1);
1271     }
1272   }
1273
1274   if (debug)
1275   {
1276     PRINT_PROGNAME;
1277     fprintf (stderr, "(read_token) : token = \"%s\"\n", token);
1278   }
1279
1280   return (nread);  /* number of bytes read from dtl file */
1281 }
1282 /* read_token */
1283
1284
1285 #define CHAR_OK  1
1286 #define CHAR_FAIL  0
1287 #define CHAR_EOS  (-1)
1288
1289 int
1290 read_string_char
1291 #ifdef STDC
1292   (FILE * fp, int * ch)
1293 #else
1294   (fp, ch)
1295   FILE * fp;
1296   int * ch;
1297 #endif
1298 {
1299   int status = CHAR_OK;  /* OK so far */
1300   int c;
1301
1302   if (read_char (fp, &c) == 0)
1303     status = CHAR_FAIL;  /* fail */
1304
1305   if (c == EMES_CHAR)  /* end-of-string char */
1306   {
1307     status = CHAR_EOS;  /* end of string */
1308   }
1309   else if (c == ESC_CHAR)  /* escape character */
1310   {
1311     /* accept the next character literally, even ESC_CHAR and EMES_CHAR */
1312     if (read_char (fp, &c) == 0)
1313       status = CHAR_FAIL;  /* fail */
1314   }
1315
1316   *ch = c;
1317   return status;
1318 }
1319 /* read_string_char */
1320
1321
1322 COUNT
1323 read_misc
1324 #ifdef STDC
1325   (FILE * fp, Token token)
1326 #else
1327   (fp, token)
1328   FILE * fp;
1329   Token token;
1330 #endif
1331 {
1332   int c;
1333   int count;
1334  /* loop ends at:  end of fp file, or reading error, or a space */
1335   for (count=0;  count <= MAXTOKLEN;  ++count)
1336   {
1337     if (read_char (fp, &c) == 0  ||  isspace (c))
1338       break;
1339     if (group && c == ECOM_CHAR)
1340     {
1341       (Void) unread_char ();
1342       break;
1343     }
1344
1345     token[count] = c;
1346   }
1347   token[count] = '\0';
1348   return count;
1349 }
1350 /* read_misc */
1351
1352
1353 COUNT
1354 read_mes
1355 #ifdef STDC
1356   (FILE * fp, char * token)
1357 #else
1358   (fp, token)
1359   FILE * fp;
1360   char * token;
1361 #endif
1362 /* called **AFTER** a BMES_CHAR has been read */
1363 /* read file fp for characters up to next unescaped EMES_CHAR */
1364 /* this is called a "string token" */
1365 /* write string, including EMES_CHAR, into token[] */
1366 /* return number of characters read from fp */
1367 {
1368   COUNT dtl_count;  /* number of DTL characters read by read_mes from fp */
1369   int more;  /* flag more == 0 to terminate loop */
1370   int escape;  /* flag escape == 1 if previous character was ESC_CHAR */
1371   int ch;  /* current DTL character */
1372
1373   escape = 0;
1374   more = 1;
1375   dtl_count = 0;
1376   while (more)
1377   {
1378     if (read_char (fp, &ch) == 0)
1379     {
1380       /* end of fp file, or reading error */
1381       more = 0;
1382     }
1383     else  /* error checking passed */
1384     {
1385       ++ dtl_count;
1386       if (ch == EMES_CHAR && escape == 0)  /* end of string */
1387       {
1388         /* include final EMES_CHAR */
1389         * token ++ = ch;
1390         more = 0;
1391       }
1392       else if (ch == ESC_CHAR && escape == 0)
1393       {
1394         /* next character is not end of string */
1395         escape = 1;
1396       }
1397       else
1398       {
1399         /* store any other character, */
1400         /* including escaped EMES_CHAR and ESC_CHAR*/
1401         * token ++ = ch;
1402         escape = 0;
1403       }
1404     }
1405   }
1406   * token = '\0';
1407   return dtl_count;
1408 }
1409 /* read_mes */
1410
1411
1412 int
1413 unread_char (VOID)
1414 /* wind input back, to allow rereading of one character */
1415 /* return 1 if this works, 0 on error */
1416 {
1417   extern Line dtl_line;
1418   int status;
1419   if (dtl_line.read > 0)
1420   {
1421     -- dtl_line.read;  /* back up one character in dtl_line */
1422     -- dtl_read;  /* correct the count of DTL characters */
1423     -- com_read;  /* count another DTL command character */
1424     status = 1;  /* OK */
1425   }
1426   else /* current DTL line is empty */
1427   {
1428     status = 0;  /* error */
1429   }
1430   return status;
1431 }
1432 /* unread_char */
1433
1434
1435 int
1436 find_command
1437 #ifdef STDC
1438   (char * command, int * opcode)
1439 #else
1440   (command, opcode)
1441   char * command;
1442   int * opcode;
1443 #endif
1444 {
1445   int found;
1446   int i;
1447
1448   found = 0;
1449   for (i=0; i < NCMDS; i++)
1450   {
1451     if ((cmd_table[i] != 0) && (strcmp (command, cmd_table[i]) == 0))
1452     {
1453       found = 1;
1454       break;
1455     }
1456   }
1457
1458   *opcode = i;
1459
1460   return found;
1461 }
1462 /* find_command */
1463
1464
1465 int
1466 check_byte
1467 #ifdef STDC
1468   (int byte)
1469 #else
1470   (byte)
1471   int byte;
1472 #endif
1473 {
1474   if (byte < 0 || byte > 255)
1475   {
1476     PRINT_PROGNAME;
1477     fprintf (stderr, "(check_byte) : INTERNAL ERROR : ");
1478     fprintf (stderr, "byte %d not in the range of 0 to 255.\n", byte);
1479     dexit (1);
1480   }
1481   return 1;  /* OK */
1482 }
1483 /* check_byte */
1484
1485
1486 int
1487 xfer_args
1488 #ifdef STDC
1489   (FILE * dtl, FILE * dvi, int opcode)
1490 #else
1491   (dtl, dvi, opcode)
1492   FILE * dtl;
1493   FILE * dvi;
1494   int opcode;
1495 #endif
1496 {
1497   int n;
1498
1499   if (opcode >= 0 && opcode <= 127)
1500     ;  /* SETCHAR uses no data */
1501   else if (opcode >= 128 && opcode <= 170)
1502   {
1503     word_t this_bop_address = last_bop_address;
1504
1505     if (opcode == 139)  /* BOP */
1506     {
1507       this_bop_address = dvi_written - 1;
1508     }
1509     put_table (op_128_170, opcode, dtl, dvi);
1510     if (opcode == 139)  /* BOP */
1511     {
1512       xfer_bop_address (dtl, dvi);
1513       last_bop_address = this_bop_address;
1514     }
1515   }
1516   else if (opcode >= 171 && opcode <= 234)
1517     ;  /* FONTNUM uses no data */
1518   else if (opcode >= 235 && opcode <= 238)
1519     put_table (fnt, opcode, dtl, dvi);
1520   else if (opcode >= 239 && opcode <= 242)
1521   {
1522     n = opcode - 238;
1523     special (dtl, dvi, n);
1524   }
1525   else if (opcode >= 243 && opcode <= 246)
1526   {
1527     n = opcode - 242;
1528     fontdef (dtl, dvi, n);
1529   }
1530   else if (opcode == 247)
1531     preamble (dtl, dvi);
1532   else if (opcode == 248)
1533     postamble (dtl, dvi);
1534   else if (opcode == 249)
1535     post_post (dtl, dvi);
1536   else if (opcode >= 250 && opcode <= 255)
1537     ;  /* these, undefined, opcodes use no data */
1538   else
1539   {
1540     PRINT_PROGNAME;
1541     fprintf (stderr,
1542       "(xfer_args) : opcode %d not handled.\n",
1543       opcode);
1544   }
1545
1546   return 1;  /* OK */
1547 }
1548 /* xfer_args */
1549
1550
1551 int
1552 set_seq
1553 #ifdef STDC
1554   (FILE * dtl, FILE * dvi)
1555 #else
1556   (dtl, dvi)
1557   FILE * dtl;
1558   FILE * dvi;
1559 #endif
1560 /* Called _after_ a BSEQ_CHAR command */
1561 /* Read bytes from dtl file, */
1562 /* writing corresponding SETCHAR or SET1 commands to DVI file, */
1563 /* _until_ unescaped ESEQ_CHAR is found */
1564 /* Return 1 if OK, 0 on error */
1565 /****  dt2dv assumes 8 bit characters,      ****/
1566 /****  but some day one might change that.  ****/
1567 {
1568   int status = 1;  /* status = 1 if OK, 0 if error */
1569   int more;  /* sequence of font characters continuing? */
1570   int escape = 0;  /* flag set if previous character was an escape */
1571   int ch;  /* character read from DTL file */
1572   more = 1;
1573   while (more)
1574   {
1575     /* ignore read_char status, to allow unprintable characters */
1576     (Void) read_char (dtl, &ch);
1577     /* but check for end of dtl file, or serious file reading error */
1578     if (ch < 0)
1579     {
1580       PRINT_PROGNAME;
1581       fprintf (stderr, "(set_seq) : ");
1582       fprintf (stderr, "end of dtl file, ");
1583       fprintf (stderr, "or serious dtl file reading error\n");
1584       dinfo();
1585       more = 0;
1586       status = 0;  /* bad news */
1587     }
1588     else  /* read dtl file, okay */
1589     {
1590       if (ch == ESC_CHAR && escape == 0)  /* escape next character */
1591       {
1592         escape = 1;
1593       }
1594       else
1595       {
1596         if (ch == ESEQ_CHAR && escape == 0)  /* end of sequence */
1597         {
1598           more = 0;
1599         }
1600         else if (ch <= 127)  /* can use SETCHAR */
1601         {
1602           put_byte (ch, dvi);
1603         }
1604         else if (ch <= 255)  /* can use SET1 */
1605         {
1606           put_byte (128, dvi);  /* SET1 opcode */
1607           put_unsigned (1, (U4) ch, dvi);
1608         }
1609         else
1610         {
1611           PRINT_PROGNAME;
1612           fprintf (stderr, "(set_seq) : ");
1613           fprintf (stderr,
1614             "ERROR : DTL character %d is not in range 0 to 255\n",
1615             ch);
1616           dexit (1);
1617           more = 0;
1618           status = 0;  /* Error, because dt2dv assumes 8 bit characters */
1619         }
1620         escape = 0;  /* current ch is not an escape character */
1621       }
1622     }
1623   }
1624   return status;
1625 }
1626 /* set_seq */
1627
1628
1629 U4
1630 xfer_hex
1631 #ifdef STDC
1632   (int n, FILE * dtl, FILE * dvi)
1633 #else
1634   (n, dtl, dvi)
1635   int n;
1636   FILE * dtl;
1637   FILE * dvi;
1638 #endif
1639 /* translate unsigned n-byte hexadecimal number from dtl to dvi file. */
1640 /* return value of hexadecimal number */
1641 {
1642   U4 unum = 0;  /* at most this space needed */
1643   COUNT nread = 0;  /* number of DTL bytes read by read_token */
1644   int nconv = 0;  /* number of arguments converted by sscanf */
1645   static Token token = "";  /* DTL token */
1646
1647   if (n < 1 || n > 4)
1648   {
1649     PRINT_PROGNAME;
1650     fprintf (stderr,
1651       "(xfer_hex) : INTERNAL ERROR : asked for %d bytes.  Must be 1 to 4.\n",
1652       n);
1653     dexit (1);
1654   }
1655
1656   nread = read_token (dtl, token);
1657
1658   nconv = sscanf (token, XF4, &unum);
1659
1660   if (nconv < 1)
1661   {
1662     PRINT_PROGNAME;
1663     fprintf (stderr, "(xfer_hex) : DTL FILE ERROR (%s) :  %s \"%s\".\n",
1664       dtl_filename, "hexadecimal number expected, not", token);
1665     dexit (1);
1666   }
1667
1668   put_unsigned (n, unum, dvi);
1669
1670   return unum;
1671 }
1672 /* xfer_hex */
1673
1674
1675 U4
1676 xfer_oct
1677 #ifdef STDC
1678   (int n, FILE * dtl, FILE * dvi)
1679 #else
1680   (n, dtl, dvi)
1681   int n;
1682   FILE * dtl;
1683   FILE * dvi;
1684 #endif
1685 /* translate unsigned n-byte octal number from dtl to dvi file. */
1686 /* return value of octal number */
1687 {
1688   U4 unum = 0;  /* at most this space needed */
1689   COUNT nread = 0;  /* number of DTL bytes read by read_token */
1690   int nconv = 0;  /* number of arguments converted by sscanf */
1691   static Token token = "";  /* DTL token */
1692
1693   if (n < 1 || n > 4)
1694   {
1695     PRINT_PROGNAME;
1696     fprintf (stderr,
1697       "(xfer_oct) : INTERNAL ERROR : asked for %d bytes.  Must be 1 to 4.\n",
1698       n);
1699     dexit (1);
1700   }
1701
1702   nread = read_token (dtl, token);
1703
1704   nconv = sscanf (token, OF4, &unum);
1705
1706   if (nconv < 1)
1707   {
1708     PRINT_PROGNAME;
1709     fprintf (stderr, "(xfer_oct) : DTL FILE ERROR (%s) :  %s \"%s\".\n",
1710       dtl_filename, "octal number expected, not", token);
1711     dexit (1);
1712   }
1713
1714   put_unsigned (n, unum, dvi);
1715
1716   return unum;
1717 }
1718 /* xfer_oct */
1719
1720
1721 U4
1722 xfer_unsigned
1723 #ifdef STDC
1724   (int n, FILE * dtl, FILE * dvi)
1725 #else
1726   (n, dtl, dvi)
1727   int n;
1728   FILE * dtl;
1729   FILE * dvi;
1730 #endif
1731 /* translate unsigned n-byte number from dtl to dvi file. */
1732 /* return value of unsigned number */
1733 {
1734   U4 unum = 0;  /* at most this space needed */
1735
1736   unum = get_unsigned (dtl);
1737   put_unsigned (n, unum, dvi);
1738
1739   return unum;
1740 }
1741 /* xfer_unsigned */
1742
1743
1744 S4
1745 xfer_signed
1746 #ifdef STDC
1747   (int n, FILE * dtl, FILE * dvi)
1748 #else
1749   (n, dtl, dvi)
1750   int n;
1751   FILE * dtl;
1752   FILE * dvi;
1753 #endif
1754 /* translate signed n-byte number from dtl to dvi file. */
1755 /* return value of signed number */
1756 {
1757   S4 snum = 0;
1758
1759   snum = get_signed (dtl);
1760   put_signed (n, snum, dvi);
1761
1762   return snum;
1763 }
1764 /* xfer_signed */
1765
1766
1767 U4
1768 get_unsigned
1769 #ifdef STDC
1770   (FILE * dtl)
1771 #else
1772   (dtl)
1773   FILE * dtl;
1774 #endif
1775 /* read unsigned number from dtl file. */
1776 /* return value of unsigned number */
1777 {
1778   U4 unum = 0;  /* at most this space needed */
1779   COUNT nread = 0;  /* number of DTL bytes read by read_token */
1780   int nconv = 0;  /* number of arguments converted by sscanf */
1781   static Token token = "";  /* DTL token */
1782
1783   nread = read_token (dtl, token);
1784
1785   nconv = sscanf (token, UF4, &unum);
1786
1787   if (nconv < 1)
1788   {
1789     PRINT_PROGNAME;
1790     fprintf (stderr, "(get_unsigned) : DTL FILE ERROR (%s) :  %s \"%s\".\n",
1791       dtl_filename, "unsigned number expected, not", token);
1792     dexit (1);
1793   }
1794
1795   return unum;
1796 }
1797 /* get_unsigned */
1798
1799
1800 S4
1801 get_signed
1802 #ifdef STDC
1803   (FILE * dtl)
1804 #else
1805   (dtl)
1806   FILE * dtl;
1807 #endif
1808 /* read signed number from dtl file. */
1809 /* return value of signed number */
1810 {
1811   S4 snum = 0;
1812   COUNT nread = 0;  /* number of DTL bytes read by read_token */
1813   int nconv = 0;  /* number of sscanf arguments converted and assigned */
1814   static Token token = "";
1815
1816   nread = read_token (dtl, token);
1817
1818   nconv = sscanf (token, SF4, &snum);
1819
1820   if (nconv < 1)
1821   {
1822     PRINT_PROGNAME;
1823     fprintf (stderr, "(get_signed) : DTL FILE ERROR (%s) :  %s \"%s\".\n",
1824       dtl_filename, "signed number expected, not", token);
1825     dexit (1);
1826   }
1827
1828   return snum;
1829 }
1830 /* get_signed */
1831
1832
1833 int
1834 put_unsigned
1835 #ifdef STDC
1836   (int n, U4 unum, FILE * dvi)
1837 #else
1838   (n, unum, dvi)
1839   int n;
1840   U4 unum;
1841   FILE * dvi;
1842 #endif
1843 /* put unsigned in-byte integer to dvi file */
1844 /* DVI format uses Big-endian storage of numbers: */
1845 /* most significant byte is first. */
1846 /* return number of bytes written. */
1847 {
1848   Byte ubyte[4];  /* at most 4 bytes needed in DVI format */
1849   int i;
1850
1851   if (n < 1 || n > 4)
1852   {
1853     PRINT_PROGNAME;
1854     fprintf (stderr,
1855       "(put_unsigned) : INTERNAL ERROR : asked for %d bytes.  Must be 1 to 4.\n",
1856       n);
1857     dexit (1);
1858   }
1859
1860   /* Big-endian storage. */
1861   for (i = 0; i < n; i++)
1862   {
1863     ubyte[i] = (Byte) (unum % 256);
1864     unum /= 256;
1865   }
1866   /* Reverse order for big-endian representation. */
1867   for (i = n-1;  i >= 0;  i--)
1868   {
1869     put_byte ((int) ubyte[i], dvi);
1870   }
1871
1872   return n;
1873 }
1874 /* put_unsigned */
1875
1876
1877 int
1878 put_signed
1879 #ifdef STDC
1880   (int n, S4 snum, FILE * dvi)
1881 #else
1882   (n, snum, dvi)
1883   int n;
1884   S4 snum;
1885   FILE * dvi;
1886 #endif
1887 /* put signed in-byte integer to dvi file */
1888 /* DVI format uses 2's complement Big-endian storage of signed numbers: */
1889 /* most significant byte is first. */
1890 /* return number of bytes written. */
1891 {
1892   /* Will this deal properly with the sign? */
1893
1894   if (n < 1 || n > 4)
1895   {
1896     PRINT_PROGNAME;
1897     fprintf (stderr,
1898       "(put_signed) : INTERNAL ERROR : asked for %d bytes.  Must be 1 to 4.\n",
1899       n);
1900     dexit (1);
1901   }
1902
1903   /* How do we ensure 2's complement representation? */
1904   /* Here's a trick that I hope is portable, given ANSI C. */
1905   /* See K&R (2nd edition), Appendix A6.2 "Integral Conversions". */
1906
1907   /* Convert snum to U4 data type */
1908   put_unsigned (n, (U4) snum, dvi);
1909
1910   return n;
1911 }
1912 /* put_signed */
1913
1914
1915 int
1916 check_bmes
1917 #ifdef STDC
1918   (FILE * dtl)
1919 #else
1920   (dtl)
1921   FILE * dtl;
1922 #endif
1923 /* check that a BMES_CHAR is the next non-whitespace character in dtl */
1924 {
1925   int ch;  /* next non-whitespace character in dtl */
1926
1927   /* `(Void)' because we ignore the number of spaces skipped */
1928   (Void) skip_space (dtl, &ch);
1929
1930   if (ch < 0)
1931   {
1932     PRINT_PROGNAME;
1933     fprintf (stderr, "(check_bmes) : DTL FILE ERROR (%s) : ",
1934       dtl_filename);
1935     fprintf (stderr, "end of dtl file, or reading error\n");
1936     dexit (1);
1937   }
1938
1939   if (ch != BMES_CHAR)
1940   {
1941     PRINT_PROGNAME;
1942     fprintf (stderr, "(check_bmes) : DTL FILE ERROR (%s) : ",
1943       dtl_filename);
1944     fprintf (stderr, "BMES_CHAR (`%c') %s, not `%c' (char %d).\n",
1945       BMES_CHAR, "expected before string", ch, ch);
1946     dexit (1);
1947   }
1948
1949   return 1;  /* OK */
1950 }
1951 /* check_bmes */
1952
1953
1954 int
1955 check_emes
1956 #ifdef STDC
1957   (FILE * dtl)
1958 #else
1959   (dtl)
1960   FILE * dtl;
1961 #endif
1962 /* check that an EMES_CHAR is the next character in dtl */
1963 {
1964   int ch;  /* dtl character */
1965
1966   if (read_char (dtl, &ch) == 0)
1967   {
1968     PRINT_PROGNAME;
1969     fprintf (stderr, "(check_emes) : DTL FILE ERROR (%s) : ",
1970       dtl_filename);
1971     fprintf (stderr, "end of dtl file, or reading error\n");
1972     dexit (1);
1973   }
1974
1975   if (ch != EMES_CHAR)
1976   {
1977     PRINT_PROGNAME;
1978     fprintf (stderr, "(check_emes) : DTL FILE ERROR (%s) : ",
1979       dtl_filename);
1980     fprintf (stderr, "EMES_CHAR (`%c') %s, not `%c' (char %d).\n",
1981       EMES_CHAR, "expected to follow string", ch, ch);
1982     dexit (1);
1983   }
1984
1985   return 1;  /* OK */
1986 }
1987 /* check_emes */
1988
1989
1990 /* Size typically used in this program for Lstring variables */
1991 #define LSIZE 1024
1992
1993
1994 Void
1995 init_Lstring
1996 #ifdef STDC
1997   (Lstring * lsp, long int n)
1998 #else
1999   (lsp, n)
2000   Lstring * lsp;
2001   long int n;
2002 #endif
2003 {
2004   lsp->l = 0;
2005   lsp->m = n;
2006   lsp->s = (char *) gmalloc (n);
2007 }
2008 /* init_Lstring */
2009
2010
2011 Void
2012 de_init_Lstring
2013 #ifdef STDC
2014   (Lstring * lsp)
2015 #else
2016   (lsp)
2017   Lstring * lsp;
2018 #endif
2019 {
2020   lsp->l = 0;
2021   lsp->m = 0;
2022   free (lsp->s);
2023   lsp->s = NULL;  /* to be sure */
2024 }
2025 /* de_init_Lstring */
2026
2027
2028 Lstring *
2029 alloc_Lstring
2030 #ifdef STDC
2031   (long int n)
2032 #else
2033   (n)
2034   long int n;
2035 #endif
2036 {
2037   Lstring * lsp;
2038   lsp = (Lstring *) gmalloc (sizeof (Lstring));
2039   init_Lstring (lsp, n);
2040   return (lsp);
2041 }
2042 /* alloc_Lstring */
2043
2044
2045 Void
2046 free_Lstring
2047 #ifdef STDC
2048   (Lstring * lstr)
2049 #else
2050   (lstr)
2051   Lstring * lstr;
2052 #endif
2053 {
2054   free (lstr->s);
2055   free (lstr);
2056 }
2057 /* free_Lstring */
2058
2059
2060 Void
2061 ls_putb
2062 #ifdef STDC
2063   (int ch, Lstring * lstr)
2064 #else
2065   (ch, lstr)
2066   int ch;
2067   Lstring * lstr;
2068 #endif
2069 /* write byte ch into Lstring *lstr */
2070 {
2071   if (lstr->l >= lstr->m)
2072   {
2073     PRINT_PROGNAME;
2074     fprintf (stderr, "(ls_putb) : ERROR : No more room in Lstring.\n");
2075     dexit (1);
2076   }
2077   else
2078   {
2079     lstr->s [(lstr->l)++] = ch;
2080   }
2081 }
2082 /* ls_putb */
2083
2084
2085 long int
2086 get_Lstring
2087 #ifdef STDC
2088   (FILE * dtl, Lstring * lstr)
2089 #else
2090   (dtl, lstr)
2091   FILE * dtl;
2092   Lstring * lstr;
2093 #endif
2094 /* get a string from dtl file, store as an Lstring in *lstr. */
2095 /* lstr must already be allocated and initialised. */
2096 /* return length of Lstring *lstr */
2097 {
2098   U4 nch;
2099   int char_status = CHAR_OK;  /* OK so far */
2100
2101   if (debug)
2102   {
2103     PRINT_PROGNAME;
2104     fprintf (stderr, "(get_Lstring) : entering get_Lstring.\n");
2105   }
2106
2107   check_bmes (dtl);
2108
2109   if (debug)
2110   {
2111     PRINT_PROGNAME;
2112     fprintf (stderr,
2113       "(get_Lstring) : string is: \"");
2114   }
2115
2116   for (nch=0; ; nch++)
2117   {
2118     int ch;
2119
2120     char_status = read_string_char (dtl, &ch);
2121
2122     if (char_status == CHAR_FAIL)
2123     {
2124       /* end of dtl file, or reading error */
2125       fprintf (stderr, "\n");
2126       PRINT_PROGNAME;
2127       fprintf (stderr, "(get_Lstring) : DTL FILE ERROR (%s) : ",
2128         dtl_filename);
2129       fprintf (stderr, "cannot read string[");
2130       fprintf (stderr, UF4, nch);
2131       fprintf (stderr, "] from dtl file.\n");
2132       dexit (1);
2133     }
2134
2135     if (debug)
2136     {
2137       fprintf (stderr, "%c", ch);
2138     }
2139
2140     if (char_status == CHAR_EOS)
2141     {
2142       if (ch != EMES_CHAR)
2143       {
2144         PRINT_PROGNAME;
2145         fprintf (stderr, "(get_Lstring) : INTERNAL ERROR : ");
2146         fprintf (stderr, "char_status = CHAR_FAIL,\n");
2147         fprintf (stderr,
2148           "but ch = %c (char %d) is not EMES_CHAR = %c (char %d)\n",
2149           ch, ch, EMES_CHAR, EMES_CHAR);
2150         dexit (1);
2151       }
2152       (Void) unread_char ();
2153       break;  /* end of string */
2154     }
2155     else if (char_status == CHAR_OK)
2156     {
2157       ls_putb (ch, lstr);
2158     }
2159     else
2160     {
2161         PRINT_PROGNAME;
2162         fprintf (stderr, "(get_Lstring) : INTERNAL ERROR : ");
2163         fprintf (stderr, "char_status = %d is unfamiliar!\n", char_status);
2164         dexit (1);
2165     }
2166   }
2167   /* end for */
2168
2169   if (debug)
2170   {
2171     fprintf (stderr, "\".\n");
2172   }
2173
2174   check_emes (dtl);
2175
2176   if (debug)
2177   {
2178     PRINT_PROGNAME;
2179     fprintf (stderr, "(get_Lstring) : leaving get_Lstring.\n");
2180   }
2181
2182   return (lstr->l);
2183 }
2184 /* get_Lstring */
2185
2186
2187 Void
2188 put_Lstring
2189 #ifdef STDC
2190   (const Lstring * lstr, FILE * dvi)
2191 #else
2192   (str, dvi)
2193   Lstring lstr;
2194   FILE * dvi;
2195 #endif
2196 {
2197   size_t fwret;
2198   fwret = fwrite ((lstr->s), sizeof (char), (size_t) (lstr->l), dvi);
2199
2200   dvi_written += fwret;
2201
2202   if (fwret < lstr->l)
2203   {
2204     PRINT_PROGNAME;
2205     fprintf (stderr,
2206       "(put_Lstring) : DVI File ERROR : not all bytes written ");
2207     fprintf (stderr, "(%ld of %ld).\n",
2208       (long int) fwret, (long int) (lstr->l));
2209     dexit (1);
2210   }
2211 }
2212 /* put_Lstring */
2213
2214
2215 U4
2216 xfer_len_string
2217 #ifdef STDC
2218   (int n, FILE * dtl, FILE * dvi)
2219 #else
2220   (n, dtl, dvi)
2221   int n;
2222   FILE * dtl;
2223   FILE * dvi;
2224 #endif
2225 /* transfer (length and) quoted string from dtl to dvi file, */
2226 /* return number of bytes written to dvi file. */
2227 {
2228   U4 k, k2, lstr_maxsize;
2229   Lstring lstr;
2230
2231   if (debug)
2232   {
2233     PRINT_PROGNAME;
2234     fprintf (stderr, "(xfer_len_string) : entering xfer_len_string.\n");
2235   }
2236
2237   /* k[n] : length of special string */
2238
2239   k = get_unsigned (dtl);
2240
2241   lstr_maxsize = (k > LSIZE) ? k : LSIZE;
2242   init_Lstring (&lstr, lstr_maxsize);
2243
2244   if (debug)
2245   {
2246     PRINT_PROGNAME;
2247     fprintf (stderr, "(xfer_len_string) : string's nominal length k = ");
2248     fprintf (stderr, UF4, k);
2249     fprintf (stderr, " characters.\n");
2250   }
2251
2252   k2 = get_Lstring (dtl, &lstr);
2253
2254   if (k2 != k)
2255   {
2256     PRINT_PROGNAME;
2257     fprintf (stderr, "(xfer_len_string) : WARNING : string length (");
2258     fprintf (stderr, UF4, k);
2259     fprintf (stderr, ") in DTL file is wrong\n");
2260     fprintf (stderr, "Writing correct value (");
2261     fprintf (stderr, UF4, k2);
2262     fprintf (stderr, ") to DVI file\n");
2263   }
2264
2265   put_unsigned (n, k2, dvi);
2266
2267   put_Lstring (&lstr, dvi);
2268
2269   if (debug)
2270   {
2271     PRINT_PROGNAME;
2272     fprintf (stderr, "(xfer_len_string) : leaving xfer_len_string.\n");
2273   }
2274
2275   de_init_Lstring (&lstr);
2276
2277   return (n + k2);
2278 }
2279 /* xfer_len_string */
2280
2281
2282 S4
2283 xfer_bop_address
2284 #ifdef STDC
2285   (FILE * dtl, FILE * dvi)
2286 #else
2287   (dtl, dvi)
2288   FILE * dtl;
2289   FILE * dvi;
2290 #endif
2291 /* translate signed 4-byte bop address from dtl to dvi file. */
2292 /* return value of bop address written to DVI file */
2293 {
2294   S4 snum = 0;  /* at most this space needed for byte address */
2295   COUNT nread = 0;  /* number of DTL bytes read by read_token */
2296   int nconv = 0;  /* number of arguments converted by sscanf */
2297   static Token token = "";  /* DTL token */
2298
2299   nread += read_token (dtl, token);
2300
2301   nconv = sscanf (token, SF4, &snum);
2302
2303   if (nconv != 1)
2304   {
2305     PRINT_PROGNAME;
2306     fprintf (stderr, "(xfer_bop_address) : DTL FILE ERROR (%s) : ",
2307       dtl_filename);
2308     fprintf (stderr, "signed number expected, not \"%s\".\n", token);
2309     dexit (1);
2310   }
2311
2312   if (snum != last_bop_address)
2313   {
2314     PRINT_PROGNAME;
2315     fprintf (stderr, "(xfer_bop_address) : WARNING : byte address (");
2316     fprintf (stderr, WF, snum);
2317     fprintf (stderr, ")\n");
2318     fprintf (stderr, "for previous bop in DTL file is wrong\n");
2319     fprintf (stderr, "Writing correct value (");
2320     fprintf (stderr, WF, last_bop_address);
2321     fprintf (stderr, ") to DVI file\n");
2322   }
2323
2324   put_signed (4, last_bop_address, dvi);
2325
2326   return last_bop_address;
2327 }
2328 /* xfer_bop_address */
2329
2330
2331 S4
2332 xfer_postamble_address
2333 #ifdef STDC
2334   (FILE * dtl, FILE * dvi)
2335 #else
2336   (dtl, dvi)
2337   FILE * dtl;
2338   FILE * dvi;
2339 #endif
2340 /* translate signed 4-byte postamble address from dtl to dvi file. */
2341 /* return value of postamble address written to DVI file */
2342 {
2343   S4 snum = 0;  /* at most this space needed for byte address */
2344   COUNT nread = 0;  /* number of DTL bytes read by read_token */
2345   int nconv = 0;  /* number of arguments converted by sscanf */
2346   static Token token = "";  /* DTL token */
2347
2348   nread += read_token (dtl, token);
2349
2350   nconv = sscanf (token, SF4, &snum);
2351
2352   if (nconv != 1)
2353   {
2354     PRINT_PROGNAME;
2355     fprintf (stderr, "(xfer_postamble_address) : DTL FILE ERROR (%s) : ",
2356       dtl_filename);
2357     fprintf (stderr, "signed number expected, not \"%s\".\n", token);
2358     dexit (1);
2359   }
2360
2361   if (snum != postamble_address)
2362   {
2363     PRINT_PROGNAME;
2364     fprintf (stderr, "(xfer_postamble_address) : WARNING : byte address (");
2365     fprintf (stderr, WF, snum);
2366     fprintf (stderr, ")\n");
2367     fprintf (stderr, "for postamble in DTL file is wrong\n");
2368     fprintf (stderr, "Writing correct value (");
2369     fprintf (stderr, WF, postamble_address);
2370     fprintf (stderr, ") to DVI file\n");
2371   }
2372
2373   put_signed (4, postamble_address, dvi);
2374
2375   return postamble_address;
2376 }
2377 /* xfer_postamble_address */
2378
2379
2380 int
2381 put_table
2382 #ifdef STDC
2383   (op_table table, int opcode, FILE * dtl, FILE * dvi)
2384 #else
2385   (table, opcode, dtl, dvi)
2386   op_table table;
2387   int opcode;
2388   FILE * dtl;
2389   FILE * dvi;
2390 #endif
2391 {
2392   /* table:  {char * name; int first, last; op_info * list; }; */
2393   /* op_info:   {int code; char * name; int nargs; char * args; }; */
2394
2395   op_info op;  /* entry in table */
2396   int i;
2397   int pos;  /* current position in string being scanned */
2398   static String args = "";
2399
2400   /* Defensive programming. */
2401   if (opcode < table.first || opcode > table.last)
2402   {
2403     PRINT_PROGNAME;
2404     fprintf (stderr,
2405       "(put_table) : DTL FILE (OR INTERNAL) ERROR : opcode %d ", opcode);
2406     fprintf (stderr, "is outside table %s [ %d to %d ] !\n",
2407       table.name, table.first, table.last);
2408     dexit (1);
2409   }
2410
2411   op = table.list [ opcode - table.first ];
2412
2413   /* More defensive programming. */
2414   if (opcode != op.code)
2415   {
2416     PRINT_PROGNAME;
2417     fprintf (stderr,
2418       "(put_table) : INTERNAL ERROR : opcode %d for command \"%s\"",
2419       opcode, op.name);
2420     fprintf (stderr, " faulty in table \"%s\".\n", table.name);
2421     dexit (1);
2422   }
2423
2424   /* process all the arguments, according to size and sign */
2425
2426   strncpy (args, op.args, MAXSTRLEN);
2427
2428   pos = 0;
2429   for (i=0; i < op.nargs; i++)
2430   {
2431     int argtype = 0;
2432     int nscan = 0;  /* number of bytes read by sscanf */
2433     int nconv = 0;  /* number of sscanf arguments converted & assigned */
2434
2435     /* sscanf() does NOT advance over its input: */
2436     /* C strings lack internal state information, which C files have. */
2437     /* On Sun/OS, sscanf calls ungetc on the string it reads, */
2438     /* which therefore has to be writable. */
2439
2440     nconv = sscanf (args + pos, "%d%n", &argtype, &nscan);
2441
2442     if (nconv < 1 || nscan < 1)
2443     {
2444       PRINT_PROGNAME;
2445       fprintf (stderr,
2446         "(put_table) : INTERNAL ERROR : internal read of table %s failed!\n",
2447         table.name);
2448       dexit (1);
2449     }
2450
2451     pos += nscan;
2452
2453     if (argtype < 0)
2454       xfer_signed (-argtype, dtl, dvi);
2455     else
2456       xfer_unsigned (argtype, dtl, dvi);
2457   }
2458   /* end for */
2459
2460   return 1;  /* OK */
2461 }
2462 /* put_table */
2463
2464
2465 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2466
2467
2468 U4
2469 special
2470 #ifdef STDC
2471   (FILE * dtl,  FILE * dvi,  int n)
2472 #else
2473   (dtl,  dvi,  n)
2474   FILE * dtl;
2475   FILE * dvi;
2476   int n;
2477 #endif
2478 /* read special (1 <= n <= 4 byte) data from dtl, and write in dvi */
2479 /* return number of bytes written */
2480 {
2481   U4  nk;
2482
2483   if (debug)
2484   {
2485     PRINT_PROGNAME;
2486     fprintf (stderr, "(special) : entering special.\n");
2487   }
2488
2489   if (n < 1 || n > 4)
2490   {
2491     PRINT_PROGNAME;
2492     fprintf (stderr, "(special) : DTL FILE ERROR (%s) : special %d, ",
2493       dtl_filename, n);
2494     fprintf (stderr, "range is 1 to 4.\n");
2495     dexit (1);
2496   }
2497
2498   /* k[n] : length of special string */
2499   /* x[k] : special string */
2500   /* nk = n + k */
2501   nk = xfer_len_string (n, dtl, dvi);
2502
2503   if (debug)
2504   {
2505     PRINT_PROGNAME;
2506     fprintf (stderr, "(special) : leaving special.\n");
2507   }
2508
2509   return (nk);
2510 }
2511 /* special */
2512
2513
2514 int
2515 fontdef
2516 #ifdef STDC
2517   (FILE * dtl,  FILE * dvi,  int suffix)
2518 #else
2519   (dtl,  dvi,  suffix)
2520   FILE * dtl;
2521   FILE * dvi;
2522   int suffix;
2523 #endif
2524 /* read fontdef fnt_def1 .. fnt_def4 from dtl, and write in dvi */
2525 /* suffix is the fontdef suffix : 1 to 4 */
2526 /* return number of bytes written */
2527 {
2528   U4  a, l, a2, l2;
2529   U4 k;
2530   Lstring lstr1, lstr2;
2531
2532   if (debug)
2533   {
2534     PRINT_PROGNAME;
2535     fprintf (stderr, "(fontdef) : entering fontdef.\n");
2536   }
2537
2538   if (suffix < 1 || suffix > 4)
2539   {
2540     PRINT_PROGNAME;
2541     fprintf (stderr, "(fontdef) : DTL FILE ERROR (%s) : ",
2542       dtl_filename);
2543     fprintf (stderr, "font def %d, but range is 1 to 4.\n", suffix);
2544     dexit (1);
2545   }
2546
2547   init_Lstring (&lstr1, LSIZE);
2548   init_Lstring (&lstr2, LSIZE);
2549
2550   if (debug)
2551   {
2552     PRINT_PROGNAME;
2553     fprintf (stderr, "(fontdef) : about to read font number.\n");
2554   }
2555
2556   /* k[suffix] : font number */
2557   if (suffix == 4)
2558     k = xfer_signed (suffix, dtl, dvi);
2559   else
2560     k = xfer_unsigned (suffix, dtl, dvi);
2561
2562   if (debug)
2563   {
2564     PRINT_PROGNAME;
2565     fprintf (stderr, "(fontdef) : font ");
2566     fprintf (stderr, UF4, k);
2567     fprintf (stderr, ".\n");
2568   }
2569
2570 #ifdef HEX_CHECKSUM
2571   /* c[4] : (hexadecimal) checksum : I (gt) would prefer this */
2572   xfer_hex (4, dtl, dvi);
2573 #else /*NOT HEX_CHECKSUM */
2574   /* c[4] : checksum (octal, for comparison with tftopl's .pl file) */
2575   xfer_oct (4, dtl, dvi);
2576 #endif
2577
2578   /* s[4] */
2579   xfer_unsigned (4, dtl, dvi);
2580
2581   /* d[4] */
2582   xfer_unsigned (4, dtl, dvi);
2583
2584   /* If DTL file's edited, a and l may be wrong. */
2585
2586   /* a[1] : length of font `area' (directory) portion of pathname string */
2587   a = get_unsigned (dtl);
2588
2589   /* l[1] : length of font portion of pathname string */
2590   l = get_unsigned (dtl);
2591
2592   /* n[a+l] : font pathname string <= area + font */
2593
2594   a2 = get_Lstring (dtl, &lstr1);
2595
2596   if (a2 != a)
2597   {
2598     PRINT_PROGNAME;
2599     fprintf (stderr, "(fontdef) : WARNING : font area string's length (");
2600     fprintf (stderr, UF4, a);
2601     fprintf (stderr, ") in DTL file is wrong\n");
2602     fprintf (stderr, "Writing correct value (");
2603     fprintf (stderr, UF4, a2);
2604     fprintf (stderr, ") to DVI file\n");
2605   }
2606
2607   put_unsigned (1, a2, dvi);
2608
2609   l2 = get_Lstring (dtl, &lstr2);
2610
2611   if (l2 != l)
2612   {
2613     PRINT_PROGNAME;
2614     fprintf (stderr, "(fontdef) : WARNING : font string's length (");
2615     fprintf (stderr, UF4, l);
2616     fprintf (stderr, ") in DTL file is wrong\n");
2617     fprintf (stderr, "Writing correct value (");
2618     fprintf (stderr, UF4, l2);
2619     fprintf (stderr, ") to DVI file\n");
2620   }
2621
2622   put_unsigned (1, l2, dvi);
2623
2624   put_Lstring (&lstr1, dvi);
2625   put_Lstring (&lstr2, dvi);
2626
2627   de_init_Lstring (&lstr2);
2628   de_init_Lstring (&lstr1);
2629
2630   if (debug)
2631   {
2632     PRINT_PROGNAME;
2633     fprintf (stderr, "(fontdef) : leaving fontdef.\n");
2634   }
2635
2636   return (suffix + 4*4 + 2*1 + a2 + l2);
2637 }
2638 /* fontdef */
2639
2640
2641 U4
2642 preamble
2643 #ifdef STDC
2644   (FILE * dtl,  FILE * dvi)
2645 #else
2646   (dtl,  dvi)
2647   FILE * dtl;
2648   FILE * dvi;
2649 #endif
2650 /* read preamble from dtl, and write in dvi */
2651 /* return number of bytes written */
2652 {
2653   U4  k1;
2654
2655   if (debug)
2656   {
2657     PRINT_PROGNAME;
2658     fprintf (stderr, "(preamble) : entering preamble.\n");
2659   }
2660
2661   /* i[1] */
2662   xfer_unsigned (1, dtl, dvi);
2663
2664   /* num[4] */
2665   xfer_unsigned (4, dtl, dvi);
2666
2667   /* den[4] */
2668   xfer_unsigned (4, dtl, dvi);
2669
2670   /* mag[4] */
2671   xfer_unsigned (4, dtl, dvi);
2672
2673   /* k[1] : length of comment */
2674   /* x[k] : comment string */
2675   /* k1 = 1 + k */
2676   k1 = xfer_len_string (1, dtl, dvi);
2677
2678   if (debug)
2679   {
2680     PRINT_PROGNAME;
2681     fprintf (stderr, "(preamble) : leaving preamble.\n");
2682   }
2683
2684   return (1 + 3*4 + k1);
2685 }
2686 /* preamble */
2687
2688
2689 int
2690 postamble
2691 #ifdef STDC
2692   (FILE * dtl,  FILE * dvi)
2693 #else
2694   (dtl,  dvi)
2695   FILE * dtl;
2696   FILE * dvi;
2697 #endif
2698 /* read postamble from dtl, and write in dvi */
2699 /* return number of bytes written */
2700 {
2701   postamble_address = dvi_written - 1;
2702
2703   /* p[4] : DVI address of previous bop command */
2704   /*        --- unsigned? --- or signed, as I assume? */
2705   /* For, surely  p  should be  -1  if the DVI file has NO bop? */
2706   xfer_bop_address (dtl, dvi);
2707
2708   /* num[4] */
2709   xfer_unsigned (4, dtl, dvi);
2710
2711   /* den[4] */
2712   xfer_unsigned (4, dtl, dvi);
2713
2714   /* mag[4] */
2715   xfer_unsigned (4, dtl, dvi);
2716
2717   /* l[4] */
2718   xfer_unsigned (4, dtl, dvi);
2719
2720   /* u[4] */
2721   xfer_unsigned (4, dtl, dvi);
2722
2723   /* s[2] */
2724   xfer_unsigned (2, dtl, dvi);
2725
2726   /* t[2] */
2727   xfer_unsigned (2, dtl, dvi);
2728
2729   return (6*4 + 2*2);
2730 }
2731 /* postamble */
2732
2733
2734 int
2735 post_post
2736 #ifdef STDC
2737   (FILE * dtl,  FILE * dvi)
2738 #else
2739   (dtl,  dvi)
2740   FILE * dtl;
2741   FILE * dvi;
2742 #endif
2743 /* read post_post from dtl, and write in dvi */
2744 /* return number of bytes written */
2745 {
2746   /* hope I'm writing the "223" bytes in an 8-bit clean way */
2747   int n223 = 0;  /* number of "223" bytes in final padding */
2748
2749   /* q[4] : DVI address of post command */
2750   /*        --- unsigned? --- or signed, as I assume? */
2751   /* what happens if there is NO postamble command? */
2752   /* shouldn't  q  be  -1  then? */
2753
2754   xfer_postamble_address (dtl, dvi);
2755
2756   /* i[1] : DVI identification byte = 2 */
2757   xfer_unsigned (1, dtl, dvi);
2758
2759   for (n223 = 0;  true;  n223++)
2760   {
2761     COUNT nread = 0;  /* number of DTL bytes read by read_token */
2762     static Token token;
2763
2764     strcpy (token, "");
2765
2766     nread = read_token (dtl, token);
2767
2768     /* check whether end of dtl file */
2769     if (nread == 0)
2770     {
2771       if (group)
2772       {
2773         /* dtl file shouldn't end before an ECOM */
2774         PRINT_PROGNAME;
2775         fprintf (stderr, "(post_post) : DTL FILE ERROR (%s) : ",
2776           dtl_filename);
2777         fprintf (stderr, "premature end of DTL file!\n");
2778         fprintf (stderr,
2779           "%d complete iterations of \"padding byte\" loop;\n", n223);
2780         fprintf (stderr, "troublesome token = \"%s\"\n", token);
2781         dexit (1);
2782       }
2783       /* leave the "223" loop */
2784       break;
2785     }
2786     else if (strcmp (token, "223") == 0)
2787     {
2788       /* token is a "223" padding byte */
2789       /* loop again */
2790     }
2791     else
2792     {
2793       /* read a non-empty token that wasn't "223" */
2794       (Void) unread_char ();
2795       if (group)
2796       {
2797         if (strcmp (token, ECOM) == 0)
2798         {
2799           /* end of DTL's post_post command */
2800         }
2801         else
2802         {
2803           /* error : expected end of post_post */
2804           PRINT_PROGNAME;
2805           fprintf (stderr, "(post_post) : DTL FILE ERROR (%s) : ",
2806             dtl_filename);
2807           fprintf (stderr, "token \"%s\" should be ECOM (\"%s\")\n",
2808             token, ECOM);
2809           dexit (1);
2810         }
2811       }
2812       /* leave the "223" loop */
2813       break;
2814     }
2815   }
2816   /* end for */
2817
2818   if (n223 < 4)
2819   {
2820     PRINT_PROGNAME;
2821     fprintf (stderr, "(post_post) : DTL FILE ERROR (%s) : \n",
2822       dtl_filename);
2823     fprintf (stderr, "fewer than four `223' padding bytes.\n");
2824     fprintf (stderr, "Will write at least four `223' padding bytes.\n");
2825   }
2826
2827   /* check whether the DVI file size is a multiple of 4 bytes */
2828   if ((dvi_written + n223) % 4 != 0)
2829   {
2830     PRINT_PROGNAME;
2831     fprintf (stderr, "(post_post) : WARNING : \n");
2832     fprintf (stderr, "DVI size ");
2833     fprintf (stderr, WF, dvi_written);
2834     fprintf (stderr, " (bytes) wouldn't be a multiple of 4 !\n");
2835     fprintf (stderr,
2836       "Will write (at least four) `223' padding bytes until it is.\n");
2837   }
2838
2839   /* final padding of DVI file by "223" bytes to a multiple of 4 bytes, */
2840   /* with at least 4 bytes */
2841
2842   for (n223 = 0;  (n223 < 4) || (dvi_written % 4 != 0);  n223++)
2843   {
2844     /* add a "223" padding byte */
2845     put_byte (223, dvi);
2846   }
2847
2848   return (4 + 1 + n223);
2849 }
2850 /* post_post */
2851
2852
2853 /* end of dt2dv.c */