wb: allow longer ligatures
[neatroff.git] / font.c
blobf8ddffc252278bdfdc6c8397dc3e9c938aaa7ff4
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;
17 for (i = 0; i < fn->n; i++)
18 if (name[0] == fn->c[i][0] && !strcmp(name, fn->c[i]))
19 return fn->g[i];
20 return NULL;
23 struct glyph *font_glyph(struct font *fn, char *id)
25 int i;
26 for (i = 0; i < fn->nglyphs; i++)
27 if (!strcmp(fn->glyphs[i].id, id))
28 return &fn->glyphs[i];
29 return NULL;
32 static int font_section(struct font *fn, FILE *fin, char *name);
34 static void font_charset(struct font *fn, FILE *fin)
36 char tok[ILNLEN];
37 char name[ILNLEN];
38 char id[ILNLEN];
39 struct glyph *glyph = NULL;
40 struct glyph *prev = NULL;
41 int wid, type;
42 while (fscanf(fin, "%s", name) == 1) {
43 if (!font_section(fn, fin, name))
44 break;
45 if (fn->n >= NGLYPHS) {
46 skipline(fin);
47 continue;
49 fscanf(fin, "%s", tok);
50 glyph = prev;
51 if (!strcmp("---", name))
52 sprintf(name, "c%04d", fn->n);
53 if (strcmp("\"", tok)) {
54 wid = atoi(tok);
55 fscanf(fin, "%d %s", &type, id);
56 skipline(fin);
57 glyph = &fn->glyphs[fn->nglyphs++];
58 strcpy(glyph->id, id);
59 strcpy(glyph->name, name);
60 glyph->wid = wid;
61 glyph->type = type;
62 glyph->font = fn;
64 prev = glyph;
65 strcpy(fn->c[fn->n], name);
66 fn->g[fn->n] = glyph;
67 fn->n++;
71 static void font_kernpairs(struct font *fn, FILE *fin)
73 char c1[ILNLEN], c2[ILNLEN];
74 int val;
75 while (fscanf(fin, "%s", c1) == 1) {
76 if (!font_section(fn, fin, c1))
77 break;
78 if (fscanf(fin, "%s %d", c2, &val) != 2)
79 break;
80 if (fn->nkern < NKERNS) {
81 strcpy(fn->kern_c1[fn->nkern], c1);
82 strcpy(fn->kern_c2[fn->nkern], c2);
83 fn->kern[fn->nkern] = val;
84 fn->nkern++;
89 static int font_section(struct font *fn, FILE *fin, char *name)
91 if (!strcmp("charset", name)) {
92 font_charset(fn, fin);
93 return 0;
95 if (!strcmp("kernpairs", name)) {
96 font_kernpairs(fn, fin);
97 return 0;
99 return 1;
103 * Given a list of characters in the reverse order, font_lig()
104 * returns the number of characters from the beginning of this
105 * list that form a ligature in this font. Zero naturally means
106 * no ligature was matched.
108 int font_lig(struct font *fn, char **c, int n)
110 int i;
111 /* concatenated characters in c[], in the correct order */
112 char s[GNLEN * 2] = "";
113 /* b[i] is the number of character of c[] in s + i */
114 int b[GNLEN * 2] = {0};
115 int len = 0;
116 for (i = 0; i < n; i++) {
117 char *cur = c[n - i - 1];
118 b[len] = n - i;
119 strcpy(s + len, cur);
120 len += strlen(cur);
122 for (i = 0; i < fn->nlig; i++) {
123 int l = strlen(fn->lig[i]);
124 if (b[len - l] && !strcmp(s + len - l, fn->lig[i]))
125 if (font_find(fn, fn->lig[i]))
126 return b[len - l];
128 return 0;
131 /* return pairwise kerning value between c1 and c2 */
132 int font_kern(struct font *fn, char *c1, char *c2)
134 int i;
135 for (i = 0; i < fn->nkern; i++)
136 if (!strcmp(fn->kern_c1[i], c1) && !strcmp(fn->kern_c2[i], c2))
137 return fn->kern[i];
138 return 0;
141 struct font *font_open(char *path)
143 struct font *fn = malloc(sizeof(*fn));
144 char tok[ILNLEN];
145 FILE *fin;
146 fin = fopen(path, "r");
147 memset(fn, 0, sizeof(*fn));
148 while (fscanf(fin, "%s", tok) == 1) {
149 if (tok[0] == '#') {
150 skipline(fin);
151 continue;
153 if (!strcmp("spacewidth", tok)) {
154 fscanf(fin, "%d", &fn->spacewid);
155 continue;
157 if (!strcmp("special", tok)) {
158 fn->special = 1;
159 continue;
161 if (!strcmp("name", tok)) {
162 fscanf(fin, "%s", fn->name);
163 continue;
165 if (!strcmp("fontname", tok)) {
166 fscanf(fin, "%s", fn->fontname);
167 continue;
169 if (!strcmp("named", tok)) {
170 skipline(fin);
171 continue;
173 if (!strcmp("ligatures", tok)) {
174 while (fscanf(fin, "%s", tok) == 1) {
175 if (!strcmp("0", tok))
176 break;
177 if (fn->nlig < NLIGS)
178 strcpy(fn->lig[fn->nlig++], tok);
180 skipline(fin);
181 continue;
183 if (!font_section(fn, fin, tok))
184 break;
185 skipline(fin);
187 fclose(fin);
188 return fn;
191 void font_close(struct font *fn)
193 free(fn);