OSDN Git Service

removed a strcat bug (via want_version).
[putex/putex.git] / src / texsourc / tex3.c
1 /* Copyright 2014 Clerk Ma
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2 of the License, or
6    (at your option) any later version.
7
8    This program is distributed in the hope that it will be useful, but
9    WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11    General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16    02110-1301 USA.  */
17
18 #define EXTERN extern
19
20 #include "texd.h"
21
22 /* sec 0440 */
23 void scan_int (void)
24 {
25   boolean negative;
26   integer m;
27   small_number d;
28   boolean vacuous;
29   boolean OK_so_far;
30
31   radix = 0;
32   OK_so_far = true;
33   negative = false;
34
35   do
36     {
37       do 
38         {
39           get_x_token();
40         }
41       while (!(cur_cmd != spacer));
42
43       if (cur_tok == other_token + '-')
44       {
45         negative = !negative;
46         cur_tok = other_token + '+';
47       }
48     }
49   while (!(cur_tok != other_token + '+'));
50
51   if (cur_tok == alpha_token)
52   {
53     get_token();
54
55     if (cur_tok < cs_token_flag)
56     {
57       cur_val = cur_chr;
58
59       if (cur_cmd <= right_brace)
60         if (cur_cmd == right_brace)
61           incr(align_state);
62         else
63           decr(align_state);
64     }
65     else if (cur_tok < cs_token_flag + single_base)
66       cur_val = cur_tok - cs_token_flag - active_base;
67     else
68       cur_val = cur_tok - cs_token_flag - single_base;
69
70     if (cur_val > 255)
71     {
72       print_err("Improper alphabetic constant");
73       help2("A one-character control sequence belongs after a ` mark.",
74         "So I'm essentially inserting \\0 here.");
75       cur_val = '0';
76       back_error();
77     }
78     else
79     {
80       get_x_token();
81
82       if (cur_cmd != spacer)
83         back_input();
84     }
85   }
86   else if ((cur_cmd >= min_internal) && (cur_cmd <= max_internal))
87   {
88     scan_something_internal(int_val, false);
89   }
90   else
91   {
92     radix = 10;
93     m = 214748364L;   /* 7FFFFFFF hex */
94
95     if (cur_tok == octal_token)
96     {
97       radix = 8;
98       m = 268435456L;   /* 2^28 */
99       get_x_token();
100     }
101     else if (cur_tok == hex_token)
102     {
103       radix = 16;
104       m = 134217728L;   /* 2^27 8000000 hex */
105       get_x_token();
106     }
107
108     vacuous = true;
109     cur_val = 0;
110
111     while (true)
112     {
113       if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token) && (cur_tok <= zero_token + 9))
114         d = cur_tok - zero_token;
115       else if (radix == 16)
116         if ((cur_tok <= A_token + 5) && (cur_tok >= A_token))
117           d = cur_tok - A_token + 10;
118         else if ((cur_tok <= other_A_token + 5) && (cur_tok >= other_A_token))
119           d = cur_tok - other_A_token;
120         else
121           goto done;
122       else
123         goto done;
124
125       vacuous = false;
126
127       if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10)))
128       {
129         if (OK_so_far)
130         {
131           print_err("Number too big");
132           help2("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
133             "so I'm using that number instead of yours.");
134           error();
135           cur_val = 2147483647L;    /* 7FFFFFFF hex */
136           OK_so_far = false;
137         }
138       }
139       else
140         cur_val = cur_val * radix + d;
141       get_x_token();
142     }
143
144 done:
145     if (vacuous)
146     {
147       print_err("Missing number, treated as zero");
148       help3("A number should have been here; I inserted `0'.",
149         "(If you can't figure out why I needed to see a number,",
150         "look up `weird error' in the index to The TeXbook.)");
151       back_error();
152     } 
153     else if (cur_cmd != spacer)
154       back_input();
155   }
156
157   if (negative)
158     cur_val = - (integer) cur_val;
159 }
160 /* sec 0448 */
161 void scan_dimen_(boolean mu, boolean inf, boolean shortcut)
162 {
163   boolean negative;
164   integer f;
165   integer num, denom;
166   small_number k, kk;
167   halfword p, q;
168   scaled v;
169   integer save_cur_val;
170
171   f = 0;
172   arith_error = false;
173   cur_order = 0;
174   negative = false;
175
176   if (!shortcut)
177   {
178     negative = false;
179
180     do
181       {
182         do
183           {
184             get_x_token();
185           }
186         while (!(cur_cmd != spacer));
187
188         if (cur_tok == other_token + '-')
189         {
190           negative = ! negative;
191           cur_tok = other_token + '+';
192         }
193       }
194     while (!(cur_tok != other_token + '+'));
195
196     if ((cur_cmd >= min_internal) && (cur_cmd <= max_internal))
197     {
198       if (mu)
199       {
200         scan_something_internal(mu_val, false);
201
202         if (cur_val_level >= glue_val)
203         {
204           v = width(cur_val);
205           delete_glue_ref(cur_val);
206           cur_val = v;
207         }
208
209         if (cur_val_level == mu_val)
210           goto attach_sign;
211
212         if (cur_val_level != int_val)
213           mu_error();
214       }
215       else
216       {
217         scan_something_internal(dimen_val, false);
218
219         if (cur_val_level == dimen_val)
220           goto attach_sign;
221       }
222     }
223     else
224     {
225       back_input();
226
227       if (cur_tok == continental_point_token)
228         cur_tok = point_token;
229
230       if (cur_tok != point_token)
231       {
232         scan_int();
233       }
234       else
235       {
236         radix = 10;
237         cur_val = 0;
238       }
239
240       if (cur_tok == continental_point_token)
241         cur_tok = point_token;
242
243       if ((radix == 10) && (cur_tok == point_token))
244       {
245         k = 0;
246         p = 0;
247         get_token();
248
249         while (true)
250         {
251           get_x_token();
252
253           if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
254             goto done1;
255
256           if (k < 17)
257           {
258             q = get_avail();
259             link(q) = p;
260             info(q) = cur_tok - zero_token;
261             p = q;
262             incr(k);
263           }
264         }
265 done1:
266         for (kk = k; kk >= 1; kk--)
267         {
268           dig[kk - 1] = info(p);
269           q = p;
270           p = link(p);
271           free_avail(q);
272         }
273
274         f = round_decimals(k);
275
276         if (cur_cmd != spacer)
277           back_input();
278         }
279       }
280   }
281
282   if (cur_val < 0)
283   {
284     negative = !negative;
285     cur_val = - (integer) cur_val;
286   }
287
288   if (inf)
289   {
290     if (scan_keyword("fil"))
291     {
292       cur_order = fil;
293
294       while (scan_keyword("l"))
295       {
296         if (cur_order == filll)
297         {
298           print_err("Illegal unit of measure (");
299           prints("replaced by filll)");
300           help1("I dddon't go any higher than filll.");
301           error();
302         }
303         else
304           incr(cur_order);
305       }
306       goto attach_fraction;
307     }
308   }
309
310   save_cur_val = cur_val;
311
312   do
313     {
314       get_x_token();
315     }
316   while (!(cur_cmd != spacer));
317
318   if ((cur_cmd < min_internal) || (cur_cmd > max_internal))
319     back_input();
320   else
321   {
322     if (mu)
323     {
324       scan_something_internal(mu_val, false);
325
326       if (cur_val_level >= glue_val)
327       {
328         v = width(cur_val);
329         delete_glue_ref(cur_val);
330         cur_val = v;
331       }
332
333       if (cur_val_level != mu_val)
334       {
335         mu_error();
336       }
337     }
338     else
339     {
340       scan_something_internal(dimen_val, false);
341     }
342
343     v = cur_val;
344     goto found;
345   }
346
347   if (mu)
348     goto not_found;
349
350   if (scan_keyword("em"))
351     v = quad(cur_font);
352   else if (scan_keyword("ex"))
353     v = x_height(cur_font);
354   else
355     goto not_found;
356
357   {
358     get_x_token();
359
360     if (cur_cmd != spacer)
361       back_input();
362   }
363
364 found:
365   cur_val = mult_and_add(save_cur_val, v, xn_over_d(v, f, 65536L), 1073741823L);   /* 2^30 - 1 */
366   goto attach_sign;
367
368 not_found:
369   if (mu)
370   {
371     if (scan_keyword("mu"))
372       goto attach_fraction;
373     else
374     {
375       print_err("Illegal unit of measure (");
376       prints("mu inserted)");
377       help4("The unit of measurement in math glue must be mu.",
378           "To recover gracefully from this error, it's best to",
379           "delete the erroneous units; e.g., type `2' to delete",
380           "two letters. (See Chapter 27 of The TeXbook.)");
381       error();
382       goto attach_fraction;
383     }
384   }
385
386   if (scan_keyword("true"))
387   {
388     prepare_mag();
389
390     if (mag != 1000)
391     {
392       cur_val = xn_over_d(cur_val, 1000, mag);
393       f = (1000 * f + 65536L * tex_remainder) / mag;
394       cur_val = cur_val + (f / 65536L);
395       f = f % 65536L;
396     }
397   }
398
399   if (scan_keyword("pt"))
400     goto attach_fraction;
401
402   if (scan_keyword("in"))
403     set_conversion(7227, 100);
404   else if (scan_keyword("pc"))
405     set_conversion(12, 1);
406   else if (scan_keyword("cm"))
407     set_conversion(7227, 254);
408   else if (scan_keyword("mm"))
409     set_conversion(7227, 2540);
410   else if (scan_keyword("bp"))
411     set_conversion(7227, 7200);
412   else if (scan_keyword("dd"))
413     set_conversion(1238, 1157);
414   else if (scan_keyword("cc"))
415     set_conversion(14856, 1157);
416   else if (scan_keyword("Q"))
417     set_conversion(7227, 10160);
418   else if (scan_keyword("H"))
419     set_conversion(7227, 10160);
420   else if (scan_keyword("sp"))
421     goto done;
422   else
423   {
424     print_err("Illegal unit of measure (");
425     prints("pt inserted)");
426     help6("Dimensions can be in units of em, ex, in, pt, pc,",
427       "cm, mm, dd, cc, bp, or sp; but yours is a new one!",
428       "I'll assume that you meant to say pt, for printer's points.",
429       "To recover gracefully from this error, it's best to",
430       "delete the erroneous units; e.g., type `2' to delete",
431       "two letters. (See Chapter 27 of The TeXbook.)");
432     error();
433     goto done2;
434   }
435
436   cur_val = xn_over_d(cur_val, num, denom);
437   f = (num * f + 65536L * tex_remainder) / denom;
438   cur_val = cur_val +(f / 65536L);
439   f = f % 65536L;
440
441 done2:
442 attach_fraction:
443   if (cur_val >= 16384)     /* 2^14 */
444     arith_error = true;
445   else
446     cur_val = cur_val * unity + f;
447
448 done:
449   {
450     get_x_token();
451
452     if (cur_cmd != spacer)
453       back_input();
454   }
455
456 attach_sign:
457   if (arith_error || (abs(cur_val) >= 1073741824L)) /* 2^30 */
458   {
459     print_err("Dimension too large");
460     help2("I can't work with sizes bigger than about 19 feet.",
461         "Continue and I'll use the largest value I can.");
462     error();
463     cur_val = max_dimen;
464     arith_error = false;
465   }
466
467   if (negative)
468     cur_val = - (integer) cur_val;
469 }
470 /* sec 0461 */
471 void scan_glue_(small_number level)
472 {
473   boolean negative;
474   halfword q;
475   boolean mu;
476
477   mu = (level == mu_val);
478   negative = false;
479
480   do
481     {
482       do
483         {
484           get_x_token();
485         }
486       while (!(cur_cmd != spacer));
487
488       if (cur_tok == other_token + '-')
489       {
490         negative = !negative;
491         cur_tok = other_token + '+';
492       }
493     }
494   while (!(cur_tok != other_token + '+'));
495
496   if ((cur_cmd >= min_internal) && (cur_cmd <= max_internal))
497   {
498     scan_something_internal(level, negative);
499
500     if (cur_val_level >= glue_val)
501     {
502       if (cur_val_level != level)
503       {
504         mu_error();
505       }
506       return;
507     }
508
509     if (cur_val_level == int_val)
510     {
511       scan_dimen(mu, false, true);
512     }
513     else if (level == mu_val)
514     {
515       mu_error();
516     }
517   }
518   else
519   {
520     back_input();
521     scan_dimen(mu, false, false);
522
523     if (negative)
524       cur_val = - (integer) cur_val;
525   }
526   q = new_spec(zero_glue);
527   width(q) = cur_val;
528
529   if (scan_keyword("plus"))
530   {
531     scan_dimen(mu, true, false);
532     stretch(q) = cur_val;
533     stretch_order(q) = cur_order;
534   }
535
536   if (scan_keyword("minus"))
537   {
538     scan_dimen(mu, true, false);
539     shrink(q) = cur_val;
540     shrink_order(q) = cur_order;
541   }
542
543   cur_val = q;
544 }
545 /* sec 0463 */
546 halfword scan_rule_spec (void)
547 {
548   halfword q;
549
550   q = new_rule();
551
552   if (cur_cmd == vrule)
553     width(q) = default_rule;
554   else
555   {
556     height(q) = default_rule;
557     depth(q) = 0;
558   }
559
560 reswitch:
561
562   if (scan_keyword("width"))
563   {
564     scan_dimen(false, false, false);
565     width(q) = cur_val;
566     goto reswitch;
567   }
568
569   if (scan_keyword("height"))
570   {
571     scan_dimen(false, false, false);
572     height(q) = cur_val;
573     goto reswitch;
574   }
575
576   if (scan_keyword("depth"))
577   {
578     scan_dimen(false, false, false);
579     depth(q) = cur_val;
580     goto reswitch;
581   }
582
583   return q;
584 }
585 /* sec 0464 */
586 halfword str_toks_(pool_pointer b)
587 {
588   halfword p;
589   halfword q;
590   halfword t;
591   pool_pointer k;
592
593   str_room(1);
594   p = temp_head;
595   link(p) = 0;
596   k = b;
597
598   while (k < pool_ptr)
599   {
600     t = str_pool[k];
601
602     if (t == ' ')
603       t = space_token;
604     else
605       t = other_token + t;
606
607     fast_store_new_token(t);
608     incr(k);
609   }
610
611   pool_ptr = b;
612
613   return p;
614 }
615 /* sec 0465 */
616 halfword the_toks (void)
617 {
618   char old_setting;
619   halfword p, q, r;
620   pool_pointer b;
621
622   get_x_token();
623   scan_something_internal(tok_val, false);
624
625   if (cur_val_level >= ident_val)
626   {
627     p = temp_head;
628     link(p) = 0;
629
630     if (cur_val_level == ident_val)
631       store_new_token(cs_token_flag + cur_val);
632     else if (cur_val != 0)
633     {
634       r = link(cur_val);
635
636       while (r != 0)
637       {
638         fast_store_new_token(info(r));
639         r = link(r);
640       }
641     }
642
643     return p;
644   }
645   else
646   {
647     old_setting = selector;
648     selector = new_string;
649     b = pool_ptr;
650
651     switch (cur_val_level)
652     {
653       case int_val:
654         print_int(cur_val);
655         break;
656
657       case dimen_val:
658         {
659           print_scaled(cur_val);
660           prints("pt");
661         }
662         break;
663
664       case glue_val:
665         {
666           print_spec(cur_val, "pt");
667           delete_glue_ref(cur_val);
668         }
669         break;
670
671       case mu_val:
672         {
673           print_spec(cur_val, "mu");
674           delete_glue_ref(cur_val);
675         }
676         break;
677     }
678
679     selector = old_setting;
680     return str_toks(b);
681   }
682 }
683 /* sec 0467 */
684 void ins_the_toks (void) 
685
686   link(garbage) = the_toks();
687   ins_list(link(temp_head));
688 }
689 /* sec 0470 */
690 void conv_toks (void)
691 {
692   char old_setting;
693   char c;
694   small_number save_scanner_status;
695   pool_pointer b;
696
697   c = cur_chr;
698
699   switch (c)
700   {
701     case number_code:
702     case roman_numeral_code:
703       scan_int();
704       break;
705
706     case string_code:
707     case meaning_code:
708       save_scanner_status = scanner_status;
709       scanner_status = 0;
710       get_token();
711       scanner_status = save_scanner_status;
712       break;
713
714     case font_name_code:
715       scan_font_ident();
716       break;
717
718     case job_name_code:
719       if (job_name == 0)
720         open_log_file();
721       break;
722   }
723
724   old_setting = selector;
725   selector = new_string;
726   b = pool_ptr;
727
728   switch (c)
729   {
730     case number_code:
731       print_int(cur_val);
732       break;
733
734     case roman_numeral_code:
735       print_roman_int(cur_val);
736       break;
737
738     case string_code:
739       if (cur_cs != 0)
740         sprint_cs(cur_cs);
741       else
742         print_char(cur_chr);
743       break;
744
745     case meaning_code:
746       print_meaning();
747       break;
748
749     case font_name_code:
750       print(font_name[cur_val]);
751
752       if (font_size[cur_val] != font_dsize[cur_val])
753       {
754         prints(" at ");
755         print_scaled(font_size[cur_val]);
756         prints("pt");
757       }
758       break;
759
760     case job_name_code:
761       print(job_name);
762       break;
763   }
764
765   selector = old_setting;
766   link(garbage) = str_toks(b);
767   begin_token_list(link(temp_head), 4);
768 }
769 /* sec 0473 */
770 pointer scan_toks_(boolean macro_def, boolean xpand)
771 {
772   halfword t;
773   halfword s;
774   pointer p;
775   pointer q;
776   halfword unbalance;
777   halfword hash_brace;
778
779   if (macro_def)
780     scanner_status = defining;
781   else
782     scanner_status = absorbing;
783
784   warning_index = cur_cs;
785   def_ref = get_avail();
786   token_ref_count(def_ref) = 0;
787   p = def_ref;
788   hash_brace = 0;
789   t = zero_token;
790
791   if (macro_def)
792   {
793     while (true)
794     {
795       get_token();
796
797       if (cur_tok < right_brace_limit)
798         goto done1;
799
800       if (cur_cmd == mac_param)
801       {
802         s = match_token + cur_chr;
803         get_token();
804
805         if (cur_cmd == left_brace)
806         {
807           hash_brace = cur_tok;
808           store_new_token(cur_tok);
809           store_new_token(end_match_token);
810           goto done;
811         }
812
813         if (t == zero_token + 9)
814         {
815           print_err("You already have nine parameters");
816           help1("I'm going to ignore the # sign you just used.");
817           error();
818         }
819         else
820         {
821           incr(t);
822
823           if (cur_tok != t)
824           {
825             print_err("Parameters must be numbered consecutively");
826             help2("I've inserted the digit you should have used after the #.",
827                 "Type `1' to delete what you did use.");
828             back_error();
829           }
830
831           cur_tok = s;
832         }
833       }
834
835       store_new_token(cur_tok);
836     }
837
838 done1:
839     store_new_token(end_match_token);
840
841     if (cur_cmd == right_brace)
842     {
843       print_err("Missing { inserted");
844       incr(align_state);
845       help2("Where was the left brace? You said something like `\\def\\a}',",
846           "which I'm going to interpret as `\\def\\a{}'.");
847       error();
848       goto found;
849     }
850 done:;
851   }
852   else
853   {
854     scan_left_brace();
855   }
856
857   unbalance = 1;
858
859   while (true)
860   {
861     if (xpand)
862     {
863       while (true)
864       {
865         get_next();
866
867         if (cur_cmd <= max_command)
868           goto done2;
869
870         if (cur_cmd != the)
871         {
872           expand();
873         }
874         else
875         {
876           q = the_toks();
877
878           if (link(temp_head) != 0)
879           {
880             link(p) = link(temp_head);
881             p = q;
882           }
883         }
884       }
885 done2:
886       x_token();
887     }
888     else
889       get_token();
890
891     if (cur_tok < right_brace_limit)
892       if (cur_cmd < right_brace)
893         incr(unbalance);
894       else
895       {
896         decr(unbalance);
897
898         if (unbalance == 0)
899           goto found;
900       }
901     else if (cur_cmd == mac_param)
902       if (macro_def)
903       {
904         s = cur_tok;
905
906         if (xpand)
907           get_x_token();
908         else
909           get_token();
910
911         if (cur_cmd != mac_param)
912           if ((cur_tok <= zero_token) || (cur_tok > t))
913           {
914             print_err("Illegal parameter number in definition of ");
915             sprint_cs(warning_index);
916             help3("You meant to type ## instead of #, right?",
917                 "Or maybe a } was forgotten somewhere earlier, and things",
918                 "are all screwed up? I'm going to assume that you meant ##.");
919             back_error();
920             cur_tok = s;
921           }
922           else
923             cur_tok = out_param_token - '0' + cur_chr;
924       }
925
926     store_new_token(cur_tok);
927   }
928 found:
929   scanner_status = 0;
930
931   if (hash_brace != 0)
932     store_new_token(hash_brace);
933
934   return p;
935 }
936 /* used only in ITEX.C */
937 /* sec 0482 */
938 void read_toks_(integer n, halfword r)
939 {
940   halfword p;
941   halfword q;
942   integer s;
943 /*  small_number m;  */
944   int m; /* 95/Jan/7 */
945
946   scanner_status = defining;
947   warning_index = r;
948   def_ref = get_avail();
949   token_ref_count(def_ref) = 0;
950   p = def_ref;
951   store_new_token(end_match_token);
952
953   if ((n < 0) || (n > 15))
954     m = 16;
955   else
956     m = n;
957
958   s = align_state;
959   align_state = 1000000L;
960
961   do
962     {
963       begin_file_reading();
964       name = m + 1;
965
966       if (read_open[m] == closed)
967         if (interaction > nonstop_mode)
968           if (n < 0)
969             prompt_input("");
970           else
971           {
972             print_ln();
973             sprint_cs(r);
974             prompt_input("=");
975             n = -1;
976           }
977         else
978         {
979           fatal_error("*** (cannot \\read from terminal in nonstop modes)");
980           return;
981         }
982       else if (read_open[m] == 1)
983         if (input_ln(read_file[m], false))
984           read_open[m] = 0;
985         else
986         {
987           (void) a_close(read_file[m]);
988           read_open[m] = 2;
989         }
990       else
991       {
992         if (!input_ln(read_file[m], true))
993         {
994           (void) a_close(read_file[m]);
995           read_open[m] = 2;
996
997           if (align_state != 1000000L)
998           {
999             runaway();
1000             print_err("File ended within ");
1001             print_esc("read");
1002             help1("This \\read has unbalanced braces.");
1003             align_state = 1000000L;
1004             error();
1005           }
1006         }
1007       }
1008
1009       limit = last;
1010
1011       if (end_line_char_inactive())
1012         decr(limit);
1013       else
1014         buffer[limit] = end_line_char;
1015
1016       first = limit + 1;
1017       loc = start;
1018       state = new_line;
1019
1020       while (true)
1021       {
1022         get_token();
1023
1024         if (cur_tok == 0)
1025           goto done;
1026
1027         if (align_state < 1000000L)
1028         {
1029           do
1030             {
1031               get_token();
1032             }
1033           while (!(cur_tok == 0));
1034
1035           align_state = 1000000L;
1036           goto done;
1037         }
1038
1039         store_new_token(cur_tok);
1040       }
1041 done:
1042       end_file_reading();
1043     }
1044   while (!(align_state == 1000000L));
1045
1046   cur_val = def_ref;
1047   scanner_status = normal;
1048   align_state = s;
1049 }
1050 /* sec 0494 */
1051 void pass_text (void)
1052 {
1053   integer l;
1054   small_number save_scanner_status;
1055
1056   save_scanner_status = scanner_status;
1057   scanner_status = skipping;
1058   l = 0;
1059   skip_line = line;
1060
1061   while (true)
1062   {
1063     get_next();
1064
1065     if (cur_cmd == fi_or_else)
1066     {
1067       if (l == 0)
1068         goto done;
1069
1070       if (cur_chr == 2)
1071         decr(l);
1072     }
1073     else if (cur_cmd == if_test)
1074       incr(l);
1075   }
1076 done:
1077   scanner_status = save_scanner_status;
1078 }
1079 /* sec 0497 */
1080 void change_if_limit_(small_number l, halfword p)
1081 {
1082   halfword q;
1083
1084   if (p == cond_ptr)
1085     if_limit = l;
1086   else
1087   {
1088     q = cond_ptr;
1089
1090     while (true)
1091     {
1092       if (q == 0)
1093       {
1094         confusion("if");
1095         return;
1096       }
1097
1098       if (link(q) == p)
1099       {
1100         type(p) = l;
1101         return;
1102       }
1103
1104       q = link(q);
1105     }
1106   }
1107 }
1108 /* called from tex2.c */
1109 /* sec 0498 */
1110 void conditional (void)
1111 {
1112   boolean b;
1113   char r;
1114   integer m, n;
1115   halfword p, q;
1116   small_number save_scanner_status;
1117   halfword save_cond_ptr;
1118   small_number this_if;
1119
1120   {
1121     p = get_node(if_node_size);
1122     link(p) = cond_ptr;
1123     type(p) = if_limit;
1124     subtype(p) = cur_if;
1125     if_line_field(p) = if_line;
1126     cond_ptr = p;
1127     cur_if = cur_chr;
1128     if_limit = if_code;
1129     if_line = line;
1130   }
1131
1132   save_cond_ptr = cond_ptr;
1133   this_if = cur_chr;
1134
1135   switch (this_if)
1136   {
1137     case if_char_code:
1138     case if_cat_code:
1139       {
1140         {
1141           get_x_token();
1142
1143           if (cur_cmd == relax)
1144             if (cur_chr == no_expand_flag)
1145             {
1146               cur_cmd = active_char;
1147               cur_chr = cur_tok - cs_token_flag - active_base;
1148             }
1149         }
1150
1151         if ((cur_cmd > active_char) || (cur_chr > 255))
1152         {
1153           m = relax;
1154           n = 256;
1155         }
1156         else
1157         {
1158           m = cur_cmd;
1159           n = cur_chr;
1160         }
1161         {
1162           get_x_token();
1163
1164           if (cur_cmd == relax)
1165             if (cur_chr == no_expand_flag)
1166             {
1167               cur_cmd = active_char;
1168               cur_chr = cur_tok - cs_token_flag - active_base;
1169             }
1170         }
1171
1172         if ((cur_cmd > active_char) || (cur_chr > 255))
1173         {
1174           cur_cmd = relax;
1175           cur_chr = 256;
1176         }
1177
1178         if (this_if == if_char_code)
1179           b = (n == cur_chr); 
1180         else
1181           b = (m == cur_cmd);
1182       }
1183       break;
1184
1185     case if_int_code:
1186     case if_dim_code:
1187       {
1188         if (this_if == if_int_code)
1189           scan_int();
1190         else
1191           scan_dimen(false, false, false);
1192
1193         n = cur_val;
1194         
1195         do
1196           {
1197             get_x_token();
1198           }
1199         while (!(cur_cmd != spacer));
1200
1201         if ((cur_tok >= other_token + '<') && (cur_tok <= other_token + '>'))
1202           r = cur_tok - other_token;
1203         else
1204         {
1205           print_err("Missing = inserted for ");
1206           print_cmd_chr(if_test, this_if);
1207           help1("I was expecting to see `<', `=', or `>'. Didn't.");
1208           back_error();
1209           r = '=';
1210         }
1211
1212         if (this_if == if_int_code)
1213           scan_int();
1214         else 
1215           scan_dimen(false, false, false);
1216
1217         switch (r)
1218         {
1219           case '<':
1220             b = (n < cur_val);
1221             break;
1222
1223           case '=':
1224             b = (n == cur_val);
1225             break;
1226
1227           case '>':
1228             b = (n > cur_val);
1229             break;
1230         }
1231       }
1232       break;
1233
1234     case if_odd_code:
1235       scan_int();
1236       b = odd(cur_val);
1237       break;
1238
1239     case if_vmode_code:
1240       b = (abs(mode) == vmode);
1241       break;
1242
1243     case if_hmode_code:
1244       b = (abs(mode) == hmode);
1245       break;
1246
1247     case if_mmode_code:
1248       b = (abs(mode) == mmode);
1249       break;
1250
1251     case if_inner_code:
1252       b = (mode < 0);
1253       break;
1254
1255     case if_void_code:
1256     case if_hbox_code:
1257     case if_vbox_code:
1258       {
1259         scan_eight_bit_int();
1260         p = box(cur_val);
1261
1262         if (this_if == if_void_code)
1263           b = (p == 0);
1264         else if (p == 0)
1265           b = false;
1266         else if (this_if == if_hbox_code)
1267           b = (type(p) == hlist_node);
1268         else
1269           b = (type(p) == vlist_node);
1270       }
1271       break;
1272
1273     case ifx_code:
1274       {
1275         save_scanner_status = scanner_status;
1276         scanner_status = 0;
1277         get_next();
1278         n = cur_cs;
1279         p = cur_cmd;
1280         q = cur_chr;
1281         get_next();
1282
1283         if (cur_cmd != p)
1284           b = false;
1285         else if (cur_cmd < call)
1286           b = (cur_chr == q);
1287         else
1288         {
1289           p = link(cur_chr);
1290           q = link(equiv(n));
1291
1292           if (p == q)
1293             b = true;
1294           else
1295           {
1296             while ((p != 0) && (q != 0))
1297               if (info(p) != info(q))
1298                 p = 0;
1299               else
1300               {
1301                 p = link(p);
1302                 q = link(q);
1303               }
1304
1305             b = ((p == 0) && (q == 0));
1306           }
1307         }
1308
1309         scanner_status = save_scanner_status;
1310       }
1311       break;
1312
1313     case if_eof_code:
1314       {
1315         scan_four_bit_int();
1316         b = (read_open[cur_val] == closed);
1317       }
1318       break;
1319
1320     case if_true_code:
1321       b = true;
1322       break;
1323
1324     case if_false_code:
1325       b = false;
1326       break;
1327
1328     case if_case_code:
1329       {
1330         scan_int();
1331         n = cur_val;
1332
1333         if (tracing_commands > 1)
1334         {
1335           begin_diagnostic();
1336           prints("{case ");
1337           print_int(n); 
1338           print_char('}');
1339           end_diagnostic(false);
1340         }
1341
1342         while (n != 0)
1343         {
1344           pass_text();
1345
1346           if (cond_ptr == save_cond_ptr)
1347             if (cur_chr == or_code)
1348               decr(n);
1349             else 
1350               goto common_ending;
1351           else if (cur_chr == fi_code)
1352           {
1353             p = cond_ptr;
1354             if_line = if_line_field(p);
1355             cur_if = subtype(p);
1356             if_limit = type(p);
1357             cond_ptr = link(p);
1358             free_node(p, if_node_size);
1359           }
1360         }
1361
1362         change_if_limit(or_code, save_cond_ptr);
1363         return;
1364       }
1365       break;
1366   }
1367
1368   if (tracing_commands > 1)
1369   {
1370     begin_diagnostic();
1371
1372     if (b)
1373       prints("{true}");
1374     else
1375       prints("{false}");
1376
1377     end_diagnostic(false);
1378   }
1379
1380   if (b)
1381   {
1382     change_if_limit(else_code, save_cond_ptr);
1383     return;
1384   }
1385
1386   while (true)
1387   {
1388     pass_text();
1389
1390     if (cond_ptr == save_cond_ptr)
1391     {
1392       if (cur_chr != or_code)
1393         goto common_ending;
1394
1395       print_err("Extra ");
1396       print_esc("or");
1397       help1("I'm ignoring this; it doesn't match any \\if.");
1398       error();
1399     }
1400     else if (cur_chr == fi_code)
1401     {
1402       p = cond_ptr;
1403       if_line = if_line_field(p);
1404       cur_if = subtype(p);
1405       if_limit = type(p);
1406       cond_ptr = link(p);
1407       free_node(p, if_node_size);
1408     }
1409   }
1410
1411 common_ending:
1412   if (cur_chr == fi_code)
1413   {
1414     p = cond_ptr;
1415     if_line = if_line_field(p);
1416     cur_if = subtype(p);
1417     if_limit = type(p);
1418     cond_ptr = link(p);
1419     free_node(p, if_node_size);
1420   }
1421   else
1422     if_limit = fi_code;
1423 }
1424 /* sec 0515 */
1425 void begin_name (void)
1426 {
1427   area_delimiter = 0;
1428   ext_delimiter = 0;
1429 }
1430 /* This gathers up a file name and makes a string of it */
1431 /* Also tries to break it into `file area' `file name' and `file extension' */
1432 /* Used by scan_file_name and prompt_file_name */
1433 /* We assume tilde has been converted to pseudo_tilde and space to pseudo_space */
1434 /* returns false if it is given a space character - end of file name */
1435 /* sec 0516 */
1436 boolean more_name_(ASCII_code c)
1437 {
1438   if (quoted_file_name == false && c == ' ')
1439     return false;
1440   else if (quoted_file_name != false && c == '"')
1441   {
1442     quoted_file_name = false; /* catch next space character */
1443     return true;     /* accept ending quote, but throw away */
1444   }
1445   else
1446   {   
1447     str_room(1);
1448     append_char(c);
1449
1450     //  for DOS/Windows
1451     if ((c == '/' || c == '\\' || c == ':')) 
1452     {
1453       area_delimiter = cur_length;
1454       ext_delimiter = 0;
1455     } 
1456     else if (c == '.')
1457       ext_delimiter = cur_length;
1458
1459     return true;
1460   }
1461 }
1462
1463 /* sec 0517 */
1464 void end_name (void) 
1465 {
1466 #ifdef ALLOCATESTRING
1467   if (str_ptr + 3 > current_max_strings)
1468     str_start = realloc_str_start(increment_max_strings + 3);
1469
1470   if (str_ptr + 3 > current_max_strings)
1471   {
1472     overflow("number of strings", current_max_strings - init_str_ptr);
1473     return;
1474   }
1475 #else
1476   if (str_ptr + 3 > max_strings)
1477   {
1478     overflow("number of strings", max_strings - init_str_ptr);
1479     return;
1480   }
1481 #endif
1482
1483   if (area_delimiter == 0)   // no area delimiter ':' '/' or '\' found
1484     cur_area = 335;     // "" default area 
1485   else
1486   {
1487     cur_area = str_ptr;
1488     str_start[str_ptr + 1] = str_start[str_ptr] + area_delimiter;
1489     incr(str_ptr);
1490   }
1491
1492   if (ext_delimiter == 0) // no extension delimiter '.' found
1493   {
1494     cur_ext = 335;        // "" default extension 
1495     cur_name = make_string();
1496   } 
1497   else            // did find an extension
1498   {
1499     cur_name = str_ptr;
1500     str_start[str_ptr + 1] = str_start[str_ptr] + ext_delimiter - area_delimiter - 1;
1501     incr(str_ptr);
1502     cur_ext = make_string();
1503   }
1504 }
1505
1506 /* n current name, a current area, e current extension */
1507 /* result in name_of_file[] */
1508 /* sec 0519 */
1509 void pack_file_name_(str_number n, str_number a, str_number e)
1510 {
1511   integer k;
1512   ASCII_code c;
1513   pool_pointer j;
1514
1515   k = 0;
1516
1517   for (j = str_start[a]; j <= str_start[a + 1] - 1; j++)
1518   {
1519     c = str_pool[j];
1520     incr(k);
1521
1522     if (k <= file_name_size)
1523       name_of_file[k] = xchr[c];
1524   }
1525
1526   for (j = str_start[n]; j <= str_start[n + 1] - 1; j++)
1527   {
1528     c = str_pool[j];
1529     incr(k);
1530
1531     if (k <= file_name_size)
1532       name_of_file[k] = xchr[c];
1533   }
1534
1535   for (j = str_start[e]; j <= str_start[e + 1] - 1; j++)
1536   {
1537     c = str_pool[j];
1538     incr(k);
1539
1540     if (k <= file_name_size)
1541       name_of_file[k] = xchr[c];
1542   }
1543
1544   if (k < file_name_size)
1545     name_length = k;
1546   else
1547     name_length = file_name_size - 1;
1548
1549 /*  pad it out with spaces ... what for ? in case we modify and forget  ? */
1550   for (k = name_length + 1; k <= file_name_size; k++)
1551     name_of_file[k] = ' ';
1552
1553   name_of_file[file_name_size] = '\0';    /* paranoia 94/Mar/24 */
1554
1555   {
1556     name_of_file [name_length+1] = '\0';
1557
1558     if (trace_flag)
1559     {
1560       sprintf(log_line, " pack_file_name `%s' (%lld) ", name_of_file + 1, name_length); /* debugging */
1561       show_line(log_line, 0);
1562     }
1563
1564     name_of_file [name_length + 1] = ' ';
1565   }
1566 }
1567 /* Called only from two places tex9.c for format name - specified and default */
1568 /* for specified format name args are 0, a, b name in buffer[a] --- buffer[b] */
1569 /* for default args are format_default_length-4, 1, 0 */
1570 /* sec 0523 */
1571 void pack_buffered_name_(small_number n, integer a, integer b)
1572 {
1573   integer k;
1574   ASCII_code c;
1575   integer j;
1576
1577   if (n + b - a + 5 > file_name_size)
1578     b = a + file_name_size - n - 5;
1579
1580   k = 0;
1581
1582 /*  This loop kicks in when we want the default format name */
1583   for (j = 1; j <= n; j++)
1584   {
1585     c = xord[TEX_format_default[j]];
1586     incr(k);
1587
1588     if (k <= file_name_size)
1589       name_of_file[k] = xchr[c];
1590   }
1591 /*  This loop kicks in when we want a specififed format name */
1592   for (j = a; j <= b; j++)
1593   {
1594     c = buffer[j];
1595     incr(k);
1596
1597     if (k <= file_name_size)
1598       name_of_file[k] = xchr[c];
1599   }
1600
1601 /*  This adds the extension from the default format name */
1602   for (j = format_default_length - 3; j <= format_default_length; j++)
1603   {
1604     c = xord[TEX_format_default[j]];
1605     incr(k);
1606
1607     if (k <= file_name_size)
1608       name_of_file[k] = xchr[c];
1609   }
1610
1611   if (k < file_name_size)
1612     name_length = k;
1613   else
1614     name_length = file_name_size - 1;
1615
1616  /*  pad it out with spaces ... what for ? */
1617   for (k = name_length + 1; k <= file_name_size; k++)
1618     name_of_file[k]= ' ';
1619
1620   name_of_file[file_name_size] = '\0';    /* paranoia 94/Mar/24 */
1621 }
1622 /* sec 0525 */
1623 str_number make_name_string (void)
1624 {
1625   integer k;
1626
1627 #ifdef ALLOCATESTRING
1628   if (pool_ptr + name_length > current_pool_size)
1629     str_pool = realloc_str_pool(increment_pool_size + name_length);
1630
1631   if (str_ptr == current_max_strings)
1632     str_start = realloc_str_start(increment_max_strings);
1633
1634   if ((pool_ptr + name_length > current_pool_size) || (str_ptr == current_max_strings) || (cur_length > 0))
1635 #else
1636   if ((pool_ptr + name_length > pool_size) || (str_ptr == max_strings) || (cur_length > 0))
1637 #endif
1638   {
1639     return '?';
1640   }
1641   else
1642   {
1643     for (k = 1; k <= name_length; k++)
1644       append_char(xord[name_of_file[k]]);
1645
1646     return make_string();
1647   }
1648 }
1649 /* sec 0525 */
1650 //str_number a_make_name_string_(alpha_file * f)
1651 str_number a_make_name_string_(void)
1652 {
1653   return make_name_string();
1654 }
1655 /* sec 0525 */
1656 //str_number b_make_name_string_(byte_file * f)
1657 str_number b_make_name_string_(void)
1658 {
1659   return make_name_string(); 
1660 }
1661 /* sec 0525 */
1662 //str_number w_make_name_string_(word_file * f)
1663 str_number w_make_name_string_(void)
1664 {
1665   return make_name_string();
1666 }
1667
1668 /* Used by start_input to scan file name on command line */
1669 /* Also in tex8.c new_font_, open_or_close_in, and do_extension */
1670 /* sec 0526 */
1671 void scan_file_name (void)
1672 {
1673   name_in_progress = true;
1674   begin_name();
1675
1676   do
1677     {
1678       get_x_token(); 
1679     }
1680   while (!(cur_cmd != spacer));
1681
1682   quoted_file_name = false;
1683
1684   if (allow_quoted_names)
1685   {
1686     if (cur_chr == '"')
1687     {
1688       quoted_file_name = true;
1689       get_x_token();
1690     }
1691   }
1692
1693   while (true)
1694   {
1695     if ((cur_cmd > other_char) || (cur_chr > 255)) 
1696     {
1697       back_input();
1698       goto done; 
1699     } 
1700
1701     if (!more_name(cur_chr))    /* up to next white space */
1702       goto done;
1703
1704     get_x_token();
1705   }
1706
1707 done:
1708   end_name();
1709   name_in_progress = false;
1710 }
1711 /* argument is string .fmt, .log, or .dvi */
1712 /* sec 0529 */
1713 void pack_job_name_(str_number s)
1714 {
1715   cur_area = 335;       /* "" */
1716   cur_ext  = s;
1717   cur_name = job_name;
1718   pack_file_name(cur_name, cur_area, cur_ext);
1719 }
1720 /* sec 0530 */
1721 /* s - what can't be found, e - default */
1722 void prompt_file_name_(char * s, str_number e) 
1723 {
1724   integer k;
1725
1726   if (interaction == scroll_mode)
1727     do_nothing();
1728
1729   if (!strcmp("input file name", s))
1730     print_err("I can't find file `");
1731   else
1732     print_err("I can't write on file `");
1733
1734   print_file_name(cur_name, cur_area, cur_ext);
1735   prints("'.");
1736
1737   if (e == 785)    /* .tex */
1738     show_context();
1739
1740   print_nl("Please type another ");
1741   prints(s); 
1742
1743   if (interaction < 2)
1744   {
1745     fatal_error("*** (job aborted, file error in nonstop mode)");
1746     return;
1747   }
1748
1749   if (!knuth_flag)
1750 #ifdef _WINDOWS
1751     show_line(" (or ^z to exit)", 0);
1752 #else
1753     show_line(" (or Ctrl-Z to exit)", 0);
1754 #endif
1755
1756   prompt_input(": ");
1757
1758 /*  should we deal with tilde and space in file name here ??? */
1759   {
1760     begin_name();
1761     k = first;
1762
1763     while ((buffer[k] == ' ') && (k < last))
1764       incr(k);
1765
1766     quoted_file_name = false;
1767
1768     if (allow_quoted_names && k < last) /* check whether quoted name */
1769     {
1770       if (buffer[k]== '"')
1771       {
1772         quoted_file_name = true;
1773         incr(k);
1774       }
1775     }
1776
1777     while (true)
1778     {
1779       if (k == last)
1780         goto done;
1781 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
1782 /*  convert tilde '~' to pseudo tilde */
1783       if (pseudo_tilde != 0 && buffer[k]== '~')
1784         buffer[k] = pseudo_tilde;
1785 /*  convert space ' ' to pseudo space */
1786       if (pseudo_space != 0 && buffer[k]== ' ')
1787         buffer[k] = pseudo_space;
1788 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
1789       if (!more_name(buffer[k]))
1790         goto done;
1791
1792       incr(k);
1793     }
1794 done:
1795     end_name();
1796   }
1797
1798   if (cur_ext == 335)    /* "" */
1799     cur_ext = e;      /* use default extension */
1800
1801   pack_file_name(cur_name, cur_area, cur_ext);
1802 }
1803 /* sec 0534 */
1804 void open_log_file (void)
1805 {
1806   char old_setting;
1807   integer k;
1808   integer l;
1809   char * months;
1810
1811   old_setting = selector;
1812
1813   if (job_name == 0)
1814     job_name = 790;
1815
1816   pack_job_name(".log");
1817
1818   while (!a_open_out(log_file))
1819   {
1820     selector = term_only;
1821     prompt_file_name("transcript file name", ".log");
1822   }
1823
1824   texmf_log_name = a_make_name_string(log_file);
1825   selector = log_only;
1826   log_opened = true;
1827
1828   {
1829     fprintf(log_file, "%s (%s %s)", tex_version, application, yandyversion);
1830
1831     if (format_ident > 0)
1832       slow_print(format_ident);
1833
1834     prints("  ");
1835
1836     if (civilize_flag)
1837       print_int(year);
1838     else
1839       print_int(day);
1840
1841     print_char(' ');
1842     months = " JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
1843
1844     for (k = 3 * month - 2; k <= 3 * month; k++)
1845       putc(months[k],  log_file);
1846
1847     print_char(' ');
1848
1849     if (civilize_flag)
1850       print_int(day);
1851     else
1852       print_int(year);
1853
1854     print_char(' ');
1855     print_two(tex_time / 60);
1856     print_char(':');
1857     print_two(tex_time % 60);
1858   }
1859
1860   input_stack[input_ptr] = cur_input;
1861   print_nl("**");
1862   l = input_stack[0].limit_field;
1863
1864   if (buffer[l] == end_line_char)
1865     decr(l);
1866
1867   for (k = 1; k <= l; k++)
1868     print(buffer[k]);
1869
1870   print_ln(); 
1871
1872   if (show_fmt_flag)
1873   {
1874     if (format_file != NULL)
1875     {
1876       fprintf(log_file, "(%s)\n", format_file);
1877       free(format_file);
1878       format_file = NULL;
1879     }
1880   }
1881
1882   selector = old_setting + 2;
1883 }
1884
1885 // Attempt to deal with foo.bar.tex given as foo.bar on command line
1886 // Makes copy of job_name with extension
1887
1888 void more_name_copy(ASCII_code c)
1889 {
1890 #ifdef ALLOCATESTRING
1891   if (pool_ptr + 1 > current_pool_size)
1892     str_pool = realloc_str_pool (increment_pool_size);
1893
1894   if (pool_ptr + 1 > current_pool_size)
1895   {
1896     overflow("pool size", current_pool_size - init_pool_ptr);
1897     return;
1898   }
1899 #else
1900   if (pool_ptr + 1 > pool_size)
1901   {
1902     overflow("pool size", pool_size - init_pool_ptr);
1903     return;
1904   }
1905 #endif
1906
1907   str_pool[pool_ptr] = c; 
1908   incr(pool_ptr);
1909 }
1910
1911 int end_name_copy(void)
1912 {
1913 #ifdef ALLOCATESTRING
1914   if (str_ptr + 1 > current_max_strings)
1915     str_start = realloc_str_start(increment_max_strings + 1);
1916
1917   if (str_ptr + 1 > current_max_strings)
1918   {
1919     overflow("number of strings", current_max_strings - init_str_ptr);
1920     return 0;
1921   }
1922 #else
1923   if (str_ptr + 1 > max_strings)
1924   {
1925     overflow("number of strings", max_strings - init_str_ptr);
1926     return 0;
1927   }
1928 #endif
1929
1930   return make_string();
1931 }
1932 /* sec 0537 */
1933 void start_input(void)
1934 {
1935   scan_file_name();
1936   pack_file_name(cur_name, cur_area, cur_ext); 
1937
1938   while (true)
1939   {
1940     begin_file_reading();
1941     
1942     if (a_open_in(cur_file, TEXINPUTPATH))
1943       goto done;
1944
1945     end_file_reading();
1946     prompt_file_name("input file name", ".tex");
1947   }
1948
1949 done: 
1950   name = a_make_name_string(cur_file);
1951
1952   if (job_name == 0)
1953   {
1954     job_name = cur_name;
1955     open_log_file();
1956   }
1957
1958   if (term_offset + length(name) > max_print_line - 2)
1959     print_ln();
1960   else if ((term_offset > 0) || (file_offset > 0))
1961     print_char(' ');
1962
1963   print_char('(');
1964   incr(open_parens);
1965
1966   if (open_parens > max_open_parens)
1967     max_open_parens = open_parens;
1968
1969   slow_print(name);
1970   update_terminal();
1971   state = new_line;
1972
1973   {
1974     line = 1;
1975
1976     if (input_ln(cur_file, false))
1977       do_nothing();
1978
1979     firm_up_the_line();
1980
1981     if (end_line_char_inactive())
1982       decr(limit);
1983     else
1984       buffer[limit] = end_line_char;
1985
1986     first = limit + 1;
1987     loc = start;
1988   }
1989 }
1990 /* sec 0560 */
1991 internal_font_number read_font_info_(halfword u, str_number nom, str_number aire, scaled s)
1992 {
1993   font_index k;
1994   boolean file_opened;
1995   halfword lf, lh, nw, nh, nd, ni, nl, nk, ne, np;
1996   int bc, ec;
1997   internal_font_number f;
1998   internal_font_number g;
1999   eight_bits a, b, c, d;
2000   four_quarters qw;
2001   scaled sw;
2002   integer bch_label;
2003   short bchar;
2004   scaled z;
2005   integer alpha;
2006   char beta;
2007
2008   g = 0;
2009   file_opened = false;
2010   pack_file_name(nom, aire, 805); /* .tfm */
2011
2012   if (!b_open_in(tfm_file))
2013     goto bad_tfm;
2014
2015   file_opened = true;
2016
2017   {
2018     read_sixteen(lf);
2019     tfm_temp = getc(tfm_file);
2020     read_sixteen(lh);
2021     tfm_temp = getc(tfm_file);
2022     read_sixteen(bc);
2023     tfm_temp = getc(tfm_file);
2024     read_sixteen(ec);
2025
2026     if ((bc > ec + 1) || (ec > 255))
2027       goto bad_tfm;
2028
2029     if (bc > 255)
2030     {
2031       bc = 1;
2032       ec = 0;
2033     }
2034
2035     tfm_temp = getc(tfm_file);
2036     read_sixteen(nw);
2037     tfm_temp = getc(tfm_file);
2038     read_sixteen(nh);
2039     tfm_temp = getc(tfm_file);
2040     read_sixteen(nd);
2041     tfm_temp = getc(tfm_file);
2042     read_sixteen(ni);
2043     tfm_temp = getc(tfm_file);
2044     read_sixteen(nl);
2045     tfm_temp = getc(tfm_file);
2046     read_sixteen(nk);
2047     tfm_temp = getc(tfm_file);
2048     read_sixteen(ne);
2049     tfm_temp = getc(tfm_file);
2050     read_sixteen(np);
2051
2052     if (lf != 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np)
2053       goto bad_tfm;
2054
2055     if ((nw == 0) || (nh == 0) || (nd == 0) || (ni == 0))
2056       goto bad_tfm;
2057   }
2058
2059   lf = lf - 6 - lh;
2060
2061   if (np < 7)
2062     lf = lf + 7 - np;
2063
2064 #ifdef ALLOCATEFONT
2065   if ((fmem_ptr + lf > current_font_mem_size))
2066     font_info = realloc_font_info (increment_font_mem_size + lf);
2067
2068   if ((font_ptr == font_max) || (fmem_ptr + lf > current_font_mem_size))
2069 #else
2070   if ((font_ptr == font_max) || (fmem_ptr + lf > font_mem_size))
2071 #endif
2072   {
2073     if (trace_flag)
2074     {
2075       sprintf(log_line, "font_ptr %lld font_max %d fmem_ptr %lld lf %ld font_mem_size %ld\n",
2076           font_ptr, font_max, fmem_ptr, lf, font_mem_size);
2077       show_line(log_line, 0);
2078     }
2079
2080     print_err("Font ");
2081     sprint_cs(u);
2082     print_char('=');
2083     print_file_name(nom, aire, 335); /* "" */
2084
2085     if (s >= 0)
2086     {
2087       prints(" at ");
2088       print_scaled(s);
2089       prints("pt");
2090     }
2091     else if (s != -1000)
2092     {
2093       prints(" scaled ");
2094       print_int(- (integer) s);
2095     }
2096
2097     prints(" not loaded: Not enough room left");
2098     help4("I'm afraid I won't be able to make use of this font,",
2099         "because my memory for character-size data is too small.",
2100         "If you're really stuck, ask a wizard to enlarge me.",
2101         "Or maybe try `I\\font<same font id>=<name of loaded font>'.");
2102     error();
2103     goto done;
2104   }
2105
2106   f = font_ptr + 1;
2107   char_base[f] = fmem_ptr - bc;
2108   width_base[f] = char_base[f] + ec + 1;
2109   height_base[f] = width_base[f] + nw;
2110   depth_base[f] = height_base[f] + nh;
2111   italic_base[f] = depth_base[f] + nd;
2112   lig_kern_base[f] = italic_base[f] + ni;
2113   kern_base[f] = lig_kern_base[f] + nl - 256 * (128);
2114   exten_base[f] = kern_base[f] + 256 * (128) + nk;
2115   param_base[f] = exten_base[f] + ne;
2116
2117   {
2118     if (lh < 2)
2119       goto bad_tfm;
2120     
2121     store_four_quarters(font_check[f]);
2122     tfm_temp = getc(tfm_file);
2123     read_sixteen(z);
2124     tfm_temp = getc(tfm_file);
2125     z = z * 256 + tfm_temp;
2126     tfm_temp = getc(tfm_file);
2127     z =(z * 16) + (tfm_temp / 16);
2128
2129     if (z < unity)
2130       goto bad_tfm; 
2131
2132     while (lh > 2)
2133     {
2134       tfm_temp = getc(tfm_file);
2135       tfm_temp = getc(tfm_file);
2136       tfm_temp = getc(tfm_file);
2137       tfm_temp = getc(tfm_file);
2138       decr(lh);
2139     }
2140
2141     font_dsize[f] = z;
2142
2143     if (s != -1000)
2144       if (s >= 0)
2145         z = s;
2146       else
2147         z = xn_over_d(z, - (integer) s, 1000);
2148
2149     font_size[f] = z;
2150   }
2151
2152   for (k = fmem_ptr; k <= width_base[f] - 1; k++)
2153   {
2154     store_four_quarters(font_info[k].qqqq);
2155
2156     if ((a >= nw) || (b / 16 >= nh) || (b % 16 >= nd) || (c / 4 >= ni))
2157       goto bad_tfm;
2158
2159     switch (c % 4)
2160     {
2161       case lig_tag:
2162         if (d >= nl)
2163           goto bad_tfm;
2164         break;
2165
2166       case ext_tag:
2167         if (d >= ne)
2168           goto bad_tfm;
2169         break;
2170
2171       case list_tag:
2172         {
2173           {
2174             if ((d < bc) || (d > ec))
2175               goto bad_tfm;
2176           }
2177
2178           while (d < k + bc - fmem_ptr)
2179           {
2180             qw = char_info(f, d);
2181  
2182             if (char_tag(qw) != list_tag)
2183               goto not_found;
2184
2185             d = rem_byte(qw);
2186           }
2187
2188           if (d == k + bc - fmem_ptr)
2189             goto bad_tfm;
2190 not_found:; 
2191         }
2192         break;
2193
2194       default:
2195         break;
2196     }
2197   }
2198
2199   {
2200     {
2201       alpha = 16;
2202
2203       while (z >= 8388608L)   /* 2^23 */
2204       {
2205         z = z / 2;
2206         alpha = alpha + alpha;
2207       }
2208
2209       beta = (char) (256 / alpha);
2210       alpha = alpha * z;
2211     }
2212
2213     for (k = width_base[f]; k <= lig_kern_base[f] - 1; k++)
2214     {
2215       tfm_temp = getc(tfm_file);
2216       a = tfm_temp;
2217       tfm_temp = getc(tfm_file);
2218       b = tfm_temp;
2219       tfm_temp = getc(tfm_file);
2220       c = tfm_temp;
2221       tfm_temp = getc(tfm_file);
2222       d = tfm_temp;
2223       sw = (((((d * z) / 256) + (c * z)) / 256) + (b * z)) / beta;
2224
2225       if (a == 0)
2226         font_info[k].cint = sw;
2227       else if (a == 255)
2228         font_info[k].cint = sw - alpha;
2229       else
2230         goto bad_tfm;
2231     }
2232
2233     if (font_info[width_base[f]].cint != 0)
2234       goto bad_tfm;
2235
2236     if (font_info[height_base[f]].cint != 0)
2237       goto bad_tfm;
2238
2239     if (font_info[depth_base[f]].cint != 0)
2240       goto bad_tfm;
2241
2242     if (font_info[italic_base[f]].cint != 0)
2243       goto bad_tfm;
2244   }
2245
2246   bch_label = 32767;     /* '77777 */
2247   bchar = 256;
2248
2249   if (nl > 0)
2250   {
2251     for (k = lig_kern_base[f]; k <= kern_base[f] + 256 * (128) - 1; k++)
2252     {
2253       store_four_quarters(font_info[k].qqqq);
2254
2255       if (a > 128)
2256       {
2257         if (256 * c + d >= nl)
2258           goto bad_tfm;
2259
2260         if (a == 255)
2261           if (k == lig_kern_base[f])
2262             bchar = b;
2263       }
2264       else
2265       {
2266         if (b != bchar)
2267           check_existence(b);
2268
2269         if (c < 128)
2270           check_existence(d);
2271         else if (256 * (c - 128) + d >= nk)
2272           goto bad_tfm;
2273
2274         if (a < 128)
2275           if (k - lig_kern_base[f] + a + 1 >= nl)
2276             goto bad_tfm;
2277       }
2278     }
2279
2280     if (a == 255)
2281       bch_label = 256 * c + d;
2282   }
2283
2284   for (k = kern_base[f] + 256 * (128); k <= exten_base[f] - 1; k++)
2285   {
2286     tfm_temp = getc(tfm_file);
2287     a = tfm_temp;
2288     tfm_temp = getc(tfm_file);
2289     b = tfm_temp;
2290     tfm_temp = getc(tfm_file);
2291     c = tfm_temp;
2292     tfm_temp = getc(tfm_file);
2293     d = tfm_temp;
2294     sw = (((((d * z) / 256) + (c * z)) / 256) + (b * z)) / beta;
2295
2296     if (a == 0)
2297       font_info[k].cint = sw;
2298     else if (a == 255)
2299       font_info[k].cint = sw - alpha;
2300     else
2301       goto bad_tfm;
2302   }
2303
2304   for (k = exten_base[f]; k <= param_base[f] - 1; k++)
2305   {
2306     store_four_quarters(font_info[k].qqqq);
2307
2308     if (a != 0)
2309       check_existence(a);
2310
2311     if (b != 0)
2312       check_existence(b);
2313
2314     if (c != 0)
2315       check_existence(c);
2316
2317     check_existence(d);
2318   }
2319
2320   {
2321     for (k = 1; k <= np; k++)
2322       if (k == 1)
2323       {
2324         tfm_temp = getc(tfm_file);
2325         sw = tfm_temp;
2326
2327         if (sw > 127)
2328           sw = sw - 256;
2329
2330         tfm_temp = getc(tfm_file);
2331         sw = sw * 256 + tfm_temp;
2332         tfm_temp = getc(tfm_file);
2333         sw = sw * 256 + tfm_temp;
2334         tfm_temp = getc(tfm_file);
2335         font_info[param_base[f]].cint = (sw * 16) + (tfm_temp / 16);
2336       }
2337       else
2338       {
2339         tfm_temp = getc(tfm_file);
2340         a = tfm_temp;
2341         tfm_temp = getc(tfm_file);
2342         b = tfm_temp;
2343         tfm_temp = getc(tfm_file);
2344         c = tfm_temp;
2345         tfm_temp = getc(tfm_file);
2346         d = tfm_temp;
2347         sw = (((((d * z) / 256) + (c * z)) / 256) + (b * z)) / beta;
2348
2349         if (a == 0)
2350           font_info[param_base[f] + k - 1].cint = sw;
2351         else if (a == 255)
2352           font_info[param_base[f] + k - 1].cint = sw - alpha;
2353         else goto bad_tfm;
2354       }
2355
2356     if (feof(tfm_file))
2357       goto bad_tfm;
2358
2359     for (k = np + 1; k <= 7; k++)
2360       font_info[param_base[f] + k - 1].cint = 0;
2361   }
2362
2363   if (np >= 7)
2364     font_params[f] = np;
2365   else
2366     font_params[f] = 7;
2367
2368   hyphen_char[f] = default_hyphen_char;
2369   skew_char[f] = default_skew_char;
2370
2371   if (bch_label < nl)
2372     bchar_label[f] = bch_label + lig_kern_base[f];
2373   else
2374     bchar_label[f] = non_address;
2375
2376   font_bchar[f] = bchar;
2377   font_false_bchar[f] = bchar;
2378
2379   if (bchar <= ec)
2380     if (bchar >= bc)
2381     {
2382       qw = char_info(f, bchar);
2383
2384       if (char_exists(qw))
2385         font_false_bchar[f] = 256;
2386     }
2387
2388   font_name[f] = nom;
2389   font_area[f] = aire;
2390   font_bc[f] = bc;
2391   font_ec[f] = ec;
2392   font_glue[f] = 0;
2393   char_base[f] = char_base[f];
2394   width_base[f] = width_base[f];
2395   lig_kern_base[f] = lig_kern_base[f];
2396   kern_base[f] = kern_base[f];
2397   exten_base[f] = exten_base[f];
2398   decr(param_base[f]);
2399   fmem_ptr = fmem_ptr + lf;
2400   font_ptr = f;
2401   g = f;
2402   goto done;
2403
2404 bad_tfm:
2405   print_err("Font ");
2406   sprint_cs(u); 
2407   print_char('=');
2408   print_file_name(nom, aire, 335);
2409
2410   if (s >= 0)
2411   {
2412     prints(" at ");
2413     print_scaled(s);
2414     prints("pt");
2415   }
2416   else if (s != -1000)
2417   {
2418     prints("scaled");
2419     print_int(-(integer)s);
2420   } 
2421
2422   if (file_opened)
2423     prints(" not loadable: Bad metric (TFM) file");
2424   else
2425     prints(" not loadable: Metric (TFM) file not found");
2426
2427   help5("I wasn't able to read the size data for this font,",
2428       "so I will ignore the font specification.",
2429       "[Wizards can fix TFM files using TFtoPL/PLtoTF.]",
2430       "You might try inserting a different font spec;",
2431       "e.g., type `I\\font<same font id>=<substitute font name>'.");
2432   error();
2433
2434 done:
2435   if (file_opened)
2436     b_close(tfm_file);
2437
2438   return g;
2439 }