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