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