Blame doc/edit-sgml.c

Packit 352660
/*
Packit 352660
 * fontconfig/doc/edit-sgml.c
Packit 352660
 *
Packit 352660
 * Copyright © 2003 Keith Packard
Packit 352660
 *
Packit 352660
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 352660
 * documentation for any purpose is hereby granted without fee, provided that
Packit 352660
 * the above copyright notice appear in all copies and that both that
Packit 352660
 * copyright notice and this permission notice appear in supporting
Packit 352660
 * documentation, and that the name of the author(s) not be used in
Packit 352660
 * advertising or publicity pertaining to distribution of the software without
Packit 352660
 * specific, written prior permission.  The authors make no
Packit 352660
 * representations about the suitability of this software for any purpose.  It
Packit 352660
 * is provided "as is" without express or implied warranty.
Packit 352660
 *
Packit 352660
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit 352660
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit 352660
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit 352660
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit 352660
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit 352660
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
Packit 352660
 * PERFORMANCE OF THIS SOFTWARE.
Packit 352660
 */
Packit 352660
Packit 352660
#include <stdio.h>
Packit 352660
#include <stdlib.h>
Packit 352660
#include <string.h>
Packit 352660
#include <ctype.h>
Packit 352660
Packit 352660
static void *
Packit 352660
New (int size);
Packit 352660
Packit 352660
static void *
Packit 352660
Reallocate (void *p, int size);
Packit 352660
Packit 352660
static void
Packit 352660
Dispose (void *p);
Packit 352660
Packit 352660
typedef enum { False, True } Bool;
Packit 352660
Packit 352660
typedef struct {
Packit 352660
    char    *buf;
Packit 352660
    int	    size;
Packit 352660
    int	    len;
Packit 352660
} String;
Packit 352660
Packit 352660
static String *
Packit 352660
StringNew (void);
Packit 352660
Packit 352660
static void
Packit 352660
StringAdd (String *s, char c);
Packit 352660
Packit 352660
static void
Packit 352660
StringAddString (String *s, char *buf);
Packit 352660
Packit 352660
static String *
Packit 352660
StringMake (char *buf);
Packit 352660
Packit 352660
static void
Packit 352660
StringDel (String *s);
Packit 352660
Packit 352660
static void
Packit 352660
StringPut (FILE *f, String *s);
Packit 352660
Packit 352660
static void
Packit 352660
StringDispose (String *s);
Packit 352660
Packit 352660
typedef struct {
Packit 352660
    String  *tag;
Packit 352660
    String  *text;
Packit 352660
} Replace;
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceNew (void);
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceDispose (Replace *r);
Packit 352660
Packit 352660
static void
Packit 352660
Bail (const char *format, int line, const char *arg);
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceRead (FILE *f, int *linep);
Packit 352660
Packit 352660
typedef struct _replaceList {
Packit 352660
    struct _replaceList	*next;
Packit 352660
    Replace		*r;
Packit 352660
} ReplaceList;
Packit 352660
Packit 352660
static ReplaceList *
Packit 352660
ReplaceListNew (Replace *r, ReplaceList *next);
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceListDispose (ReplaceList *l);
Packit 352660
Packit 352660
typedef struct {
Packit 352660
    ReplaceList	*head;
Packit 352660
} ReplaceSet;
Packit 352660
Packit 352660
static ReplaceSet *
Packit 352660
ReplaceSetNew (void);
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceSetDispose (ReplaceSet *s);
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceSetAdd (ReplaceSet *s, Replace *r);
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceSetFind (ReplaceSet *s, char *tag);
Packit 352660
Packit 352660
static ReplaceSet *
Packit 352660
ReplaceSetRead (FILE *f, int *linep);
Packit 352660
Packit 352660
typedef struct _skipStack {
Packit 352660
    struct _skipStack	*prev;
Packit 352660
    int			skipping;
Packit 352660
} SkipStack;
Packit 352660
Packit 352660
static SkipStack *
Packit 352660
SkipStackPush (SkipStack *prev, int skipping);
Packit 352660
Packit 352660
static SkipStack *
Packit 352660
SkipStackPop (SkipStack *prev);
Packit 352660
Packit 352660
typedef struct _loopStack {
Packit 352660
    struct _loopStack	*prev;
Packit 352660
    String		*tag;
Packit 352660
    String		*extra;
Packit 352660
    long		pos;
Packit 352660
} LoopStack;
Packit 352660
Packit 352660
static LoopStack *
Packit 352660
LoopStackPush (LoopStack *prev, FILE *f, char *tag);
Packit 352660
Packit 352660
static LoopStack *
Packit 352660
LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f);
Packit 352660
Packit 352660
static void
Packit 352660
LineSkip (FILE *f, int *linep);
Packit 352660
Packit 352660
static void
Packit 352660
DoReplace (FILE *f, int *linep, ReplaceSet *s);
Packit 352660
Packit 352660
#define STRING_INIT 128
Packit 352660
Packit 352660
static void *
Packit 352660
New (int size)
Packit 352660
{
Packit 352660
    void    *m = malloc (size);
Packit 352660
    if (!m)
Packit 352660
	abort ();
Packit 352660
    return m;
Packit 352660
}
Packit 352660
Packit 352660
static void *
Packit 352660
Reallocate (void *p, int size)
Packit 352660
{
Packit 352660
    void    *r = realloc (p, size);
Packit 352660
Packit 352660
    if (!r)
Packit 352660
	abort ();
Packit 352660
    return r;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
Dispose (void *p)
Packit 352660
{
Packit 352660
    free (p);
Packit 352660
}
Packit 352660
Packit 352660
static String *
Packit 352660
StringNew (void)
Packit 352660
{
Packit 352660
    String  *s;
Packit 352660
Packit 352660
    s = New (sizeof (String));
Packit 352660
    s->buf = New (STRING_INIT);
Packit 352660
    s->size = STRING_INIT - 1;
Packit 352660
    s->buf[0] = '\0';
Packit 352660
    s->len = 0;
Packit 352660
    return s;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
StringAdd (String *s, char c)
Packit 352660
{
Packit 352660
    if (s->len == s->size)
Packit 352660
	s->buf = Reallocate (s->buf, (s->size *= 2) + 1);
Packit 352660
    s->buf[s->len++] = c;
Packit 352660
    s->buf[s->len] = '\0';
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
StringAddString (String *s, char *buf)
Packit 352660
{
Packit 352660
    while (*buf)
Packit 352660
	StringAdd (s, *buf++);
Packit 352660
}
Packit 352660
Packit 352660
static String *
Packit 352660
StringMake (char *buf)
Packit 352660
{
Packit 352660
    String  *s = StringNew ();
Packit 352660
    StringAddString (s, buf);
Packit 352660
    return s;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
StringDel (String *s)
Packit 352660
{
Packit 352660
    if (s->len)
Packit 352660
	s->buf[--s->len] = '\0';
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
StringPut (FILE *f, String *s)
Packit 352660
{
Packit 352660
    char    *b = s->buf;
Packit 352660
Packit 352660
    while (*b)
Packit 352660
	putc (*b++, f);
Packit 352660
}
Packit 352660
Packit 352660
#define StringLast(s)	((s)->len ? (s)->buf[(s)->len - 1] : '\0')
Packit 352660
Packit 352660
static void
Packit 352660
StringDispose (String *s)
Packit 352660
{
Packit 352660
    Dispose (s->buf);
Packit 352660
    Dispose (s);
Packit 352660
}
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceNew (void)
Packit 352660
{
Packit 352660
    Replace *r = New (sizeof (Replace));
Packit 352660
    r->tag = StringNew ();
Packit 352660
    r->text = StringNew ();
Packit 352660
    return r;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceDispose (Replace *r)
Packit 352660
{
Packit 352660
    StringDispose (r->tag);
Packit 352660
    StringDispose (r->text);
Packit 352660
    Dispose (r);
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
Bail (const char *format, int line, const char *arg)
Packit 352660
{
Packit 352660
    fprintf (stderr, "fatal: ");
Packit 352660
    fprintf (stderr, format, line, arg);
Packit 352660
    fprintf (stderr, "\n");
Packit 352660
    exit (1);
Packit 352660
}
Packit 352660
Packit 352660
static int
Packit 352660
Getc (FILE *f, int *linep)
Packit 352660
{
Packit 352660
    int	c = getc (f);
Packit 352660
    if (c == '\n')
Packit 352660
	++(*linep);
Packit 352660
    return c;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
Ungetc (int c, FILE *f, int *linep)
Packit 352660
{
Packit 352660
    if (c == '\n')
Packit 352660
	--(*linep);
Packit 352660
    ungetc (c, f);
Packit 352660
}
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceRead (FILE *f, int *linep)
Packit 352660
{
Packit 352660
    int	    c;
Packit 352660
    Replace *r;
Packit 352660
Packit 352660
    while ((c = Getc (f, linep)) != '@')
Packit 352660
    {
Packit 352660
	if (c == EOF)
Packit 352660
	    return 0;
Packit 352660
    }
Packit 352660
    r = ReplaceNew();
Packit 352660
    while ((c = Getc (f, linep)) != '@')
Packit 352660
    {
Packit 352660
	if (c == EOF)
Packit 352660
	{
Packit 352660
	    ReplaceDispose (r);
Packit 352660
	    return 0;
Packit 352660
	}
Packit 352660
	if (isspace (c))
Packit 352660
	    Bail ("%d: invalid character after tag %s", *linep, r->tag->buf);
Packit 352660
	StringAdd (r->tag, c);
Packit 352660
    }
Packit 352660
    if (r->tag->buf[0] == '\0')
Packit 352660
    {
Packit 352660
	ReplaceDispose (r);
Packit 352660
	return 0;
Packit 352660
    }
Packit 352660
    while (isspace ((c = Getc (f, linep))))
Packit 352660
	;
Packit 352660
    Ungetc (c, f, linep);
Packit 352660
    while ((c = Getc (f, linep)) != '@' && c != EOF)
Packit 352660
	StringAdd (r->text, c);
Packit 352660
    if (c == '@')
Packit 352660
	Ungetc (c, f, linep);
Packit 352660
    while (isspace (StringLast (r->text)))
Packit 352660
	StringDel (r->text);
Packit 352660
    if (StringLast(r->text) == '%')
Packit 352660
    {
Packit 352660
	StringDel (r->text);
Packit 352660
	StringAdd (r->text, ' ');
Packit 352660
    }
Packit 352660
    return r;
Packit 352660
}
Packit 352660
Packit 352660
static ReplaceList *
Packit 352660
ReplaceListNew (Replace *r, ReplaceList *next)
Packit 352660
{
Packit 352660
    ReplaceList	*l = New (sizeof (ReplaceList));
Packit 352660
    l->r = r;
Packit 352660
    l->next = next;
Packit 352660
    return l;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceListDispose (ReplaceList *l)
Packit 352660
{
Packit 352660
    if (l)
Packit 352660
    {
Packit 352660
	ReplaceListDispose (l->next);
Packit 352660
	ReplaceDispose (l->r);
Packit 352660
	Dispose (l);
Packit 352660
    }
Packit 352660
}
Packit 352660
Packit 352660
static ReplaceSet *
Packit 352660
ReplaceSetNew (void)
Packit 352660
{
Packit 352660
    ReplaceSet	*s = New (sizeof (ReplaceSet));
Packit 352660
    s->head = 0;
Packit 352660
    return s;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceSetDispose (ReplaceSet *s)
Packit 352660
{
Packit 352660
    ReplaceListDispose (s->head);
Packit 352660
    Dispose (s);
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
ReplaceSetAdd (ReplaceSet *s, Replace *r)
Packit 352660
{
Packit 352660
    s->head = ReplaceListNew (r, s->head);
Packit 352660
}
Packit 352660
Packit 352660
static Replace *
Packit 352660
ReplaceSetFind (ReplaceSet *s, char *tag)
Packit 352660
{
Packit 352660
    ReplaceList	*l;
Packit 352660
Packit 352660
    for (l = s->head; l; l = l->next)
Packit 352660
	if (!strcmp (tag, l->r->tag->buf))
Packit 352660
	    return l->r;
Packit 352660
    return 0;
Packit 352660
}
Packit 352660
Packit 352660
static ReplaceSet *
Packit 352660
ReplaceSetRead (FILE *f, int *linep)
Packit 352660
{
Packit 352660
    ReplaceSet	*s = ReplaceSetNew ();
Packit 352660
    Replace	*r;
Packit 352660
Packit 352660
    while ((r = ReplaceRead (f, linep)))
Packit 352660
    {
Packit 352660
	while (ReplaceSetFind (s, r->tag->buf))
Packit 352660
	    StringAdd (r->tag, '+');
Packit 352660
	ReplaceSetAdd (s, r);
Packit 352660
    }
Packit 352660
    if (!s->head)
Packit 352660
    {
Packit 352660
	ReplaceSetDispose (s);
Packit 352660
	s = 0;
Packit 352660
    }
Packit 352660
    return s;
Packit 352660
}
Packit 352660
Packit 352660
static SkipStack *
Packit 352660
SkipStackPush (SkipStack *prev, int skipping)
Packit 352660
{
Packit 352660
    SkipStack	*ss = New (sizeof (SkipStack));
Packit 352660
    ss->prev = prev;
Packit 352660
    ss->skipping = skipping;
Packit 352660
    return ss;
Packit 352660
}
Packit 352660
Packit 352660
static SkipStack *
Packit 352660
SkipStackPop (SkipStack *prev)
Packit 352660
{
Packit 352660
    SkipStack	*ss = prev->prev;
Packit 352660
    Dispose (prev);
Packit 352660
    return ss;
Packit 352660
}
Packit 352660
Packit 352660
static LoopStack *
Packit 352660
LoopStackPush (LoopStack *prev, FILE *f, char *tag)
Packit 352660
{
Packit 352660
    LoopStack	*ls = New (sizeof (LoopStack));
Packit 352660
    ls->prev = prev;
Packit 352660
    ls->tag = StringMake (tag);
Packit 352660
    ls->extra = StringNew ();
Packit 352660
    ls->pos = ftell (f);
Packit 352660
    return ls;
Packit 352660
}
Packit 352660
Packit 352660
static LoopStack *
Packit 352660
LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
Packit 352660
{
Packit 352660
    String	*s = StringMake (ls->tag->buf);
Packit 352660
    LoopStack	*ret = ls;
Packit 352660
    Bool	loop;
Packit 352660
Packit 352660
    StringAdd (ls->extra, '+');
Packit 352660
    StringAddString (s, ls->extra->buf);
Packit 352660
    loop = ReplaceSetFind (rs, s->buf) != 0;
Packit 352660
    StringDispose (s);
Packit 352660
    if (loop)
Packit 352660
	fseek (f, ls->pos, SEEK_SET);
Packit 352660
    else
Packit 352660
    {
Packit 352660
	ret = ls->prev;
Packit 352660
	StringDispose (ls->tag);
Packit 352660
	StringDispose (ls->extra);
Packit 352660
	Dispose (ls);
Packit 352660
    }
Packit 352660
    return ret;
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
LineSkip (FILE *f, int *linep)
Packit 352660
{
Packit 352660
    int	c;
Packit 352660
Packit 352660
    while ((c = Getc (f, linep)) == '\n')
Packit 352660
	;
Packit 352660
    Ungetc (c, f, linep);
Packit 352660
}
Packit 352660
Packit 352660
static void
Packit 352660
DoReplace (FILE *f, int *linep, ReplaceSet *s)
Packit 352660
{
Packit 352660
    int		c;
Packit 352660
    String	*tag;
Packit 352660
    Replace	*r;
Packit 352660
    SkipStack	*ss = 0;
Packit 352660
    LoopStack	*ls = 0;
Packit 352660
    int		skipping = 0;
Packit 352660
Packit 352660
    while ((c = Getc (f, linep)) != EOF)
Packit 352660
    {
Packit 352660
	if (c == '@')
Packit 352660
	{
Packit 352660
	    tag = StringNew ();
Packit 352660
	    while ((c = Getc (f, linep)) != '@')
Packit 352660
	    {
Packit 352660
		if (c == EOF)
Packit 352660
		    abort ();
Packit 352660
		StringAdd (tag, c);
Packit 352660
	    }
Packit 352660
	    if (ls)
Packit 352660
		StringAddString (tag, ls->extra->buf);
Packit 352660
	    switch (tag->buf[0]) {
Packit 352660
	    case '?':
Packit 352660
		ss = SkipStackPush (ss, skipping);
Packit 352660
		if (!ReplaceSetFind (s, tag->buf + 1))
Packit 352660
		    skipping++;
Packit 352660
		LineSkip (f, linep);
Packit 352660
		break;
Packit 352660
	    case ':':
Packit 352660
		if (!ss)
Packit 352660
		    abort ();
Packit 352660
		if (ss->skipping == skipping)
Packit 352660
		    ++skipping;
Packit 352660
		else
Packit 352660
		    --skipping;
Packit 352660
		LineSkip (f, linep);
Packit 352660
		break;
Packit 352660
	    case ';':
Packit 352660
		skipping = ss->skipping;
Packit 352660
		ss = SkipStackPop (ss);
Packit 352660
		LineSkip (f, linep);
Packit 352660
		break;
Packit 352660
	    case '{':
Packit 352660
		ls = LoopStackPush (ls, f, tag->buf + 1);
Packit 352660
		LineSkip (f, linep);
Packit 352660
		break;
Packit 352660
	    case '}':
Packit 352660
		ls = LoopStackLoop (s, ls, f);
Packit 352660
		LineSkip (f, linep);
Packit 352660
		break;
Packit 352660
	    default:
Packit 352660
		r = ReplaceSetFind (s, tag->buf);
Packit 352660
		if (r && !skipping)
Packit 352660
		    StringPut (stdout, r->text);
Packit 352660
		break;
Packit 352660
	    }
Packit 352660
	    StringDispose (tag);
Packit 352660
	}
Packit 352660
	else if (!skipping)
Packit 352660
	    putchar (c);
Packit 352660
    }
Packit 352660
}
Packit 352660
Packit 352660
int
Packit 352660
main (int argc, char **argv)
Packit 352660
{
Packit 352660
    FILE	*f;
Packit 352660
    ReplaceSet	*s;
Packit 352660
    int		iline, oline;
Packit 352660
Packit 352660
    if (!argv[1])
Packit 352660
	Bail ("usage: %*s <template.sgml>", 0, argv[0]);
Packit 352660
    f = fopen (argv[1], "r");
Packit 352660
    if (!f)
Packit 352660
    {
Packit 352660
	Bail ("can't open file %s", 0, argv[1]);
Packit 352660
	exit (1);
Packit 352660
    }
Packit 352660
    iline = 1;
Packit 352660
    while ((s = ReplaceSetRead (stdin, &iline)))
Packit 352660
    {
Packit 352660
	oline = 1;
Packit 352660
	DoReplace (f, &oline, s);
Packit 352660
	ReplaceSetDispose (s);
Packit 352660
	rewind (f);
Packit 352660
    }
Packit 352660
    if (ferror (stdout))
Packit 352660
	Bail ("%s", 0, "error writing output");
Packit 352660
    exit (0);
Packit 352660
}