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