diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/edit-sgml.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/doc/edit-sgml.c b/doc/edit-sgml.c new file mode 100644 index 0000000..6e04e1c --- /dev/null +++ b/doc/edit-sgml.c @@ -0,0 +1,426 @@ +/* + * $Id$ + * + * Copyright © 2003 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +typedef enum { False, True } Bool; + +typedef struct { + char *buf; + int size; + int len; +} String; + +#define STRING_INIT 128 + +void * +New (int size) +{ + void *m = malloc (size); + if (!m) + abort (); + return m; +} + +void * +Reallocate (void *p, int size) +{ + void *r = realloc (p, size); + + if (!r) + abort (); + return r; +} + +void +Dispose (void *p) +{ + free (p); +} + +String * +StringNew (void) +{ + String *s; + + s = New (sizeof (String)); + s->buf = New (STRING_INIT); + s->size = STRING_INIT - 1; + s->buf[0] = '\0'; + s->len = 0; + return s; +} + +void +StringAdd (String *s, char c) +{ + if (s->len == s->size) + s->buf = Reallocate (s->buf, (s->size *= 2) + 1); + s->buf[s->len++] = c; + s->buf[s->len] = '\0'; +} + +void +StringAddString (String *s, char *buf) +{ + while (*buf) + StringAdd (s, *buf++); +} + +String * +StringMake (char *buf) +{ + String *s = StringNew (); + StringAddString (s, buf); + return s; +} + +void +StringDel (String *s) +{ + if (s->len) + s->buf[--s->len] = '\0'; +} + +void +StringPut (FILE *f, String *s) +{ + char *b = s->buf; + + while (*b) + putc (*b++, f); +} + +#define StringLast(s) ((s)->len ? (s)->buf[(s)->len - 1] : '\0') + +void +StringDispose (String *s) +{ + Dispose (s->buf); + Dispose (s); +} + +typedef struct { + String *tag; + String *text; +} Replace; + +Replace * +ReplaceNew (void) +{ + Replace *r = New (sizeof (Replace)); + r->tag = StringNew (); + r->text = StringNew (); + return r; +} + +void +ReplaceDispose (Replace *r) +{ + StringDispose (r->tag); + StringDispose (r->text); + Dispose (r); +} + +Replace * +ReplaceRead (FILE *f) +{ + int c; + Replace *r; + + while ((c = getc (f)) != '@') + { + if (c == EOF) + return 0; + } + r = ReplaceNew(); + while ((c = getc (f)) != '@') + { + if (c == EOF) + { + ReplaceDispose (r); + return 0; + } + StringAdd (r->tag, c); + } + if (r->tag->buf[0] == '\0') + { + ReplaceDispose (r); + return 0; + } + while (isspace ((c = getc (f)))) + ; + ungetc (c, f); + while ((c = getc (f)) != '@' && c != EOF) + StringAdd (r->text, c); + if (c == '@') + ungetc (c, f); + while (StringLast (r->text) == '\n') + StringDel (r->text); + return r; +} + +typedef struct _replaceList { + struct _replaceList *next; + Replace *r; +} ReplaceList; + +ReplaceList * +ReplaceListNew (Replace *r, ReplaceList *next) +{ + ReplaceList *l = New (sizeof (ReplaceList)); + l->r = r; + l->next = next; + return l; +} + +void +ReplaceListDispose (ReplaceList *l) +{ + if (l) + { + ReplaceListDispose (l->next); + ReplaceDispose (l->r); + Dispose (l); + } +} + +typedef struct { + ReplaceList *head; +} ReplaceSet; + +ReplaceSet * +ReplaceSetNew (void) +{ + ReplaceSet *s = New (sizeof (ReplaceSet)); + s->head = 0; + return s; +} + +void +ReplaceSetDispose (ReplaceSet *s) +{ + ReplaceListDispose (s->head); + Dispose (s); +} + +void +ReplaceSetAdd (ReplaceSet *s, Replace *r) +{ + s->head = ReplaceListNew (r, s->head); +} + +Replace * +ReplaceSetFind (ReplaceSet *s, char *tag) +{ + ReplaceList *l; + + for (l = s->head; l; l = l->next) + if (!strcmp (tag, l->r->tag->buf)) + return l->r; + return 0; +} + +ReplaceSet * +ReplaceSetRead (FILE *f) +{ + ReplaceSet *s = ReplaceSetNew (); + Replace *r; + + while ((r = ReplaceRead (f))) + { + while (ReplaceSetFind (s, r->tag->buf)) + StringAdd (r->tag, '+'); + ReplaceSetAdd (s, r); + } + if (!s->head) + { + ReplaceSetDispose (s); + s = 0; + } + return s; +} + +typedef struct _skipStack { + struct _skipStack *prev; + int skipping; +} SkipStack; + +SkipStack * +SkipStackPush (SkipStack *prev, int skipping) +{ + SkipStack *ss = New (sizeof (SkipStack)); + ss->prev = prev; + ss->skipping = skipping; + return ss; +} + +SkipStack * +SkipStackPop (SkipStack *prev) +{ + SkipStack *ss = prev->prev; + Dispose (prev); + return ss; +} + +typedef struct _loopStack { + struct _loopStack *prev; + String *tag; + String *extra; + long pos; +} LoopStack; + +LoopStack * +LoopStackPush (LoopStack *prev, FILE *f, char *tag) +{ + LoopStack *ls = New (sizeof (LoopStack)); + ls->prev = prev; + ls->tag = StringMake (tag); + ls->extra = StringNew (); + ls->pos = ftell (f); + return ls; +} + +LoopStack * +LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f) +{ + String *s = StringMake (ls->tag->buf); + LoopStack *ret = ls; + Bool loop; + + StringAdd (ls->extra, '+'); + StringAddString (s, ls->extra->buf); + loop = ReplaceSetFind (rs, s->buf) != 0; + StringDispose (s); + if (loop) + fseek (f, ls->pos, SEEK_SET); + else + { + ret = ls->prev; + StringDispose (ls->tag); + StringDispose (ls->extra); + Dispose (ls); + } + return ret; +} + +void +LineSkip (FILE *f) +{ + int c; + + while ((c = getc (f)) == '\n') + ; + ungetc (c, f); +} + +void +DoReplace (FILE *f, ReplaceSet *s) +{ + int c; + String *tag; + Replace *r; + SkipStack *ss = 0; + LoopStack *ls = 0; + int skipping = 0; + + while ((c = getc (f)) != EOF) + { + if (c == '@') + { + tag = StringNew (); + while ((c = getc (f)) != '@') + { + if (c == EOF) + abort (); + StringAdd (tag, c); + } + if (ls) + StringAddString (tag, ls->extra->buf); + switch (tag->buf[0]) { + case '?': + ss = SkipStackPush (ss, skipping); + if (!ReplaceSetFind (s, tag->buf + 1)) + skipping++; + LineSkip (f); + break; + case ':': + if (!ss) + abort (); + if (ss->skipping == skipping) + ++skipping; + else + --skipping; + LineSkip (f); + break; + case ';': + skipping = ss->skipping; + ss = SkipStackPop (ss); + LineSkip (f); + break; + case '{': + ls = LoopStackPush (ls, f, tag->buf + 1); + LineSkip (f); + break; + case '}': + ls = LoopStackLoop (s, ls, f); + LineSkip (f); + break; + default: + r = ReplaceSetFind (s, tag->buf); + if (r && !skipping) + StringPut (stdout, r->text); + break; + } + StringDispose (tag); + } + else if (!skipping) + putchar (c); + } +} + +int +main (int argc, char **argv) +{ + FILE *f; + ReplaceSet *s; + + f = fopen (argv[1], "r"); + if (!f) + { + perror (argv[1]); + exit (1); + } + while ((s = ReplaceSetRead (stdin))) + { + DoReplace (f, s); + ReplaceSetDispose (s); + rewind (f); + } + if (ferror (stdout)) + exit (1); + exit (0); +} |