map: use starting character lists for keys[]
[neatroff.git] / font.c
blob65a51f082941579f70ed503a9e38e92b8e61aee7
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "roff.h"
6 static void skipline(FILE* filp)
8 int c;
9 do {
10 c = getc(filp);
11 } while (c != '\n' && c != EOF);
14 struct glyph *font_find(struct font *fn, char *name)
16 int i = fn->head[(unsigned char) name[0]];
17 while (i >= 0) {
18 if (!strcmp(name, fn->c[i]))
19 return fn->g[i];
20 i = fn->next[i];
22 return NULL;
25 struct glyph *font_glyph(struct font *fn, char *id)
27 int i;
28 for (i = 0; i < fn->nglyphs; i++)
29 if (!strcmp(fn->glyphs[i].id, id))
30 return &fn->glyphs[i];
31 return NULL;
34 static int font_idx(struct font *fn, struct glyph *g)
36 return g ? g - fn->glyphs : -1;
40 * Given a list of characters in the reverse order, font_lig()
41 * returns the number of characters from the beginning of this
42 * list that form a ligature in this font. Zero naturally means
43 * no ligature was matched.
45 int font_lig(struct font *fn, char **c, int n)
47 int i;
48 /* concatenated characters in c[], in the correct order */
49 char s[GNLEN * 2] = "";
50 /* b[i] is the number of character of c[] in s + i */
51 int b[GNLEN * 2] = {0};
52 int len = 0;
53 for (i = 0; i < n; i++) {
54 char *cur = c[n - i - 1];
55 b[len] = n - i;
56 strcpy(s + len, cur);
57 len += strlen(cur);
59 for (i = 0; i < fn->nlig; i++) {
60 int l = strlen(fn->lig[i]);
61 if (b[len - l] && !strcmp(s + len - l, fn->lig[i]))
62 if (font_find(fn, fn->lig[i]))
63 return b[len - l];
65 return 0;
68 /* return pairwise kerning value between c1 and c2 */
69 int font_kern(struct font *fn, char *c1, char *c2)
71 int i1, i2, i;
72 i1 = font_idx(fn, font_find(fn, c1));
73 i2 = font_idx(fn, font_find(fn, c2));
74 if (i1 < 0 || i2 < 0)
75 return 0;
76 i = fn->knhead[i1];
77 while (i >= 0) {
78 if (fn->knpair[i] == i2)
79 return fn->knval[i];
80 i = fn->knnext[i];
82 return 0;
85 static int font_section(struct font *fn, FILE *fin, char *name);
87 static void font_charset(struct font *fn, FILE *fin)
89 char tok[ILNLEN];
90 char name[ILNLEN];
91 char id[ILNLEN];
92 struct glyph *glyph = NULL;
93 struct glyph *prev = NULL;
94 int wid, type;
95 while (fscanf(fin, "%s", name) == 1) {
96 if (!font_section(fn, fin, name))
97 break;
98 if (fn->n >= NGLYPHS) {
99 skipline(fin);
100 continue;
102 fscanf(fin, "%s", tok);
103 glyph = prev;
104 if (!strcmp("---", name))
105 sprintf(name, "c%04d", fn->n);
106 if (strcmp("\"", tok)) {
107 wid = atoi(tok);
108 fscanf(fin, "%d %s", &type, id);
109 skipline(fin);
110 glyph = &fn->glyphs[fn->nglyphs++];
111 strcpy(glyph->id, id);
112 strcpy(glyph->name, name);
113 glyph->wid = wid;
114 glyph->type = type;
115 glyph->font = fn;
117 prev = glyph;
118 strcpy(fn->c[fn->n], name);
119 fn->g[fn->n] = glyph;
120 fn->next[fn->n] = fn->head[(unsigned char) name[0]];
121 fn->head[(unsigned char) name[0]] = fn->n;
122 fn->n++;
126 static void font_kernpairs(struct font *fn, FILE *fin)
128 char c1[ILNLEN], c2[ILNLEN];
129 int i1, i2, val;
130 while (fscanf(fin, "%s", c1) == 1) {
131 if (!font_section(fn, fin, c1))
132 break;
133 if (fscanf(fin, "%s %d", c2, &val) != 2)
134 break;
135 if (fn->knn < NKERNS) {
136 i1 = font_idx(fn, font_find(fn, c1));
137 i2 = font_idx(fn, font_find(fn, c2));
138 if (i1 >= 0 && i2 >= 0) {
139 fn->knnext[fn->knn] = fn->knhead[i1];
140 fn->knhead[i1] = fn->knn;
141 fn->knval[fn->knn] = val;
142 fn->knpair[fn->knn] = i2;
143 fn->knn++;
149 static int font_section(struct font *fn, FILE *fin, char *name)
151 if (!strcmp("charset", name)) {
152 font_charset(fn, fin);
153 return 0;
155 if (!strcmp("kernpairs", name)) {
156 font_kernpairs(fn, fin);
157 return 0;
159 return 1;
162 struct font *font_open(char *path)
164 struct font *fn;
165 char tok[ILNLEN];
166 FILE *fin;
167 int i;
168 fin = fopen(path, "r");
169 if (!fin)
170 return NULL;
171 fn = malloc(sizeof(*fn));
172 memset(fn, 0, sizeof(*fn));
173 for (i = 0; i < LEN(fn->head); i++)
174 fn->head[i] = -1;
175 for (i = 0; i < LEN(fn->knhead); i++)
176 fn->knhead[i] = -1;
177 while (fscanf(fin, "%s", tok) == 1) {
178 if (tok[0] == '#') {
179 skipline(fin);
180 continue;
182 if (!strcmp("spacewidth", tok)) {
183 fscanf(fin, "%d", &fn->spacewid);
184 continue;
186 if (!strcmp("special", tok)) {
187 fn->special = 1;
188 continue;
190 if (!strcmp("name", tok)) {
191 fscanf(fin, "%s", fn->name);
192 continue;
194 if (!strcmp("fontname", tok)) {
195 fscanf(fin, "%s", fn->fontname);
196 continue;
198 if (!strcmp("named", tok)) {
199 skipline(fin);
200 continue;
202 if (!strcmp("ligatures", tok)) {
203 while (fscanf(fin, "%s", tok) == 1) {
204 if (!strcmp("0", tok))
205 break;
206 if (fn->nlig < NLIGS)
207 strcpy(fn->lig[fn->nlig++], tok);
209 skipline(fin);
210 continue;
212 if (!font_section(fn, fin, tok))
213 break;
214 skipline(fin);
216 fclose(fin);
217 return fn;
220 void font_close(struct font *fn)
222 free(fn);