4 * Copyright © 2003 Keith Packard
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.
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.
29 typedef enum { False, True } Bool;
37 #define STRING_INIT 128
42 void *m = malloc (size);
49 Reallocate (void *p, int size)
51 void *r = realloc (p, size);
69 s = New (sizeof (String));
70 s->buf = New (STRING_INIT);
71 s->size = STRING_INIT - 1;
78 StringAdd (String *s, char c)
80 if (s->len == s->size)
81 s->buf = Reallocate (s->buf, (s->size *= 2) + 1);
83 s->buf[s->len] = '\0';
87 StringAddString (String *s, char *buf)
90 StringAdd (s, *buf++);
94 StringMake (char *buf)
96 String *s = StringNew ();
97 StringAddString (s, buf);
102 StringDel (String *s)
105 s->buf[--s->len] = '\0';
109 StringPut (FILE *f, String *s)
117 #define StringLast(s) ((s)->len ? (s)->buf[(s)->len - 1] : '\0')
120 StringDispose (String *s)
134 Replace *r = New (sizeof (Replace));
135 r->tag = StringNew ();
136 r->text = StringNew ();
141 ReplaceDispose (Replace *r)
143 StringDispose (r->tag);
144 StringDispose (r->text);
149 Bail (char *format, char *arg)
151 fprintf (stderr, "fatal: ");
152 fprintf (stderr, format, arg);
153 fprintf (stderr, "\n");
158 ReplaceRead (FILE *f)
163 while ((c = getc (f)) != '@')
169 while ((c = getc (f)) != '@')
177 Bail ("invalid character after tag %s", r->tag->buf);
178 StringAdd (r->tag, c);
180 if (r->tag->buf[0] == '\0')
185 while (isspace ((c = getc (f))))
188 while ((c = getc (f)) != '@' && c != EOF)
189 StringAdd (r->text, c);
192 while (isspace (StringLast (r->text)))
197 typedef struct _replaceList {
198 struct _replaceList *next;
203 ReplaceListNew (Replace *r, ReplaceList *next)
205 ReplaceList *l = New (sizeof (ReplaceList));
212 ReplaceListDispose (ReplaceList *l)
216 ReplaceListDispose (l->next);
217 ReplaceDispose (l->r);
229 ReplaceSet *s = New (sizeof (ReplaceSet));
235 ReplaceSetDispose (ReplaceSet *s)
237 ReplaceListDispose (s->head);
242 ReplaceSetAdd (ReplaceSet *s, Replace *r)
244 s->head = ReplaceListNew (r, s->head);
248 ReplaceSetFind (ReplaceSet *s, char *tag)
252 for (l = s->head; l; l = l->next)
253 if (!strcmp (tag, l->r->tag->buf))
259 ReplaceSetRead (FILE *f)
261 ReplaceSet *s = ReplaceSetNew ();
264 while ((r = ReplaceRead (f)))
266 while (ReplaceSetFind (s, r->tag->buf))
267 StringAdd (r->tag, '+');
268 ReplaceSetAdd (s, r);
272 ReplaceSetDispose (s);
278 typedef struct _skipStack {
279 struct _skipStack *prev;
284 SkipStackPush (SkipStack *prev, int skipping)
286 SkipStack *ss = New (sizeof (SkipStack));
288 ss->skipping = skipping;
293 SkipStackPop (SkipStack *prev)
295 SkipStack *ss = prev->prev;
300 typedef struct _loopStack {
301 struct _loopStack *prev;
308 LoopStackPush (LoopStack *prev, FILE *f, char *tag)
310 LoopStack *ls = New (sizeof (LoopStack));
312 ls->tag = StringMake (tag);
313 ls->extra = StringNew ();
319 LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
321 String *s = StringMake (ls->tag->buf);
325 StringAdd (ls->extra, '+');
326 StringAddString (s, ls->extra->buf);
327 loop = ReplaceSetFind (rs, s->buf) != 0;
330 fseek (f, ls->pos, SEEK_SET);
334 StringDispose (ls->tag);
335 StringDispose (ls->extra);
346 while ((c = getc (f)) == '\n')
352 DoReplace (FILE *f, ReplaceSet *s)
361 while ((c = getc (f)) != EOF)
366 while ((c = getc (f)) != '@')
373 StringAddString (tag, ls->extra->buf);
374 switch (tag->buf[0]) {
376 ss = SkipStackPush (ss, skipping);
377 if (!ReplaceSetFind (s, tag->buf + 1))
384 if (ss->skipping == skipping)
391 skipping = ss->skipping;
392 ss = SkipStackPop (ss);
396 ls = LoopStackPush (ls, f, tag->buf + 1);
400 ls = LoopStackLoop (s, ls, f);
404 r = ReplaceSetFind (s, tag->buf);
406 StringPut (stdout, r->text);
417 main (int argc, char **argv)
423 Bail ("usage: %s <template.sgml>", argv[0]);
424 f = fopen (argv[1], "r");
427 Bail ("can't open file %s", argv[1]);
430 while ((s = ReplaceSetRead (stdin)))
433 ReplaceSetDispose (s);
437 Bail ("%s", "error writing output");