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