1 /* char_routines.c: Data structures for character information
2 
3 This file is part of Omega,
4 which is based on the web2c distribution of TeX,
5 
6 Copyright (c) 1994--2001 John Plaice and Yannis Haralambous
7 
8 Omega is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 Omega is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Omega; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 
22 */
23 
24 #include "cpascal.h"
25 #include "manifests.h"
26 #include "list_routines.h"
27 #include "char_routines.h"
28 #include "print_routines.h"
29 #include "out_routines.h"
30 #include "error_routines.h"
31 #include "ligkern_routines.h"
32 #include "dimen_routines.h"
33 #include "header_routines.h"
34 #include "font_routines.h"
35 #include "out_ofm.h"
36 #include "omfonts.h"
37 #include "parse_ofm.h"
38 #include "dvi.h"
39 
40 #define PLANE		0x10000
41 #define INDEX_MAX	(PLANE-1)
42 #define HALFPLANE	0x08000
43 
44 #define MAX_START_OFM	65535
45 #define MAX_START_TFM	255
46 
47 /*
48  * Characters can range from 0x0 to 0x7fffffff (31 bits unsigned),
49  * which is a lot of characters.  We would expect characters to either
50  * be bunched up in a given region, or else sparsely defined throughout
51  * the range.  The data structure to hold them is an array of HALFPLANE
52  * arrays, each of which holds a full PLANE (0x10000) of characters.
53  *
54  * At all times, init_character ensures that planes[0] to planes[plane_max]
55  * are either NULL or allocated arrays of PLANE characters.
56  *
57  * For allocated array p, init_character also ensures that planes[p][0]
58  * to planes[p][char_max[p]] are either NULL or pointers to allocated
59  * char_entry values.
60  *
61  * init_character can be called when actually reading a CHARACTER definition
62  * or when the character is referenced in a charlist cycle, an extensible
63  * piece or in a ligature/kerning table.  In the latter case, ensure_existence
64  * is called, and it sets the defined field of the character to be FALSE;
65  *
66  * init_character also sets current_character to the character entry;
67  *
68  */
69 
70 unsigned bc=0x7fffffff;
71 unsigned ec=0x0;
72 unsigned ne=0;
73 
74 char_entry **planes[HALFPLANE];
75 unsigned char_max[HALFPLANE];
76 unsigned plane_max = 0;
77 
78 char_entry *current_character = NULL;
79 char_entry *current_secondary_character = NULL;
80 
81 queue exten_queue;
82 four_pieces **exten_table = NULL;
83 
84 unsigned no_labels = 0;
85 label_entry *label_table;
86 int label_ptr, sort_ptr;
87 int lk_offset;
88 boolean extra_loc_needed;
89 
90 void
init_planes(void)91 init_planes(void)
92 {
93     plane_max = 0;
94     planes[plane_max] = NULL;
95 }
96 
97 void
init_character(unsigned c,char_entry * ready_made)98 init_character(unsigned c, char_entry *ready_made)
99 {
100     register unsigned i, index, plane;
101 
102     if ((c<CHAR_MINIMUM) || (c>CHAR_MAXIMUM)) {
103         warning_1("CHARACTER index (H %X) not 31-bit unsigned integer; "
104                   "ignored", c);
105         current_character = NULL;
106         return;
107     }
108     plane = c / PLANE;
109     index = c % PLANE;
110     for (i=plane_max+1; i<=plane; i++) {
111 	    planes[i] = NULL;
112     }
113     if (planes[plane]==NULL) {
114         planes[plane] = (char_entry **)xmalloc(PLANE * sizeof(char_entry *));
115         char_max[plane] = 0;
116         planes[plane][0] = NULL;
117     }
118     for (i=char_max[plane]+1; i<=index; i++) {
119         planes[plane][i] = NULL;
120     }
121     if (plane>plane_max)       plane_max = plane;
122     if (index>char_max[plane])   char_max[plane] = index;
123 
124     if (planes[plane][index] != NULL) {
125         if (planes[plane][index]->defined == FALSE) {
126             current_character = planes[plane][index];
127             current_character->defined = TRUE;
128             return;
129         }
130         warning_1("CHARACTER index (H %X) previously defined; "
131                   "old definition ignored", c);
132         free(current_character);
133         current_character = NULL;
134     }
135     if (ready_made != NULL) {
136         current_character = ready_made;
137         planes[plane][index] = current_character;
138     } else {
139         current_character = (char_entry *)xmalloc(sizeof(char_entry));
140         planes[plane][index] = current_character;
141         for (i=C_MIN; i<=C_MAX; i++) {
142             current_character->indices[i] = NULL;
143             current_character->index_indices[i] = 0;
144         }
145         current_character->c = c;
146         current_character->copies = 0;
147         current_character->remainder = 0;
148         current_character->tag = TAG_NONE;
149         current_character->defined = TRUE;
150         current_character->accent = ACC_NONE;
151         current_character->ovf_packet_length = 0;
152         current_character->ovf_packet = NULL;
153         cur_packet = NULL;
154     }
155 }
156 
157 void
copy_characters(unsigned c,unsigned copies)158 copy_characters(unsigned c, unsigned copies)
159 {
160     unsigned i=0;
161     unsigned plane, index;
162     char_entry *the_entry;
163 
164     if ((c<CHAR_MINIMUM) || (c>CHAR_MAXIMUM)) {
165         warning_1("CHARACTER index (H %X) not 31-bit unsigned integer; "
166                   "ignored", c);
167         current_character = NULL;
168         return;
169     }
170     plane = c / PLANE;
171     index = c % PLANE;
172     if ((plane>plane_max) || (planes[plane]==NULL))
173         internal_error_1("copy_characters (plane %d)", plane);
174     the_entry = planes[plane][index];
175     if (the_entry==NULL)
176         internal_error_1("copy_characters (index %d)", index);
177     the_entry->copies = copies;
178     for (i=(c+1); i<=(c+copies); i++)
179         init_character(i, the_entry);
180 }
181 
182 void
ensure_existence(unsigned c)183 ensure_existence(unsigned c)
184 {
185     register unsigned index, plane;
186     plane = c / PLANE;
187     index = c % PLANE;
188 
189     if ((plane>plane_max) || (planes[plane]==NULL) ||
190         (index>char_max[plane]) || (planes[plane][index]==NULL)) {
191         init_character(c, NULL);
192         planes[plane][index]->defined = FALSE;
193     }
194     current_secondary_character = planes[plane][index];
195 }
196 
197 #define FOR_ALL_CHARACTERS(FOR_ALL_CHARACTERS_ACTION) \
198     for (plane = 0; plane <=plane_max; plane++) { \
199         if (planes[plane] != NULL) { \
200             for (index = 0; index <=char_max[plane]; index++) { \
201                 entry = planes[plane][index]; \
202                 if (entry != NULL) {  \
203                     FOR_ALL_CHARACTERS_ACTION \
204                 } \
205             } \
206         } \
207     }
208 
209 #define FOR_ALL_EXISTING_CHARACTERS(FOR_ALL_EXISTING_CHARACTERS_ACTION) \
210     FOR_ALL_CHARACTERS( \
211         if (entry->defined == TRUE) { \
212             FOR_ALL_EXISTING_CHARACTERS_ACTION \
213         } \
214     )
215 
216 void
output_ovf_chars(void)217 output_ovf_chars(void)
218 {
219     register unsigned index, plane, k;
220     char_entry *entry;
221     fix wd;
222 
223     FOR_ALL_EXISTING_CHARACTERS(
224         unsigned c = plane*PLANE + index;
225 
226         if ((entry->indices[C_WD] == NULL) || (entry->indices[C_WD]->index == 0))
227             continue;
228         wd = lval(entry->indices[C_WD]);
229         if (design_units != UNITY)
230             wd = zround(((double)wd) / ((double)design_units) * 1048576.0);
231         if ((entry->ovf_packet_length>241) ||
232             (wd < 0) || (wd >= 0x1000000) ||
233             (c < 0) || (c >255)) {
234             out_ovf(242); out_ovf_4(entry->ovf_packet_length);
235             out_ovf_4(c); out_ovf_4(wd);
236         } else {
237             out_ovf(entry->ovf_packet_length); out_ovf(c);
238             out_ovf((wd >>16) & 0xff); out_ovf((wd >>8) & 0xff);
239             out_ovf(wd & 0xff);
240         }
241         for (k=0; k<entry->ovf_packet_length; k++)
242             out_ovf(entry->ovf_packet[k]);
243     )
244 }
245 
246 
247 static void
check_existence_all_character_fields(void)248 check_existence_all_character_fields(void)
249 {
250     register unsigned index, plane;
251     char_entry *entry;
252     unsigned *exten;
253     unsigned j;
254 
255     FOR_ALL_EXISTING_CHARACTERS(
256         unsigned c = plane*PLANE + index;
257         if (entry->indices[C_WD] == NULL) {
258             current_character = entry;
259             set_character_measure(C_WD, 0);
260         }
261         switch(entry->tag) {
262             case TAG_NONE: { break; }
263             case TAG_LIG: {
264                 check_ligature_program(c, entry->remainder);
265                 break;
266             }
267             case TAG_LIST:{
268                 check_existence_and_safety(c, entry->remainder, "",
269                     "%sCharacter (H %X) NEXTLARGER than (H %X) "
270                     "has no CHARACTER spec");
271                 if (entry->remainder > 0xffff) {
272                     fprintf(stderr, "Character (H %X) NEXTLARGER than (H %X) "
273                         "exceeds ffff\n", entry->remainder, c);
274                     exit(2);
275                 }
276                 break;
277             }
278             case TAG_EXT:{
279                 exten = entry->extens;
280                 for (j=E_MIN; j<=E_MAX; j++) {
281                     if (exten[j]!=0) {
282                         check_existence_and_safety(c, exten[j],
283                             extensible_pieces[j],
284                             "%s piece (H %X) of character (H %X) "
285                             "has no CHARACTER spec");
286                         if (exten[j] > 0xfff) {
287                             fprintf(stderr, "%s piece (H %X) of character (H %X) "
288                                 "exceeds ffff\n", extensible_pieces[j], exten[j], c);
289                             exit(2);
290                         }
291                     }
292                 }
293                 break;
294             }
295         }
296     )
297 }
298 
299 void
clear_ligature_entries(void)300 clear_ligature_entries(void)
301 {
302     register unsigned index, plane;
303     char_entry *entry;
304 
305     FOR_ALL_EXISTING_CHARACTERS(
306         if (entry->tag == TAG_LIG) {
307             entry->tag = TAG_NONE;
308             entry->remainder = 0;
309         }
310     )
311 }
312 
313 void
check_existence_and_safety(unsigned c,unsigned g,const_string extra,const_string fmt)314 check_existence_and_safety(unsigned c, unsigned g, const_string extra, const_string fmt)
315 {
316     char_entry *gentry;
317 
318     if ((g<CHAR_MINIMUM) || (g>CHAR_MAXIMUM))
319         internal_error_1("check_existence_and_safety (g=%d)", g);
320     ensure_existence(g);
321     gentry = current_secondary_character;
322     if ((g>=128) && (c<128))
323         seven_bit_calculated = 0;
324     if (gentry->defined == FALSE) {
325         warning_s_2(fmt, extra, g, c);
326         current_character = gentry;
327         set_character_measure(C_WD, 0);
328         gentry->defined = TRUE;
329     }
330 }
331 
332 void
doublecheck_existence(unsigned g,const_string extra,const_string fmt)333 doublecheck_existence(unsigned g, const_string extra, const_string fmt)
334 {
335     char_entry *gentry;
336 
337     if ((g<CHAR_MINIMUM) || (g>CHAR_MAXIMUM))
338         internal_error_1("doublecheck_existence (g=%d)", g);
339     ensure_existence(g);
340     gentry = current_secondary_character;
341     if (gentry->defined == FALSE) {
342         warning_s_1(fmt, extra, g);
343         current_character = gentry;
344 /*
345         set_character_measure(C_WD, 0);
346 */
347     }
348 }
349 
350 static void print_packet(unsigned char *, unsigned);
351 
352 #define check_range(ndx, mx, name) \
353         if (entry->index_indices[ndx] >= mx) { \
354             fprintf(stderr, "\n%s index for character \"%x is too large;\n" \
355                             "so I reset it to zero.\n", name, c); \
356             entry->index_indices[ndx] = 0; \
357             changed = TRUE; \
358         }
359 
360 void
print_characters(boolean read_ovf)361 print_characters(boolean read_ovf)
362 {
363     register unsigned index, plane;
364     char_entry *entry;
365     four_pieces *exten;
366     four_entries *lentry;
367     unsigned j,k;
368     unsigned copies = 0;
369 
370     FOR_ALL_CHARACTERS(
371       unsigned c = plane*PLANE + index;
372       if (copies > 0)
373         copies--;
374       else {
375         if (entry->index_indices[C_WD] != 0) {
376         copies = entry->copies;
377         if (copies > 0)
378             print_character_repeat(c, copies);
379         else
380             print_character(c);
381         check_range(C_WD, nw, "Width")
382         check_range(C_HT, nh, "Height")
383         check_range(C_DP, nd, "Depth")
384         check_range(C_IC, ni, "Italic correction")
385         for (k=C_MIN; k<C_MAX; k++) {
386             if (entry->index_indices[k] != 0) {
387                 print_character_measure(k,
388                   dimen_tables[k][entry->index_indices[k]]);
389             }
390         }
391         fflush(file_output);
392         switch (entry->tag) {
393             case TAG_NONE: { break; }
394             case TAG_LIG:  {
395                 if (entry->remainder >= nl) {
396                     fprintf(stderr, "\nLigature/kern starting index for character \"%x is too large;\n"
397                                     "so I removed it.\n", c);
398                     entry->tag = 0;
399                     entry->remainder = 0;
400                     changed = TRUE;
401                     break;
402                 }
403                 left();
404                 out("COMMENT"); out_ln();
405                 lentry = lig_kern_table + entry->remainder;
406                 if (lentry->entries[0] > STOP_FLAG) {
407                     lentry = lig_kern_table +
408                              (256*lentry->entries[2]+lentry->entries[3]);
409                 }
410 		do {
411                     print_one_lig_kern_entry(lentry, FALSE);
412 		    if (lentry->entries[0] >= STOP_FLAG) {
413                         lentry = lig_kern_table + nl;
414                     } else {
415                         lentry = lentry + 1 + lentry->entries[0];
416                     }
417                 } while (lentry < (lig_kern_table + nl));
418                 right();
419                 break;
420             }
421             case TAG_LIST: {
422                 print_next_larger(entry->remainder);
423                 break;
424             }
425             case TAG_EXT: {
426 	        if (entry->remainder >= ne) {
427 	            fprintf(stderr, "\nExtensible index for character \"%x is too large;\n"
428 	                             "so I reset it to zero.\n", c);
429 	            entry->tag = 0;
430 	            entry->remainder = 0;
431 	            changed = TRUE;
432 	            break;
433 	        }
434 	        print_var_character();
435                 exten = exten_table[entry->remainder];
436                 for (j=E_MIN; j<=E_MAX; j++) {
437                     if (exten->pieces[j]!=0)
438                         print_extensible_piece(j,exten->pieces[j]);
439                 }
440                 right();
441                 break;
442             }
443         }
444         if ((read_ovf==TRUE) && (entry->ovf_packet_length>0)) {
445             print_map();
446             print_packet(entry->ovf_packet, entry->ovf_packet_length);
447             right();
448         }
449         right();
450         fflush(file_output);
451         }
452       }
453     )
454 }
455 
456 unsigned stack_top = 0;
457 int wstack[1000];
458 int xstack[1000];
459 int ystack[1000];
460 int zstack[1000];
461 
462 static int
string_balance(unsigned char * special,int k)463 string_balance(unsigned char *special, int k)
464 {
465     unsigned paren_level = 0;
466 
467     if (k == 0)
468         return 1;
469     if (*special == ' ')
470         return 0;
471     for (; k > 0; k--, special++) {
472         if ((*special < ' ') || (*special > '~'))
473             return 0;
474         if (*special == '(')
475             paren_level++;
476         if (*special == ')') {
477             if (paren_level-- == 0)
478                 return 0;
479         }
480     }
481     return (paren_level == 0);
482 }
483 
484 static void
print_packet(unsigned char * packet_start,unsigned packet_length)485 print_packet(unsigned char *packet_start, unsigned packet_length)
486 {
487    unsigned cmd, arg;
488    fix fix_arg, fix_arg1;
489    unsigned char *packet = packet_start;
490    unsigned char *max_packet = packet+packet_length;
491 
492    stack_top = 0;
493    wstack[stack_top] = xstack[stack_top] =
494    ystack[stack_top] = zstack[stack_top] = 0;
495    while (packet <max_packet) {
496    if (*packet <= DVI_SET_CHAR_127) {
497          arg = *packet; packet++;
498          print_set_char(arg);
499    } else if ((*packet >= DVI_FNT_NUM_0) && (*packet <= DVI_FNT_NUM_63)) {
500          arg = *packet - DVI_FNT_NUM_0; packet++;
501          print_select_font(arg);
502    } else switch(*packet) {
503       case DVI_SET_1: case DVI_SET_2: case DVI_SET_3: case DVI_SET_4:
504          cmd = *packet; packet++;
505          arg = ovf_get_arg(&packet, cmd - DVI_SET_1 + 1, FALSE);
506          print_set_char(arg);
507          break;
508       case DVI_NOP:
509          packet++;
510          break;
511       case DVI_PUSH:
512          cmd = DVI_PUSH; packet++; stack_top++;
513          wstack[stack_top] = wstack[stack_top-1];
514          xstack[stack_top] = xstack[stack_top-1];
515          ystack[stack_top] = ystack[stack_top-1];
516          zstack[stack_top] = zstack[stack_top-1];
517          print_push();
518          break;
519       case DVI_POP:
520          cmd = DVI_PUSH; packet++; stack_top--;
521          print_pop();
522          break;
523       case DVI_SET_RULE:
524          cmd = DVI_SET_RULE; packet++; fix_arg = ovf_get_arg(&packet, 4, TRUE);
525          fix_arg1 = ovf_get_arg(&packet, 4, TRUE);
526          print_set_rule(fix_arg, fix_arg1);
527          break;
528       case DVI_PUT_RULE:
529          cmd = DVI_PUT_RULE; packet++; fix_arg = ovf_get_arg(&packet, 4, TRUE);
530          fix_arg1 = ovf_get_arg(&packet, 4, TRUE);
531          print_put_rule(fix_arg, fix_arg1);
532          break;
533       case DVI_RIGHT_1: case DVI_RIGHT_2: case DVI_RIGHT_3: case DVI_RIGHT_4:
534          cmd = *packet; packet++;
535          fix_arg = ovf_get_arg(&packet, cmd - DVI_RIGHT_1 + 1, TRUE);
536          print_move(M_RIGHT, fix_arg);
537          break;
538       case DVI_DOWN_1:  case DVI_DOWN_2:  case DVI_DOWN_3:  case DVI_DOWN_4:
539          cmd = *packet; packet++;
540          fix_arg = ovf_get_arg(&packet, cmd - DVI_DOWN_1 + 1, TRUE);
541          print_move(M_DOWN, fix_arg);
542          break;
543       case DVI_W_0:
544          cmd = DVI_W_0; packet++;
545          print_move(M_RIGHT, wstack[stack_top]);
546          break;
547       case DVI_W_1: case DVI_W_2: case DVI_W_3: case DVI_W_4:
548          cmd = *packet; packet++;
549          wstack[stack_top] = ovf_get_arg(&packet, cmd - DVI_W_1 + 1, TRUE);
550          print_move(M_RIGHT, wstack[stack_top]);
551          break;
552       case DVI_X_0:
553          cmd = DVI_X_0; packet++;
554          print_move(M_RIGHT, xstack[stack_top]);
555          break;
556       case DVI_X_1: case DVI_X_2: case DVI_X_3: case DVI_X_4:
557          cmd = *packet; packet++;
558          xstack[stack_top] = ovf_get_arg(&packet, cmd - DVI_X_1 + 1, TRUE);
559          print_move(M_RIGHT, xstack[stack_top]);
560          break;
561       case DVI_Y_0:
562          cmd = DVI_Y_0; packet++;
563          print_move(M_DOWN, ystack[stack_top]);
564          break;
565       case DVI_Y_1: case DVI_Y_2: case DVI_Y_3: case DVI_Y_4:
566          cmd = *packet; packet++;
567          ystack[stack_top] = ovf_get_arg(&packet, cmd - DVI_Y_1 + 1, TRUE);
568          print_move(M_DOWN, ystack[stack_top]);
569          break;
570       case DVI_Z_0:
571          cmd = DVI_Z_0; packet++;
572          print_move(M_DOWN, zstack[stack_top]);
573          break;
574       case DVI_Z_1: case DVI_Z_2: case DVI_Z_3: case DVI_Z_4:
575          cmd = *packet; packet++;
576          zstack[stack_top] = ovf_get_arg(&packet, cmd - DVI_Z_1 + 1, TRUE);
577          print_move(M_DOWN, zstack[stack_top]);
578          break;
579       case DVI_PUT_1: case DVI_PUT_2: case DVI_PUT_3: case DVI_PUT_4:
580          cmd = *packet; packet++;
581          fix_arg = ovf_get_arg(&packet, cmd - DVI_PUT_1 + 1, FALSE);
582          print_put_char(fix_arg);
583          break;
584       case DVI_XXX_1: case DVI_XXX_2: case DVI_XXX_3: case DVI_XXX_4:
585          cmd = *packet; packet++;
586          fix_arg = ovf_get_arg(&packet, cmd - DVI_XXX_1 + 1, FALSE);
587          if (fix_arg < 0) {
588              internal_error_1("Special string with negative length (%d)\n", fix_arg);
589          }
590          if ((fix_arg <= 64) && string_balance(packet, fix_arg)) {
591              char *special = (char *) xmalloc(fix_arg+1);
592              strncpy(special, (const char *)packet, fix_arg);
593              special[fix_arg] = '\0';
594              print_special(special);
595              free(special);
596          } else {
597              print_special_hex(packet, fix_arg);
598          }
599          packet += fix_arg;
600          break;
601       case DVI_FNT_1: case DVI_FNT_2: case DVI_FNT_3: case DVI_FNT_4:
602          cmd = *packet; packet++;
603          fix_arg = ovf_get_arg(&packet, cmd - DVI_FNT_1 + 1, FALSE);
604          print_select_font(fix_arg);
605          break;
606       default:
607          internal_error_1("Unrecognized DVI packet (%d)\n", *packet);
608    }
609    }
610    fflush(file_output);
611    fflush(stderr);
612 }
613 
614 void
check_char_tag(unsigned c)615 check_char_tag(unsigned c)
616 {
617     ensure_existence(c);
618 }
619 
620 void
set_char_tag(unsigned c,unsigned tag)621 set_char_tag(unsigned c, unsigned tag)
622 {
623     ensure_existence(c);
624     planes[c/PLANE][c%PLANE]->tag = tag;
625 }
626 
627 void
set_char_remainder(unsigned c,unsigned remainder)628 set_char_remainder(unsigned c, unsigned remainder)
629 {
630     ensure_existence(c);
631     planes[c/PLANE][c%PLANE]->remainder = remainder;
632 }
633 
634 static int
get_char_remainder(unsigned c)635 get_char_remainder(unsigned c)
636 {
637     ensure_existence(c);
638     return planes[c/PLANE][c%PLANE]->remainder;
639 }
640 
641 void
set_next_larger(unsigned larger)642 set_next_larger(unsigned larger)
643 {
644     check_char_tag(current_character->c);
645     set_char_tag(current_character->c, TAG_LIST);
646     set_char_remainder(current_character->c, larger);
647 }
648 
649 void
init_var_character(void)650 init_var_character(void)
651 {
652     four_pieces *entry = (four_pieces *) xmalloc(sizeof(four_pieces));
653     unsigned j;
654 
655     check_char_tag(current_character->c);
656     set_char_tag(current_character->c, TAG_EXT);
657     append_to_queue(&exten_queue, entry);
658     for (j=E_MIN; j<=E_MAX; j++) {
659         entry->pieces[j] = 0;
660     }
661     set_char_remainder(current_character->c, ne);
662     current_character->extens = (unsigned int *)entry->pieces;
663     ne++;
664 }
665 
666 void
set_extensible_piece(unsigned piece,unsigned val)667 set_extensible_piece(unsigned piece, unsigned val)
668 {
669     unsigned *exten = current_character->extens;
670 
671     if ((piece < E_MIN) || (piece > E_MAX))
672         internal_error_1("set_extensible_piece (piece=%d)", piece);
673     if (exten[piece]!=0)
674         warning_0("value already defined");
675     exten[piece] = val;
676 }
677 
678 void
adjust_labels(boolean play_with_starts)679 adjust_labels(boolean play_with_starts)
680 {
681     unsigned plane, index;
682     char_entry *entry;
683     int max_start = (ofm_level==OFM_TFM) ? MAX_START_TFM : MAX_START_OFM;
684 
685     label_table = (label_entry *)xmalloc((no_labels+2)*sizeof(label_entry));
686     label_ptr = 0;
687     label_table[0].rr = -1; /* sentinel */
688 
689     if (!play_with_starts && (bchar_label < nl)) {
690         label_ptr = 1;
691         label_table[1].cc = -1;
692         label_table[1].rr = bchar_label;
693     }
694 
695     FOR_ALL_CHARACTERS(
696         unsigned c = plane*PLANE + index;
697         if ((c>=bc) && (c<=ec) && (entry->tag == TAG_LIG)) {
698             int r = entry->remainder;
699             if (r < nl) {
700                 unsigned s = lig_kern_table[r].entries[0];
701                 if ((s < 256) && (s > STOP_FLAG)) {
702                     r = 256 * lig_kern_table[r].entries[2] + lig_kern_table[r].entries[3];
703                     if (!play_with_starts && (r < nl) && (activity[entry->remainder] == A_UNREACHABLE))
704                         activity[entry->remainder] = A_PASS_THROUGH;
705                 }
706             }
707             sort_ptr = label_ptr; /* hole at position sort_ptr+1 */
708             while (label_table[sort_ptr].rr > r) {
709                 label_table[sort_ptr+1] = label_table[sort_ptr];
710                 sort_ptr--; /* move the hole */
711             }
712             label_table[sort_ptr+1].cc = c;
713             label_table[sort_ptr+1].rr = r;
714             label_ptr++;
715             if (!play_with_starts)
716               activity[r] = A_ACCESSIBLE;
717         }
718     )
719     if (play_with_starts) {
720       if (bchar != CHAR_BOUNDARY) {
721         extra_loc_needed = TRUE; lk_offset = 1;
722       } else {
723         extra_loc_needed = FALSE; lk_offset = 0;
724       }
725       sort_ptr = label_ptr; /* the largest unallocated label */
726       if ((label_table[sort_ptr].rr + lk_offset) > max_start) {
727         lk_offset=0; extra_loc_needed=FALSE;
728         /* location 0 can do double duty */
729         do {
730             set_char_remainder(label_table[sort_ptr].cc, lk_offset);
731             while (label_table[sort_ptr-1].rr == label_table[sort_ptr].rr) {
732                 sort_ptr--;
733                 set_char_remainder(label_table[sort_ptr].cc, lk_offset);
734             }
735             lk_offset++; sort_ptr--;
736         } while ((lk_offset+label_table[sort_ptr].rr) > max_start);
737         /* N.B. lk_offset=MAX_START+1 satisfies this when sort_ptr=0 */
738       }
739       if (lk_offset>0) {
740         while (sort_ptr>0) {
741             set_char_remainder(label_table[sort_ptr].cc,
742                                get_char_remainder(label_table[sort_ptr].cc)
743                                +lk_offset);
744             sort_ptr--;
745         }
746       }
747     }
748     if (bchar_label < nl) {
749         lig_kern_table[nl-1].entries[2] = (bchar_label + lk_offset) / (max_start + 1);
750         lig_kern_table[nl-1].entries[3] = (bchar_label + lk_offset) % (max_start + 1);
751     }
752 }
753 
754 void
print_labels(void)755 print_labels(void)
756 {
757     unsigned i;
758 
759     if (label_ptr>0) {
760         left(); out("COMMENT"); out_ln();
761         for (i=1; i<=label_ptr; i++) {
762             left(); out("LABEL_ENTRY"); out(" ");
763             out_int(i,10); out(" ");
764             out_char(label_table[i].cc); out(" ");
765             out_int(label_table[i].rr, 10); right();
766         }
767         right();
768     }
769 }
770 
771 static void check_charlist_infinite_loops(void);
772 static void doublecheck_extens(void);
773 static void build_exten_table(void);
774 
775 void
check_and_correct(void)776 check_and_correct(void)
777 {
778     check_existence_all_character_fields();
779     build_kern_table();
780     build_dimen_tables();
781     build_exten_table();
782     check_ligature_ends_properly();
783     compute_ofm_character_info();
784     adjust_labels(TRUE);
785     calculate_seven_bit_safe_flag();
786     check_ligature_infinite_loops();
787     check_charlist_infinite_loops();
788     doublecheck_ligatures();
789     doublecheck_extens();
790 }
791 
792 static void
check_charlist_infinite_loops(void)793 check_charlist_infinite_loops(void)
794 {
795     unsigned plane, index;
796     char_entry *entry;
797     unsigned g;
798 
799     FOR_ALL_CHARACTERS(
800         unsigned c = plane*PLANE + index;
801         if (entry->tag == TAG_LIST) {
802             g = entry->remainder;
803             while ((g < c) && (planes[g/PLANE][g%PLANE]->tag == TAG_LIST)) {
804                 g = planes[g/PLANE][g%PLANE]->remainder;
805             }
806             if (g == c) {
807                 entry->tag = TAG_NONE;
808                 entry->remainder = 0;
809                 warning_1("Cycle of NEXTLARGER characters "
810                           "has been broken at ",c);
811             }
812         }
813     )
814 }
815 
816 static void
build_exten_table(void)817 build_exten_table(void)
818 {
819     list L1 = exten_queue.front, L2;
820     unsigned i = 0;
821 
822     exten_table = (four_pieces **) xmalloc(ne*sizeof(four_pieces *));
823     while (L1 != NULL) {
824         exten_table[i] = (four_pieces *)L1->contents;
825         L2 = L1->ptr;
826         free(L1); L1 = L2;
827         i++;
828     }
829 }
830 
831 void
retrieve_exten_table(unsigned char * table)832 retrieve_exten_table(unsigned char *table)
833 {
834     unsigned i = 0, j;
835     four_pieces *entry;
836 
837     exten_table = (four_pieces **) xmalloc(ne*sizeof(four_pieces *));
838     for (i=0; i<ne; i++) {
839         exten_table[i] = entry = (four_pieces *) xmalloc(sizeof(four_pieces));
840         for (j=E_MIN; j<=E_MAX; j++) {
841             if (ofm_level==OFM_TFM) {
842                 entry->pieces[j] = table[4*i+j] & 0xff;
843             } else {
844                 entry->pieces[j] =
845                   ((table[8*i+j*2] & 0xff) << 8) |
846                   (table[8*i+j*2+1] & 0xff);
847             }
848         }
849     }
850 }
851 
852 void
print_extens(void)853 print_extens(void)
854 {
855     unsigned i,j;
856 
857     if (ne>0) {
858         left(); out("COMMENT"); out_ln();
859         for (i=0; i<ne; i++) {
860             left(); out("EXTEN_ENTRY");
861             out(" "); out_int(i,10); out_ln();
862             for (j=E_MIN; j<=E_MAX; j++) {
863                 if (exten_table[i]->pieces[j] != 0)
864                     print_extensible_piece(j,exten_table[i]->pieces[j]);
865             }
866             right();
867         }
868         right();
869     }
870 }
871 
872 static void
doublecheck_extens(void)873 doublecheck_extens(void)
874 {
875     unsigned i,j;
876 
877     if (ne>0) {
878         for (i=0; i<ne; i++) {
879             for (j=E_MIN; j<=E_MAX; j++) {
880                 if (exten_table[i]->pieces[j] != 0)
881                     doublecheck_existence(
882                         exten_table[i]->pieces[j], extensible_pieces[j],
883                         "Unused %s piece (H %X) refers to "
884                         "nonexistent character");
885             }
886         }
887     }
888 }
889 
890 void
compute_ligkern_offset(void)891 compute_ligkern_offset(void)
892 {
893 }
894 
895 void
output_ofm_extensible(void)896 output_ofm_extensible(void)
897 {
898     unsigned i,j;
899 
900     for (i=0; i<ne; i++) {
901         for (j=E_MIN; j<=E_MAX; j++) {
902             if (exten_table[i]->pieces[j] != 0)
903                 out_ofm_char(exten_table[i]->pieces[j]);
904             else out_ofm_char(0);
905         }
906     }
907 }
908 
909 unsigned num_char_info, words_per_entry;
910 
911 #define XX_ENTRY(key) (entry->indices[key] != NULL ? entry->indices[key]->index : 0)
912 #define WD_ENTRY XX_ENTRY(C_WD)
913 #define HT_ENTRY XX_ENTRY(C_HT)
914 #define DP_ENTRY XX_ENTRY(C_DP)
915 #define IC_ENTRY XX_ENTRY(C_IC)
916 
917 #define XX_NEXT(key) ((next != NULL) && (next->indices[key] != NULL) ? next->indices[key]->index : 0)
918 #define WD_NEXT XX_NEXT(C_WD)
919 #define HT_NEXT XX_NEXT(C_HT)
920 #define DP_NEXT XX_NEXT(C_DP)
921 #define IC_NEXT XX_NEXT(C_IC)
922 #define YY_NEXT(field) (next != NULL ? next->field : 0)
923 #define RM_NEXT YY_NEXT(remainder)
924 #define TG_NEXT YY_NEXT(tag)
925 
926 static void
compute_check_sum(void)927 compute_check_sum(void)
928 {
929     unsigned c;
930     unsigned plane, index;
931     char_entry *entry;
932     unsigned c0 = bc, c1 = ec, c2 = bc, c3 = ec;
933     fix wd;
934 
935     for (c = bc; c <= ec; c++) {
936         plane = c / PLANE;
937         index = c % PLANE;
938         entry = planes[plane][index];
939         if ((entry == NULL) || (WD_ENTRY == 0))
940             continue;
941         wd = lval(entry->indices[C_WD]);
942         if (design_units != UNITY)
943             wd = zround((wd / (double)design_units) * 1048576.0);
944         wd += (c + 4) * 0x400000;	/* this should be positive */
945         c0 = (c0 + c0 + wd) % 255;
946         c1 = (c1 + c1 + wd) % 253;
947         c2 = (c2 + c2 + wd) % 251;
948         c3 = (c3 + c3 + wd) % 247;
949     }
950     check_sum = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
951 }
952 
953 void
compute_ofm_character_info(void)954 compute_ofm_character_info(void)
955 {
956     unsigned c;
957     unsigned plane, index;
958     char_entry *entry;
959 
960     bc = 0x7fffffff; ec=0;
961     FOR_ALL_EXISTING_CHARACTERS(
962         c = plane*PLANE + index;
963         if (c < bc) bc = c;
964         if (c > ec) ec = c;
965     )
966     if (bc > ec) bc = 1;
967 
968     /* fill gaps */
969     for (plane = 0; plane < plane_max; plane++) {
970         if (planes[plane] == NULL) {
971             planes[plane] = (char_entry **)xmalloc(PLANE * sizeof(char_entry *));
972             char_max[plane] = 0;
973             planes[plane][0] = NULL;
974         }
975         for (index = char_max[plane]+1; index <= INDEX_MAX; index++) {
976             planes[plane][index] = NULL;
977         }
978         char_max[plane] = INDEX_MAX;
979     }
980 
981     switch (ofm_level) {
982         case OFM_TFM: {
983             if (ec>0xff)
984                 fatal_error_1(
985                    "Char (%x) too big for TFM (max ff); use OFM file",ec);
986             break;
987         }
988         case OFM_LEVEL0: {
989             if (ec>0x10ffff)
990                 fatal_error_1(
991                 "Char (%x) too big for OFM level-0 (max 10ffff); use level-2",
992                 ec);
993             break;
994         }
995         case OFM_LEVEL1: {
996             if (ec>0x10ffff)
997                 fatal_error_1(
998                 "Char (%x) too big for OFM level-1 (max 10ffff); use level-2",
999                 ec);
1000             num_char_info = 0;
1001             for (c = bc; c <= ec; c++) {
1002                 unsigned saved_c = c;
1003                 char_entry *next;
1004 
1005                 plane = c / PLANE;
1006                 index = c % PLANE;
1007                 entry = planes[plane][index];
1008                 if ((entry != NULL) && (WD_ENTRY != 0)) {
1009                     unsigned wd = WD_ENTRY, ht = HT_ENTRY, dp = DP_ENTRY, ic = IC_ENTRY;
1010 
1011                     c += entry->copies;
1012                     for (; (c < ec) && (c-saved_c < 0xffff); c++) {
1013                         plane = (c+1) / PLANE;
1014                         index = (c+1) % PLANE;
1015                         next = planes[plane][index];
1016                         if ((WD_NEXT != wd) || (HT_NEXT != ht) ||
1017                             (DP_NEXT != dp) || (IC_NEXT != ic) ||
1018                             (RM_NEXT != entry->remainder) || (TG_NEXT != entry->tag))
1019                             break;
1020                         planes[plane][index] = entry;
1021                     }
1022                 } else {
1023                     plane = c / PLANE;
1024                     index = c % PLANE;
1025                     planes[plane][index] = NULL;
1026                     init_character(c, NULL);
1027                     entry = current_character;
1028                     for (; (c < ec) && (c-saved_c < 0xffff); c++) {
1029                         plane = (c+1) / PLANE;
1030                         index = (c+1) % PLANE;
1031                         next = planes[plane][index];
1032                         if (WD_NEXT != 0)
1033                             break;
1034                         planes[plane][index] = entry;
1035                     }
1036                 }
1037                 entry->copies = c - saved_c;
1038                 num_char_info++;
1039             }
1040             break;
1041         }
1042         default: { internal_error_0("compute_ofm_character_info"); }
1043     }
1044 
1045     if (check_sum_specified==FALSE)
1046         compute_check_sum();
1047 }
1048 
1049 void
output_ofm_character_info(void)1050 output_ofm_character_info(void)
1051 {
1052     unsigned plane, index;
1053     char_entry *entry;
1054 
1055     switch (ofm_level) {
1056         case OFM_TFM: {
1057             plane=0;
1058             for (index = bc; index <= ec; index++) {
1059                 entry = planes[plane][index];
1060                 if (entry == NULL) {
1061                     out_ofm_4(0);
1062                 } else {
1063                     out_ofm(WD_ENTRY);
1064                     out_ofm(HT_ENTRY*16 + DP_ENTRY);
1065                     out_ofm(IC_ENTRY*4 + entry->tag);
1066                     out_ofm(entry->remainder);
1067                 }
1068             }
1069             break;
1070         }
1071         case OFM_LEVEL0: {
1072             unsigned c;
1073 
1074             for (c = bc; c <= ec; c++) {
1075                 plane = c / PLANE;
1076                 index = c % PLANE;
1077                 entry = planes[plane][index];
1078                 if (entry == NULL) {
1079                     out_ofm_4(0); out_ofm_4(0);
1080                 } else {
1081                     out_ofm_2(WD_ENTRY);
1082                     out_ofm(HT_ENTRY);
1083                     out_ofm(DP_ENTRY);
1084                     out_ofm(IC_ENTRY);
1085                     out_ofm(entry->tag);
1086                     out_ofm_2(entry->remainder);
1087                 }
1088             }
1089             break;
1090         }
1091         case OFM_LEVEL1: {
1092             unsigned i;
1093             unsigned c;
1094 
1095             for (c = bc; c <= ec; c++) {
1096                 plane = c / PLANE;
1097                 index = c % PLANE;
1098                 entry = planes[plane][index];
1099                 if (entry == NULL) {
1100                     for (i=0; i<words_per_entry; i++)
1101                         out_ofm_4(0);
1102                 } else {
1103                     unsigned copies = entry->copies;
1104 
1105                     out_ofm_2(WD_ENTRY);
1106                     out_ofm(HT_ENTRY);
1107                     out_ofm(DP_ENTRY);
1108                     out_ofm(IC_ENTRY);
1109                     /* assume no ctag */
1110                     out_ofm(entry->tag);
1111                     out_ofm_2(entry->remainder);
1112                     out_ofm_2(copies);
1113                     /* assume no character params */
1114                     for (i=0; i<npc; i++)
1115                         out_ofm_2(0);
1116                     /* padding */
1117                     if (0 == npc % 2)
1118                         out_ofm_2(0);
1119                     c += copies;
1120                 }
1121             }
1122             break;
1123         }
1124         default: { internal_error_0("compute_ofm_character_info"); }
1125     }
1126 }
1127