fc-cache: --sysroot option takes an argument
[platform/upstream/fontconfig.git] / doc / edit-sgml.c
1 /*
2  * fontconfig/doc/edit-sgml.c
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 the author(s) not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  The authors make 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  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) 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 <string.h>
28 #include <ctype.h>
29
30 static void *
31 New (int size);
32
33 static void *
34 Reallocate (void *p, int size);
35
36 static void
37 Dispose (void *p);
38
39 typedef enum { False, True } Bool;
40
41 typedef struct {
42     char    *buf;
43     int     size;
44     int     len;
45 } String;
46
47 static String *
48 StringNew (void);
49
50 static void
51 StringAdd (String *s, char c);
52
53 static void
54 StringAddString (String *s, char *buf);
55
56 static String *
57 StringMake (char *buf);
58
59 static void
60 StringDel (String *s);
61
62 static void
63 StringPut (FILE *f, String *s);
64
65 static void
66 StringDispose (String *s);
67
68 typedef struct {
69     String  *tag;
70     String  *text;
71 } Replace;
72
73 static Replace *
74 ReplaceNew (void);
75
76 static void
77 ReplaceDispose (Replace *r);
78
79 static void
80 Bail (const char *format, int line, const char *arg);
81
82 static Replace *
83 ReplaceRead (FILE *f, int *linep);
84
85 typedef struct _replaceList {
86     struct _replaceList *next;
87     Replace             *r;
88 } ReplaceList;
89
90 static ReplaceList *
91 ReplaceListNew (Replace *r, ReplaceList *next);
92
93 static void
94 ReplaceListDispose (ReplaceList *l);
95
96 typedef struct {
97     ReplaceList *head;
98 } ReplaceSet;
99
100 static ReplaceSet *
101 ReplaceSetNew (void);
102
103 static void
104 ReplaceSetDispose (ReplaceSet *s);
105
106 static void
107 ReplaceSetAdd (ReplaceSet *s, Replace *r);
108
109 static Replace *
110 ReplaceSetFind (ReplaceSet *s, char *tag);
111
112 static ReplaceSet *
113 ReplaceSetRead (FILE *f, int *linep);
114
115 typedef struct _skipStack {
116     struct _skipStack   *prev;
117     int                 skipping;
118 } SkipStack;
119
120 static SkipStack *
121 SkipStackPush (SkipStack *prev, int skipping);
122
123 static SkipStack *
124 SkipStackPop (SkipStack *prev);
125
126 typedef struct _loopStack {
127     struct _loopStack   *prev;
128     String              *tag;
129     String              *extra;
130     long                pos;
131 } LoopStack;
132
133 static LoopStack *
134 LoopStackPush (LoopStack *prev, FILE *f, char *tag);
135
136 static LoopStack *
137 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f);
138
139 static void
140 LineSkip (FILE *f, int *linep);
141
142 static void
143 DoReplace (FILE *f, int *linep, ReplaceSet *s);
144
145 #define STRING_INIT 128
146
147 static void *
148 New (int size)
149 {
150     void    *m = malloc (size);
151     if (!m)
152         abort ();
153     return m;
154 }
155
156 static void *
157 Reallocate (void *p, int size)
158 {
159     void    *r = realloc (p, size);
160
161     if (!r)
162         abort ();
163     return r;
164 }
165
166 static void
167 Dispose (void *p)
168 {
169     free (p);
170 }
171
172 static String *
173 StringNew (void)
174 {
175     String  *s;
176
177     s = New (sizeof (String));
178     s->buf = New (STRING_INIT);
179     s->size = STRING_INIT - 1;
180     s->buf[0] = '\0';
181     s->len = 0;
182     return s;
183 }
184
185 static void
186 StringAdd (String *s, char c)
187 {
188     if (s->len == s->size)
189         s->buf = Reallocate (s->buf, (s->size *= 2) + 1);
190     s->buf[s->len++] = c;
191     s->buf[s->len] = '\0';
192 }
193
194 static void
195 StringAddString (String *s, char *buf)
196 {
197     while (*buf)
198         StringAdd (s, *buf++);
199 }
200
201 static String *
202 StringMake (char *buf)
203 {
204     String  *s = StringNew ();
205     StringAddString (s, buf);
206     return s;
207 }
208
209 static void
210 StringDel (String *s)
211 {
212     if (s->len)
213         s->buf[--s->len] = '\0';
214 }
215
216 static void
217 StringPut (FILE *f, String *s)
218 {
219     char    *b = s->buf;
220
221     while (*b)
222         putc (*b++, f);
223 }
224
225 #define StringLast(s)   ((s)->len ? (s)->buf[(s)->len - 1] : '\0')
226
227 static void
228 StringDispose (String *s)
229 {
230     Dispose (s->buf);
231     Dispose (s);
232 }
233
234 static Replace *
235 ReplaceNew (void)
236 {
237     Replace *r = New (sizeof (Replace));
238     r->tag = StringNew ();
239     r->text = StringNew ();
240     return r;
241 }
242
243 static void
244 ReplaceDispose (Replace *r)
245 {
246     StringDispose (r->tag);
247     StringDispose (r->text);
248     Dispose (r);
249 }
250
251 static void
252 Bail (const char *format, int line, const char *arg)
253 {
254     fprintf (stderr, "fatal: ");
255     fprintf (stderr, format, line, arg);
256     fprintf (stderr, "\n");
257     exit (1);
258 }
259
260 static int
261 Getc (FILE *f, int *linep)
262 {
263     int c = getc (f);
264     if (c == '\n')
265         ++(*linep);
266     return c;
267 }
268
269 static void
270 Ungetc (int c, FILE *f, int *linep)
271 {
272     if (c == '\n')
273         --(*linep);
274     ungetc (c, f);
275 }
276
277 static Replace *
278 ReplaceRead (FILE *f, int *linep)
279 {
280     int     c;
281     Replace *r;
282
283     while ((c = Getc (f, linep)) != '@')
284     {
285         if (c == EOF)
286             return 0;
287     }
288     r = ReplaceNew();
289     while ((c = Getc (f, linep)) != '@')
290     {
291         if (c == EOF)
292         {
293             ReplaceDispose (r);
294             return 0;
295         }
296         if (isspace (c))
297             Bail ("%d: invalid character after tag %s", *linep, r->tag->buf);
298         StringAdd (r->tag, c);
299     }
300     if (r->tag->buf[0] == '\0')
301     {
302         ReplaceDispose (r);
303         return 0;
304     }
305     while (isspace ((c = Getc (f, linep))))
306         ;
307     Ungetc (c, f, linep);
308     while ((c = Getc (f, linep)) != '@' && c != EOF)
309         StringAdd (r->text, c);
310     if (c == '@')
311         Ungetc (c, f, linep);
312     while (isspace (StringLast (r->text)))
313         StringDel (r->text);
314     if (StringLast(r->text) == '%')
315     {
316         StringDel (r->text);
317         StringAdd (r->text, ' ');
318     }
319     return r;
320 }
321
322 static ReplaceList *
323 ReplaceListNew (Replace *r, ReplaceList *next)
324 {
325     ReplaceList *l = New (sizeof (ReplaceList));
326     l->r = r;
327     l->next = next;
328     return l;
329 }
330
331 static void
332 ReplaceListDispose (ReplaceList *l)
333 {
334     if (l)
335     {
336         ReplaceListDispose (l->next);
337         ReplaceDispose (l->r);
338         Dispose (l);
339     }
340 }
341
342 static ReplaceSet *
343 ReplaceSetNew (void)
344 {
345     ReplaceSet  *s = New (sizeof (ReplaceSet));
346     s->head = 0;
347     return s;
348 }
349
350 static void
351 ReplaceSetDispose (ReplaceSet *s)
352 {
353     ReplaceListDispose (s->head);
354     Dispose (s);
355 }
356
357 static void
358 ReplaceSetAdd (ReplaceSet *s, Replace *r)
359 {
360     s->head = ReplaceListNew (r, s->head);
361 }
362
363 static Replace *
364 ReplaceSetFind (ReplaceSet *s, char *tag)
365 {
366     ReplaceList *l;
367
368     for (l = s->head; l; l = l->next)
369         if (!strcmp (tag, l->r->tag->buf))
370             return l->r;
371     return 0;
372 }
373
374 static ReplaceSet *
375 ReplaceSetRead (FILE *f, int *linep)
376 {
377     ReplaceSet  *s = ReplaceSetNew ();
378     Replace     *r;
379
380     while ((r = ReplaceRead (f, linep)))
381     {
382         while (ReplaceSetFind (s, r->tag->buf))
383             StringAdd (r->tag, '+');
384         ReplaceSetAdd (s, r);
385     }
386     if (!s->head)
387     {
388         ReplaceSetDispose (s);
389         s = 0;
390     }
391     return s;
392 }
393
394 static SkipStack *
395 SkipStackPush (SkipStack *prev, int skipping)
396 {
397     SkipStack   *ss = New (sizeof (SkipStack));
398     ss->prev = prev;
399     ss->skipping = skipping;
400     return ss;
401 }
402
403 static SkipStack *
404 SkipStackPop (SkipStack *prev)
405 {
406     SkipStack   *ss = prev->prev;
407     Dispose (prev);
408     return ss;
409 }
410
411 static LoopStack *
412 LoopStackPush (LoopStack *prev, FILE *f, char *tag)
413 {
414     LoopStack   *ls = New (sizeof (LoopStack));
415     ls->prev = prev;
416     ls->tag = StringMake (tag);
417     ls->extra = StringNew ();
418     ls->pos = ftell (f);
419     return ls;
420 }
421
422 static LoopStack *
423 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
424 {
425     String      *s = StringMake (ls->tag->buf);
426     LoopStack   *ret = ls;
427     Bool        loop;
428
429     StringAdd (ls->extra, '+');
430     StringAddString (s, ls->extra->buf);
431     loop = ReplaceSetFind (rs, s->buf) != 0;
432     StringDispose (s);
433     if (loop)
434         fseek (f, ls->pos, SEEK_SET);
435     else
436     {
437         ret = ls->prev;
438         StringDispose (ls->tag);
439         StringDispose (ls->extra);
440         Dispose (ls);
441     }
442     return ret;
443 }
444
445 static void
446 LineSkip (FILE *f, int *linep)
447 {
448     int c;
449
450     while ((c = Getc (f, linep)) == '\n')
451         ;
452     Ungetc (c, f, linep);
453 }
454
455 static void
456 DoReplace (FILE *f, int *linep, ReplaceSet *s)
457 {
458     int         c;
459     String      *tag;
460     Replace     *r;
461     SkipStack   *ss = 0;
462     LoopStack   *ls = 0;
463     int         skipping = 0;
464
465     while ((c = Getc (f, linep)) != EOF)
466     {
467         if (c == '@')
468         {
469             tag = StringNew ();
470             while ((c = Getc (f, linep)) != '@')
471             {
472                 if (c == EOF)
473                     abort ();
474                 StringAdd (tag, c);
475             }
476             if (ls)
477                 StringAddString (tag, ls->extra->buf);
478             switch (tag->buf[0]) {
479             case '?':
480                 ss = SkipStackPush (ss, skipping);
481                 if (!ReplaceSetFind (s, tag->buf + 1))
482                     skipping++;
483                 LineSkip (f, linep);
484                 break;
485             case ':':
486                 if (!ss)
487                     abort ();
488                 if (ss->skipping == skipping)
489                     ++skipping;
490                 else
491                     --skipping;
492                 LineSkip (f, linep);
493                 break;
494             case ';':
495                 skipping = ss->skipping;
496                 ss = SkipStackPop (ss);
497                 LineSkip (f, linep);
498                 break;
499             case '{':
500                 ls = LoopStackPush (ls, f, tag->buf + 1);
501                 LineSkip (f, linep);
502                 break;
503             case '}':
504                 ls = LoopStackLoop (s, ls, f);
505                 LineSkip (f, linep);
506                 break;
507             default:
508                 r = ReplaceSetFind (s, tag->buf);
509                 if (r && !skipping)
510                     StringPut (stdout, r->text);
511                 break;
512             }
513             StringDispose (tag);
514         }
515         else if (!skipping)
516             putchar (c);
517     }
518 }
519
520 int
521 main (int argc, char **argv)
522 {
523     FILE        *f;
524     ReplaceSet  *s;
525     int         iline, oline;
526
527     if (!argv[1])
528         Bail ("usage: %*s <template.sgml>", 0, argv[0]);
529     f = fopen (argv[1], "r");
530     if (!f)
531     {
532         Bail ("can't open file %s", 0, argv[1]);
533         exit (1);
534     }
535     iline = 1;
536     while ((s = ReplaceSetRead (stdin, &iline)))
537     {
538         oline = 1;
539         DoReplace (f, &oline, s);
540         ReplaceSetDispose (s);
541         rewind (f);
542     }
543     if (ferror (stdout))
544         Bail ("%s", 0, "error writing output");
545     exit (0);
546 }