]> git.wh0rd.org - fontconfig.git/blob - doc/edit-sgml.c
Add confdir.sgml to .cvsignore
[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 <string.h>
28 #include <ctype.h>
29
30 typedef enum { False, True } Bool;
31
32 typedef struct {
33 char *buf;
34 int size;
35 int len;
36 } String;
37
38 #define STRING_INIT 128
39
40 void *
41 New (int size)
42 {
43 void *m = malloc (size);
44 if (!m)
45 abort ();
46 return m;
47 }
48
49 void *
50 Reallocate (void *p, int size)
51 {
52 void *r = realloc (p, size);
53
54 if (!r)
55 abort ();
56 return r;
57 }
58
59 void
60 Dispose (void *p)
61 {
62 free (p);
63 }
64
65 String *
66 StringNew (void)
67 {
68 String *s;
69
70 s = New (sizeof (String));
71 s->buf = New (STRING_INIT);
72 s->size = STRING_INIT - 1;
73 s->buf[0] = '\0';
74 s->len = 0;
75 return s;
76 }
77
78 void
79 StringAdd (String *s, char c)
80 {
81 if (s->len == s->size)
82 s->buf = Reallocate (s->buf, (s->size *= 2) + 1);
83 s->buf[s->len++] = c;
84 s->buf[s->len] = '\0';
85 }
86
87 void
88 StringAddString (String *s, char *buf)
89 {
90 while (*buf)
91 StringAdd (s, *buf++);
92 }
93
94 String *
95 StringMake (char *buf)
96 {
97 String *s = StringNew ();
98 StringAddString (s, buf);
99 return s;
100 }
101
102 void
103 StringDel (String *s)
104 {
105 if (s->len)
106 s->buf[--s->len] = '\0';
107 }
108
109 void
110 StringPut (FILE *f, String *s)
111 {
112 char *b = s->buf;
113
114 while (*b)
115 putc (*b++, f);
116 }
117
118 #define StringLast(s) ((s)->len ? (s)->buf[(s)->len - 1] : '\0')
119
120 void
121 StringDispose (String *s)
122 {
123 Dispose (s->buf);
124 Dispose (s);
125 }
126
127 typedef struct {
128 String *tag;
129 String *text;
130 } Replace;
131
132 Replace *
133 ReplaceNew (void)
134 {
135 Replace *r = New (sizeof (Replace));
136 r->tag = StringNew ();
137 r->text = StringNew ();
138 return r;
139 }
140
141 void
142 ReplaceDispose (Replace *r)
143 {
144 StringDispose (r->tag);
145 StringDispose (r->text);
146 Dispose (r);
147 }
148
149 void
150 Bail (char *format, char *arg)
151 {
152 fprintf (stderr, "fatal: ");
153 fprintf (stderr, format, arg);
154 fprintf (stderr, "\n");
155 exit (1);
156 }
157
158 Replace *
159 ReplaceRead (FILE *f)
160 {
161 int c;
162 Replace *r;
163
164 while ((c = getc (f)) != '@')
165 {
166 if (c == EOF)
167 return 0;
168 }
169 r = ReplaceNew();
170 while ((c = getc (f)) != '@')
171 {
172 if (c == EOF)
173 {
174 ReplaceDispose (r);
175 return 0;
176 }
177 if (isspace (c))
178 Bail ("invalid character after tag %s", r->tag->buf);
179 StringAdd (r->tag, c);
180 }
181 if (r->tag->buf[0] == '\0')
182 {
183 ReplaceDispose (r);
184 return 0;
185 }
186 while (isspace ((c = getc (f))))
187 ;
188 ungetc (c, f);
189 while ((c = getc (f)) != '@' && c != EOF)
190 StringAdd (r->text, c);
191 if (c == '@')
192 ungetc (c, f);
193 while (isspace (StringLast (r->text)))
194 StringDel (r->text);
195 return r;
196 }
197
198 typedef struct _replaceList {
199 struct _replaceList *next;
200 Replace *r;
201 } ReplaceList;
202
203 ReplaceList *
204 ReplaceListNew (Replace *r, ReplaceList *next)
205 {
206 ReplaceList *l = New (sizeof (ReplaceList));
207 l->r = r;
208 l->next = next;
209 return l;
210 }
211
212 void
213 ReplaceListDispose (ReplaceList *l)
214 {
215 if (l)
216 {
217 ReplaceListDispose (l->next);
218 ReplaceDispose (l->r);
219 Dispose (l);
220 }
221 }
222
223 typedef struct {
224 ReplaceList *head;
225 } ReplaceSet;
226
227 ReplaceSet *
228 ReplaceSetNew (void)
229 {
230 ReplaceSet *s = New (sizeof (ReplaceSet));
231 s->head = 0;
232 return s;
233 }
234
235 void
236 ReplaceSetDispose (ReplaceSet *s)
237 {
238 ReplaceListDispose (s->head);
239 Dispose (s);
240 }
241
242 void
243 ReplaceSetAdd (ReplaceSet *s, Replace *r)
244 {
245 s->head = ReplaceListNew (r, s->head);
246 }
247
248 Replace *
249 ReplaceSetFind (ReplaceSet *s, char *tag)
250 {
251 ReplaceList *l;
252
253 for (l = s->head; l; l = l->next)
254 if (!strcmp (tag, l->r->tag->buf))
255 return l->r;
256 return 0;
257 }
258
259 ReplaceSet *
260 ReplaceSetRead (FILE *f)
261 {
262 ReplaceSet *s = ReplaceSetNew ();
263 Replace *r;
264
265 while ((r = ReplaceRead (f)))
266 {
267 while (ReplaceSetFind (s, r->tag->buf))
268 StringAdd (r->tag, '+');
269 ReplaceSetAdd (s, r);
270 }
271 if (!s->head)
272 {
273 ReplaceSetDispose (s);
274 s = 0;
275 }
276 return s;
277 }
278
279 typedef struct _skipStack {
280 struct _skipStack *prev;
281 int skipping;
282 } SkipStack;
283
284 SkipStack *
285 SkipStackPush (SkipStack *prev, int skipping)
286 {
287 SkipStack *ss = New (sizeof (SkipStack));
288 ss->prev = prev;
289 ss->skipping = skipping;
290 return ss;
291 }
292
293 SkipStack *
294 SkipStackPop (SkipStack *prev)
295 {
296 SkipStack *ss = prev->prev;
297 Dispose (prev);
298 return ss;
299 }
300
301 typedef struct _loopStack {
302 struct _loopStack *prev;
303 String *tag;
304 String *extra;
305 long pos;
306 } LoopStack;
307
308 LoopStack *
309 LoopStackPush (LoopStack *prev, FILE *f, char *tag)
310 {
311 LoopStack *ls = New (sizeof (LoopStack));
312 ls->prev = prev;
313 ls->tag = StringMake (tag);
314 ls->extra = StringNew ();
315 ls->pos = ftell (f);
316 return ls;
317 }
318
319 LoopStack *
320 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
321 {
322 String *s = StringMake (ls->tag->buf);
323 LoopStack *ret = ls;
324 Bool loop;
325
326 StringAdd (ls->extra, '+');
327 StringAddString (s, ls->extra->buf);
328 loop = ReplaceSetFind (rs, s->buf) != 0;
329 StringDispose (s);
330 if (loop)
331 fseek (f, ls->pos, SEEK_SET);
332 else
333 {
334 ret = ls->prev;
335 StringDispose (ls->tag);
336 StringDispose (ls->extra);
337 Dispose (ls);
338 }
339 return ret;
340 }
341
342 void
343 LineSkip (FILE *f)
344 {
345 int c;
346
347 while ((c = getc (f)) == '\n')
348 ;
349 ungetc (c, f);
350 }
351
352 void
353 DoReplace (FILE *f, ReplaceSet *s)
354 {
355 int c;
356 String *tag;
357 Replace *r;
358 SkipStack *ss = 0;
359 LoopStack *ls = 0;
360 int skipping = 0;
361
362 while ((c = getc (f)) != EOF)
363 {
364 if (c == '@')
365 {
366 tag = StringNew ();
367 while ((c = getc (f)) != '@')
368 {
369 if (c == EOF)
370 abort ();
371 StringAdd (tag, c);
372 }
373 if (ls)
374 StringAddString (tag, ls->extra->buf);
375 switch (tag->buf[0]) {
376 case '?':
377 ss = SkipStackPush (ss, skipping);
378 if (!ReplaceSetFind (s, tag->buf + 1))
379 skipping++;
380 LineSkip (f);
381 break;
382 case ':':
383 if (!ss)
384 abort ();
385 if (ss->skipping == skipping)
386 ++skipping;
387 else
388 --skipping;
389 LineSkip (f);
390 break;
391 case ';':
392 skipping = ss->skipping;
393 ss = SkipStackPop (ss);
394 LineSkip (f);
395 break;
396 case '{':
397 ls = LoopStackPush (ls, f, tag->buf + 1);
398 LineSkip (f);
399 break;
400 case '}':
401 ls = LoopStackLoop (s, ls, f);
402 LineSkip (f);
403 break;
404 default:
405 r = ReplaceSetFind (s, tag->buf);
406 if (r && !skipping)
407 StringPut (stdout, r->text);
408 break;
409 }
410 StringDispose (tag);
411 }
412 else if (!skipping)
413 putchar (c);
414 }
415 }
416
417 int
418 main (int argc, char **argv)
419 {
420 FILE *f;
421 ReplaceSet *s;
422
423 if (!argv[1])
424 Bail ("usage: %s <template.sgml>", argv[0]);
425 f = fopen (argv[1], "r");
426 if (!f)
427 {
428 Bail ("can't open file %s", argv[1]);
429 exit (1);
430 }
431 while ((s = ReplaceSetRead (stdin)))
432 {
433 DoReplace (f, s);
434 ReplaceSetDispose (s);
435 rewind (f);
436 }
437 if (ferror (stdout))
438 Bail ("%s", "error writing output");
439 exit (0);
440 }