Don't use .Xo/.Xc. Fix date format.
[netbsd-mini2440.git] / gnu / usr.bin / groff / dvi / tfmtodit.c
blob0db323d611386dfa038881f6f6fca0686d541ab9
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.uucp)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 1, or (at your option) any later
10 version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file LICENSE. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
22 but I haven't tested them. */
24 /* Groff requires more font metric information than TeX. The reason
25 for this is that TeX has separate Math Italic fonts, whereas groff
26 uses normal italic fonts for math. The two additional pieces of
27 information required by groff correspond to the two arguments to the
28 math_fit() macro in the Metafont programs for the CM fonts. In the
29 case of a font for which math_fitting is false, these two arguments
30 are normally ignored by Metafont. We need to get hold of these two
31 parameters and put them in the groff font file.
33 We do this by loading this definition after cmbase when creating cm.base.
35 def ignore_math_fit(expr left_adjustment,right_adjustment) =
36 special "adjustment";
37 numspecial left_adjustment*16/designsize;
38 numspecial right_adjustment*16/designsize;
39 enddef;
41 This puts the two arguments to the math_fit macro into the gf file.
42 (They will appear in the gf file immediately before the character to
43 which they apply.) We then create a gf file using this cm.base. Then
44 we run tfmtodit and specify this gf file with the -g option.
46 This need only be done for a font for which math_fitting is false;
47 When it's true, the left_correction and subscript_correction should
48 both be zero. */
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <math.h>
53 #include <string.h>
54 #include "lib.h"
55 #include "errarg.h"
56 #include "error.h"
57 #include "assert.h"
58 #include "cset.h"
60 /* Values in the tfm file should be multiplied by this. */
62 #define MULTIPLIER 1
64 struct char_info_word {
65 unsigned char width_index;
66 char height_index;
67 char depth_index;
68 char italic_index;
69 char tag;
70 unsigned char remainder;
73 struct lig_kern_command {
74 unsigned char skip_byte;
75 unsigned char next_char;
76 unsigned char op_byte;
77 unsigned char remainder;
80 class tfm {
81 int bc;
82 int ec;
83 int nw;
84 int nh;
85 int nd;
86 int ni;
87 int nl;
88 int nk;
89 int np;
90 int cs;
91 int ds;
92 char_info_word *char_info;
93 int *width;
94 int *height;
95 int *depth;
96 int *italic;
97 lig_kern_command *lig_kern;
98 int *kern;
99 int *param;
100 public:
101 tfm();
102 ~tfm();
103 int load(const char *);
104 int contains(int);
105 int get_width(int);
106 int get_height(int);
107 int get_depth(int);
108 int get_italic(int);
109 int get_param(int, int *);
110 int get_checksum();
111 int get_design_size();
112 int get_lig(unsigned char, unsigned char, unsigned char *);
113 friend class kern_iterator;
116 class kern_iterator {
117 tfm *t;
118 int c;
119 int i;
120 public:
121 kern_iterator(tfm *);
122 int next(unsigned char *c1, unsigned char *c2, int *k);
126 kern_iterator::kern_iterator(tfm *p)
127 : t(p), i(-1), c(t->bc)
131 int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
133 for (; c <= t->ec; c++)
134 if (t->char_info[c - t->bc].tag == 1) {
135 if (i < 0) {
136 i = t->char_info[c - t->bc].remainder;
137 if (t->lig_kern[i].skip_byte > 128)
138 i = (256*t->lig_kern[i].op_byte
139 + t->lig_kern[i].remainder);
141 for (;;) {
142 int skip = t->lig_kern[i].skip_byte;
143 if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
144 *c1 = c;
145 *c2 = t->lig_kern[i].next_char;
146 *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
147 + t->lig_kern[i].remainder];
148 if (skip == 128) {
149 c++;
150 i = -1;
152 else
153 i += skip + 1;
154 return 1;
156 if (skip >= 128)
157 break;
158 i += skip + 1;
160 i = -1;
162 return 0;
165 tfm::tfm()
166 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
167 kern(0), param(0)
171 int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
173 if (contains(c1) && char_info[c1 - bc].tag == 1) {
174 int i = char_info[c1 - bc].remainder;
175 if (lig_kern[i].skip_byte > 128)
176 i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
177 for (;;) {
178 int skip = lig_kern[i].skip_byte;
179 if (skip > 128)
180 break;
181 // We are only interested in normal ligatures, for which
182 // op_byte == 0.
183 if (lig_kern[i].op_byte == 0
184 && lig_kern[i].next_char == c2) {
185 *cp = lig_kern[i].remainder;
186 return 1;
188 if (skip == 128)
189 break;
190 i += skip + 1;
193 return 0;
196 int tfm::contains(int i)
198 return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
201 int tfm::get_width(int i)
203 return width[char_info[i - bc].width_index];
206 int tfm::get_height(int i)
208 return height[char_info[i - bc].height_index];
211 int tfm::get_depth(int i)
213 return depth[char_info[i - bc].depth_index];
216 int tfm::get_italic(int i)
218 return italic[char_info[i - bc].italic_index];
221 int tfm::get_param(int i, int *p)
223 if (i <= 0 || i > np)
224 return 0;
225 else {
226 *p = param[i - 1];
227 return 1;
231 int tfm::get_checksum()
233 return cs;
236 int tfm::get_design_size()
238 return ds;
241 tfm::~tfm()
243 delete char_info;
244 delete width;
245 delete height;
246 delete depth;
247 delete italic;
248 delete lig_kern;
249 delete kern;
250 delete param;
253 int read2(unsigned char *&s)
255 int n;
256 n = *s++ << 8;
257 n |= *s++;
258 return n;
261 int read4(unsigned char *&s)
263 int n;
264 n = *s++ << 24;
265 n |= *s++ << 16;
266 n |= *s++ << 8;
267 n |= *s++;
268 return n;
272 int tfm::load(const char *file)
274 FILE *fp = fopen(file, "r");
275 if (!fp) {
276 error("can't open `%1': %2", file, strerror(errno));
277 return 0;
279 int c1 = getc(fp);
280 int c2 = getc(fp);
281 if (c1 == EOF || c2 == EOF) {
282 fclose(fp);
283 error("unexpected end of file on `%1'", file);
284 return 0;
286 int lf = (c1 << 8) + c2;
287 int toread = lf*4 - 2;
288 unsigned char *buf = new unsigned char[toread];
289 if (fread(buf, 1, toread, fp) != toread) {
290 if (feof(fp))
291 error("unexpected end of file on `%1'", file);
292 else
293 error("error on file `%1'", file);
294 delete buf;
295 fclose(fp);
296 return 0;
298 fclose(fp);
299 if (lf < 6) {
300 error("bad tfm file `%1': impossibly short", file);
301 delete buf;
302 return 0;
304 unsigned char *ptr = buf;
305 int lh = read2(ptr);
306 bc = read2(ptr);
307 ec = read2(ptr);
308 nw = read2(ptr);
309 nh = read2(ptr);
310 nd = read2(ptr);
311 ni = read2(ptr);
312 nl = read2(ptr);
313 nk = read2(ptr);
314 int ne = read2(ptr);
315 np = read2(ptr);
316 if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
317 error("bad tfm file `%1': lengths do not sum", file);
318 delete buf;
319 return 0;
321 if (lh < 2) {
322 error("bad tfm file `%1': header too short", file);
323 delete buf;
324 return 0;
326 char_info = new char_info_word[ec - bc + 1];
327 width = new int[nw];
328 height = new int[nh];
329 depth = new int[nd];
330 italic = new int[ni];
331 lig_kern = new lig_kern_command[nl];
332 kern = new int[nk];
333 param = new int[np];
334 int i;
335 cs = read4(ptr);
336 ds = read4(ptr);
337 ptr += (lh-2)*4;
338 for (i = 0; i < ec - bc + 1; i++) {
339 char_info[i].width_index = *ptr++;
340 unsigned char tem = *ptr++;
341 char_info[i].depth_index = tem & 0xf;
342 char_info[i].height_index = tem >> 4;
343 tem = *ptr++;
344 char_info[i].italic_index = tem >> 2;
345 char_info[i].tag = tem & 3;
346 char_info[i].remainder = *ptr++;
348 for (i = 0; i < nw; i++)
349 width[i] = read4(ptr);
350 for (i = 0; i < nh; i++)
351 height[i] = read4(ptr);
352 for (i = 0; i < nd; i++)
353 depth[i] = read4(ptr);
354 for (i = 0; i < ni; i++)
355 italic[i] = read4(ptr);
356 for (i = 0; i < nl; i++) {
357 lig_kern[i].skip_byte = *ptr++;
358 lig_kern[i].next_char = *ptr++;
359 lig_kern[i].op_byte = *ptr++;
360 lig_kern[i].remainder = *ptr++;
362 for (i = 0; i < nk; i++)
363 kern[i] = read4(ptr);
364 ptr += ne*4;
365 for (i = 0; i < np; i++)
366 param[i] = read4(ptr);
367 assert(ptr == buf + lf*4 - 2);
368 delete buf;
369 return 1;
372 class gf {
373 int left[256];
374 int right[256];
375 static int sread4(int *p, FILE *fp);
376 static int uread3(int *p, FILE *fp);
377 static int uread2(int *p, FILE *fp);
378 static int skip(int n, FILE *fp);
379 public:
380 gf();
381 int load(const char *file);
382 int get_left_adjustment(int i) { return left[i]; }
383 int get_right_adjustment(int i) { return right[i]; }
386 gf::gf()
388 for (int i = 0; i < 256; i++)
389 left[i] = right[i] = 0;
392 int gf::load(const char *file)
394 enum {
395 paint_0 = 0,
396 paint1 = 64,
397 boc = 67,
398 boc1 = 68,
399 eoc = 69,
400 skip0 = 70,
401 skip1 = 71,
402 new_row_0 = 74,
403 xxx1 = 239,
404 yyy = 243,
405 no_op = 244,
406 pre = 247,
407 post = 248,
409 int got_an_adjustment = 0;
410 int pending_adjustment = 0;
411 int left_adj, right_adj;
412 const int gf_id_byte = 131;
413 FILE *fp = fopen(file, "r");
414 if (!fp) {
415 error("can't open `%1': %2", file, strerror(errno));
416 return 0;
418 if (getc(fp) != pre || getc(fp) != gf_id_byte) {
419 error("bad gf file");
420 return 0;
422 int n = getc(fp);
423 if (n == EOF)
424 goto eof;
425 if (!skip(n, fp))
426 goto eof;
427 for (;;) {
428 int op = getc(fp);
429 if (op == EOF)
430 goto eof;
431 if (op == post)
432 break;
433 if ((op >= paint_0 && op <= paint_0 + 63)
434 || (op >= new_row_0 && op <= new_row_0 + 164))
435 continue;
436 switch (op) {
437 case no_op:
438 case eoc:
439 case skip0:
440 break;
441 case paint1:
442 case skip1:
443 if (!skip(1, fp))
444 goto eof;
445 break;
446 case paint1 + 1:
447 case skip1 + 1:
448 if (!skip(2, fp))
449 goto eof;
450 break;
451 case paint1 + 2:
452 case skip1 + 2:
453 if (!skip(3, fp))
454 goto eof;
455 break;
456 case boc:
458 int code;
459 if (!sread4(&code, fp))
460 goto eof;
461 if (pending_adjustment) {
462 pending_adjustment = 0;
463 left[code & 0377] = left_adj;
464 right[code & 0377] = right_adj;
466 if (!skip(20, fp))
467 goto eof;
468 break;
470 case boc1:
472 int code = getc(fp);
473 if (code == EOF)
474 goto eof;
475 if (pending_adjustment) {
476 pending_adjustment = 0;
477 left[code] = left_adj;
478 right[code] = right_adj;
480 if (!skip(4, fp))
481 goto eof;
482 break;
484 case xxx1:
486 int len = getc(fp);
487 if (len == EOF)
488 goto eof;
489 char buf[256];
490 if (fread(buf, 1, len, fp) != len)
491 goto eof;
492 if (len == 10 /* strlen("adjustment") */
493 && memcmp(buf, "adjustment", len) == 0) {
494 int c = getc(fp);
495 if (c != yyy) {
496 if (c != EOF)
497 ungetc(c, fp);
498 break;
500 if (!sread4(&left_adj, fp))
501 goto eof;
502 c = getc(fp);
503 if (c != yyy) {
504 if (c != EOF)
505 ungetc(c, fp);
506 break;
508 if (!sread4(&right_adj, fp))
509 goto eof;
510 got_an_adjustment = 1;
511 pending_adjustment = 1;
513 break;
515 case xxx1 + 1:
516 if (!uread2(&n, fp) || !skip(n, fp))
517 goto eof;
518 break;
519 case xxx1 + 2:
520 if (!uread3(&n, fp) || !skip(n, fp))
521 goto eof;
522 break;
523 case xxx1 + 3:
524 if (!sread4(&n, fp) || !skip(n, fp))
525 goto eof;
526 break;
527 case yyy:
528 if (!skip(4, fp))
529 goto eof;
530 break;
531 default:
532 fatal("unrecognized opcode `%1'", op);
533 break;
536 if (!got_an_adjustment)
537 warning("no adjustment specials found in gf file");
538 return 1;
539 eof:
540 error("unexpected end of file");
541 return 0;
544 int gf::sread4(int *p, FILE *fp)
546 *p = getc(fp);
547 if (*p >= 128)
548 *p -= 256;
549 *p <<= 8;
550 *p |= getc(fp);
551 *p <<= 8;
552 *p |= getc(fp);
553 *p <<= 8;
554 *p |= getc(fp);
555 return !ferror(fp) && !feof(fp);
558 int gf::uread3(int *p, FILE *fp)
560 *p = getc(fp);
561 *p <<= 8;
562 *p |= getc(fp);
563 *p <<= 8;
564 *p |= getc(fp);
565 return !ferror(fp) && !feof(fp);
568 int gf::uread2(int *p, FILE *fp)
570 *p = getc(fp);
571 *p <<= 8;
572 *p |= getc(fp);
573 return !ferror(fp) && !feof(fp);
576 int gf::skip(int n, FILE *fp)
578 while (--n >= 0)
579 if (getc(fp) == EOF)
580 return 0;
581 return 1;
585 struct char_list {
586 char *ch;
587 char_list *next;
588 char_list(const char *, char_list * = 0);
591 char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
596 int read_map(const char *file, char_list **table)
598 FILE *fp = fopen(file, "r");
599 if (!fp) {
600 error("can't open `%1': %2", file, strerror(errno));
601 return 0;
603 for (int i = 0; i < 256; i++)
604 table[i] = 0;
605 char buf[512];
606 int lineno = 0;
607 while (fgets(buf, int(sizeof(buf)), fp)) {
608 lineno++;
609 char *ptr = buf;
610 while (csspace(*ptr))
611 ptr++;
612 if (*ptr == '\0' || *ptr == '#')
613 continue;
614 ptr = strtok(ptr, " \n\t");
615 if (!ptr)
616 continue;
617 int n;
618 if (sscanf(ptr, "%d", &n) != 1) {
619 error("%1:%2: bad map file", file, lineno);
620 fclose(fp);
621 return 0;
623 if (n < 0 || n > 255) {
624 error("%1:%2: code out of range", file, lineno);
625 fclose(fp);
626 return 0;
628 ptr = strtok(0, " \n\t");
629 if (!ptr) {
630 error("%1:%2: missing names", file, lineno);
631 fclose(fp);
632 return 0;
634 for (; ptr; ptr = strtok(0, " \n\t"))
635 table[n] = new char_list(ptr, table[n]);
637 fclose(fp);
638 return 1;
642 /* Every character that can participate in a ligature appears in the
643 lig_chars table. `ch' gives the full-name of the character, `name'
644 gives the groff name of the character, `i' gives its index in
645 the encoding, which is filled in later (-1 if it does not appear). */
647 struct {
648 const char *ch;
649 int i;
650 } lig_chars[] = {
651 "f", -1,
652 "i", -1,
653 "l", -1,
654 "ff", -1,
655 "fi", -1,
656 "fl", -1,
657 "Fi", -1,
658 "Fl", -1,
661 // Indices into lig_chars[].
663 enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
665 // Each possible ligature appears in this table.
667 struct {
668 unsigned char c1, c2, res;
669 const char *ch;
670 } lig_table[] = {
671 CH_f, CH_f, CH_ff, "ff",
672 CH_f, CH_i, CH_fi, "fi",
673 CH_f, CH_l, CH_fl, "fl",
674 CH_ff, CH_i, CH_ffi, "ffi",
675 CH_ff, CH_l, CH_ffl, "ffl",
678 static void usage();
680 int main(int argc, char **argv)
682 program_name = argv[0];
683 int special_flag = 0;
684 int skewchar = -1;
685 int opt;
686 const char *gf_file = 0;
687 while ((opt = getopt(argc, argv, "svg:k:")) != EOF)
688 switch (opt) {
689 case 'g':
690 gf_file = optarg;
691 break;
692 case 's':
693 special_flag = 1;
694 break;
695 case 'k':
697 char *ptr;
698 long n = strtol(optarg, &ptr, 0);
699 if ((n == 0 && ptr == optarg)
700 || *ptr != '\0'
701 || n < 0
702 || n > UCHAR_MAX)
703 error("invalid skewchar");
704 else
705 skewchar = (int)n;
706 break;
708 case 'v':
710 extern const char *version_string;
711 fprintf(stderr, "tfmtodit version %s\n", version_string);
712 fflush(stderr);
713 break;
715 case '?':
716 usage();
717 break;
718 case EOF:
719 assert(0);
721 if (argc - optind != 3)
722 usage();
723 gf g;
724 if (gf_file) {
725 if (!g.load(gf_file))
726 return 1;
728 const char *tfm_file = argv[optind];
729 const char *map_file = argv[optind + 1];
730 const char *font_file = argv[optind + 2];
731 tfm t;
732 if (!t.load(tfm_file))
733 return 1;
734 char_list *table[256];
735 if (!read_map(map_file, table))
736 return 1;
737 if (!freopen(font_file, "w", stdout)) {
738 error("can't open `%1' for writing: %2", font_file, strerror(errno));
739 return 1;
741 printf("name %s\n", font_file);
742 if (special_flag)
743 fputs("special\n", stdout);
744 char *internal_name = strsave(argv[optind]);
745 int len = strlen(internal_name);
746 if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
747 internal_name[len - 4] = '\0';
748 char *s = strrchr(internal_name, '/');
749 printf("internalname %s\n", s ? s + 1 : internal_name);
750 int n;
751 if (t.get_param(2, &n)) {
752 if (n > 0)
753 printf("spacewidth %d\n", n*MULTIPLIER);
755 if (t.get_param(1, &n) && n != 0)
756 printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/M_PI);
757 int xheight;
758 if (!t.get_param(5, &xheight))
759 xheight = 0;
760 int i;
761 // Print the list of ligatures.
762 // First find the indices of each character that can participate in
763 // a ligature.
764 for (i = 0; i < 256; i++)
765 for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
766 for (char_list *p = table[i]; p; p = p->next)
767 if (strcmp(lig_chars[j].ch, p->ch) == 0)
768 lig_chars[j].i = i;
769 // For each possible ligature, if its participants all exist,
770 // and it appears as a ligature in the tfm file, include in
771 // the list of ligatures.
772 int started = 0;
773 for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
774 int i1 = lig_chars[lig_table[i].c1].i;
775 int i2 = lig_chars[lig_table[i].c2].i;
776 int r = lig_chars[lig_table[i].res].i;
777 if (i1 >= 0 && i2 >= 0 && r >= 0) {
778 unsigned char c;
779 if (t.get_lig(i1, i2, &c) && c == r) {
780 if (!started) {
781 started = 1;
782 fputs("ligatures", stdout);
784 printf(" %s", lig_table[i].ch);
788 if (started)
789 fputs(" 0\n", stdout);
790 printf("checksum %d\n", t.get_checksum());
791 printf("designsize %d\n", t.get_design_size());
792 // Now print out the kerning information.
793 int had_kern = 0;
794 kern_iterator iter(&t);
795 unsigned char c1, c2;
796 int k;
797 while (iter.next(&c1, &c2, &k))
798 if (c2 != skewchar) {
799 k *= MULTIPLIER;
800 char_list *q = table[c2];
801 for (char_list *p1 = table[c1]; p1; p1 = p1->next)
802 for (char_list *p2 = q; p2; p2 = p2->next) {
803 if (!had_kern) {
804 printf("kernpairs\n");
805 had_kern = 1;
807 printf("%s %s %d\n", p1->ch, p2->ch, k);
810 printf("charset\n");
811 char_list unnamed("---");
812 for (i = 0; i < 256; i++)
813 if (t.contains(i)) {
814 char_list *p = table[i] ? table[i] : &unnamed;
815 int m[6];
816 m[0] = t.get_width(i);
817 m[1] = t.get_height(i);
818 m[2] = t.get_depth(i);
819 m[3] = t.get_italic(i);
820 m[4] = g.get_left_adjustment(i);
821 m[5] = g.get_right_adjustment(i);
822 printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
823 for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
824 if (m[j] != 0)
825 break;
826 for (int k = 1; k <= j; k++)
827 printf(",%d", m[k]*MULTIPLIER);
828 int type = 0;
829 if (m[2] > 0)
830 type = 1;
831 if (m[1] > xheight)
832 type += 2;
833 printf("\t%d\t%04o\n", type, i);
834 for (p = p->next; p; p = p->next)
835 printf("%s\t\"\n", p->ch);
837 return 0;
840 static void usage()
842 fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
843 program_name);
844 exit(1);