]> git.wh0rd.org - fontconfig.git/blob - doc/edit-sgml.c
Make documentation build
[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 void
149 Bail (char *format, char *arg)
150 {
151 fprintf (stderr, "fatal: ");
152 fprintf (stderr, format, arg);
153 fprintf (stderr, "\n");
154 exit (1);
155 }
156
157 Replace *
158 ReplaceRead (FILE *f)
159 {
160 int c;
161 Replace *r;
162
163 while ((c = getc (f)) != '@')
164 {
165 if (c == EOF)
166 return 0;
167 }
168 r = ReplaceNew();
169 while ((c = getc (f)) != '@')
170 {
171 if (c == EOF)
172 {
173 ReplaceDispose (r);
174 return 0;
175 }
176 if (isspace (c))
177 Bail ("invalid character after tag %s", r->tag->buf);
178 StringAdd (r->tag, c);
179 }
180 if (r->tag->buf[0] == '\0')
181 {
182 ReplaceDispose (r);
183 return 0;
184 }
185 while (isspace ((c = getc (f))))
186 ;
187 ungetc (c, f);
188 while ((c = getc (f)) != '@' && c != EOF)
189 StringAdd (r->text, c);
190 if (c == '@')
191 ungetc (c, f);
192 while (isspace (StringLast (r->text)))
193 StringDel (r->text);
194 return r;
195 }
196
197 typedef struct _replaceList {
198 struct _replaceList *next;
199 Replace *r;
200 } ReplaceList;
201
202 ReplaceList *
203 ReplaceListNew (Replace *r, ReplaceList *next)
204 {
205 ReplaceList *l = New (sizeof (ReplaceList));
206 l->r = r;
207 l->next = next;
208 return l;
209 }
210
211 void
212 ReplaceListDispose (ReplaceList *l)
213 {
214 if (l)
215 {
216 ReplaceListDispose (l->next);
217 ReplaceDispose (l->r);
218 Dispose (l);
219 }
220 }
221
222 typedef struct {
223 ReplaceList *head;
224 } ReplaceSet;
225
226 ReplaceSet *
227 ReplaceSetNew (void)
228 {
229 ReplaceSet *s = New (sizeof (ReplaceSet));
230 s->head = 0;
231 return s;
232 }
233
234 void
235 ReplaceSetDispose (ReplaceSet *s)
236 {
237 ReplaceListDispose (s->head);
238 Dispose (s);
239 }
240
241 void
242 ReplaceSetAdd (ReplaceSet *s, Replace *r)
243 {
244 s->head = ReplaceListNew (r, s->head);
245 }
246
247 Replace *
248 ReplaceSetFind (ReplaceSet *s, char *tag)
249 {
250 ReplaceList *l;
251
252 for (l = s->head; l; l = l->next)
253 if (!strcmp (tag, l->r->tag->buf))
254 return l->r;
255 return 0;
256 }
257
258 ReplaceSet *
259 ReplaceSetRead (FILE *f)
260 {
261 ReplaceSet *s = ReplaceSetNew ();
262 Replace *r;
263
264 while ((r = ReplaceRead (f)))
265 {
266 while (ReplaceSetFind (s, r->tag->buf))
267 StringAdd (r->tag, '+');
268 ReplaceSetAdd (s, r);
269 }
270 if (!s->head)
271 {
272 ReplaceSetDispose (s);
273 s = 0;
274 }
275 return s;
276 }
277
278 typedef struct _skipStack {
279 struct _skipStack *prev;
280 int skipping;
281 } SkipStack;
282
283 SkipStack *
284 SkipStackPush (SkipStack *prev, int skipping)
285 {
286 SkipStack *ss = New (sizeof (SkipStack));
287 ss->prev = prev;
288 ss->skipping = skipping;
289 return ss;
290 }
291
292 SkipStack *
293 SkipStackPop (SkipStack *prev)
294 {
295 SkipStack *ss = prev->prev;
296 Dispose (prev);
297 return ss;
298 }
299
300 typedef struct _loopStack {
301 struct _loopStack *prev;
302 String *tag;
303 String *extra;
304 long pos;
305 } LoopStack;
306
307 LoopStack *
308 LoopStackPush (LoopStack *prev, FILE *f, char *tag)
309 {
310 LoopStack *ls = New (sizeof (LoopStack));
311 ls->prev = prev;
312 ls->tag = StringMake (tag);
313 ls->extra = StringNew ();
314 ls->pos = ftell (f);
315 return ls;
316 }
317
318 LoopStack *
319 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
320 {
321 String *s = StringMake (ls->tag->buf);
322 LoopStack *ret = ls;
323 Bool loop;
324
325 StringAdd (ls->extra, '+');
326 StringAddString (s, ls->extra->buf);
327 loop = ReplaceSetFind (rs, s->buf) != 0;
328 StringDispose (s);
329 if (loop)
330 fseek (f, ls->pos, SEEK_SET);
331 else
332 {
333 ret = ls->prev;
334 StringDispose (ls->tag);
335 StringDispose (ls->extra);
336 Dispose (ls);
337 }
338 return ret;
339 }
340
341 void
342 LineSkip (FILE *f)
343 {
344 int c;
345
346 while ((c = getc (f)) == '\n')
347 ;
348 ungetc (c, f);
349 }
350
351 void
352 DoReplace (FILE *f, ReplaceSet *s)
353 {
354 int c;
355 String *tag;
356 Replace *r;
357 SkipStack *ss = 0;
358 LoopStack *ls = 0;
359 int skipping = 0;
360
361 while ((c = getc (f)) != EOF)
362 {
363 if (c == '@')
364 {
365 tag = StringNew ();
366 while ((c = getc (f)) != '@')
367 {
368 if (c == EOF)
369 abort ();
370 StringAdd (tag, c);
371 }
372 if (ls)
373 StringAddString (tag, ls->extra->buf);
374 switch (tag->buf[0]) {
375 case '?':
376 ss = SkipStackPush (ss, skipping);
377 if (!ReplaceSetFind (s, tag->buf + 1))
378 skipping++;
379 LineSkip (f);
380 break;
381 case ':':
382 if (!ss)
383 abort ();
384 if (ss->skipping == skipping)
385 ++skipping;
386 else
387 --skipping;
388 LineSkip (f);
389 break;
390 case ';':
391 skipping = ss->skipping;
392 ss = SkipStackPop (ss);
393 LineSkip (f);
394 break;
395 case '{':
396 ls = LoopStackPush (ls, f, tag->buf + 1);
397 LineSkip (f);
398 break;
399 case '}':
400 ls = LoopStackLoop (s, ls, f);
401 LineSkip (f);
402 break;
403 default:
404 r = ReplaceSetFind (s, tag->buf);
405 if (r && !skipping)
406 StringPut (stdout, r->text);
407 break;
408 }
409 StringDispose (tag);
410 }
411 else if (!skipping)
412 putchar (c);
413 }
414 }
415
416 int
417 main (int argc, char **argv)
418 {
419 FILE *f;
420 ReplaceSet *s;
421
422 if (!argv[1])
423 Bail ("usage: %s <template.sgml>", argv[0]);
424 f = fopen (argv[1], "r");
425 if (!f)
426 {
427 Bail ("can't open file %s", argv[1]);
428 exit (1);
429 }
430 while ((s = ReplaceSetRead (stdin)))
431 {
432 DoReplace (f, s);
433 ReplaceSetDispose (s);
434 rewind (f);
435 }
436 if (ferror (stdout))
437 Bail ("%s", "error writing output");
438 exit (0);
439 }