OSDN Git Service

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