]> git.wh0rd.org Git - 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 }