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