]> git.wh0rd.org - fontconfig.git/blob - doc/edit-sgml.c
6e04e1cb1536d9e95c447dfc0ace333d6de75afe
[fontconfig.git] / doc / edit-sgml.c
1 /*
2 * $Id$
3 *
4 * Copyright © 2003 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28
29 typedef enum { False, True } Bool;
30
31 typedef struct {
32 char *buf;
33 int size;
34 int len;
35 } String;
36
37 #define STRING_INIT 128
38
39 void *
40 New (int size)
41 {
42 void *m = malloc (size);
43 if (!m)
44 abort ();
45 return m;
46 }
47
48 void *
49 Reallocate (void *p, int size)
50 {
51 void *r = realloc (p, size);
52
53 if (!r)
54 abort ();
55 return r;
56 }
57
58 void
59 Dispose (void *p)
60 {
61 free (p);
62 }
63
64 String *
65 StringNew (void)
66 {
67 String *s;
68
69 s = New (sizeof (String));
70 s->buf = New (STRING_INIT);
71 s->size = STRING_INIT - 1;
72 s->buf[0] = '\0';
73 s->len = 0;
74 return s;
75 }
76
77 void
78 StringAdd (String *s, char c)
79 {
80 if (s->len == s->size)
81 s->buf = Reallocate (s->buf, (s->size *= 2) + 1);
82 s->buf[s->len++] = c;
83 s->buf[s->len] = '\0';
84 }
85
86 void
87 StringAddString (String *s, char *buf)
88 {
89 while (*buf)
90 StringAdd (s, *buf++);
91 }
92
93 String *
94 StringMake (char *buf)
95 {
96 String *s = StringNew ();
97 StringAddString (s, buf);
98 return s;
99 }
100
101 void
102 StringDel (String *s)
103 {
104 if (s->len)
105 s->buf[--s->len] = '\0';
106 }
107
108 void
109 StringPut (FILE *f, String *s)
110 {
111 char *b = s->buf;
112
113 while (*b)
114 putc (*b++, f);
115 }
116
117 #define StringLast(s) ((s)->len ? (s)->buf[(s)->len - 1] : '\0')
118
119 void
120 StringDispose (String *s)
121 {
122 Dispose (s->buf);
123 Dispose (s);
124 }
125
126 typedef struct {
127 String *tag;
128 String *text;
129 } Replace;
130
131 Replace *
132 ReplaceNew (void)
133 {
134 Replace *r = New (sizeof (Replace));
135 r->tag = StringNew ();
136 r->text = StringNew ();
137 return r;
138 }
139
140 void
141 ReplaceDispose (Replace *r)
142 {
143 StringDispose (r->tag);
144 StringDispose (r->text);
145 Dispose (r);
146 }
147
148 Replace *
149 ReplaceRead (FILE *f)
150 {
151 int c;
152 Replace *r;
153
154 while ((c = getc (f)) != '@')
155 {
156 if (c == EOF)
157 return 0;
158 }
159 r = ReplaceNew();
160 while ((c = getc (f)) != '@')
161 {
162 if (c == EOF)
163 {
164 ReplaceDispose (r);
165 return 0;
166 }
167 StringAdd (r->tag, c);
168 }
169 if (r->tag->buf[0] == '\0')
170 {
171 ReplaceDispose (r);
172 return 0;
173 }
174 while (isspace ((c = getc (f))))
175 ;
176 ungetc (c, f);
177 while ((c = getc (f)) != '@' && c != EOF)
178 StringAdd (r->text, c);
179 if (c == '@')
180 ungetc (c, f);
181 while (StringLast (r->text) == '\n')
182 StringDel (r->text);
183 return r;
184 }
185
186 typedef struct _replaceList {
187 struct _replaceList *next;
188 Replace *r;
189 } ReplaceList;
190
191 ReplaceList *
192 ReplaceListNew (Replace *r, ReplaceList *next)
193 {
194 ReplaceList *l = New (sizeof (ReplaceList));
195 l->r = r;
196 l->next = next;
197 return l;
198 }
199
200 void
201 ReplaceListDispose (ReplaceList *l)
202 {
203 if (l)
204 {
205 ReplaceListDispose (l->next);
206 ReplaceDispose (l->r);
207 Dispose (l);
208 }
209 }
210
211 typedef struct {
212 ReplaceList *head;
213 } ReplaceSet;
214
215 ReplaceSet *
216 ReplaceSetNew (void)
217 {
218 ReplaceSet *s = New (sizeof (ReplaceSet));
219 s->head = 0;
220 return s;
221 }
222
223 void
224 ReplaceSetDispose (ReplaceSet *s)
225 {
226 ReplaceListDispose (s->head);
227 Dispose (s);
228 }
229
230 void
231 ReplaceSetAdd (ReplaceSet *s, Replace *r)
232 {
233 s->head = ReplaceListNew (r, s->head);
234 }
235
236 Replace *
237 ReplaceSetFind (ReplaceSet *s, char *tag)
238 {
239 ReplaceList *l;
240
241 for (l = s->head; l; l = l->next)
242 if (!strcmp (tag, l->r->tag->buf))
243 return l->r;
244 return 0;
245 }
246
247 ReplaceSet *
248 ReplaceSetRead (FILE *f)
249 {
250 ReplaceSet *s = ReplaceSetNew ();
251 Replace *r;
252
253 while ((r = ReplaceRead (f)))
254 {
255 while (ReplaceSetFind (s, r->tag->buf))
256 StringAdd (r->tag, '+');
257 ReplaceSetAdd (s, r);
258 }
259 if (!s->head)
260 {
261 ReplaceSetDispose (s);
262 s = 0;
263 }
264 return s;
265 }
266
267 typedef struct _skipStack {
268 struct _skipStack *prev;
269 int skipping;
270 } SkipStack;
271
272 SkipStack *
273 SkipStackPush (SkipStack *prev, int skipping)
274 {
275 SkipStack *ss = New (sizeof (SkipStack));
276 ss->prev = prev;
277 ss->skipping = skipping;
278 return ss;
279 }
280
281 SkipStack *
282 SkipStackPop (SkipStack *prev)
283 {
284 SkipStack *ss = prev->prev;
285 Dispose (prev);
286 return ss;
287 }
288
289 typedef struct _loopStack {
290 struct _loopStack *prev;
291 String *tag;
292 String *extra;
293 long pos;
294 } LoopStack;
295
296 LoopStack *
297 LoopStackPush (LoopStack *prev, FILE *f, char *tag)
298 {
299 LoopStack *ls = New (sizeof (LoopStack));
300 ls->prev = prev;
301 ls->tag = StringMake (tag);
302 ls->extra = StringNew ();
303 ls->pos = ftell (f);
304 return ls;
305 }
306
307 LoopStack *
308 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
309 {
310 String *s = StringMake (ls->tag->buf);
311 LoopStack *ret = ls;
312 Bool loop;
313
314 StringAdd (ls->extra, '+');
315 StringAddString (s, ls->extra->buf);
316 loop = ReplaceSetFind (rs, s->buf) != 0;
317 StringDispose (s);
318 if (loop)
319 fseek (f, ls->pos, SEEK_SET);
320 else
321 {
322 ret = ls->prev;
323 StringDispose (ls->tag);
324 StringDispose (ls->extra);
325 Dispose (ls);
326 }
327 return ret;
328 }
329
330 void
331 LineSkip (FILE *f)
332 {
333 int c;
334
335 while ((c = getc (f)) == '\n')
336 ;
337 ungetc (c, f);
338 }
339
340 void
341 DoReplace (FILE *f, ReplaceSet *s)
342 {
343 int c;
344 String *tag;
345 Replace *r;
346 SkipStack *ss = 0;
347 LoopStack *ls = 0;
348 int skipping = 0;
349
350 while ((c = getc (f)) != EOF)
351 {
352 if (c == '@')
353 {
354 tag = StringNew ();
355 while ((c = getc (f)) != '@')
356 {
357 if (c == EOF)
358 abort ();
359 StringAdd (tag, c);
360 }
361 if (ls)
362 StringAddString (tag, ls->extra->buf);
363 switch (tag->buf[0]) {
364 case '?':
365 ss = SkipStackPush (ss, skipping);
366 if (!ReplaceSetFind (s, tag->buf + 1))
367 skipping++;
368 LineSkip (f);
369 break;
370 case ':':
371 if (!ss)
372 abort ();
373 if (ss->skipping == skipping)
374 ++skipping;
375 else
376 --skipping;
377 LineSkip (f);
378 break;
379 case ';':
380 skipping = ss->skipping;
381 ss = SkipStackPop (ss);
382 LineSkip (f);
383 break;
384 case '{':
385 ls = LoopStackPush (ls, f, tag->buf + 1);
386 LineSkip (f);
387 break;
388 case '}':
389 ls = LoopStackLoop (s, ls, f);
390 LineSkip (f);
391 break;
392 default:
393 r = ReplaceSetFind (s, tag->buf);
394 if (r && !skipping)
395 StringPut (stdout, r->text);
396 break;
397 }
398 StringDispose (tag);
399 }
400 else if (!skipping)
401 putchar (c);
402 }
403 }
404
405 int
406 main (int argc, char **argv)
407 {
408 FILE *f;
409 ReplaceSet *s;
410
411 f = fopen (argv[1], "r");
412 if (!f)
413 {
414 perror (argv[1]);
415 exit (1);
416 }
417 while ((s = ReplaceSetRead (stdin)))
418 {
419 DoReplace (f, s);
420 ReplaceSetDispose (s);
421 rewind (f);
422 }
423 if (ferror (stdout))
424 exit (1);
425 exit (0);
426 }