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