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