=================================================================== RCS file: /cvs/texi2mdoc/util.c,v retrieving revision 1.17 retrieving revision 1.20 diff -u -p -r1.17 -r1.20 --- texi2mdoc/util.c 2015/02/28 00:03:20 1.17 +++ texi2mdoc/util.c 2015/03/01 00:25:08 1.20 @@ -1,4 +1,4 @@ -/* $Id: util.c,v 1.17 2015/02/28 00:03:20 kristaps Exp $ */ +/* $Id: util.c,v 1.20 2015/03/01 00:25:08 kristaps Exp $ */ /* * Copyright (c) 2015 Kristaps Dzonsons * @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include #include @@ -79,7 +77,9 @@ texiexit(struct texi *p) /* Make sure we're newline-terminated. */ if (p->outcol) - putchar('\n'); + fputc('\n', p->outfile); + if (NULL != p->chapters) + teximdocclose(p, 1); /* Unmap all files. */ while (p->filepos > 0) @@ -180,13 +180,13 @@ texiputchar(struct texi *p, char c) if (p->ign) return; if ('.' == c && 0 == p->outcol) - fputs("\\&", stdout); + fputs("\\&", p->outfile); if ('\'' == c && 0 == p->outcol) - fputs("\\&", stdout); + fputs("\\&", p->outfile); - putchar(c); + fputc(c, p->outfile); if ('\\' == c) - putchar('e'); + fputc('e', p->outfile); p->seenvs = 0; if ('\n' == c) { p->outcol = 0; @@ -207,10 +207,10 @@ texiputchars(struct texi *p, const char *s) if (p->ign) return; if ('.' == *s && 0 == p->outcol) - fputs("\\&", stdout); + fputs("\\&", p->outfile); if ('\'' == *s && 0 == p->outcol) - fputs("\\&", stdout); - p->outcol += fputs(s, stdout); + fputs("\\&", p->outfile); + p->outcol += fputs(s, p->outfile); p->seenvs = 0; } @@ -239,7 +239,7 @@ teximacroclose(struct texi *p) return; if (0 == --p->outmacro) { - putchar('\n'); + fputc('\n', p->outfile); p->outcol = p->seenws = 0; } } @@ -259,19 +259,19 @@ teximacroopen(struct texi *p, const char *s) return; if (p->outcol && 0 == p->outmacro) { - putchar('\n'); + fputc('\n', p->outfile); p->outcol = 0; } if (0 == p->outmacro) - putchar('.'); + fputc('.', p->outfile); else - putchar(' '); + fputc(' ', p->outfile); - if (EOF != (rc = fputs(s, stdout))) + if (EOF != (rc = fputs(s, p->outfile))) p->outcol += rc; - putchar(' '); + fputc(' ', p->outfile); p->outcol++; p->outmacro++; p->seenws = 0; @@ -293,10 +293,11 @@ teximacro(struct texi *p, const char *s) texierr(p, "\"%s\" in a literal scope!?", s); if (p->outcol) - putchar('\n'); + fputc('\n', p->outfile); - putchar('.'); - puts(s); + fputc('.', p->outfile); + fputs(s, p->outfile); + fputc('\n', p->outfile); p->outcol = p->seenws = 0; } @@ -591,7 +592,7 @@ parseword(struct texi *p, size_t *pos, char extra) * index after the command name. */ enum texicmd -texicmd(struct texi *p, size_t pos, size_t *end, struct teximacro **macro) +texicmd(const struct texi *p, size_t pos, size_t *end, struct teximacro **macro) { size_t i, len, toksz; @@ -719,9 +720,9 @@ parsearg(struct texi *p, size_t *pos, size_t num) * This will stop in the event of EOF or if we're not at a bracket. */ void -parsebracket(struct texi *p, size_t *pos) +parsebracket(struct texi *p, size_t *pos, int dostack) { - size_t end, sv; + size_t end, sv, stack; enum texicmd cmd; struct teximacro *macro; @@ -732,12 +733,25 @@ parsebracket(struct texi *p, size_t *pos) return; advance(p, pos); + stack = 0; while ((*pos = advancenext(p, pos)) < BUFSZ(p)) { switch (BUF(p)[*pos]) { case ('}'): + if (stack > 0) { + stack--; + advance(p, pos); + texiputchar(p, '}'); + continue; + } advance(p, pos); return; case ('{'): + if (dostack) { + stack++; + advance(p, pos); + texiputchar(p, '{'); + continue; + } if (0 == p->ign) texiwarn(p, "unexpected \"{\""); advance(p, pos); @@ -814,6 +828,23 @@ parseeoln(struct texi *p, size_t *pos) } /* + * Peek to see if there's a command after subsequent whitespace. + * If so, return the macro identifier. + * This DOES NOT work with user-defined macros. + */ +enum texicmd +peekcmd(const struct texi *p, size_t pos) +{ + size_t end; + + while (pos < BUFSZ(p) && ismspace(BUF(p)[pos])) + pos++; + if (pos == BUFSZ(p) || '@' != BUF(p)[pos]) + return(TEXICMD__MAX); + return(texicmd(p, pos, &end, NULL)); +} + +/* * Parse a single word or command. * This will return immediately at the EOF. */ @@ -874,7 +905,7 @@ parselinearg(struct texi *p, size_t *pos) } if (*pos < BUFSZ(p) && '{' == BUF(p)[*pos]) - parsebracket(p, pos); + parsebracket(p, pos, 0); else if (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) parsesingle(p, pos); else @@ -1318,3 +1349,108 @@ argparse(struct texi *p, size_t *pos, size_t *argsz, s advance(p, pos); return(args); } + +/* + * If we're printing chapters, then do some naviation here and then + * close our outfile. + * I want to call this the SEE ALSO section, but that's not really what + * it is: we'll refer to the "initial" (top) node and the next and + * previous chapters. + */ +void +teximdocclose(struct texi *p, int last) +{ + char buf[PATH_MAX]; + + if (NULL == p->chapters || 0 == p->chapnum) + return; + + teximacro(p, "Sh INFO NAVIGATION"); + + /* Print a reference to the "top" node. */ + if (p->chapnum > 1) { + snprintf(buf, sizeof(buf), "node1 7"); + teximacroopen(p, "Xr "); + texiputchars(p, buf); + texiputchars(p, " ,"); + teximacroclose(p); + } + + /* Print a reference to the previous node. */ + if (p->chapnum > 2) { + snprintf(buf, sizeof(buf), + "node%zu 7", p->chapnum - 1); + teximacroopen(p, "Xr "); + texiputchars(p, buf); + if ( ! last) + texiputchars(p, " ,"); + teximacroclose(p); + } + + /* Print a reference to the next node. */ + if ( ! last) { + snprintf(buf, sizeof(buf), + "node%zu 7", p->chapnum + 1); + teximacroopen(p, "Xr "); + texiputchars(p, buf); + teximacroclose(p); + } + + fclose(p->outfile); +} + +/* + * Open a mdoc(7) context. + * If we're printing chapters, then open the outfile here, too. + * Otherwise just print the mdoc(7) prologue. + */ +void +teximdocopen(struct texi *p) +{ + const char *cp; + time_t t; + char date[32]; + char fname[PATH_MAX]; + + if (NULL != p->chapters) { + snprintf(fname, sizeof(fname), "%s/node%zu.7", + p->chapters, ++p->chapnum); + p->outfile = fopen(fname, "w"); + if (NULL == p->outfile) + texiabort(p, fname); + } + + /* + * Here we print our standard mdoc(7) prologue. + * We use the title set with @settitle for the `Nd' description + * and the source document filename (the first one as invoked on + * the command line) for the title. + * The date is set to the current date. + */ + t = time(NULL); + strftime(date, sizeof(date), "%F", localtime(&t)); + + teximacroopen(p, "Dd"); + texiputchars(p, date); + teximacroclose(p); + teximacroopen(p, "Dt"); + for (cp = p->title; '\0' != *cp; cp++) + texiputchar(p, toupper((unsigned int)*cp)); + texiputchars(p, " 7"); + teximacroclose(p); + teximacro(p, "Os"); + teximacro(p, "Sh NAME"); + teximacroopen(p, "Nm"); + for (cp = p->title; '\0' != *cp; cp++) + texiputchar(p, *cp); + teximacroclose(p); + teximacroopen(p, "Nd"); + if (NULL != p->subtitle) + for (cp = p->subtitle; '\0' != *cp; cp++) + texiputchar(p, *cp); + else + texiputchars(p, "Unknown description"); + teximacroclose(p); + p->seenvs = 1; +} +