Track line numbers in sgml edit tool input.

Errors in the documentation can be hard to find unless the tool outputs the
line number where the problem exists.
This commit is contained in:
Keith Packard 2007-11-03 21:55:39 -07:00
parent 088b582a26
commit b868a14473
1 changed files with 52 additions and 33 deletions

View File

@ -77,10 +77,10 @@ static void
ReplaceDispose (Replace *r); ReplaceDispose (Replace *r);
static void static void
Bail (const char *format, const char *arg); Bail (const char *format, int line, const char *arg);
static Replace * static Replace *
ReplaceRead (FILE *f); ReplaceRead (FILE *f, int *linep);
typedef struct _replaceList { typedef struct _replaceList {
struct _replaceList *next; struct _replaceList *next;
@ -110,7 +110,7 @@ static Replace *
ReplaceSetFind (ReplaceSet *s, char *tag); ReplaceSetFind (ReplaceSet *s, char *tag);
static ReplaceSet * static ReplaceSet *
ReplaceSetRead (FILE *f); ReplaceSetRead (FILE *f, int *linep);
typedef struct _skipStack { typedef struct _skipStack {
struct _skipStack *prev; struct _skipStack *prev;
@ -137,10 +137,10 @@ static LoopStack *
LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f); LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f);
static void static void
LineSkip (FILE *f); LineSkip (FILE *f, int *linep);
static void static void
DoReplace (FILE *f, ReplaceSet *s); DoReplace (FILE *f, int *linep, ReplaceSet *s);
#define STRING_INIT 128 #define STRING_INIT 128
@ -249,27 +249,43 @@ ReplaceDispose (Replace *r)
} }
static void static void
Bail (const char *format, const char *arg) Bail (const char *format, int line, const char *arg)
{ {
fprintf (stderr, "fatal: "); fprintf (stderr, "fatal: ");
fprintf (stderr, format, arg); fprintf (stderr, format, line, arg);
fprintf (stderr, "\n"); fprintf (stderr, "\n");
exit (1); exit (1);
} }
static int
Getc (FILE *f, int *linep)
{
int c = getc (f);
if (c == '\n')
++(*linep);
}
static void
Ungetc (int c, FILE *f, int *linep)
{
if (c == '\n')
--(*linep);
ungetc (c, f);
}
static Replace * static Replace *
ReplaceRead (FILE *f) ReplaceRead (FILE *f, int *linep)
{ {
int c; int c;
Replace *r; Replace *r;
while ((c = getc (f)) != '@') while ((c = Getc (f, linep)) != '@')
{ {
if (c == EOF) if (c == EOF)
return 0; return 0;
} }
r = ReplaceNew(); r = ReplaceNew();
while ((c = getc (f)) != '@') while ((c = Getc (f, linep)) != '@')
{ {
if (c == EOF) if (c == EOF)
{ {
@ -277,7 +293,7 @@ ReplaceRead (FILE *f)
return 0; return 0;
} }
if (isspace (c)) if (isspace (c))
Bail ("invalid character after tag %s", r->tag->buf); Bail ("%d: invalid character after tag %s", *linep, r->tag->buf);
StringAdd (r->tag, c); StringAdd (r->tag, c);
} }
if (r->tag->buf[0] == '\0') if (r->tag->buf[0] == '\0')
@ -285,13 +301,13 @@ ReplaceRead (FILE *f)
ReplaceDispose (r); ReplaceDispose (r);
return 0; return 0;
} }
while (isspace ((c = getc (f)))) while (isspace ((c = Getc (f, linep))))
; ;
ungetc (c, f); Ungetc (c, f, linep);
while ((c = getc (f)) != '@' && c != EOF) while ((c = Getc (f, linep)) != '@' && c != EOF)
StringAdd (r->text, c); StringAdd (r->text, c);
if (c == '@') if (c == '@')
ungetc (c, f); Ungetc (c, f, linep);
while (isspace (StringLast (r->text))) while (isspace (StringLast (r->text)))
StringDel (r->text); StringDel (r->text);
if (StringLast(r->text) == '%') if (StringLast(r->text) == '%')
@ -355,12 +371,12 @@ ReplaceSetFind (ReplaceSet *s, char *tag)
} }
static ReplaceSet * static ReplaceSet *
ReplaceSetRead (FILE *f) ReplaceSetRead (FILE *f, int *linep)
{ {
ReplaceSet *s = ReplaceSetNew (); ReplaceSet *s = ReplaceSetNew ();
Replace *r; Replace *r;
while ((r = ReplaceRead (f))) while ((r = ReplaceRead (f, linep)))
{ {
while (ReplaceSetFind (s, r->tag->buf)) while (ReplaceSetFind (s, r->tag->buf))
StringAdd (r->tag, '+'); StringAdd (r->tag, '+');
@ -426,17 +442,17 @@ LoopStackLoop (ReplaceSet *rs, LoopStack *ls, FILE *f)
} }
static void static void
LineSkip (FILE *f) LineSkip (FILE *f, int *linep)
{ {
int c; int c;
while ((c = getc (f)) == '\n') while ((c = Getc (f, linep)) == '\n')
; ;
ungetc (c, f); Ungetc (c, f, linep);
} }
static void static void
DoReplace (FILE *f, ReplaceSet *s) DoReplace (FILE *f, int *linep, ReplaceSet *s)
{ {
int c; int c;
String *tag; String *tag;
@ -445,12 +461,12 @@ DoReplace (FILE *f, ReplaceSet *s)
LoopStack *ls = 0; LoopStack *ls = 0;
int skipping = 0; int skipping = 0;
while ((c = getc (f)) != EOF) while ((c = Getc (f, linep)) != EOF)
{ {
if (c == '@') if (c == '@')
{ {
tag = StringNew (); tag = StringNew ();
while ((c = getc (f)) != '@') while ((c = Getc (f, linep)) != '@')
{ {
if (c == EOF) if (c == EOF)
abort (); abort ();
@ -463,7 +479,7 @@ DoReplace (FILE *f, ReplaceSet *s)
ss = SkipStackPush (ss, skipping); ss = SkipStackPush (ss, skipping);
if (!ReplaceSetFind (s, tag->buf + 1)) if (!ReplaceSetFind (s, tag->buf + 1))
skipping++; skipping++;
LineSkip (f); LineSkip (f, linep);
break; break;
case ':': case ':':
if (!ss) if (!ss)
@ -472,20 +488,20 @@ DoReplace (FILE *f, ReplaceSet *s)
++skipping; ++skipping;
else else
--skipping; --skipping;
LineSkip (f); LineSkip (f, linep);
break; break;
case ';': case ';':
skipping = ss->skipping; skipping = ss->skipping;
ss = SkipStackPop (ss); ss = SkipStackPop (ss);
LineSkip (f); LineSkip (f, linep);
break; break;
case '{': case '{':
ls = LoopStackPush (ls, f, tag->buf + 1); ls = LoopStackPush (ls, f, tag->buf + 1);
LineSkip (f); LineSkip (f, linep);
break; break;
case '}': case '}':
ls = LoopStackLoop (s, ls, f); ls = LoopStackLoop (s, ls, f);
LineSkip (f); LineSkip (f, linep);
break; break;
default: default:
r = ReplaceSetFind (s, tag->buf); r = ReplaceSetFind (s, tag->buf);
@ -505,22 +521,25 @@ main (int argc, char **argv)
{ {
FILE *f; FILE *f;
ReplaceSet *s; ReplaceSet *s;
int iline, oline;
if (!argv[1]) if (!argv[1])
Bail ("usage: %s <template.sgml>", argv[0]); Bail ("usage: %s <template.sgml>", 0, argv[0]);
f = fopen (argv[1], "r"); f = fopen (argv[1], "r");
if (!f) if (!f)
{ {
Bail ("can't open file %s", argv[1]); Bail ("can't open file %s", 0, argv[1]);
exit (1); exit (1);
} }
while ((s = ReplaceSetRead (stdin))) iline = 1;
while ((s = ReplaceSetRead (stdin, &iline)))
{ {
DoReplace (f, s); oline = 1;
DoReplace (f, &oline, s);
ReplaceSetDispose (s); ReplaceSetDispose (s);
rewind (f); rewind (f);
} }
if (ferror (stdout)) if (ferror (stdout))
Bail ("%s", "error writing output"); Bail ("%s", 0, "error writing output");
exit (0); exit (0);
} }