1 /* ligkern_routines.c: The ligature/kerning table.
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 "ligkern_routines.h"
28 #include "char_routines.h"
29 #include "out_routines.h"
30 #include "parse_ofm.h"
31 #include "print_routines.h"
32 #include "error_routines.h"
33 #include "header_routines.h"
34 #include "out_ofm.h"
35 
36 unsigned nk=0;
37 unsigned nl=0;
38 
39 fix *kern_table;
40 av_list kern_list = NULL;
41 unsigned no_kerns = 0;
42 
43 unsigned min_nl=0;
44 unsigned bchar = CHAR_BOUNDARY;
45 #define MAX_LABEL 0x7fffffff
46 unsigned bchar_label = MAX_LABEL;
47 unsigned bchar_remainder;
48 unsigned lk_step_ended=FALSE;
49 
50 #define LIG_KERN_CHUNK 512
51 four_entries *lig_kern_table;
52 unsigned char *activity;
53 static int lig_kern_size;
54 
55 void
set_boundary_character(unsigned c)56 set_boundary_character(unsigned c)
57 {
58     /* What checks are required ? */
59     bchar = c;
60 }
61 
62 void
init_ligkern(void)63 init_ligkern(void)
64 {
65     lk_step_ended = FALSE;
66     nl = 0;
67     min_nl = 0;
68     lig_kern_size = LIG_KERN_CHUNK;
69     lig_kern_table = (four_entries *) xcalloc(lig_kern_size, sizeof(four_entries));
70 }
71 
72 static void
lig_kern_incr(void)73 lig_kern_incr(void)
74 {
75     nl++;
76     if (nl < lig_kern_size)
77         return;
78     lig_kern_size += LIG_KERN_CHUNK;
79     lig_kern_table = (four_entries *)
80                      xrealloc(lig_kern_table, lig_kern_size * sizeof(four_entries));
81     memset(lig_kern_table + nl, 0, LIG_KERN_CHUNK * sizeof(four_entries));
82 }
83 
84 void
set_label_command(unsigned c)85 set_label_command(unsigned c)
86 {
87     if (c==CHAR_BOUNDARY) { /* BOUNDARYCHAR */
88         bchar_label = nl;
89     } else {
90         check_char_tag(c);
91 	set_char_tag(c, TAG_LIG);
92 	set_char_remainder(c, nl);
93     }
94     if (min_nl <= nl) { min_nl = nl+1; }
95     lk_step_ended = FALSE;
96     no_labels++;
97 
98 }
99 
100 void
set_stop_command(void)101 set_stop_command(void)
102 {
103     if (lk_step_ended == TRUE) {
104         lig_kern_table[nl-1].entries[0] =
105         lig_kern_table[nl-1].entries[0] / 256 * 256 + STOP_FLAG;
106     } else {
107         warning_0("STOP must follow LIG or KRN; ignored");
108     }
109     lk_step_ended = FALSE;
110 }
111 
112 void
set_skip_command(unsigned val)113 set_skip_command(unsigned val)
114 {
115     if (lk_step_ended == TRUE) {
116         if (val>127) {
117             warning_0("Maximum SKIP amount is 127; ignored");
118         } else {
119             lig_kern_table[nl-1].entries[0] = val;
120             if (min_nl <= (nl+val)) { min_nl = nl+val+1; }
121         }
122     } else {
123         warning_0("SKIP must follow LIG or KRN; ignored");
124     }
125     lk_step_ended = FALSE;
126 }
127 
128 void
set_ligature_command(unsigned lig,unsigned c,unsigned val)129 set_ligature_command(unsigned lig, unsigned c, unsigned val)
130 {
131     lig_kern_table[nl].entries[0] = 0;
132     lig_kern_table[nl].entries[1] = c;
133     lig_kern_table[nl].entries[2] = lig;
134     lig_kern_table[nl].entries[3] = val;
135     lig_kern_incr();
136     lk_step_ended = TRUE;
137 
138 }
139 
140 static int  set_new_kern(fix);
141 
142 void
set_kerning_command(unsigned c,fix fval)143 set_kerning_command(unsigned c, fix fval)
144 {
145     unsigned k = set_new_kern(fval);
146 
147     lig_kern_table[nl].entries[0] = 0;
148     lig_kern_table[nl].entries[1] = c;
149     if (ofm_level==OFM_TFM) {
150         lig_kern_table[nl].entries[2] = KERN_FLAG + (k/256);
151         lig_kern_table[nl].entries[3] = k % 256;
152     } else {
153         lig_kern_table[nl].entries[2] = KERN_FLAG + (k/65536);
154         lig_kern_table[nl].entries[3] = k % 65536;
155     }
156     lig_kern_incr();
157     lk_step_ended = TRUE;
158 }
159 
160 void
set_c_label_command(unsigned new_class)161 set_c_label_command(unsigned new_class)
162 {
163     fatal_error_0("CLABEL not currently supported");
164 }
165 
166 void
set_c_kerning_command(unsigned new_class,fix fval)167 set_c_kerning_command(unsigned new_class, fix fval)
168 {
169     fatal_error_0("CKRN not currently supported");
170 }
171 
172 void
set_c_glue_command(unsigned new_class,unsigned glue_index)173 set_c_glue_command(unsigned new_class, unsigned glue_index)
174 {
175     fatal_error_0("CGLUE not currently supported");
176 }
177 
178 void
set_c_penalty_command(unsigned new_class,unsigned pen_index)179 set_c_penalty_command(unsigned new_class, unsigned pen_index)
180 {
181     fatal_error_0("CPEN not currently supported");
182 }
183 
184 void
set_c_penglue_command(unsigned new_class,unsigned pen_index,unsigned glue_index)185 set_c_penglue_command(unsigned new_class, unsigned pen_index, unsigned glue_index)
186 {
187     fatal_error_0("CPENGLUE not currently supported");
188 }
189 
190 static int
set_new_kern(fix fval)191 set_new_kern(fix fval)
192 {
193     unsigned index;
194     av_list L1, L2;
195 
196     L1 = kern_list;
197     if (L1 == NULL) {
198         index = nk++;
199         kern_list = av_list1(index, fval);
200     } else {
201         L2 = L1->ptr;
202         while ((lval(L1) != fval) && (L2 != NULL)) {
203             L1 = L2;
204             L2 = L2->ptr;
205         }
206         if (fval == lval(L1)) {
207             index = lattr(L1);
208         } else {
209             index = nk++;
210             if (index == (ofm_level==OFM_TFM ? 0x8000 : 0x800000))
211                 fatal_error_1("more than %d different kerns", index);
212             L2 = av_list1(index, fval);
213             L1->ptr = L2;
214         }
215     }
216     return index;
217 }
218 
219 
220 void
build_kern_table(void)221 build_kern_table(void)
222 {
223     av_list L1 = kern_list, L2;
224     unsigned i = 0;
225 
226     kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
227     while (L1 != NULL) {
228         kern_table[i] = lval(L1);
229         L2 = L1->ptr;
230         free(L1); L1 = L2;
231         i++;
232     }
233 }
234 
235 void
print_ligkern_table(void)236 print_ligkern_table(void)
237 {
238     unsigned i;
239 
240     sort_ptr = 1;
241     if (nl>0) {
242         left(); out("LIGTABLE"); out_ln();
243         for (i=0; i<nl; i++) {
244             unsigned r = lig_kern_table[i].entries[0];
245             if (r >= 256)
246                 activity[i] = A_ACCESSIBLE;
247             else if ((activity[i] == A_ACCESSIBLE) && (r < STOP_FLAG)) {
248                 r += i + 1;
249                 if (r >= nl) {
250                     fprintf(stderr, "Bad OFM file: Ligature/kern step %u skips too far;\n"
251                                     "I made it stop.\n", i);
252                     lig_kern_table[i].entries[0] = STOP_FLAG;
253                     changed = TRUE;
254                 } else
255                     activity[r] = A_ACCESSIBLE;
256             }
257         }
258         for (i=0; i<nl; i++) {
259             if (activity[i] == A_UNREACHABLE) {
260                 if (parenthesis_level == 1) {
261                     left();
262                     out("COMMENT THIS PART OF THE PROGRAM IS NEVER USED!");
263                     out_ln();
264                 }
265             } else if (parenthesis_level == 2)
266                 right();
267             if (activity[i] != A_PASS_THROUGH) {
268                 while ((sort_ptr<=label_ptr) && (i==label_table[sort_ptr].rr)) {
269                     print_label_command(label_table[sort_ptr].cc);
270                     sort_ptr++;
271                 }
272                 print_one_lig_kern_entry(lig_kern_table+i, TRUE);
273             }
274         }
275         if (parenthesis_level == 2)	/* the final step was unreachable */
276             right();
277         right();
278     }
279 }
280 
281 void
print_one_lig_kern_entry(four_entries * lentry,boolean show_stop)282 print_one_lig_kern_entry(four_entries *lentry, boolean show_stop)
283 {
284     if (lentry->entries[2] >= KERN_FLAG) {
285         unsigned r = (ofm_level==OFM_TFM ? 256 : 65536)*(lentry->entries[2]-KERN_FLAG)+lentry->entries[3];
286         fix v;
287         if (r < nk)
288             v = kern_table[r];
289         else {
290             if (show_stop == TRUE)
291                 fprintf(stderr, "Bad OFM file: Kern index too large.\n");
292             v = 0;
293             changed = TRUE;
294         }
295         print_kerning_command(lentry->entries[1], v);
296     } else {
297         print_ligature_command(lentry->entries[2],
298                                lentry->entries[1],
299                                lentry->entries[3]);
300     }
301     if ((show_stop == TRUE) && (lentry->entries[0] > 0) && (parenthesis_level == 1)) {
302         if (lentry->entries[0] >= STOP_FLAG) {
303             print_stop_command();
304         } else {	/* count number of accessible steps */
305             unsigned i, k = lentry-lig_kern_table, count = 0;
306             for (i=1; i<=lentry->entries[0]; i++)
307                 if (activity[k+i] == A_ACCESSIBLE)
308                     count++;
309             print_skip_command(count);
310         }
311     }
312 }
313 
314 hash_list hash_table[PRIME];
315 
316 unsigned x_lig_cycle;
317 unsigned y_lig_cycle = CHAR_BOUNDARY;
318 
319 static int l_eval(unsigned, unsigned);
320 
321 static int
l_f(hash_list h,unsigned x,unsigned y)322 l_f(hash_list h, unsigned x, unsigned y)
323 {
324     switch(h->new_class) {
325          case LIG_SIMPLE: {break;}
326          case LIG_LEFT_Z: {
327              h->new_class = LIG_PENDING;
328              h->lig_z = l_eval(h->lig_z, y);
329              h->new_class = LIG_SIMPLE;
330              break;
331          }
332          case LIG_RIGHT_Z: {
333              h->new_class = LIG_PENDING;
334              h->lig_z = l_eval(x, h->lig_z);
335              h->new_class = LIG_SIMPLE;
336              break;
337          }
338          case LIG_BOTH_Z: {
339              h->new_class = LIG_PENDING;
340              h->lig_z = l_eval(l_eval(x,h->lig_z), y);
341              h->new_class = LIG_SIMPLE;
342              break;
343          }
344          case LIG_PENDING: {
345              x_lig_cycle = x;
346              y_lig_cycle = y;
347              h->lig_z = CHAR_ERROR;
348              h->new_class = LIG_SIMPLE;
349              break;
350          }
351          default: {
352              internal_error_1("f (new_class=%d)", h->new_class);
353          }
354     }
355     return (h->lig_z);
356 }
357 
358 static hash_list l_hash_lookup(unsigned, unsigned);
359 
360 static int
l_eval(unsigned x,unsigned y)361 l_eval(unsigned x, unsigned y)
362 {
363     hash_list h;
364 
365     if ((x==CHAR_ERROR) || (y==CHAR_ERROR)) return CHAR_ERROR;
366     h = l_hash_lookup(x, y);
367     if (h == NULL) return y;
368     return l_f(h, x, y);
369 }
370 
371 static int
l_hash_input(unsigned p,unsigned c)372 l_hash_input(unsigned p, unsigned c)
373 {
374 
375     four_entries *entry = lig_kern_table+p;
376     unsigned y = entry->entries[1];
377     unsigned t = entry->entries[2];
378     unsigned cc = LIG_SIMPLE;
379     unsigned zz = entry->entries[3];
380     unsigned key;
381     hash_list L1;
382 
383     if (t >= KERN_FLAG) zz = y;
384     else {
385         switch(t) {
386              case L_0:
387              case L_Ax:   { break; }
388              case L_Bx:
389              case L_ABxx: { zz = y; break; }
390              case L_B:
391              case L_ABx:  { cc = LIG_LEFT_Z;  break; }
392              case L_A:    { cc = LIG_RIGHT_Z; break; }
393              case L_AB:   { cc = LIG_BOTH_Z;  break; }
394              default: {
395                  internal_error_1("l_hash_input (case=%d)", t);
396              }
397         }
398     }
399     key = (c & 0x7fff)*(y & 0x7fff) % PRIME;
400     L1 = hash_table[key];
401     if ((L1 == NULL) || (c < L1->x) || ((c == L1->x) && (y < L1->y)))
402         hash_table[key] = hash_list1(c,y,cc,zz,L1);
403     else {
404         hash_list L2 = L1->ptr;
405         while ((L2 != NULL) && ((c > L2->x) || ((c == L2->x) && (y > L2->y)))) {
406             L1 = L2;
407             L2 = L2->ptr;
408         }
409         if ((L2 == NULL) || (c < L2->x) || ((c == L2->x) && (y < L2->y)))
410             L1->ptr = hash_list1(c,y,cc,zz,L2);
411         else
412             return FALSE;
413     }
414     return TRUE;
415 }
416 
417 static hash_list
l_hash_lookup(unsigned x,unsigned y)418 l_hash_lookup(unsigned x, unsigned y)
419 {
420     unsigned key = (x & 0x7fff)*(y & 0x7fff) % PRIME;
421     hash_list L = hash_table[key];
422 
423     while ((L != NULL) && ((x > L->x) || ((x == L->x) && (y > L->y))))
424         L = L->ptr;
425     if ((L == NULL) || (x < L->x) || ((x == L->x) && (y < L->y)))
426         return NULL;
427     return L;
428 }
429 
430 void
check_ligature_ends_properly(void)431 check_ligature_ends_properly(void)
432 {
433     if (nl>0) {
434         if (bchar_label < nl) {
435             /* make room for it; the actual label will be stored later */
436             lig_kern_table[nl].entries[0] = 255;
437             lig_kern_incr();
438         }
439         while (min_nl > nl) {
440             lig_kern_table[nl].entries[0] = 255;
441             lig_kern_incr();
442         }
443         if (lig_kern_table[nl-1].entries[0] == 0) {
444             lig_kern_table[nl-1].entries[0] = STOP_FLAG;
445         }
446     }
447 }
448 
449 void
check_ligature_program(unsigned c,unsigned lab)450 check_ligature_program(unsigned c, unsigned lab)
451 {
452     unsigned lig_ptr = lab;
453     four_entries *entry;
454 
455     while (lig_ptr < nl) {
456         entry = lig_kern_table+lig_ptr;
457         if (l_hash_input(lig_ptr,c)) {
458             if (entry->entries[2] < KERN_FLAG) {
459                 if (entry->entries[1] != bchar) {
460                     check_existence_and_safety(c, entry->entries[1],
461                         ligature_commands[entry->entries[2]],
462                         "%s character examined by (H %X)");
463                     if (entry->entries[1] > 0xffff) {
464                         fprintf(stderr, "%s character (H %X) examined by (H %X) "
465                             "exceeds ffff\n", ligature_commands[entry->entries[2]], entry->entries[1], c);
466                         exit(2);
467                     }
468                 }
469                 if (entry->entries[3] >= 128)
470 /* Needs fixing */
471                     if ((c < 128) || (c == -1))
472                         if ((entry->entries[1] < 128) ||
473                             (entry->entries[1] == bchar))
474                             seven_bit_calculated = 0;
475                 check_existence_and_safety(c, entry->entries[3],
476                     ligature_commands[entry->entries[2]],
477                     "%s character generated by (H %X)");
478                 if (entry->entries[3] >0xffff) {
479                     fprintf(stderr, "%s character (H %X) generated by (H %X) "
480                         "exceeds ffff\n", ligature_commands[entry->entries[2]], entry->entries[3], c);
481                     exit(2);
482                 }
483             } else {
484                 check_existence_and_safety(c, entry->entries[1],
485                     "KRN", "%s character examined by (H %X)");
486                 if (entry->entries[1] > 0xffff) {
487                     fprintf(stderr, "KRN character (H %X) examined by (H %X) "
488                         "exceeds ffff\n", entry->entries[1], c);
489                     exit(2);
490                 }
491             }
492         }
493         if (entry->entries[0] >= STOP_FLAG) lig_ptr = nl;
494         else lig_ptr = lig_ptr + 1 + entry->entries[0];
495     }
496 }
497 
498 void
check_ligature_infinite_loops(void)499 check_ligature_infinite_loops(void)
500 {
501     unsigned key;
502 
503     for (key = 0; key < PRIME; key++) {
504         hash_list tt = hash_table[key];
505         while (tt != NULL) {
506             if (tt->new_class > LIG_SIMPLE)
507                 l_f(tt, tt->x, tt->y);
508             tt = tt->ptr;
509         }
510     }
511 
512     if (y_lig_cycle != CHAR_BOUNDARY) {
513         if (x_lig_cycle == CHAR_BOUNDARY) {
514             warning_1("Infinite ligature loop starting with boundary and %d",
515                       y_lig_cycle);
516         } else {
517             warning_2("Infinite ligature loop starting with %d and %d",
518                       x_lig_cycle, y_lig_cycle);
519         }
520         clear_ligature_entries();
521         nl = 0; bchar = CHAR_BOUNDARY; bchar_label = MAX_LABEL;
522     }
523 }
524 
525 void
doublecheck_ligatures(void)526 doublecheck_ligatures(void)
527 {
528     unsigned i;
529 
530     if (nl>0) {
531         for (i=0; i<nl; i++) {
532             if (lig_kern_table[i].entries[2] < KERN_FLAG) {
533                 if (lig_kern_table[i].entries[0] < 255) {
534                     doublecheck_existence(
535                         lig_kern_table[i].entries[1],
536                         ligature_commands[lig_kern_table[i].entries[2]],
537                         "Unused %s step refers to nonexistent character (H %X)");
538                     doublecheck_existence(
539                         lig_kern_table[i].entries[3],
540                         ligature_commands[lig_kern_table[i].entries[2]],
541                         "Unused %s step refers to nonexistent character (H %X)");
542                 }
543             } else {
544                 doublecheck_existence(
545                     lig_kern_table[i].entries[1],
546                     "KRN",
547                     "Unused %s step refers to nonexistent character (H %X)");
548             }
549         }
550     }
551 }
552 
553 void
output_ofm_ligkern(void)554 output_ofm_ligkern(void)
555 {
556     unsigned i;
557     four_entries *entry;
558 
559     if (extra_loc_needed) {	/* lk_offset==1 */
560         if (ofm_level == OFM_TFM) {
561             out_ofm(255); out_ofm(bchar); out_ofm(0); out_ofm(0);
562         } else {
563             out_ofm_2(255); out_ofm_2(bchar); out_ofm_2(0); out_ofm_2(0);
564         }
565     } else {	/* output the redirection specs */
566         if (ofm_level == OFM_TFM) {
567             for (sort_ptr = 1; sort_ptr <= lk_offset; sort_ptr++) {
568                 unsigned t = label_table[label_ptr].rr;
569                 if (bchar != CHAR_BOUNDARY) {
570                     out_ofm(255); out_ofm(bchar);
571                 } else {
572                     out_ofm(254); out_ofm(0);
573                 }
574                 out_ofm_2(t+lk_offset);
575                 do {
576                     label_ptr--;
577                 } while(label_table[label_ptr].rr == t);
578             }
579         } else {
580             for (sort_ptr = 1; sort_ptr <= lk_offset; sort_ptr++) {
581                 unsigned t = label_table[label_ptr].rr;
582                 if (bchar != CHAR_BOUNDARY) {
583                     out_ofm_2(255); out_ofm_2(bchar);
584                 } else {
585                     out_ofm_2(254); out_ofm_2(0);
586                 }
587                 out_ofm_2((t+lk_offset) / 256); out_ofm_2((t+lk_offset) % 256);
588                 do {
589                     label_ptr--;
590                 } while(label_table[label_ptr].rr == t);
591             }
592         }
593     }
594 
595     if (ofm_level == OFM_TFM) {
596         for (i=0; i<nl; i++) {
597             entry = lig_kern_table+i;
598             out_ofm(entry->entries[0] & 0xff);
599             out_ofm(entry->entries[1] & 0xff);
600             out_ofm(entry->entries[2] & 0xff);
601             out_ofm(entry->entries[3] & 0xff);
602         }
603     } else {
604         for (i=0; i<nl; i++) {
605             entry = lig_kern_table+i;
606             out_ofm_2(entry->entries[0] & 0xffff);
607             out_ofm_2(entry->entries[1] & 0xffff);
608             out_ofm_2(entry->entries[2] & 0xffff);
609             out_ofm_2(entry->entries[3] & 0xffff);
610         }
611     }
612     for (i=0; i<nk; i++) {
613         out_ofm_4(kern_table[i]);
614     }
615 }
616 
617 void
retrieve_ligkern_table(unsigned char * ofm_lig_table,unsigned char * ofm_kern_table)618 retrieve_ligkern_table(unsigned char *ofm_lig_table,
619                        unsigned char *ofm_kern_table)
620 {
621     unsigned i;
622     four_entries *entry;
623     unsigned char *table_entry;
624 
625     lig_kern_size = nl;
626     lig_kern_table = (four_entries *) xcalloc(lig_kern_size, sizeof(four_entries));
627 
628     if (ofm_level == OFM_TFM) {
629         for (i=0; i<nl; i++) {
630             entry = lig_kern_table+i;
631             table_entry = ofm_lig_table+(4*i);
632             entry->entries[0] = (*table_entry) & 0xff;
633             entry->entries[1] = (*(table_entry+1)) & 0xff;
634             entry->entries[2] = (*(table_entry+2)) & 0xff;
635             entry->entries[3] = (*(table_entry+3)) & 0xff;
636         }
637     } else {
638         for (i=0; i<nl; i++) {
639             entry = lig_kern_table+i;
640             table_entry = ofm_lig_table+(8*i);
641             entry->entries[0] = (((*table_entry) & 0xff) * 0x100)
642                                 + ((*(table_entry+1)) & 0xff);
643             entry->entries[1] = (((*(table_entry+2)) & 0xff) * 0x100)
644                                 + ((*(table_entry+3)) & 0xff);
645             entry->entries[2] = (((*(table_entry+4)) & 0xff) * 0x100)
646                                 + ((*(table_entry+5)) & 0xff);
647             entry->entries[3] = (((*(table_entry+6)) & 0xff) * 0x100)
648                                 + ((*(table_entry+7)) & 0xff);
649         }
650     }
651 
652     activity = (unsigned char *) xcalloc(lig_kern_size, sizeof(unsigned char));
653 
654     if (nl > 0) {
655         if (lig_kern_table[0].entries[0] == 255) {
656             bchar = lig_kern_table[0].entries[1];
657             print_boundary_char(bchar);
658             activity[0] = A_PASS_THROUGH;
659         }
660         if (lig_kern_table[nl-1].entries[0] == 255) {
661             unsigned r = 256 * lig_kern_table[nl-1].entries[2] + lig_kern_table[nl-1].entries[3];
662             if (r >= nl) {
663                 fprintf(stderr, "Ligature/kern starting index for boundarychar is too large;\n"
664                                 "so I removed it.\n");
665                 changed = TRUE;
666             } else {
667                 bchar_label = r;
668                 activity[r] = A_ACCESSIBLE;
669             }
670             activity[nl-1] = A_PASS_THROUGH;
671         }
672     }
673 
674     kern_table = (fix *) xmalloc((nk+1)*sizeof(int));
675     for (i=0; i<nk; i++) {
676         table_entry = ofm_kern_table+(4*i);
677         kern_table[i] = (((*table_entry) & 0xff) << 24) |
678                         (((*(table_entry+1)) & 0xff) << 16) |
679                         (((*(table_entry+2)) & 0xff) << 8) |
680                         ((*(table_entry+3)) & 0xff);
681     }
682 }
683