out: simply ignore unknown characters
[neatroff.git] / font.c
blobd7074274f5ffcd7ebe7feb41727bb7c2ea6072cf
1 /* font handling */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 /* look up a character in chead[]/cnext[] table */
8 static int font_cidx(struct font *fn, char *name)
10 int i = fn->chead[(unsigned char) name[0]];
11 while (i >= 0 && strcmp(name, fn->c[i]))
12 i = fn->cnext[i];
13 return i;
16 /* look up a character in ghead[]/gnext[] table */
17 static int font_gidx(struct font *fn, char *id)
19 int i = fn->ghead[(unsigned char) id[0]];
20 while (i >= 0 && strcmp(fn->glyphs[i].id, id))
21 i = fn->gnext[i];
22 return i;
25 struct glyph *font_find(struct font *fn, char *name)
27 int i = font_cidx(fn, name);
28 if (i < 0)
29 return NULL;
30 return fn->g_map[i] ? fn->g_map[i] : fn->g[i];
33 struct glyph *font_glyph(struct font *fn, char *id)
35 int i = font_gidx(fn, id);
36 return i >= 0 ? &fn->glyphs[i] : NULL;
39 static struct glyph *font_glyphput(struct font *fn, char *id, char *name, int type)
41 int i = fn->nglyphs++;
42 struct glyph *g;
43 g = &fn->glyphs[i];
44 strcpy(g->id, id);
45 strcpy(g->name, name);
46 g->type = type;
47 g->font = fn;
48 fn->gnext[i] = fn->ghead[(unsigned char) id[0]];
49 fn->ghead[(unsigned char) id[0]] = i;
50 return g;
53 /* map character name to the given glyph */
54 int font_map(struct font *fn, char *name, struct glyph *g)
56 int i = font_cidx(fn, name);
57 if (g && g->font != fn)
58 return 1;
59 if (i < 0) {
60 if (fn->n >= NGLYPHS)
61 return 1;
62 i = fn->n++;
63 strcpy(fn->c[i], name);
64 fn->cnext[i] = fn->chead[(unsigned char) name[0]];
65 fn->chead[(unsigned char) name[0]] = i;
67 fn->g_map[i] = g;
68 return 0;
71 /* return nonzero if character name has been mapped with font_map() */
72 int font_mapped(struct font *fn, char *name)
74 int i = font_cidx(fn, name);
75 return i >= 0 && fn->g_map[i];
78 /* glyph index in fn->glyphs[] */
79 static int font_idx(struct font *fn, struct glyph *g)
81 return g ? g - fn->glyphs : -1;
85 * Given a list of characters in the reverse order, font_lig()
86 * returns the number of characters from the beginning of this
87 * list that form a ligature in this font. Zero naturally means
88 * no ligature was matched.
90 int font_lig(struct font *fn, char **c, int n)
92 int i;
93 /* concatenated characters in c[], in the correct order */
94 char s[GNLEN * 2] = "";
95 /* b[i] is the number of character of c[] in s + i */
96 int b[GNLEN * 2] = {0};
97 int len = 0;
98 for (i = 0; i < n; i++) {
99 char *cur = c[n - i - 1];
100 b[len] = n - i;
101 strcpy(s + len, cur);
102 len += strlen(cur);
104 for (i = 0; i < fn->lgn; i++) {
105 int l = strlen(fn->lg[i]);
106 if (b[len - l] > 1 && !strcmp(s + len - l, fn->lg[i]))
107 if (font_find(fn, fn->lg[i]))
108 return b[len - l];
110 return 0;
113 /* return nonzero if s is a ligature */
114 int font_islig(struct font *fn, char *s)
116 int i;
117 for (i = 0; i < fn->lgn; i++)
118 if (!strcmp(s, fn->lg[i]))
119 return 1;
120 return 0;
123 /* return pairwise kerning value between c1 and c2 */
124 int font_kern(struct font *fn, char *c1, char *c2)
126 int i1, i2, i;
127 i1 = font_idx(fn, font_find(fn, c1));
128 i2 = font_idx(fn, font_find(fn, c2));
129 if (i1 < 0 || i2 < 0)
130 return 0;
131 i = fn->knhead[i1];
132 while (i >= 0) {
133 if (fn->knpair[i] == i2)
134 return fn->knval[i];
135 i = fn->knnext[i];
137 return 0;
140 static int font_readchar(struct font *fn, FILE *fin)
142 char tok[ILNLEN];
143 char name[ILNLEN];
144 char id[ILNLEN];
145 struct glyph *glyph = NULL;
146 int type;
147 if (fn->n >= NGLYPHS)
148 return 1;
149 if (fscanf(fin, "%s %s", name, tok) != 2)
150 return 1;
151 if (!strcmp("---", name))
152 sprintf(name, "c%04d", fn->n);
153 if (!strcmp("\"", tok)) {
154 glyph = fn->g[fn->n - 1];
155 } else {
156 if (fscanf(fin, "%d %s", &type, id) != 2)
157 return 1;
158 glyph = font_glyph(fn, id);
159 if (!glyph) {
160 glyph = font_glyphput(fn, id, name, type);
161 sscanf(tok, "%d,%d,%d,%d,%d", &glyph->wid,
162 &glyph->llx, &glyph->lly, &glyph->urx, &glyph->ury);
165 strcpy(fn->c[fn->n], name);
166 fn->g[fn->n] = glyph;
167 fn->cnext[fn->n] = fn->chead[(unsigned char) name[0]];
168 fn->chead[(unsigned char) name[0]] = fn->n;
169 fn->n++;
170 return 0;
173 static int font_readkern(struct font *fn, FILE *fin)
175 char c1[ILNLEN], c2[ILNLEN];
176 int i1, i2, val;
177 if (fscanf(fin, "%s %s %d", c1, c2, &val) != 3)
178 return 1;
179 i1 = font_idx(fn, font_glyph(fn, c1));
180 i2 = font_idx(fn, font_glyph(fn, c2));
181 if (fn->knn < NKERNS && i1 >= 0 && i2 >= 0) {
182 fn->knnext[fn->knn] = fn->knhead[i1];
183 fn->knhead[i1] = fn->knn;
184 fn->knval[fn->knn] = val;
185 fn->knpair[fn->knn] = i2;
186 fn->knn++;
188 return 0;
191 static void skipline(FILE* filp)
193 int c;
194 do {
195 c = getc(filp);
196 } while (c != '\n' && c != EOF);
199 struct font *font_open(char *path)
201 struct font *fn;
202 char tok[ILNLEN];
203 FILE *fin;
204 int i;
205 fin = fopen(path, "r");
206 if (!fin)
207 return NULL;
208 fn = malloc(sizeof(*fn));
209 if (!fn) {
210 fclose(fin);
211 return NULL;
213 memset(fn, 0, sizeof(*fn));
214 for (i = 0; i < LEN(fn->ghead); i++)
215 fn->ghead[i] = -1;
216 for (i = 0; i < LEN(fn->chead); i++)
217 fn->chead[i] = -1;
218 for (i = 0; i < LEN(fn->knhead); i++)
219 fn->knhead[i] = -1;
220 while (fscanf(fin, "%s", tok) == 1) {
221 if (!strcmp("char", tok)) {
222 font_readchar(fn, fin);
223 } else if (!strcmp("kern", tok)) {
224 font_readkern(fn, fin);
225 } else if (!strcmp("spacewidth", tok)) {
226 fscanf(fin, "%d", &fn->spacewid);
227 } else if (!strcmp("special", tok)) {
228 fn->special = 1;
229 } else if (!strcmp("name", tok)) {
230 fscanf(fin, "%s", fn->name);
231 } else if (!strcmp("fontname", tok)) {
232 fscanf(fin, "%s", fn->fontname);
233 } else if (!strcmp("ligatures", tok)) {
234 while (fscanf(fin, "%s", tok) == 1) {
235 if (!strcmp("0", tok))
236 break;
237 if (fn->lgn < NLIGS)
238 strcpy(fn->lg[fn->lgn++], tok);
240 } else if (!strcmp("charset", tok)) {
241 while (!font_readchar(fn, fin))
243 break;
245 skipline(fin);
247 fclose(fin);
248 return fn;
251 void font_close(struct font *fn)
253 free(fn);