Add func doc creation program edit-sgml
[platform/upstream/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 }