Annotation of texi2mdoc/main.c, Revision 1.26
1.26 ! kristaps 1: /* $Id: main.c,v 1.25 2015/02/20 12:25:25 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2015 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/mman.h>
18: #include <sys/stat.h>
19:
20: #include <assert.h>
21: #include <ctype.h>
22: #include <fcntl.h>
23: #include <getopt.h>
1.2 kristaps 24: #include <libgen.h>
25: #include <limits.h>
1.1 kristaps 26: #include <stdarg.h>
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
1.10 kristaps 30: #include <time.h>
1.6 kristaps 31: #include <unistd.h>
1.1 kristaps 32:
1.24 kristaps 33: #include "extern.h"
1.1 kristaps 34:
1.23 kristaps 35: #define SECTSZ 4
36: static const char *const sects[SECTSZ] = {
37: "Sh",
38: "Ss",
39: "Em",
40: "No",
41: };
42:
1.16 kristaps 43: static void doaccent(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.3 kristaps 44: static void doblock(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 45: static void dobracket(struct texi *, enum texicmd, const char *, size_t, size_t *);
46: static void dobye(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.15 kristaps 47: static void dodefn(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.3 kristaps 48: static void dodisplay(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.2 kristaps 49: static void doenumerate(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 50: static void doexample(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.8 kristaps 51: static void doignargn(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 52: static void doignblock(struct texi *, enum texicmd, const char *, size_t, size_t *);
53: static void doignbracket(struct texi *, enum texicmd, const char *, size_t, size_t *);
54: static void doignline(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.12 kristaps 55: static void doinline(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.2 kristaps 56: static void doinclude(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 57: static void doitem(struct texi *, enum texicmd, const char *, size_t, size_t *);
58: static void doitemize(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.8 kristaps 59: static void dolink(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.3 kristaps 60: static void domath(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.18 kristaps 61: static void domultitable(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 62: static void doquotation(struct texi *, enum texicmd, const char *, size_t, size_t *);
63: static void dotable(struct texi *, enum texicmd, const char *, size_t, size_t *);
64: static void dotop(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.23 kristaps 65: static void dosecoffs(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 66: static void dosection(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.3 kristaps 67: static void dosp(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 68: static void dosubsection(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.23 kristaps 69: static void dosubsubsection(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 70: static void dosymbol(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.18 kristaps 71: static void dotab(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.10 kristaps 72: static void dotitle(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.24 kristaps 73: static void dovalue(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.25 kristaps 74: static void doverb(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.16 kristaps 75: static void doverbinclude(struct texi *, enum texicmd, const char *, size_t, size_t *);
1.1 kristaps 76:
1.24 kristaps 77: static const struct texitok __texitoks[TEXICMD__MAX] = {
1.20 kristaps 78: /* TEXICMD__BEGIN */
1.8 kristaps 79: { doignargn, "acronym", 7 }, /* TEXICMD_ACRONYM */
1.16 kristaps 80: { doaccent, "'", 1 }, /* TEXICMD_ACUTE */
1.1 kristaps 81: { doignline, "afourpaper", 10 }, /* TEXICMD_A4PAPER */
82: { doignbracket, "anchor", 6 }, /* TEXICMD_ANCHOR */
1.12 kristaps 83: { dosection, "appendix", 8 }, /* TEXICMD_APPENDIX */
84: { dosection, "appendixsec", 11 }, /* TEXICMD_APPENDIXSEC */
1.20 kristaps 85: { dosubsection, "appendixsubsec", 14 }, /* TEXICMD_APPENDIXSUBSEC */
1.23 kristaps 86: { dosubsubsection, "appendixsubsubsec", 17 }, /* TEXICMD_APPENDIXSUBSUBSEC */
1.25 kristaps 87: { doinline, "asis", 4 }, /* TEXICMD_ASIS */
1.3 kristaps 88: { dosymbol, "*", 1 }, /* TEXICMD_ASTERISK */
1.1 kristaps 89: { dosymbol, "@", 1 }, /* TEXICMD_AT */
1.3 kristaps 90: { doignline, "author", 6 }, /* TEXICMD_AUTHOR */
1.21 kristaps 91: { doinline, "b", 1 }, /* TEXICMD_BOLD */
1.3 kristaps 92: { dosymbol, "!", 1 }, /* TEXICMD_BANG */
1.7 kristaps 93: { dosymbol, "bullet", 6 }, /* TEXICMD_BULLET */
1.1 kristaps 94: { dobye, "bye", 3 }, /* TEXICMD_BYE */
1.12 kristaps 95: { doignline, "center", 6 }, /* TEXICMD_CENTER */
96: { dosection, "chapter", 7 }, /* TEXICMD_CHAPTER */
1.1 kristaps 97: { doignline, "cindex", 6 }, /* TEXICMD_CINDEX */
1.16 kristaps 98: { doaccent, "^", 1 }, /* TEXICMD_CIRCUMFLEX */
1.24 kristaps 99: { doinline, "cite", 4 }, /* TEXICMD_CITE */
100: { dovalue, "clear", 5 }, /* TEXICMD_CLEAR */
1.21 kristaps 101: { doinline, "code", 4 }, /* TEXICMD_CODE */
1.3 kristaps 102: { dosymbol, ":", 1 }, /* TEXICMD_COLON */
1.18 kristaps 103: { NULL, "columnfractions", 15 }, /* TEXICMD_COLUMNFRACTIONS */
1.12 kristaps 104: { doinline, "command", 7 }, /* TEXICMD_COMMAND */
1.1 kristaps 105: { doignline, "c", 1 }, /* TEXICMD_COMMENT */
1.2 kristaps 106: { doignline, "comment", 7 }, /* TEXICMD_COMMENT_LONG */
1.1 kristaps 107: { doignline, "contents", 8 }, /* TEXICMD_CONTENTS */
108: { doignblock, "copying", 7 }, /* TEXICMD_COPYING */
109: { dosymbol, "copyright", 9 }, /* TEXICMD_COPYRIGHT */
1.15 kristaps 110: { dodefn, "deffn", 5 }, /* TEXICMD_DEFFN */
111: { dodefn, "deffnx", 6 }, /* TEXICMD_DEFFNX */
112: { dodefn, "defmac", 6 }, /* TEXICMD_DEFMAC */
113: { dodefn, "defmacx", 7 }, /* TEXICMD_DEFMACX */
114: { dodefn, "deftp", 5 }, /* TEXICMD_DEFTP */
115: { dodefn, "deftpx", 6 }, /* TEXICMD_DEFTPX */
116: { dodefn, "deftypefn", 9 }, /* TEXICMD_DEFTYPEFN */
117: { dodefn, "deftypefnx", 10 }, /* TEXICMD_DEFTYPEFNX */
118: { dodefn, "deftypefun", 10 }, /* TEXICMD_DEFTYPEFUN */
119: { dodefn, "deftypefunx", 11 }, /* TEXICMD_DEFTYPEFUNX */
120: { dodefn, "deftypevar", 10 }, /* TEXICMD_DEFTYPEVAR */
121: { dodefn, "deftypevarx", 11 }, /* TEXICMD_DEFTYPEVARX */
122: { dodefn, "deftypevr", 9 }, /* TEXICMD_DEFTYPEVR */
123: { dodefn, "deftypevrx", 10 }, /* TEXICMD_DEFTYPEVRX */
124: { dodefn, "defun", 5 }, /* TEXICMD_DEFUN */
125: { dodefn, "defunx", 6 }, /* TEXICMD_DEFUNX */
126: { dodefn, "defvar", 6 }, /* TEXICMD_DEFVAR */
127: { dodefn, "defvarx", 7 }, /* TEXICMD_DEFVARX */
128: { dodefn, "defvr", 5 }, /* TEXICMD_DEFVR */
129: { dodefn, "defvrx", 6 }, /* TEXICMD_DEFVRX */
1.1 kristaps 130: { doignblock, "detailmenu", 10 }, /* TEXICMD_DETAILMENU */
1.21 kristaps 131: { doinline, "dfn", 3 }, /* TEXICMD_DFN */
1.1 kristaps 132: { doignline, "dircategory", 11 }, /* TEXICMD_DIRCATEGORY */
133: { doignblock, "direntry", 8 }, /* TEXICMD_DIRENTRY */
1.3 kristaps 134: { dodisplay, "display", 7 }, /* TEXICMD_DISPLAY */
1.2 kristaps 135: { dosymbol, "dots", 4 }, /* TEXICMD_DOTS */
1.8 kristaps 136: { dolink, "email", 5 }, /* TEXICMD_EMAIL */
1.21 kristaps 137: { doinline, "emph", 4 }, /* TEXICMD_EMPH */
1.1 kristaps 138: { NULL, "end", 3 }, /* TEXICMD_END */
1.2 kristaps 139: { doenumerate, "enumerate", 9 }, /* TEXICMD_ENUMERATE */
1.12 kristaps 140: { doinline, "env", 3 }, /* TEXICMD_ENV */
1.15 kristaps 141: { dosymbol, "error", 5 }, /* TEXICMD_ERROR */
1.1 kristaps 142: { doexample, "example", 7 }, /* TEXICMD_EXAMPLE */
1.25 kristaps 143: { doignline, "exdent", 6 }, /* TEXICMD_EXDENT */
1.17 kristaps 144: { dosymbol, "expansion", 9 }, /* TEXICMD_EXPANSION */
1.12 kristaps 145: { doinline, "file", 4 }, /* TEXICMD_FILE */
1.17 kristaps 146: { doignline, "finalout", 8 }, /* TEXICMD_FINALOUT */
1.20 kristaps 147: { doignline, "findex", 6 }, /* TEXICMD_FINDEX */
148: { dotable, "ftable", 6 }, /* TEXICMD_FTABLE */
149: { dodisplay, "format", 6 }, /* TEXICMD_FORMAT */
1.16 kristaps 150: { doaccent, "`", 1 }, /* TEXICMD_GRAVE */
1.3 kristaps 151: { doblock, "group", 5 }, /* TEXICMD_GROUP */
1.2 kristaps 152: { dosection, "heading", 7 }, /* TEXICMD_HEADING */
1.3 kristaps 153: { doignline, "headings", 8 }, /* TEXICMD_HEADINGS */
1.18 kristaps 154: { doitem, "headitem", 8 }, /* TEXICMD_HEADITEM */
1.25 kristaps 155: { doignblock, "html", 4 }, /* TEXICMD_HTML */
1.3 kristaps 156: { dosymbol, "-", 1 }, /* TEXICMD_HYPHEN */
1.21 kristaps 157: { doinline, "i", 1 }, /* TEXICMD_I */
1.24 kristaps 158: { dovalue, "ifclear", 7 }, /* TEXICMD_IFCLEAR */
1.14 kristaps 159: { doignblock, "ifdocbook", 9 }, /* TEXICMD_IFDOCBOOK */
1.1 kristaps 160: { doignblock, "ifhtml", 6 }, /* TEXICMD_IFHTML */
1.26 ! kristaps 161: { doblock, "ifinfo", 6 }, /* TEXICMD_IFINFO */
1.14 kristaps 162: { doblock, "ifnotdocbook", 12 }, /* TEXICMD_IFNOTDOCBOOK */
163: { doblock, "ifnothtml", 9 }, /* TEXICMD_IFNOTHTML */
164: { doblock, "ifnotinfo", 9 }, /* TEXICMD_IFNOTINFO */
165: { doignblock, "ifnotplaintext", 14 }, /* TEXICMD_IFNOTPLAINTEXT */
1.3 kristaps 166: { doblock, "ifnottex", 8 }, /* TEXICMD_IFNOTTEX */
1.14 kristaps 167: { doblock, "ifnotxml", 8 }, /* TEXICMD_IFNOTXML */
168: { doblock, "ifplaintext", 11 }, /* TEXICMD_IFPLAINTEXT */
1.1 kristaps 169: { doignblock, "iftex", 5 }, /* TEXICMD_IFTEX */
1.3 kristaps 170: { doignblock, "ifset", 5 }, /* TEXICMD_IFSET */
1.14 kristaps 171: { doignblock, "ifxml", 5 }, /* TEXICMD_IFXML */
1.17 kristaps 172: { doignblock, "ignore", 6 }, /* TEXICMD_IGNORE */
1.1 kristaps 173: { doignbracket, "image", 5 }, /* TEXICMD_IMAGE */
1.2 kristaps 174: { doinclude, "include", 7 }, /* TEXICMD_INCLUDE */
1.13 kristaps 175: { dodisplay, "indentblock", 11 }, /* TEXICMD_INDENTBLOCK */
1.5 kristaps 176: { doignline, "insertcopying", 13 }, /* TEXICMD_INSERTCOPYING */
1.1 kristaps 177: { doitem, "item", 4 }, /* TEXICMD_ITEM */
178: { doitemize, "itemize", 7 }, /* TEXICMD_ITEMIZE */
1.20 kristaps 179: { doitem, "itemx", 5 }, /* TEXICMD_ITEMX */
1.21 kristaps 180: { doinline, "kbd", 3 }, /* TEXICMD_KBD */
1.18 kristaps 181: { dobracket, "key", 3 }, /* TEXICMD_KEY */
1.20 kristaps 182: { doignline, "kindex", 6 }, /* TEXICMD_KINDEX */
1.1 kristaps 183: { dosymbol, "LaTeX", 5 }, /* TEXICMD_LATEX */
1.23 kristaps 184: { dosecoffs, "lowersections", 13 }, /* TEXICMD_LOWERSECTIONS */
1.3 kristaps 185: { domath, "math", 4 }, /* TEXICMD_MATH */
1.1 kristaps 186: { doignblock, "menu", 4 }, /* TEXICMD_MENU */
1.25 kristaps 187: { dosymbol, "minus", 5 }, /* TEXICMD_MINUS */
1.18 kristaps 188: { domultitable, "multitable", 10 }, /* TEXICMD_MULTITABLE */
1.15 kristaps 189: { doignline, "need", 4 }, /* TEXICMD_NEED */
1.3 kristaps 190: { dosymbol, "\n", 1 }, /* TEXICMD_NEWLINE */
1.1 kristaps 191: { doignline, "node", 4 }, /* TEXICMD_NODE */
1.3 kristaps 192: { doignline, "noindent", 8 }, /* TEXICMD_NOINDENT */
1.16 kristaps 193: { doinline, "option", 6 }, /* TEXICMD_OPTION */
1.8 kristaps 194: { dolink, "pxref", 5 }, /* TEXICMD_PXREF */
1.3 kristaps 195: { dosymbol, "?", 1 }, /* TEXICMD_QUESTIONMARK */
1.1 kristaps 196: { doquotation, "quotation", 9 }, /* TEXICMD_QUOTATION */
1.3 kristaps 197: { doignline, "page", 4 }, /* TEXICMD_PAGE */
1.25 kristaps 198: { doignline, "paragraphindent", 15 }, /* TEXICMD_PARINDENT */
199: { dosymbol, ".", 1 }, /* TEXICMD_PERIOD */
1.2 kristaps 200: { doignline, "printindex", 10 }, /* TEXICMD_PRINTINDEX */
1.21 kristaps 201: { doinline, "r", 1 }, /* TEXICMD_R */
1.23 kristaps 202: { dosecoffs, "raisesections", 13 }, /* TEXICMD_RAISESECTIONS */
1.1 kristaps 203: { dobracket, "ref", 3 }, /* TEXICMD_REF */
1.15 kristaps 204: { dosymbol, "result", 6 }, /* TEXICMD_RESULT */
1.21 kristaps 205: { doinline, "samp", 4 }, /* TEXICMD_SAMP */
206: { doinline, "sansserif", 9 }, /* TEXICMD_SANSSERIF */
1.7 kristaps 207: { dobracket, "sc", 2 }, /* TEXICMD_SC */
1.1 kristaps 208: { dosection, "section", 7 }, /* TEXICMD_SECTION */
1.24 kristaps 209: { dovalue, "set", 3 }, /* TEXICMD_SET */
1.1 kristaps 210: { doignline, "setchapternewpage", 17 }, /* TEXICMD_SETCHAPNEWPAGE */
211: { doignline, "setfilename", 11 }, /* TEXICMD_SETFILENAME */
1.10 kristaps 212: { dotitle, "settitle", 8 }, /* TEXICMD_SETTITLE */
1.25 kristaps 213: { doignline, "shortcontents", 13 }, /* TEXICMD_SHORTCONTENTS */
1.21 kristaps 214: { doinline, "slanted", 7 }, /* TEXICMD_SLANTED */
1.3 kristaps 215: { dosp, "sp", 2 }, /* TEXICMD_SP */
216: { dosymbol, " ", 1 }, /* TEXICMD_SPACE */
1.17 kristaps 217: { doignline, "smallbook", 9 }, /* TEXICMD_SMALLBOOK */
1.12 kristaps 218: { dodisplay, "smalldisplay", 12 }, /* TEXICMD_SMALLDISPLAY */
1.3 kristaps 219: { doexample, "smallexample", 12 }, /* TEXICMD_SMALLEXAMPLE */
1.20 kristaps 220: { dodisplay, "smallformat", 11 }, /* TEXICMD_SMALLFORMAT */
1.13 kristaps 221: { dodisplay, "smallindentblock", 16 }, /* TEXICMD_SMALLINDENTBLOCK */
1.3 kristaps 222: { dosymbol, "{", 1 }, /* TEXICMD_SQUIGGLE_LEFT */
223: { dosymbol, "}", 1 }, /* TEXICMD_SQUIGGLE_RIGHT */
1.21 kristaps 224: { doinline, "strong", 6 }, /* TEXICMD_STRONG */
1.20 kristaps 225: { dosubsection, "subheading", 10 }, /* TEXICMD_SUBHEADING */
1.1 kristaps 226: { dosubsection, "subsection", 10 }, /* TEXICMD_SUBSECTION */
1.23 kristaps 227: { dosubsubsection, "subsubsection", 13 }, /* TEXICMD_SUBSUBSECTION */
1.3 kristaps 228: { doignline, "subtitle", 8 }, /* TEXICMD_SUBTITLE */
1.25 kristaps 229: { doignline, "summarycontents", 15 }, /* TEXICMD_SUMMARYCONTENTS */
1.20 kristaps 230: { doignline, "syncodeindex", 12 }, /* TEXICMD_SYNCODEINDEX */
1.21 kristaps 231: { doinline, "t", 1 }, /* TEXICMD_T */
1.18 kristaps 232: { dotab, "tab", 3 }, /* TEXICMD_TAB */
233: { dosymbol, "\t", 1 }, /* TEXICMD_TABSYM */
1.1 kristaps 234: { dotable, "table", 5 }, /* TEXICMD_TABLE */
235: { doignblock, "tex", 3 }, /* TEXICMD_TEX */
236: { dosymbol, "TeX", 3 }, /* TEXICMD_TEXSYM */
1.16 kristaps 237: { doaccent, "~", 1 }, /* TEXICMD_TILDE */
1.25 kristaps 238: { doignline, "tindex", 6 }, /* TEXICMD_TINDEX */
1.3 kristaps 239: { doignline, "title", 5 }, /* TEXICMD_TITLE */
1.1 kristaps 240: { dobracket, "titlefont", 9 }, /* TEXICMD_TITLEFONT */
241: { doignblock, "titlepage", 9 }, /* TEXICMD_TITLEPAGE */
242: { dotop, "top", 3 }, /* TEXICMD_TOP */
1.16 kristaps 243: { doaccent, "\"", 1 }, /* TEXICMD_UMLAUT */
1.12 kristaps 244: { dosection, "unnumbered", 10 }, /* TEXICMD_UNNUMBERED */
1.2 kristaps 245: { dosection, "unnumberedsec", 13 }, /* TEXICMD_UNNUMBEREDSEC */
1.20 kristaps 246: { dosubsection, "unnumberedsubsec", 16 }, /* TEXICMD_UNNUMBEREDSUBSEC */
1.23 kristaps 247: { dosubsubsection, "unnumberedsubsubsec", 19 }, /* TEXICMD_UNNUMBEREDSUBSUBSEC */
1.8 kristaps 248: { dolink, "uref", 4 }, /* TEXICMD_UREF */
249: { dolink, "url", 3 }, /* TEXICMD_URL */
1.24 kristaps 250: { dovalue, "value", 5 }, /* TEXICMD_VALUE */
1.12 kristaps 251: { doinline, "var", 3 }, /* TEXICMD_VAR */
1.25 kristaps 252: { doverb, "verbatim", 8 }, /* TEXICMD_VERBATIM */
1.16 kristaps 253: { doverbinclude, "verbatiminclude", 15 }, /* TEXICMD_VERBATIMINCLUDE */
1.18 kristaps 254: { doignline, "vindex", 6 }, /* TEXICMD_VINDEX */
1.9 kristaps 255: { dosp, "vskip", 5 }, /* TEXICMD_VSKIP */
1.20 kristaps 256: { dotable, "vtable", 6 }, /* TEXICMD_VTABLE */
1.3 kristaps 257: { dobracket, "w", 1 }, /* TEXICMD_W */
1.8 kristaps 258: { dolink, "xref", 4 }, /* TEXICMD_XREF */
1.20 kristaps 259: /* TEXICMD__END */
1.1 kristaps 260: };
261:
1.24 kristaps 262: const struct texitok *const texitoks = __texitoks;
1.18 kristaps 263:
1.2 kristaps 264: static void
1.15 kristaps 265: dodefn(struct texi *p, enum texicmd cmd,
1.3 kristaps 266: const char *buf, size_t sz, size_t *pos)
267: {
268: const char *blk;
269:
1.5 kristaps 270: blk = NULL;
1.3 kristaps 271: switch (cmd) {
1.15 kristaps 272: case (TEXICMD_DEFFN):
273: case (TEXICMD_DEFTP):
1.3 kristaps 274: case (TEXICMD_DEFTYPEFN):
275: case (TEXICMD_DEFTYPEFUN):
1.15 kristaps 276: case (TEXICMD_DEFTYPEVAR):
277: case (TEXICMD_DEFTYPEVR):
278: case (TEXICMD_DEFUN):
279: case (TEXICMD_DEFVAR):
280: case (TEXICMD_DEFVR):
1.5 kristaps 281: blk = texitoks[cmd].tok;
1.3 kristaps 282: break;
1.5 kristaps 283: default:
1.3 kristaps 284: break;
285: }
286:
287: if (p->ign) {
1.15 kristaps 288: NULL != blk ?
289: parseto(p, buf, sz, pos, blk) :
290: parseeoln(p, buf, sz, pos);
1.3 kristaps 291: return;
292: }
293:
1.15 kristaps 294: if (NULL != blk)
295: texivspace(p);
296:
1.3 kristaps 297: switch (cmd) {
1.15 kristaps 298: case (TEXICMD_DEFMAC):
299: case (TEXICMD_DEFMACX):
300: texiputchars(p, "Macro");
301: break;
302: case (TEXICMD_DEFTYPEVAR):
303: case (TEXICMD_DEFTYPEVARX):
304: case (TEXICMD_DEFVAR):
305: case (TEXICMD_DEFVARX):
306: texiputchars(p, "Variable");
307: break;
1.3 kristaps 308: case (TEXICMD_DEFTYPEFUN):
1.15 kristaps 309: case (TEXICMD_DEFTYPEFUNX):
310: case (TEXICMD_DEFUN):
311: case (TEXICMD_DEFUNX):
312: texiputchars(p, "Function");
1.3 kristaps 313: break;
314: default:
1.15 kristaps 315: parselinearg(p, buf, sz, pos);
1.3 kristaps 316: break;
317: }
1.15 kristaps 318:
319: texiputchars(p, ":\n");
320:
321: switch (cmd) {
322: case (TEXICMD_DEFMAC):
323: case (TEXICMD_DEFMACX):
324: teximacroopen(p, "Dv");
325: while (parselinearg(p, buf, sz, pos))
326: /* Spin. */ ;
327: teximacroclose(p);
328: break;
329: case (TEXICMD_DEFFN):
330: case (TEXICMD_DEFFNX):
331: case (TEXICMD_DEFUN):
332: case (TEXICMD_DEFUNX):
333: teximacroopen(p, "Fo");
334: parselinearg(p, buf, sz, pos);
335: teximacroclose(p);
336: teximacroopen(p, "Fa");
337: while (parselinearg(p, buf, sz, pos))
338: /* Spin. */ ;
339: teximacroclose(p);
340: teximacro(p, "Fc");
341: break;
342: case (TEXICMD_DEFTYPEFUN):
343: case (TEXICMD_DEFTYPEFUNX):
344: case (TEXICMD_DEFTYPEFN):
345: case (TEXICMD_DEFTYPEFNX):
346: teximacroopen(p, "Ft");
347: parselinearg(p, buf, sz, pos);
348: teximacroclose(p);
349: teximacroopen(p, "Fo");
350: parselinearg(p, buf, sz, pos);
351: teximacroclose(p);
352: teximacroopen(p, "Fa");
353: while (parselinearg(p, buf, sz, pos))
354: /* Spin. */ ;
355: teximacroclose(p);
356: teximacro(p, "Fc");
357: break;
358: case (TEXICMD_DEFTP):
359: case (TEXICMD_DEFTPX):
360: case (TEXICMD_DEFTYPEVAR):
361: case (TEXICMD_DEFTYPEVARX):
362: case (TEXICMD_DEFTYPEVR):
363: case (TEXICMD_DEFTYPEVRX):
364: teximacroopen(p, "Vt");
365: while (parselinearg(p, buf, sz, pos))
366: /* Spin. */ ;
367: teximacroclose(p);
368: break;
369: case (TEXICMD_DEFVAR):
370: case (TEXICMD_DEFVARX):
371: case (TEXICMD_DEFVR):
372: case (TEXICMD_DEFVRX):
373: teximacroopen(p, "Va");
374: while (parselinearg(p, buf, sz, pos))
375: /* Spin. */ ;
376: teximacroclose(p);
377: break;
378: default:
379: abort();
1.3 kristaps 380: }
1.15 kristaps 381:
1.11 kristaps 382: texivspace(p);
1.3 kristaps 383: if (NULL != blk)
384: parseto(p, buf, sz, pos, blk);
385: }
386:
387: static void
1.1 kristaps 388: doignblock(struct texi *p, enum texicmd cmd,
389: const char *buf, size_t sz, size_t *pos)
390: {
1.26 ! kristaps 391: char end[32];
! 392: const char *term;
! 393: size_t endsz, endpos;
! 394:
! 395: /*
! 396: * We want to completely ignore everything in these blocks, so
! 397: * simply jump to the @end block.
! 398: */
! 399: endsz = snprintf(end, sizeof(end),
! 400: "\n@end %s\n", texitoks[cmd].tok);
! 401: assert(endsz < sizeof(end));
! 402:
! 403: /*
! 404: * Look up where our end token occurs.
! 405: * Set our end position based on the relative offset of that
! 406: * from our current position, or the EOF if we don't have a
! 407: * proper ending point.
! 408: */
! 409: term = memmem(&buf[*pos], sz, end, endsz);
! 410: endpos = NULL == term ? sz :
! 411: *pos + term - &buf[*pos];
! 412: assert(endpos <= sz);
! 413: while (*pos < endpos)
! 414: advance(p, buf, pos);
! 415:
! 416: /* Only do this if we're not already at the end. */
! 417: if (endpos < sz)
! 418: advanceto(p, buf, pos, endpos + endsz);
1.1 kristaps 419: }
420:
421: static void
1.3 kristaps 422: doblock(struct texi *p, enum texicmd cmd,
1.1 kristaps 423: const char *buf, size_t sz, size_t *pos)
424: {
425:
1.5 kristaps 426: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1.1 kristaps 427: }
428:
429: static void
1.12 kristaps 430: doinline(struct texi *p, enum texicmd cmd,
431: const char *buf, size_t sz, size_t *pos)
1.1 kristaps 432: {
1.21 kristaps 433: const char *macro = NULL;
1.12 kristaps 434:
435: switch (cmd) {
1.21 kristaps 436: case (TEXICMD_CODE):
437: case (TEXICMD_KBD):
438: case (TEXICMD_SAMP):
439: case (TEXICMD_T):
440: macro = "Li";
441: break;
442: case (TEXICMD_CITE):
443: case (TEXICMD_DFN):
444: case (TEXICMD_EMPH):
445: case (TEXICMD_I):
446: case (TEXICMD_SLANTED):
447: macro = "Em";
448: break;
449: case (TEXICMD_B):
450: case (TEXICMD_STRONG):
451: macro = "Sy";
452: break;
1.12 kristaps 453: case (TEXICMD_COMMAND):
454: macro = "Xr";
455: break;
456: case (TEXICMD_ENV):
457: macro = "Ev";
458: break;
459: case (TEXICMD_FILE):
460: macro = "Pa";
461: break;
1.16 kristaps 462: case (TEXICMD_OPTION):
463: macro = "Op";
464: break;
1.12 kristaps 465: case (TEXICMD_VAR):
466: macro = "Va";
467: break;
468: default:
1.22 kristaps 469: break;
1.12 kristaps 470: }
471:
1.25 kristaps 472: if (NULL == macro || p->literal || TEXILIST_TABLE == p->list) {
1.12 kristaps 473: parsebracket(p, buf, sz, pos);
474: return;
475: }
1.1 kristaps 476:
1.5 kristaps 477: teximacroopen(p, macro);
1.1 kristaps 478: p->seenws = 0;
479: parsebracket(p, buf, sz, pos);
1.11 kristaps 480: texipunctuate(p, buf, sz, pos);
1.5 kristaps 481: teximacroclose(p);
1.1 kristaps 482: }
483:
484: static void
1.25 kristaps 485: doverb(struct texi *p, enum texicmd cmd,
486: const char *buf, size_t sz, size_t *pos)
487: {
488: const char *end, *term;
489: size_t endsz, endpos;
490:
1.26 ! kristaps 491: advanceeoln(p, buf, sz, pos, 1);
! 492:
1.25 kristaps 493: /* We end at exactly this token. */
494: end = "\n@end verbatim\n";
495: endsz = strlen(end);
496:
497: /*
498: * Look up where our end token occurs.
499: * Set our end position based on the relative offset of that
500: * from our current position.
501: */
502: term = memmem(&buf[*pos], sz, end, endsz);
503: endpos = NULL == term ? sz :
504: *pos + term - &buf[*pos];
505:
506: teximacro(p, "Bd -literal -offset indent");
507: assert(endpos <= sz);
1.26 ! kristaps 508: while (*pos < endpos) {
! 509: if (buf[*pos] == '\n')
! 510: p->outcol = 0;
! 511: else
! 512: p->outcol++;
1.25 kristaps 513: if (*pos > 0 && '.' == buf[*pos])
514: if ('\n' == buf[*pos - 1])
515: fputs("\\&", stdout);
516: putchar(buf[*pos]);
517: if ('\\' == buf[*pos])
518: putchar('e');
519: advance(p, buf, pos);
520: }
521: teximacro(p, "Ed");
1.26 ! kristaps 522: advanceto(p, buf, pos, endpos + endsz);
1.25 kristaps 523: }
524:
525: static void
1.16 kristaps 526: doverbinclude(struct texi *p, enum texicmd cmd,
527: const char *buf, size_t sz, size_t *pos)
528: {
1.25 kristaps 529: char fname[PATH_MAX], path[PATH_MAX];
530: int rc;
531: size_t i, end;
532: const char *v;
533: enum texicmd type;
1.16 kristaps 534:
535: while (*pos < sz && ' ' == buf[*pos])
536: advance(p, buf, pos);
537:
1.25 kristaps 538: for (i = 0; *pos < sz && '\n' != buf[*pos]; ) {
1.16 kristaps 539: if (i == sizeof(fname) - 1)
540: break;
1.25 kristaps 541: if ('@' != buf[*pos]) {
542: fname[i++] = buf[*pos];
543: advance(p, buf, pos);
544: continue;
545: }
546: type = texicmd(p, buf, *pos, sz, &end);
547: advanceto(p, buf, pos, end);
548: if (TEXICMD_VALUE != type)
549: texierr(p, "unknown verbatiminclude command");
550: v = valueblookup(p, buf, sz, pos);
551: if (NULL == v)
552: continue;
553: while ('\0' != *v) {
554: if (i == sizeof(fname) - 1)
555: break;
556: fname[i++] = *v++;
557: }
558: if ('\0' != *v)
559: break;
1.16 kristaps 560: }
561:
562: if (i == 0)
563: texierr(p, "path too short");
564: else if ('\n' != buf[*pos])
565: texierr(p, "path too long");
566: else if ('/' == fname[0])
567: texierr(p, "no absolute paths");
568: fname[i] = '\0';
569:
570: if (strstr(fname, "../") || strstr(fname, "/.."))
571: texierr(p, "insecure path");
572:
573: rc = snprintf(path, sizeof(path),
574: "%s/%s", p->dirs[0], fname);
575: if (rc < 0)
576: texierr(p, "couldn't format path");
577: else if ((size_t)rc >= sizeof(path))
578: texierr(p, "path too long");
579:
580: parsefile(p, path, 0);
581: }
582:
583: static void
1.2 kristaps 584: doinclude(struct texi *p, enum texicmd cmd,
585: const char *buf, size_t sz, size_t *pos)
586: {
1.25 kristaps 587: char fname[PATH_MAX], path[PATH_MAX];
588: size_t i, end;
589: int rc;
590: const char *v;
591: enum texicmd type;
1.2 kristaps 592:
593: while (*pos < sz && ' ' == buf[*pos])
594: advance(p, buf, pos);
595:
596: /* Read in the filename. */
1.25 kristaps 597: for (i = 0; *pos < sz && '\n' != buf[*pos]; ) {
1.2 kristaps 598: if (i == sizeof(fname) - 1)
599: break;
1.25 kristaps 600: if ('@' != buf[*pos]) {
601: fname[i++] = buf[*pos];
602: advance(p, buf, pos);
603: continue;
604: }
605: type = texicmd(p, buf, *pos, sz, &end);
606: advanceto(p, buf, pos, end);
607: if (TEXICMD_VALUE != type)
608: texierr(p, "unknown include command");
609: v = valueblookup(p, buf, sz, pos);
610: if (NULL == v)
611: continue;
612: while ('\0' != *v) {
613: if (i == sizeof(fname) - 1)
614: break;
615: fname[i++] = *v++;
616: }
617: if ('\0' != *v)
618: break;
1.2 kristaps 619: }
620:
621: if (i == 0)
622: texierr(p, "path too short");
623: else if ('\n' != buf[*pos])
624: texierr(p, "path too long");
625: else if ('/' == fname[0])
626: texierr(p, "no absolute paths");
627: fname[i] = '\0';
628:
629: if (strstr(fname, "../") || strstr(fname, "/.."))
630: texierr(p, "insecure path");
631:
1.5 kristaps 632: for (i = 0; i < p->dirsz; i++) {
633: rc = snprintf(path, sizeof(path),
634: "%s/%s", p->dirs[i], fname);
635: if (rc < 0)
636: texierr(p, "couldn't format path");
637: else if ((size_t)rc >= sizeof(path))
638: texierr(p, "path too long");
639: else if (-1 == access(path, R_OK))
640: continue;
641:
1.16 kristaps 642: parsefile(p, path, 1);
1.5 kristaps 643: return;
644: }
1.2 kristaps 645:
1.5 kristaps 646: texierr(p, "couldn't find %s in includes", fname);
1.2 kristaps 647: }
648:
649: static void
1.1 kristaps 650: dobracket(struct texi *p, enum texicmd cmd,
651: const char *buf, size_t sz, size_t *pos)
652: {
653:
654: parsebracket(p, buf, sz, pos);
655: }
656:
657: static void
1.3 kristaps 658: dodisplay(struct texi *p, enum texicmd cmd,
659: const char *buf, size_t sz, size_t *pos)
660: {
661:
1.20 kristaps 662: switch (cmd) {
663: case (TEXICMD_FORMAT):
664: case (TEXICMD_SMALLFORMAT):
665: teximacro(p, "Bd -filled");
666: break;
667: default:
668: teximacro(p, "Bd -filled -offset indent");
669: break;
670: }
671:
1.11 kristaps 672: p->seenvs = 1;
1.12 kristaps 673: /* FIXME: ignore and parseeoln. */
1.3 kristaps 674: advanceeoln(p, buf, sz, pos, 1);
1.13 kristaps 675: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1.5 kristaps 676: teximacro(p, "Ed");
1.3 kristaps 677: }
678:
679: static void
1.1 kristaps 680: doexample(struct texi *p, enum texicmd cmd,
681: const char *buf, size_t sz, size_t *pos)
682: {
683:
1.5 kristaps 684: teximacro(p, "Bd -literal -offset indent");
1.12 kristaps 685: /* FIXME: ignore and parseeoln. */
1.3 kristaps 686: advanceeoln(p, buf, sz, pos, 1);
687: p->literal++;
1.13 kristaps 688: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1.3 kristaps 689: p->literal--;
1.5 kristaps 690: teximacro(p, "Ed");
1.1 kristaps 691: }
692:
693: static void
694: dobye(struct texi *p, enum texicmd cmd,
695: const char *buf, size_t sz, size_t *pos)
696: {
697:
698: texiexit(p);
699: exit(EXIT_SUCCESS);
700: }
701:
702: static void
1.10 kristaps 703: dotitle(struct texi *p, enum texicmd cmd,
704: const char *buf, size_t sz, size_t *pos)
705: {
706: size_t start, end;
707:
708: while (*pos < sz && isws(buf[*pos]))
709: advance(p, buf, pos);
710: start = end = *pos;
711: while (end < sz && '\n' != buf[end])
712: end++;
1.26 ! kristaps 713: advanceeoln(p, buf, sz, pos, 1);
1.10 kristaps 714: free(p->subtitle);
715: p->subtitle = malloc(end - start + 1);
716: memcpy(p->subtitle, &buf[start], end - start);
717: p->subtitle[end - start] = '\0';
718: }
719:
720: static void
1.16 kristaps 721: doaccent(struct texi *p, enum texicmd cmd,
722: const char *buf, size_t sz, size_t *pos)
723: {
724:
725: if (*pos == sz)
726: return;
727: advance(p, buf, pos);
728: switch (cmd) {
729: case (TEXICMD_ACUTE):
730: switch (buf[*pos]) {
731: case ('a'): case ('A'):
732: case ('e'): case ('E'):
733: case ('i'): case ('I'):
734: case ('o'): case ('O'):
735: case ('u'): case ('U'):
736: texiputchars(p, "\\(\'");
737: texiputchar(p, buf[*pos]);
738: break;
739: default:
740: texiputchar(p, buf[*pos]);
741: }
742: break;
743: case (TEXICMD_CIRCUMFLEX):
744: switch (buf[*pos]) {
745: case ('a'): case ('A'):
746: case ('e'): case ('E'):
747: case ('i'): case ('I'):
748: case ('o'): case ('O'):
749: case ('u'): case ('U'):
750: texiputchars(p, "\\(^");
751: texiputchar(p, buf[*pos]);
752: break;
753: default:
754: texiputchar(p, buf[*pos]);
755: }
756: break;
757: case (TEXICMD_GRAVE):
758: switch (buf[*pos]) {
759: case ('a'): case ('A'):
760: case ('e'): case ('E'):
761: case ('i'): case ('I'):
762: case ('o'): case ('O'):
763: case ('u'): case ('U'):
764: texiputchars(p, "\\(`");
765: texiputchar(p, buf[*pos]);
766: break;
767: default:
768: texiputchar(p, buf[*pos]);
769: }
770: break;
771: case (TEXICMD_TILDE):
772: switch (buf[*pos]) {
773: case ('a'): case ('A'):
774: case ('n'): case ('N'):
775: case ('o'): case ('O'):
776: texiputchars(p, "\\(~");
777: texiputchar(p, buf[*pos]);
778: break;
779: default:
780: texiputchar(p, buf[*pos]);
781: }
782: break;
783: case (TEXICMD_UMLAUT):
784: switch (buf[*pos]) {
785: case ('a'): case ('A'):
786: case ('e'): case ('E'):
787: case ('i'): case ('I'):
788: case ('o'): case ('O'):
789: case ('u'): case ('U'):
790: case ('y'):
791: texiputchars(p, "\\(:");
792: texiputchar(p, buf[*pos]);
793: break;
794: default:
795: texiputchar(p, buf[*pos]);
796: }
797: break;
798: default:
799: abort();
800: }
801: }
802:
803: static void
1.1 kristaps 804: dosymbol(struct texi *p, enum texicmd cmd,
805: const char *buf, size_t sz, size_t *pos)
806: {
807:
1.3 kristaps 808: if (p->seenws && p->outcol && 0 == p->literal) {
809: texiputchar(p, ' ');
810: p->seenws = 0;
811: }
812:
1.1 kristaps 813: switch (cmd) {
1.3 kristaps 814: case (TEXICMD_ASTERISK):
815: case (TEXICMD_NEWLINE):
816: case (TEXICMD_SPACE):
1.18 kristaps 817: case (TEXICMD_TABSYM):
1.3 kristaps 818: texiputchar(p, ' ');
819: break;
1.1 kristaps 820: case (TEXICMD_AT):
1.3 kristaps 821: texiputchar(p, '@');
822: break;
823: case (TEXICMD_BANG):
824: texiputchar(p, '!');
1.7 kristaps 825: break;
826: case (TEXICMD_BULLET):
827: texiputchars(p, "\\(bu");
1.1 kristaps 828: break;
829: case (TEXICMD_COPYRIGHT):
830: texiputchars(p, "\\(co");
831: break;
1.2 kristaps 832: case (TEXICMD_DOTS):
833: texiputchars(p, "...");
834: break;
1.15 kristaps 835: case (TEXICMD_ERROR):
836: texiputchars(p, "error\\(->");
1.17 kristaps 837: break;
838: case (TEXICMD_EXPANSION):
839: texiputchars(p, "\\(->");
1.15 kristaps 840: break;
1.1 kristaps 841: case (TEXICMD_LATEX):
842: texiputchars(p, "LaTeX");
843: break;
1.25 kristaps 844: case (TEXICMD_MINUS):
845: texiputchars(p, "\\-");
846: break;
847: case (TEXICMD_PERIOD):
848: texiputchar(p, '.');
849: break;
1.3 kristaps 850: case (TEXICMD_QUESTIONMARK):
851: texiputchar(p, '?');
1.15 kristaps 852: break;
853: case (TEXICMD_RESULT):
854: texiputchars(p, "\\(rA");
1.3 kristaps 855: break;
856: case (TEXICMD_SQUIGGLE_LEFT):
857: texiputchars(p, "{");
858: break;
859: case (TEXICMD_SQUIGGLE_RIGHT):
860: texiputchars(p, "}");
861: break;
1.1 kristaps 862: case (TEXICMD_TEXSYM):
863: texiputchars(p, "TeX");
864: break;
1.3 kristaps 865: case (TEXICMD_COLON):
866: case (TEXICMD_HYPHEN):
867: break;
1.1 kristaps 868: default:
1.5 kristaps 869: texiwarn(p, "sym: %d", cmd);
1.1 kristaps 870: abort();
871: }
872:
1.5 kristaps 873: if (texitoks[cmd].len > 1)
874: doignbracket(p, cmd, buf, sz, pos);
1.1 kristaps 875: }
876:
877: static void
878: doquotation(struct texi *p, enum texicmd cmd,
879: const char *buf, size_t sz, size_t *pos)
880: {
881:
1.5 kristaps 882: teximacro(p, "Qo");
1.1 kristaps 883: parseto(p, buf, sz, pos, "quotation");
1.5 kristaps 884: teximacro(p, "Qc");
1.1 kristaps 885: }
886:
1.3 kristaps 887: static void
888: domath(struct texi *p, enum texicmd cmd,
889: const char *buf, size_t sz, size_t *pos)
890: {
891: size_t nest;
892:
893: /*
894: * Math handling is different from everything else.
895: * We don't allow any subcomponents, and we ignore the rules in
896: * terms of @-commands.
897: * This departs from GNU's rules, but whatever.
898: */
899: while (*pos < sz && isws(buf[*pos]))
900: advance(p, buf, pos);
901: if (*pos == sz || '{' != buf[*pos])
902: return;
903: advance(p, buf, pos);
904: if (p->seenws && p->outcol && 0 == p->literal)
905: texiputchar(p, ' ');
906: p->seenws = 0;
907: for (nest = 1; *pos < sz && nest > 0; ) {
908: if ('{' == buf[*pos])
909: nest++;
910: else if ('}' == buf[*pos])
911: if (0 == --nest)
912: continue;
913: texiputchar(p, buf[*pos]);
914: advance(p, buf, pos);
915: }
916: if (*pos == sz)
917: return;
918: assert('}' == buf[*pos]);
919: advance(p, buf, pos);
1.24 kristaps 920: }
921:
922: static void
923: dovalue(struct texi *p, enum texicmd cmd,
924: const char *buf, size_t sz, size_t *pos)
925: {
1.25 kristaps 926: size_t start, end;
927: char *key, *val;
928: const char *cp;
1.24 kristaps 929:
930: if (TEXICMD_SET == cmd) {
931: while (*pos < sz && isws(buf[*pos]))
932: advance(p, buf, pos);
933: for (start = end = *pos; end < sz; end++)
934: if (ismspace(buf[end]))
935: break;
1.25 kristaps 936: /* We don't allow empty keys. */
1.24 kristaps 937: if (start == end)
938: return;
1.25 kristaps 939: advanceto(p, buf, pos, end);
1.24 kristaps 940:
941: key = malloc(end - start + 1);
942: if (NULL == key) {
943: perror(NULL);
944: exit(EXIT_FAILURE);
945: }
946: memcpy(key, &buf[start], end - start);
947: key[end - start] = '\0';
948:
949: while (*pos < sz && isws(buf[*pos]))
950: advance(p, buf, pos);
951: for (start = end = *pos; end < sz; end++)
952: if ('\n' == buf[end])
953: break;
1.25 kristaps 954: /* We do allow empty values. */
955: advanceeoln(p, buf, sz, pos, 1);
1.24 kristaps 956:
957: val = malloc(end - start + 1);
958: if (NULL == val) {
959: perror(NULL);
960: exit(EXIT_FAILURE);
961: }
962: memcpy(val, &buf[start], end - start);
963: val[end - start] = '\0';
1.25 kristaps 964: valueadd(p, key, val);
1.24 kristaps 965: } else if (TEXICMD_VALUE == cmd) {
966: if (p->seenws)
967: texiputchar(p, ' ');
968: p->seenws = 0;
1.25 kristaps 969: if (NULL == (cp = valueblookup(p, buf, sz, pos)))
970: texiputchars(p, "{No value}");
971: else
972: texiputchars(p, cp);
1.24 kristaps 973: } else if (TEXICMD_IFCLEAR == cmd) {
1.26 ! kristaps 974: if (NULL != valuellookup(p, buf, sz, pos))
! 975: doignblock(p, cmd, buf, sz, pos);
! 976: else
! 977: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1.25 kristaps 978: } else if (TEXICMD_CLEAR == cmd)
979: valuelclear(p, buf, sz, pos);
1.3 kristaps 980: }
981:
1.1 kristaps 982: static void
1.8 kristaps 983: dolink(struct texi *p, enum texicmd cmd,
1.1 kristaps 984: const char *buf, size_t sz, size_t *pos)
985: {
1.8 kristaps 986: int c;
1.1 kristaps 987:
988: switch (cmd) {
989: case (TEXICMD_EMAIL):
1.5 kristaps 990: teximacroopen(p, "Mt");
1.1 kristaps 991: break;
1.3 kristaps 992: case (TEXICMD_UREF):
1.1 kristaps 993: case (TEXICMD_URL):
1.5 kristaps 994: teximacroopen(p, "Lk");
1.1 kristaps 995: break;
1.8 kristaps 996: case (TEXICMD_XREF):
997: texiputchars(p, "See Section");
998: teximacroopen(p, "Qq");
999: break;
1000: case (TEXICMD_PXREF):
1001: texiputchars(p, "see Section");
1002: teximacroopen(p, "Qq");
1003: break;
1.1 kristaps 1004: default:
1.8 kristaps 1005: abort();
1.1 kristaps 1006: }
1.8 kristaps 1007:
1008: c = parsearg(p, buf, sz, pos, 0);
1009: p->ign++;
1010: while (c > 0)
1011: c = parsearg(p, buf, sz, pos, 1);
1012: p->ign--;
1013:
1.11 kristaps 1014: texipunctuate(p, buf, sz, pos);
1.8 kristaps 1015: teximacroclose(p);
1016: }
1017:
1018: static void
1019: doignargn(struct texi *p, enum texicmd cmd,
1020: const char *buf, size_t sz, size_t *pos)
1021: {
1022: int c;
1023:
1024: c = parsearg(p, buf, sz, pos, 0);
1025: p->ign++;
1026: while (c > 0)
1027: c = parsearg(p, buf, sz, pos, 1);
1028: p->ign--;
1.1 kristaps 1029: }
1030:
1.23 kristaps 1031: /*
1032: * Sections can be made subsections and so on by way of the
1033: * @raiseections and @lowersections commands.
1034: * Perform this check here and return the actual section number adjusted
1035: * to the raise level.
1036: */
1037: static int
1038: sectioner(struct texi *p, int sec)
1039: {
1040:
1041: if ((sec -= p->secoffs) < 0) {
1042: texiwarn(p, "section below minimum, clamping");
1043: return(0);
1044: } else if (sec >= SECTSZ) {
1045: texiwarn(p, "section above maximum, clamping");
1046: return(SECTSZ - 1);
1047: }
1048: return(sec);
1049: }
1050:
1051: static void
1052: dosubsubsection(struct texi *p, enum texicmd cmd,
1053: const char *buf, size_t sz, size_t *pos)
1054: {
1055: int sec;
1056:
1057: sec = sectioner(p, 3);
1058:
1059: /* We don't have a subsubsubsection, so make one up. */
1060: texivspace(p);
1061: teximacroopen(p, sects[sec]);
1062: parseeoln(p, buf, sz, pos);
1063: teximacroclose(p);
1064: texivspace(p);
1065: }
1066:
1.1 kristaps 1067: static void
1068: dosubsection(struct texi *p, enum texicmd cmd,
1069: const char *buf, size_t sz, size_t *pos)
1070: {
1.23 kristaps 1071: int sec;
1072:
1073: sec = sectioner(p, 2);
1.13 kristaps 1074:
1075: if (p->outmacro)
1.23 kristaps 1076: texierr(p, "\"%s\" in open line scope!?", sects[sec]);
1.13 kristaps 1077: else if (p->literal)
1.23 kristaps 1078: texierr(p, "\"%s\" in a literal scope!?", sects[sec]);
1.1 kristaps 1079:
1.21 kristaps 1080: /* We don't have a subsubsection, so make one up. */
1.11 kristaps 1081: texivspace(p);
1.23 kristaps 1082: teximacroopen(p, sects[sec]);
1.3 kristaps 1083: parseeoln(p, buf, sz, pos);
1.5 kristaps 1084: teximacroclose(p);
1.11 kristaps 1085: texivspace(p);
1.1 kristaps 1086: }
1087:
1088: static void
1.23 kristaps 1089: dosecoffs(struct texi *p, enum texicmd cmd,
1090: const char *buf, size_t sz, size_t *pos)
1091: {
1092:
1093: if (TEXICMD_RAISESECTIONS == cmd)
1094: p->secoffs++;
1095: else
1096: p->secoffs--;
1097: }
1098:
1099: static void
1.1 kristaps 1100: dosection(struct texi *p, enum texicmd cmd,
1.23 kristaps 1101: const char *buf, size_t sz, size_t *pos)
1.1 kristaps 1102: {
1.23 kristaps 1103: int sec;
1.12 kristaps 1104:
1105: switch (cmd) {
1106: case (TEXICMD_APPENDIX):
1107: case (TEXICMD_CHAPTER):
1108: case (TEXICMD_TOP):
1109: case (TEXICMD_UNNUMBERED):
1.23 kristaps 1110: sec = sectioner(p, 0);
1.12 kristaps 1111: break;
1112: case (TEXICMD_APPENDIXSEC):
1113: case (TEXICMD_HEADING):
1114: case (TEXICMD_SECTION):
1115: case (TEXICMD_UNNUMBEREDSEC):
1.23 kristaps 1116: sec = sectioner(p, 1);
1.12 kristaps 1117: break;
1118: default:
1119: abort();
1120: }
1.1 kristaps 1121:
1.3 kristaps 1122: if (p->outmacro)
1.23 kristaps 1123: texierr(p, "\"%s\" in open line scope!?", sects[sec]);
1.3 kristaps 1124: else if (p->literal)
1.23 kristaps 1125: texierr(p, "\"%s\" in a literal scope!?", sects[sec]);
1.3 kristaps 1126:
1.23 kristaps 1127: teximacroopen(p, sects[sec]);
1.3 kristaps 1128: parseeoln(p, buf, sz, pos);
1129: teximacroclose(p);
1.11 kristaps 1130: p->seenvs = 1;
1.3 kristaps 1131: }
1132:
1133: static void
1134: dosp(struct texi *p, enum texicmd cmd,
1135: const char *buf, size_t sz, size_t *pos)
1136: {
1137:
1.11 kristaps 1138: texivspace(p);
1.12 kristaps 1139: /* FIXME: ignore and parseeoln. */
1.3 kristaps 1140: advanceeoln(p, buf, sz, pos, 1);
1.1 kristaps 1141: }
1142:
1143: static void
1144: dotop(struct texi *p, enum texicmd cmd,
1145: const char *buf, size_t sz, size_t *pos)
1146: {
1.10 kristaps 1147: const char *cp;
1148: time_t t;
1149: char date[32];
1150:
1.26 ! kristaps 1151: if (--p->ign)
! 1152: texierr(p, "@top command while ignoring (%d)", p->ign);
! 1153:
1.18 kristaps 1154: /*
1155: * Here we print our standard mdoc(7) prologue.
1156: * We use the title set with @settitle for the `Nd' description
1157: * and the source document filename (the first one as invoked on
1158: * the command line) for the title.
1159: * The date is set to the current date.
1160: */
1.10 kristaps 1161: t = time(NULL);
1162: strftime(date, sizeof(date), "%F", localtime(&t));
1.1 kristaps 1163:
1.10 kristaps 1164: teximacroopen(p, "Dd");
1165: texiputchars(p, date);
1166: teximacroclose(p);
1167: teximacroopen(p, "Dt");
1168: for (cp = p->title; '\0' != *cp; cp++)
1169: texiputchar(p, toupper(*cp));
1.11 kristaps 1170: texiputchars(p, " 7");
1.10 kristaps 1171: teximacroclose(p);
1.5 kristaps 1172: teximacro(p, "Os");
1173: teximacro(p, "Sh NAME");
1.10 kristaps 1174: teximacroopen(p, "Nm");
1175: texiputchars(p, p->title);
1176: teximacroclose(p);
1177: teximacroopen(p, "Nd");
1178: texiputchars(p, NULL != p->subtitle ?
1179: p->subtitle : "Unknown description");
1180: teximacroclose(p);
1.11 kristaps 1181: p->seenvs = 1;
1.12 kristaps 1182: dosection(p, cmd, buf, sz, pos);
1.1 kristaps 1183: }
1184:
1185: static void
1186: doitem(struct texi *p, enum texicmd cmd,
1187: const char *buf, size_t sz, size_t *pos)
1188: {
1189:
1.18 kristaps 1190: /* Multitable is using raw tbl(7). */
1191: if (TEXILIST_TABLE == p->list) {
1192: texiputchar(p, '\n');
1193: return;
1194: }
1195:
1.3 kristaps 1196: if (p->outmacro)
1197: texierr(p, "item in open line scope!?");
1198: else if (p->literal)
1199: texierr(p, "item in a literal scope!?");
1200:
1201: switch (p->list) {
1202: case (TEXILIST_ITEM):
1.5 kristaps 1203: teximacroopen(p, "It");
1.3 kristaps 1204: break;
1205: case (TEXILIST_NOITEM):
1.5 kristaps 1206: teximacro(p, "It");
1.3 kristaps 1207: break;
1208: default:
1.11 kristaps 1209: texivspace(p);
1.3 kristaps 1210: break;
1211: }
1.18 kristaps 1212:
1213: /* Trick so we don't start with Pp. */
1.11 kristaps 1214: p->seenvs = 1;
1.3 kristaps 1215: parseeoln(p, buf, sz, pos);
1.1 kristaps 1216:
1.3 kristaps 1217: if (TEXILIST_ITEM == p->list)
1218: teximacroclose(p);
1.9 kristaps 1219: else if (p->outcol > 0)
1.1 kristaps 1220: texiputchar(p, '\n');
1.18 kristaps 1221: }
1222:
1223: static void
1224: dotab(struct texi *p, enum texicmd cmd,
1225: const char *buf, size_t sz, size_t *pos)
1226: {
1227:
1228: /* This command is only useful in @multitable. */
1229: if (TEXILIST_TABLE == p->list)
1230: texiputchar(p, '\t');
1231: }
1232:
1233: static void
1234: domultitable(struct texi *p, enum texicmd cmd,
1235: const char *buf, size_t sz, size_t *pos)
1236: {
1237: enum texilist sv = p->list;
1238: enum texicmd type;
1239: size_t i, end, columns;
1240:
1241: p->list = TEXILIST_TABLE;
1242: teximacro(p, "TS");
1243: columns = 0;
1244:
1245: /* Advance to the first argument... */
1246: while (*pos < sz && isws(buf[*pos]))
1247: advance(p, buf, pos);
1248:
1249: /* Make sure we don't print anything when scanning. */
1250: p->ign++;
1251: if ('@' == buf[*pos]) {
1252: /*
1253: * Look for @columnfractions.
1254: * We ignore these, but we do use the number of
1255: * arguments to set the number of columns that we'll
1256: * have.
1257: */
1258: type = texicmd(p, buf, *pos, sz, &end);
1259: advanceto(p, buf, pos, end);
1260: if (TEXICMD_COLUMNFRACTIONS != type)
1.25 kristaps 1261: texierr(p, "unknown multitable command");
1.18 kristaps 1262: while (*pos < sz && '\n' != buf[*pos]) {
1263: while (*pos < sz && isws(buf[*pos]))
1264: advance(p, buf, pos);
1265: while (*pos < sz && ! isws(buf[*pos])) {
1266: if ('\n' == buf[*pos])
1267: break;
1268: advance(p, buf, pos);
1269: }
1270: columns++;
1271: }
1272: } else
1273: /*
1274: * We have arguments.
1275: * We could parse these, but it's easier to just let
1276: * tbl(7) figure it out.
1277: * So use this only to count arguments.
1278: */
1279: while (parselinearg(p, buf, sz, pos) > 0)
1280: columns++;
1281: p->ign--;
1282:
1283: /* Left-justify each table entry. */
1284: for (i = 0; i < columns; i++) {
1285: if (i > 0)
1286: texiputchar(p, ' ');
1287: texiputchar(p, 'l');
1288: }
1289: texiputchars(p, ".\n");
1290: p->outmacro++;
1291: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1292: p->outmacro--;
1293: teximacro(p, "TE");
1294: p->list = sv;
1.1 kristaps 1295: }
1296:
1297: static void
1298: dotable(struct texi *p, enum texicmd cmd,
1299: const char *buf, size_t sz, size_t *pos)
1300: {
1.3 kristaps 1301: enum texilist sv = p->list;
1302:
1303: p->list = TEXILIST_ITEM;
1.5 kristaps 1304: teximacro(p, "Bl -tag -width Ds");
1.12 kristaps 1305: /* FIXME: ignore and parseeoln. */
1306: advanceeoln(p, buf, sz, pos, 1);
1.11 kristaps 1307: p->seenvs = 1;
1.20 kristaps 1308: parseto(p, buf, sz, pos, texitoks[cmd].tok);
1.5 kristaps 1309: teximacro(p, "El");
1.3 kristaps 1310: p->list = sv;
1.1 kristaps 1311: }
1312:
1313: static void
1.2 kristaps 1314: doenumerate(struct texi *p, enum texicmd cmd,
1315: const char *buf, size_t sz, size_t *pos)
1316: {
1.3 kristaps 1317: enum texilist sv = p->list;
1.2 kristaps 1318:
1.3 kristaps 1319: p->list = TEXILIST_NOITEM;
1.5 kristaps 1320: teximacro(p, "Bl -enum");
1.11 kristaps 1321: p->seenvs = 1;
1.12 kristaps 1322: /* FIXME: ignore and parseeoln. */
1323: advanceeoln(p, buf, sz, pos, 1);
1.2 kristaps 1324: parseto(p, buf, sz, pos, "enumerate");
1.5 kristaps 1325: teximacro(p, "El");
1.3 kristaps 1326: p->list = sv;
1.2 kristaps 1327: }
1328:
1329: static void
1.1 kristaps 1330: doitemize(struct texi *p, enum texicmd cmd,
1331: const char *buf, size_t sz, size_t *pos)
1332: {
1.3 kristaps 1333: enum texilist sv = p->list;
1.1 kristaps 1334:
1.21 kristaps 1335: p->list = TEXILIST_NOITEM;
1.5 kristaps 1336: teximacro(p, "Bl -bullet");
1.11 kristaps 1337: p->seenvs = 1;
1.12 kristaps 1338: /* FIXME: ignore and parseeoln. */
1339: advanceeoln(p, buf, sz, pos, 1);
1.1 kristaps 1340: parseto(p, buf, sz, pos, "itemize");
1.5 kristaps 1341: teximacro(p, "El");
1.3 kristaps 1342: p->list = sv;
1.1 kristaps 1343: }
1344:
1345: static void
1346: doignbracket(struct texi *p, enum texicmd cmd,
1347: const char *buf, size_t sz, size_t *pos)
1348: {
1349:
1.3 kristaps 1350: p->ign++;
1.1 kristaps 1351: parsebracket(p, buf, sz, pos);
1.3 kristaps 1352: p->ign--;
1.1 kristaps 1353: }
1354:
1355: static void
1356: doignline(struct texi *p, enum texicmd cmd,
1357: const char *buf, size_t sz, size_t *pos)
1358: {
1359:
1.12 kristaps 1360: /* FIXME: ignore and parseeoln. */
1.3 kristaps 1361: advanceeoln(p, buf, sz, pos, 1);
1.1 kristaps 1362: }
1363:
1.8 kristaps 1364: /*
1365: * Parse colon-separated directories from "cp" (if not NULL) and returns
1366: * the array of pointers.
1367: * Prepends "base" to the array.
1368: * This does NOT sanitise the directories!
1369: */
1.5 kristaps 1370: static char **
1371: parsedirs(const char *base, const char *cp, size_t *sz)
1372: {
1373: char *tok, *str, *tofree;
1374: const char *cpp;
1375: size_t i;
1376: char **dirs;
1377:
1378: *sz = NULL != (cpp = cp) ? 2 : 1;
1379: if (*sz > 1)
1380: for ( ; NULL != (cpp = strchr(cpp, ':')); (*sz)++)
1381: cpp++;
1382:
1383: dirs = calloc(*sz, sizeof(char *));
1384: if (NULL == dirs) {
1385: perror(NULL);
1386: exit(EXIT_FAILURE);
1387: } else if (NULL == (dirs[0] = strdup(base))) {
1388: perror(NULL);
1389: exit(EXIT_FAILURE);
1390: }
1391:
1392: if (NULL == cp)
1393: return(dirs);
1394:
1395: if (NULL == (tofree = tok = str = strdup(cp))) {
1396: perror(NULL);
1397: exit(EXIT_FAILURE);
1398: }
1399:
1400: for (i = 1; NULL != (tok = strsep(&str, ":")); i++)
1401: if (NULL == (dirs[i] = strdup(tok))) {
1402: perror(NULL);
1403: exit(EXIT_FAILURE);
1404: }
1405:
1406: free(tofree);
1407: return(dirs);
1408: }
1409:
1.1 kristaps 1410: int
1411: main(int argc, char *argv[])
1412: {
1413: struct texi texi;
1.2 kristaps 1414: int c;
1415: char *path, *dir;
1.10 kristaps 1416: const char *progname, *Idir, *cp;
1.1 kristaps 1417:
1418: progname = strrchr(argv[0], '/');
1419: if (progname == NULL)
1420: progname = argv[0];
1421: else
1422: ++progname;
1423:
1.10 kristaps 1424: memset(&texi, 0, sizeof(struct texi));
1.5 kristaps 1425: Idir = NULL;
1.10 kristaps 1426:
1.5 kristaps 1427: while (-1 != (c = getopt(argc, argv, "I:")))
1.1 kristaps 1428: switch (c) {
1.5 kristaps 1429: case ('I'):
1430: Idir = optarg;
1431: break;
1.1 kristaps 1432: default:
1433: goto usage;
1434: }
1435:
1436: argv += optind;
1437: if (0 == (argc -= optind))
1438: goto usage;
1439:
1.2 kristaps 1440: if (NULL == (path = strdup(argv[0]))) {
1441: perror(NULL);
1442: exit(EXIT_FAILURE);
1443: } else if (NULL == (dir = dirname(path))) {
1444: perror(argv[0]);
1445: free(path);
1446: exit(EXIT_FAILURE);
1447: }
1448: free(path);
1449:
1.10 kristaps 1450: if (NULL != (cp = strrchr(argv[0], '/')))
1451: texi.title = strdup(cp + 1);
1452: else
1453: texi.title = strdup(argv[0]);
1454:
1455: if (NULL == texi.title) {
1456: perror(NULL);
1457: exit(EXIT_FAILURE);
1458: } else if (NULL != (path = strchr(texi.title, '.')))
1459: *path = '\0';
1460:
1.3 kristaps 1461: texi.ign = 1;
1.5 kristaps 1462: texi.dirs = parsedirs(dir, Idir, &texi.dirsz);
1.16 kristaps 1463: parsefile(&texi, argv[0], 1);
1.5 kristaps 1464: /* We shouldn't get here. */
1.2 kristaps 1465: texiexit(&texi);
1466: return(EXIT_FAILURE);
1.1 kristaps 1467: usage:
1.8 kristaps 1468: fprintf(stderr, "usage: %s [-Idirs] file\n", progname);
1.1 kristaps 1469: return(EXIT_FAILURE);
1470: }
CVSweb