Initial support for adding fonts at run-time. Currently we only support
[sgt/halibut] / in_afm.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "halibut.h"
4 #include "paper.h"
5
6 char *afm_read_line(input *in) {
7 int i, len = 256;
8 int c;
9 char *line;
10
11 do {
12 i = 0;
13 in->pos.line++;
14 c = getc(in->currfp);
15 if (c == EOF) {
16 error(err_afmeof, &in->pos);
17 return NULL;
18 }
19 line = snewn(len, char);
20 while (c != EOF && c != '\r' && c != '\n') {
21 if (i >= len - 1) {
22 len += 256;
23 line = sresize(line, len, char);
24 }
25 line[i++] = c;
26 c = getc(in->currfp);
27 }
28 if (c == '\r') {
29 /* Cope with CRLF terminated lines */
30 c = getc(in->currfp);
31 if (c != '\n' && c != EOF)
32 ungetc(c, in->currfp);
33 }
34 line[i] = 0;
35 } while (line[(strspn(line, " \t"))] == 0 ||
36 strncmp(line, "Comment ", 8) == 0 ||
37 strncmp(line, "Comment\t", 8) == 0);
38
39 return line;
40 }
41
42 static int afm_require_key(char *line, char const *expected, input *in) {
43 char *key = strtok(line, " \t");
44
45 if (strcmp(key, expected) == 0)
46 return TRUE;
47 error(err_afmkey, &in->pos, expected);
48 return FALSE;
49 }
50
51 void read_afm_file(input *in) {
52 char *line, *key, *val;
53 font_info *fi;
54
55 fi = snew(font_info);
56 fi->name = NULL;
57 fi->nglyphs = 0;
58 fi->glyphs = NULL;
59 fi->widths = NULL;
60 fi->kerns = newtree234(kern_cmp);
61 in->pos.line = 0;
62 line = afm_read_line(in);
63 if (!line || !afm_require_key(line, "StartFontMetrics", in))
64 goto giveup;
65 if (!(val = strtok(NULL, " \t"))) {
66 error(err_afmval, in->pos, "StartFontMetrics", 1);
67 goto giveup;
68 }
69 if (atof(val) >= 5.0) {
70 error(err_afmvers, &in->pos);
71 goto giveup;
72 }
73 sfree(line);
74 for (;;) {
75 line = afm_read_line(in);
76 if (line == NULL)
77 goto giveup;
78 key = strtok(line, " \t");
79 if (strcmp(key, "EndFontMetrics") == 0) {
80 fi->next = all_fonts;
81 all_fonts = fi;
82 fclose(in->currfp);
83 return;
84 } else if (strcmp(key, "FontName") == 0) {
85 if (!(val = strtok(NULL, " \t"))) {
86 error(err_afmval, &in->pos, key, 1);
87 goto giveup;
88 }
89 fi->name = dupstr(val);
90 } else if (strcmp(key, "StartCharMetrics") == 0) {
91 char const **glyphs;
92 int *widths;
93 int i;
94 if (!(val = strtok(NULL, " \t"))) {
95 error(err_afmval, &in->pos, key, 1);
96 goto giveup;
97 }
98 fi->nglyphs = atoi(val);
99 sfree(line);
100 glyphs = snewn(fi->nglyphs, char const *);
101 widths = snewn(fi->nglyphs, int);
102 for (i = 0; i < fi->nglyphs; i++) {
103 glyphs[i] = NULL;
104 line = afm_read_line(in);
105 if (line == NULL)
106 goto giveup;
107 key = strtok(line, " \t");
108 while (key != NULL) {
109 if (strcmp(key, "WX") == 0 || strcmp(key, "W0X") == 0) {
110 if (!(val = strtok(NULL, " \t")) ||
111 !strcmp(val, ";")) {
112 error(err_afmval, &in->pos, key, 1);
113 goto giveup;
114 }
115 widths[i] = atoi(val);
116 } else if (strcmp(key, "N") == 0) {
117 if (!(val = strtok(NULL, " \t")) ||
118 !strcmp(val, ";")) {
119 error(err_afmval, &in->pos, key, 1);
120 goto giveup;
121 }
122 glyphs[i] = dupstr(val);
123 }
124 do {
125 key = strtok(NULL, " \t");
126 } while (key && strcmp(key, ";"));
127 key = strtok(NULL, " \t");
128 }
129 sfree(line);
130 }
131 line = afm_read_line(in);
132 if (!line || !afm_require_key(line, "EndCharMetrics", in))
133 goto giveup;
134 sfree(line);
135 fi->glyphs = glyphs;
136 fi->widths = widths;
137
138 for (i = 0; i < fi->nglyphs; i++) {
139 wchar_t ucs;
140 ucs = ps_glyph_to_unicode(fi->glyphs[i]);
141 if (ucs < 0xFFFF)
142 fi->bmp[ucs] = i;
143 }
144 font_index_glyphs(fi);
145 } else if (strcmp(key, "StartKernPairs") == 0 ||
146 strcmp(key, "StartKernPairs0") == 0) {
147 int nkerns, i;
148 kern_pair *kerns;
149 if (!(val = strtok(NULL, " \t"))) {
150 error(err_afmval, &in->pos, key, 1);
151 goto giveup;
152 }
153 nkerns = atoi(val);
154 sfree(line);
155 kerns = snewn(nkerns, kern_pair);
156 for (i = 0; i < nkerns; i++) {
157 line = afm_read_line(in);
158 if (line == NULL)
159 goto giveup;
160 key = strtok(line, " \t");
161 if (strcmp(key, "KPX") == 0) {
162 char *nl, *nr;
163 int l, r;
164 kern_pair *kp;
165 nl = strtok(NULL, " \t");
166 nr = strtok(NULL, " \t");
167 val = strtok(NULL, " \t");
168 if (!val) {
169 error(err_afmval, &in->pos, key, 3);
170 goto giveup;
171 }
172 l = find_glyph(fi, nl);
173 r = find_glyph(fi, nr);
174 if (l == -1 || r == -1) continue;
175 kp = snew(kern_pair);
176 kp->left = l;
177 kp->right = r;
178 kp->kern = atoi(val);
179 add234(fi->kerns, kp);
180 }
181 }
182 line = afm_read_line(in);
183 if (!line || !afm_require_key(line, "EndKernPairs", in))
184 goto giveup;
185 sfree(line);
186 }
187 }
188 giveup:
189 sfree(fi);
190 fclose(in->currfp);
191 return;
192 }