=================================================================== RCS file: /cvs/texi2mdoc/util.c,v retrieving revision 1.31 retrieving revision 1.36 diff -u -p -r1.31 -r1.36 --- texi2mdoc/util.c 2015/03/12 04:24:19 1.31 +++ texi2mdoc/util.c 2018/11/13 09:07:58 1.36 @@ -1,4 +1,4 @@ -/* $Id: util.c,v 1.31 2015/03/12 04:24:19 kristaps Exp $ */ +/* $Id: util.c,v 1.36 2018/11/13 09:07:58 schwarze Exp $ */ /* * Copyright (c) 2015 Kristaps Dzonsons * @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "extern.h" @@ -155,13 +154,13 @@ texindex(struct texi *p, const char *tok, texiabort(p, NULL); /* Add term to term array. */ - p->indexs[i].index[isz].chapter = p->nodesz - 1; + p->indexs[i].index[isz].chapter = p->nodecur; p->indexs[i].index[isz].term = malloc(sz + 1); if (NULL == p->indexs[i].index[isz].term) texiabort(p, NULL); memcpy(p->indexs[i].index[isz].term, index, sz); p->indexs[i].index[isz].term[sz] = '\0'; - + /* Output mdoc(7) for index. */ #ifdef HAVE_INDEX p->seenvs = -1; @@ -169,10 +168,8 @@ texindex(struct texi *p, const char *tok, texiputchars(p, "idx"); texiputchars(p, p->indexs[i].name); cp = p->indexs[i].index[isz].term; - while ('\n' != *cp) { - assert('\0' != *cp); + while ('\n' != *cp) texiputchar(p, *cp++); - } teximacroclose(p); #endif p->indexs[i].indexsz++; @@ -202,8 +199,8 @@ texindex_add(struct texi *p, const char *tok, size_t s } /* Reallocate indices. */ - p->indexs = realloc(p->indexs, - sizeof(struct texidex) * + p->indexs = realloc(p->indexs, + sizeof(struct texidex) * (p->indexsz + 1)); if (NULL == p->indexs) texiabort(p, NULL); @@ -243,10 +240,10 @@ texiexit(struct texi *p) free(p->dirs[i]); for (i = 0; i < p->indexsz; i++) texidex_free(&p->indexs[i]); - for (i = 0; i < p->valsz; i++) + for (i = 0; i < p->valsz; i++) texivaluefree(&p->vals[i]); - free(p->nodes); + free(p->nodecache); free(p->macros); free(p->vals); free(p->indexs); @@ -276,14 +273,14 @@ texiabort(struct texi *p, const char *errstring) void texiwarn(const struct texi *p, const char *fmt, ...) { - va_list ap; + va_list ap; const struct texifile *f; f = &p->files[p->filepos - 1]; if (f->insplice) fprintf(stderr, "%s:%zu:%zu (%zuB left in splice): " - "warning: ", f->name, f->line + 1, + "warning: ", f->name, f->line + 1, f->col + 1, f->insplice); else fprintf(stderr, "%s:%zu:%zu: warning: ", @@ -302,14 +299,14 @@ texiwarn(const struct texi *p, const char *fmt, ...) void texierr(struct texi *p, const char *fmt, ...) { - va_list ap; + va_list ap; struct texifile *f; f = &p->files[p->filepos - 1]; - if (f->insplice) + if (f->insplice) fprintf(stderr, "%s:%zu:%zu: (%zuB left in splice): " - "error: ", f->name, f->line + 1, + "error: ", f->name, f->line + 1, f->col + 1, f->insplice); else fprintf(stderr, "%s:%zu:%zu: error: ", @@ -366,7 +363,7 @@ texiputchars(struct texi *p, const char *s) fputs("\\&", p->outfile); if ('\'' == *s && 0 == p->outcol) fputs("\\&", p->outfile); - if (p->uppercase) + if (p->uppercase) for ( ; '\0' != *s; s++) p->outcol += fputc(toupper ((unsigned int)*s), p->outfile); @@ -535,7 +532,7 @@ texipunctuate(struct texi *p, size_t *pos) } if (end == *pos) return; - if (end + 1 == BUFSZ(p) || ' ' == BUF(p)[end] || + if (end + 1 == BUFSZ(p) || ' ' == BUF(p)[end] || '@' == BUF(p)[end] || '\n' == BUF(p)[end]) { for ( ; start < end; start++) { texiputchar(p, ' '); @@ -553,14 +550,14 @@ texipunctuate(struct texi *p, size_t *pos) static size_t advancenext(struct texi *p, size_t *pos) { - + if (p->literal) { while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos])) { texiputchar(p, BUF(p)[*pos]); advance(p, pos); } return(*pos); - } + } while (*pos < BUFSZ(p) && ismspace(BUF(p)[*pos])) { p->seenws = 1; @@ -584,7 +581,8 @@ advanceeoln(struct texi *p, size_t *pos, int consumenl while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) { if ('@' == BUF(p)[*pos]) advance(p, pos); - advance(p, pos); + if (*pos < BUFSZ(p)) + advance(p, pos); } if (*pos < BUFSZ(p) && consumenl) advance(p, pos); @@ -600,14 +598,14 @@ advanceto(struct texi *p, size_t *pos, size_t end) { assert(*pos <= end); - while (*pos < end) + while (*pos < end) advance(p, pos); } static void texiexecmacro(struct texi *p, struct teximacro *m, size_t sv, size_t *pos) { - size_t valsz, realsz, aasz, asz, + size_t valsz, realsz, aasz, asz, ssz, i, j, k, start, end; char *val; char **args; @@ -665,7 +663,7 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz /* Parse to terminating delimiter. */ /* FIXME: embedded, escaped delimiters? */ - for (start = end = i + 1; end < realsz; end++) + for (start = end = i + 1; end < realsz; end++) if ('\\' == m->value[end]) break; if (end == realsz) @@ -679,8 +677,8 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz break; } - /* - * Argument didn't exist in argument table. + /* + * Argument didn't exist in argument table. * Just ignore it. */ if (k == aasz) { @@ -695,7 +693,7 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz texiabort(p, NULL); } - for (cp = args[k]; '\0' != *cp; cp++) + for (cp = args[k]; '\0' != *cp; cp++) val[j++] = *cp; val[j] = '\0'; @@ -708,7 +706,7 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz free(args[i]); free(args); free(val); -} +} /* * Output a free-form word in the input stream, progressing to the next @@ -718,8 +716,8 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz static void parseword(struct texi *p, size_t *pos, char extra) { - size_t i, end, len; - int c; + size_t i, end, len; + int c; /* * If a prior word had a terminating double-newline, then begin @@ -730,7 +728,8 @@ parseword(struct texi *p, size_t *pos, char extra) if (p->seenvs > 0 && 0 == p->literal && TEXILIST_TABLE != p->list) { if (p->outcol > 0) fputc('\n', p->outfile); - fputs(".Pp\n", p->outfile); + if (p->ign == 0) + fputs(".Pp\n", p->outfile); p->outcol = 0; } @@ -739,7 +738,7 @@ parseword(struct texi *p, size_t *pos, char extra) * have more than 72 characters written to the screen, then * output a newline before getting started. */ - if (p->seenws && 0 == p->outmacro && + if (p->seenws && 0 == p->outmacro && p->outcol > 72 && 0 == p->literal) texiputchar(p, '\n'); @@ -807,25 +806,25 @@ parseword(struct texi *p, size_t *pos, char extra) if ('"' == BUF(p)[*pos]) { texiputchars(p, "\\(dq"); - } else if (*pos < BUFSZ(p) - 2 && - '-' == BUF(p)[*pos] && - '-' == BUF(p)[*pos + 1] && + } else if (*pos < BUFSZ(p) - 2 && + '-' == BUF(p)[*pos] && + '-' == BUF(p)[*pos + 1] && '-' == BUF(p)[*pos + 2]) { texiputchars(p, "\\(em"); advance(p, pos); advance(p, pos); - } else if (*pos < BUFSZ(p) - 1 && - '-' == BUF(p)[*pos] && + } else if (*pos < BUFSZ(p) - 1 && + '-' == BUF(p)[*pos] && '-' == BUF(p)[*pos + 1]) { texiputchars(p, "\\(en"); advance(p, pos); - } else if (*pos < BUFSZ(p) - 1 && - '`' == BUF(p)[*pos] && + } else if (*pos < BUFSZ(p) - 1 && + '`' == BUF(p)[*pos] && '`' == BUF(p)[*pos + 1]) { texiputchars(p, "\\(lq"); advance(p, pos); - } else if (*pos < BUFSZ(p) - 1 && - '\'' == BUF(p)[*pos] && + } else if (*pos < BUFSZ(p) - 1 && + '\'' == BUF(p)[*pos] && '\'' == BUF(p)[*pos + 1]) { texiputchars(p, "\\(rq"); advance(p, pos); @@ -835,7 +834,7 @@ parseword(struct texi *p, size_t *pos, char extra) advance(p, pos); } - /* + /* * New sentence, new line:if we (non-macro, non-literal) see a * period at the end of the last printed word, then open a * newline. @@ -890,7 +889,7 @@ texicmd(const struct texi *p, size_t pos, size_t *end, /* Scan to the end of the possible command name. */ for (*end = pos; *end < BUFSZ(p) && ! ismspace(BUF(p)[*end]); (*end)++) - if ((*end > pos && ('@' == BUF(p)[*end] || + if ((*end > pos && ('@' == BUF(p)[*end] || '{' == BUF(p)[*end] || '}' == BUF(p)[*end]))) break; @@ -975,7 +974,7 @@ parsearg(struct texi *p, size_t *pos, size_t num) advanceto(p, pos, end); if (NULL != macro) texiexecmacro(p, macro, sv, pos); - if (TEXICMD__MAX == cmd) + if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) (*texitoks[cmd].fp)(p, cmd, pos); @@ -1036,7 +1035,7 @@ parsebracket(struct texi *p, size_t *pos, int dostack) advanceto(p, pos, end); if (NULL != macro) texiexecmacro(p, macro, sv, pos); - if (TEXICMD__MAX == cmd) + if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) (*texitoks[cmd].fp)(p, cmd, pos); @@ -1062,6 +1061,10 @@ parseeoln(struct texi *p, size_t *pos) texiputchar(p, BUF(p)[*pos]); advance(p, pos); } + if (*pos == BUFSZ(p)) { + texiwarn(p, "unexpected EOF"); + return; + } switch (BUF(p)[*pos]) { case ('}'): if (0 == p->ign) @@ -1087,7 +1090,7 @@ parseeoln(struct texi *p, size_t *pos) advanceto(p, pos, end); if (NULL != macro) texiexecmacro(p, macro, sv, pos); - if (TEXICMD__MAX == cmd) + if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) (*texitoks[cmd].fp)(p, cmd, pos); @@ -1130,7 +1133,7 @@ peekcmd(const struct texi *p, size_t pos) * Parse a single word or command. * This will return immediately at the EOF. */ -static void +void parsesingle(struct texi *p, size_t *pos) { size_t end, sv; @@ -1163,7 +1166,7 @@ parsesingle(struct texi *p, size_t *pos) advanceto(p, pos, end); if (NULL != macro) texiexecmacro(p, macro, sv, pos); - if (TEXICMD__MAX == cmd) + if (TEXICMD__MAX == cmd) return; if (NULL != texitoks[cmd].fp) (*texitoks[cmd].fp)(p, cmd, pos); @@ -1204,7 +1207,7 @@ parseeof(struct texi *p) { size_t pos; - for (pos = 0; pos < BUFSZ(p); ) + for (pos = 0; pos < BUFSZ(p); ) parsesingle(p, &pos); } @@ -1246,7 +1249,7 @@ parseto(struct texi *p, size_t *pos, const char *endto endtoksz = strlen(endtoken); assert(endtoksz > 0); - + while ((*pos = advancenext(p, pos)) < BUFSZ(p)) { switch (BUF(p)[*pos]) { case ('}'): @@ -1272,7 +1275,7 @@ parseto(struct texi *p, size_t *pos, const char *endto if (TEXICMD_END == cmd) { while (*pos < BUFSZ(p) && isws(BUF(p)[*pos])) advance(p, pos); - /* + /* * FIXME: check the full word, not just its * initial substring! */ @@ -1285,16 +1288,16 @@ parseto(struct texi *p, size_t *pos, const char *endto texiwarn(p, "unexpected \"end\""); advanceeoln(p, pos, 0); continue; - } + } if (NULL != macro) texiexecmacro(p, macro, sv, pos); - if (TEXICMD__MAX == cmd) + if (TEXICMD__MAX == cmd) continue; - if (NULL != texitoks[cmd].fp) + if (NULL != texitoks[cmd].fp) (*texitoks[cmd].fp)(p, cmd, pos); } - if (*pos == BUFSZ(p)) + if (*pos == BUFSZ(p)) texiwarn(p, "EOF expecting \"%s\" end\n", endtoken); } @@ -1319,17 +1322,17 @@ parsestdin(struct texi *p) if (f->mapsz == f->mapmaxsz) { if (f->mapmaxsz == (1U << 31)) texierr(p, "stdin buffer too long"); - f->mapmaxsz = f->mapmaxsz > 65536 / 2 ? + f->mapmaxsz = f->mapmaxsz > 65536 / 2 ? 2 * f->mapmaxsz : 65536; f->map = realloc(f->map, f->mapmaxsz); - if (NULL == f->map) + if (NULL == f->map) texiabort(p, NULL); } - ssz = read(STDIN_FILENO, f->map + + ssz = read(STDIN_FILENO, f->map + (int)f->mapsz, f->mapmaxsz - f->mapsz); if (0 == ssz) break; - else if (-1 == ssz) + else if (-1 == ssz) texiabort(p, NULL); } @@ -1353,7 +1356,7 @@ parsefile(struct texi *p, const char *fname, int parse size_t i; char *map; - if (64 == p->filepos) + if (64 == p->filepos) texierr(p, "too many open files"); f = &p->files[p->filepos]; memset(f, 0, sizeof(struct texifile)); @@ -1365,7 +1368,7 @@ parsefile(struct texi *p, const char *fname, int parse } else if (-1 == fstat(fd, &st)) { close(fd); texiabort(p, fname); - } + } f->mapsz = f->mapmaxsz = st.st_size; map = mmap(NULL, f->mapsz, @@ -1515,7 +1518,7 @@ valueadd(struct texi *p, char *key, char *val) p->vals[i].value = val; } else { /* FIXME: reallocarray() */ - p->vals = realloc(p->vals, + p->vals = realloc(p->vals, (p->valsz + 1) * sizeof(struct texivalue)); if (NULL == p->vals) @@ -1586,7 +1589,7 @@ argparse(struct texi *p, size_t *pos, size_t *argsz, s start = *pos; stack = 0; while (*pos < BUFSZ(p)) { - /* + /* * According to the manual, commas within * embedded commands are escaped. * We keep track of embedded-ness in the "stack" @@ -1628,7 +1631,7 @@ argparse(struct texi *p, size_t *pos, size_t *argsz, s advance(p, pos); } - if (*pos == BUFSZ(p)) + if (*pos == BUFSZ(p)) texierr(p, "unterminated arguments"); assert('}' == BUF(p)[*pos]); advance(p, pos); @@ -1647,15 +1650,16 @@ teximdocclose(struct texi *p, int last) { char buf[PATH_MAX]; - if (NULL == p->chapters || 0 == p->chapnum) + if (NULL == p->chapters || 1 == p->nodesz) return; teximacro(p, "Sh INFO NAVIGATION"); /* Print a reference to the "top" node. */ - if (p->chapnum > 1) { + if (-1 != p->nodecache[p->nodecur].up) { texiputchars(p, "Top node,"); - snprintf(buf, sizeof(buf), "%s-1 7", p->chapters); + snprintf(buf, sizeof(buf), "%s-%zd 7", + p->chapters, p->nodecache[p->nodecur].up); p->seenvs = 0; teximacroopen(p, "Xr "); texiputchars(p, buf); @@ -1663,27 +1667,22 @@ teximdocclose(struct texi *p, int last) teximacroclose(p); } - /* Print a reference to the previous node. */ - if (p->chapnum > 2) { + if (-1 != p->nodecache[p->nodecur].prev) { texiputchars(p, "previous node,"); - snprintf(buf, sizeof(buf), - "%s-%zu 7", p->chapters, p->chapnum - 1); + snprintf(buf, sizeof(buf), "%s-%zd 7", + p->chapters, p->nodecache[p->nodecur].prev); p->seenvs = 0; teximacroopen(p, "Xr "); texiputchars(p, buf); - if ( ! last) + if ( ! last) texiputchars(p, " ;"); teximacroclose(p); - } + } - /* Print a reference to the next node. */ - if ( ! last) { - if (1 == p->chapnum) - texiputchars(p, "Next node,"); - else - texiputchars(p, "next node,"); - snprintf(buf, sizeof(buf), - "%s-%zu 7", p->chapters, p->chapnum + 1); + if (-1 != p->nodecache[p->nodecur].next) { + texiputchars(p, "next node,"); + snprintf(buf, sizeof(buf), "%s-%zd 7", + p->chapters, p->nodecache[p->nodecur].next); p->seenvs = 0; teximacroopen(p, "Xr "); texiputchars(p, buf); @@ -1691,53 +1690,57 @@ teximdocclose(struct texi *p, int last) } fclose(p->outfile); + p->outfile = NULL; } +ssize_t +texicache(struct texi *p, const char *buf, size_t sz) +{ + size_t i; + + for (i = 0; i < p->nodecachesz; i++) { + if (sz != strlen(p->nodecache[i].name)) + continue; + if (strncmp(buf, p->nodecache[i].name, sz)) + continue; + break; + } + if (i < p->nodecachesz) + return(i); + if (NULL == buf) + return(-1); + p->nodecache = realloc + (p->nodecache, + (p->nodecachesz + 1) * sizeof(struct texinode)); + if (NULL == p->nodecache) + texiabort(p, NULL); + p->nodecache[p->nodecachesz].name = malloc(sz + 1); + if (NULL == p->nodecache[p->nodecachesz].name) + texiabort(p, NULL); + memcpy(p->nodecache[p->nodecachesz].name, buf, sz); + p->nodecache[p->nodecachesz].name[sz] = '\0'; + p->nodecache[p->nodecachesz].up = + p->nodecache[p->nodecachesz].next = + p->nodecache[p->nodecachesz].prev = -1; + p->nodecachesz++; + return(p->nodecachesz - 1); +} + /* - * Open a mdoc(7) context. - * If we're printing chapters, then open the outfile here, too. - * Otherwise just print the mdoc(7) prologue. + * 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 modification time of the input. */ void teximdocopen(struct texi *p, size_t *pos) { const char *cp; - time_t t; - char date[32]; - char fname[PATH_MAX]; - if (NULL != p->chapters) { - p->chapnum++; - snprintf(fname, sizeof(fname), "%s-%zu", - p->chapters, p->chapnum); - p->nodes = realloc(p->nodes, - (p->nodesz + 1) * sizeof(char *)); - if (NULL == p->nodes) - texiabort(p, NULL); - p->nodes[p->nodesz] = strdup(fname); - if (NULL == p->nodes[p->nodesz]) - texiabort(p, NULL); - p->nodesz++; - snprintf(fname, sizeof(fname), "%s-%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)); - p->seenvs = -1; teximacroopen(p, "Dd"); - texiputchars(p, date); + texiputchars(p, p->date); teximacroclose(p); teximacroopen(p, "Dt"); for (cp = p->title; '\0' != *cp; cp++)