Annotation of texi2mdoc/main.c, Revision 1.72
1.72 ! schwarze 1: /* $Id: main.c,v 1.71 2015/03/19 09:53:35 schwarze 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: */
1.37 kristaps 17: #if defined(__linux__) || defined(__MINT__)
18: # define _GNU_SOURCE /* memmem */
19: #endif
1.72 ! schwarze 20:
! 21: #include <sys/stat.h>
! 22:
1.1 kristaps 23: #include <assert.h>
24: #include <ctype.h>
25: #include <getopt.h>
1.2 kristaps 26: #include <libgen.h>
27: #include <limits.h>
1.1 kristaps 28: #include <stdarg.h>
29: #include <stdio.h>
30: #include <stdlib.h>
31: #include <string.h>
1.72 ! schwarze 32: #include <time.h>
1.47 kristaps 33: #include <unistd.h>
1.1 kristaps 34:
1.24 kristaps 35: #include "extern.h"
1.1 kristaps 36:
1.66 kristaps 37: #define HAVE_INDEX 1
38:
39: /*
40: * Texinfo can change the "meaning" of its section headings: chapter,
41: * section, subsection, etc., can be promoted and/or demoted to other
42: * levels of heading.
43: * Thus, we use an offset and just jump into this array.
44: */
1.23 kristaps 45: #define SECTSZ 4
46: static const char *const sects[SECTSZ] = {
1.66 kristaps 47: "Sh", /* Chapters (sections) */
48: "Ss", /* Sections (subsections) */
49: "Em", /* Subsections (subsubsection) */
50: "Sy", /* Subsubsections (...). */
1.23 kristaps 51: };
52:
1.46 kristaps 53: static void doaccent(struct texi *, enum texicmd, size_t *);
54: static void doblock(struct texi *, enum texicmd, size_t *);
55: static void dobracket(struct texi *, enum texicmd, size_t *);
56: static void dobye(struct texi *, enum texicmd, size_t *);
1.61 kristaps 57: static void docopying(struct texi *, enum texicmd, size_t *);
1.46 kristaps 58: static void dodefindex(struct texi *, enum texicmd, size_t *);
59: static void dodefn(struct texi *, enum texicmd, size_t *);
60: static void dodisplay(struct texi *, enum texicmd, size_t *);
61: static void doend(struct texi *, enum texicmd, size_t *);
62: static void doenumerate(struct texi *, enum texicmd, size_t *);
63: static void doexample(struct texi *, enum texicmd, size_t *);
64: static void doignargn(struct texi *, enum texicmd, size_t *);
65: static void doignblock(struct texi *, enum texicmd, size_t *);
66: static void doignbracket(struct texi *, enum texicmd, size_t *);
67: static void doignline(struct texi *, enum texicmd, size_t *);
1.66 kristaps 68: static void doindex(struct texi *, enum texicmd, size_t *);
1.46 kristaps 69: static void doinline(struct texi *, enum texicmd, size_t *);
70: static void doinclude(struct texi *, enum texicmd, size_t *);
1.61 kristaps 71: static void doinsertcopying(struct texi *, enum texicmd, size_t *);
1.46 kristaps 72: static void doitem(struct texi *, enum texicmd, size_t *);
73: static void doitemize(struct texi *, enum texicmd, size_t *);
74: static void dolink(struct texi *, enum texicmd, size_t *);
75: static void domacro(struct texi *, enum texicmd, size_t *);
76: static void domath(struct texi *, enum texicmd, size_t *);
1.64 kristaps 77: static void domenu(struct texi *, enum texicmd, size_t *);
1.46 kristaps 78: static void domultitable(struct texi *, enum texicmd, size_t *);
1.65 kristaps 79: static void donode(struct texi *, enum texicmd, size_t *);
1.66 kristaps 80: static void doprintindex(struct texi *, enum texicmd, size_t *);
1.46 kristaps 81: static void doquotation(struct texi *, enum texicmd, size_t *);
82: static void dotable(struct texi *, enum texicmd, size_t *);
83: static void dosecoffs(struct texi *, enum texicmd, size_t *);
84: static void dosection(struct texi *, enum texicmd, size_t *);
85: static void dosp(struct texi *, enum texicmd, size_t *);
86: static void dosymbol(struct texi *, enum texicmd, size_t *);
87: static void dotab(struct texi *, enum texicmd, size_t *);
88: static void dotitle(struct texi *, enum texicmd, size_t *);
89: static void dovalue(struct texi *, enum texicmd, size_t *);
90: static void doverb(struct texi *, enum texicmd, size_t *);
91: static void doverbatim(struct texi *, enum texicmd, size_t *);
92: static void doverbinclude(struct texi *, enum texicmd, size_t *);
1.1 kristaps 93:
1.24 kristaps 94: static const struct texitok __texitoks[TEXICMD__MAX] = {
1.20 kristaps 95: /* TEXICMD__BEGIN */
1.42 kristaps 96: { doignline, "afourpaper", 10 }, /* TEXICMD_A4PAPER */
97: { dosymbol, "AA", 2 }, /* TEXICMD_AA */
98: { dosymbol, "aa", 2 }, /* TEXICMD_AASMALL */
1.8 kristaps 99: { doignargn, "acronym", 7 }, /* TEXICMD_ACRONYM */
1.16 kristaps 100: { doaccent, "'", 1 }, /* TEXICMD_ACUTE */
1.42 kristaps 101: { dosymbol, "AE", 2 }, /* TEXICMD_AE */
102: { dosymbol, "ae", 2 }, /* TEXICMD_AESMALL */
1.1 kristaps 103: { doignbracket, "anchor", 6 }, /* TEXICMD_ANCHOR */
1.12 kristaps 104: { dosection, "appendix", 8 }, /* TEXICMD_APPENDIX */
105: { dosection, "appendixsec", 11 }, /* TEXICMD_APPENDIXSEC */
1.66 kristaps 106: { dosection, "appendixsubsec", 14 }, /* TEXICMD_APPENDIXSUBSEC */
107: { dosection, "appendixsubsubsec", 17 }, /* TEXICMD_APPENDIXSUBSUBSEC */
1.25 kristaps 108: { doinline, "asis", 4 }, /* TEXICMD_ASIS */
1.3 kristaps 109: { dosymbol, "*", 1 }, /* TEXICMD_ASTERISK */
1.1 kristaps 110: { dosymbol, "@", 1 }, /* TEXICMD_AT */
1.3 kristaps 111: { doignline, "author", 6 }, /* TEXICMD_AUTHOR */
1.59 kristaps 112: { doinline, "b", 1 }, /* TEXICMD_B */
113: { dosymbol, "\\", 1 }, /* TEXICMD_BACKSLASH */
1.3 kristaps 114: { dosymbol, "!", 1 }, /* TEXICMD_BANG */
1.7 kristaps 115: { dosymbol, "bullet", 6 }, /* TEXICMD_BULLET */
1.1 kristaps 116: { dobye, "bye", 3 }, /* TEXICMD_BYE */
1.34 kristaps 117: { doblock, "cartouche", 9 }, /* TEXICMD_CARTOUCHE */
118: { doaccent, ",", 1 }, /* TEXICMD_CEDILLA */
1.12 kristaps 119: { doignline, "center", 6 }, /* TEXICMD_CENTER */
120: { dosection, "chapter", 7 }, /* TEXICMD_CHAPTER */
1.66 kristaps 121: { doindex, "cindex", 6 }, /* TEXICMD_CINDEX */
1.16 kristaps 122: { doaccent, "^", 1 }, /* TEXICMD_CIRCUMFLEX */
1.24 kristaps 123: { doinline, "cite", 4 }, /* TEXICMD_CITE */
124: { dovalue, "clear", 5 }, /* TEXICMD_CLEAR */
1.21 kristaps 125: { doinline, "code", 4 }, /* TEXICMD_CODE */
1.3 kristaps 126: { dosymbol, ":", 1 }, /* TEXICMD_COLON */
1.18 kristaps 127: { NULL, "columnfractions", 15 }, /* TEXICMD_COLUMNFRACTIONS */
1.35 kristaps 128: { dosymbol, "comma", 5 }, /* TEXICMD_COMMA */
1.12 kristaps 129: { doinline, "command", 7 }, /* TEXICMD_COMMAND */
1.1 kristaps 130: { doignline, "c", 1 }, /* TEXICMD_COMMENT */
1.2 kristaps 131: { doignline, "comment", 7 }, /* TEXICMD_COMMENT_LONG */
1.1 kristaps 132: { doignline, "contents", 8 }, /* TEXICMD_CONTENTS */
1.61 kristaps 133: { docopying, "copying", 7 }, /* TEXICMD_COPYING */
1.1 kristaps 134: { dosymbol, "copyright", 9 }, /* TEXICMD_COPYRIGHT */
1.27 kristaps 135: { dodefindex, "defcodeindex", 12 }, /* TEXICMD_DEFCODEINDEX */
1.15 kristaps 136: { dodefn, "deffn", 5 }, /* TEXICMD_DEFFN */
137: { dodefn, "deffnx", 6 }, /* TEXICMD_DEFFNX */
1.27 kristaps 138: { dodefindex, "defindex", 8 }, /* TEXICMD_DEFINDEX */
1.15 kristaps 139: { dodefn, "defmac", 6 }, /* TEXICMD_DEFMAC */
140: { dodefn, "defmacx", 7 }, /* TEXICMD_DEFMACX */
1.68 kristaps 141: { dodefn, "defop", 5 }, /* TEXICMD_DEFOP */
142: { dodefn, "defopx", 6 }, /* TEXICMD_DEFOPX */
143: { dodefn, "defopt", 6 }, /* TEXICMD_DEFOPT */
144: { dodefn, "defoptx", 7 }, /* TEXICMD_DEFOPTX */
1.15 kristaps 145: { dodefn, "deftp", 5 }, /* TEXICMD_DEFTP */
146: { dodefn, "deftpx", 6 }, /* TEXICMD_DEFTPX */
147: { dodefn, "deftypefn", 9 }, /* TEXICMD_DEFTYPEFN */
148: { dodefn, "deftypefnx", 10 }, /* TEXICMD_DEFTYPEFNX */
149: { dodefn, "deftypefun", 10 }, /* TEXICMD_DEFTYPEFUN */
150: { dodefn, "deftypefunx", 11 }, /* TEXICMD_DEFTYPEFUNX */
1.34 kristaps 151: { dodefn, "deftypemethod", 13 }, /* TEXICMD_DEFTYPEMETHOD */
152: { dodefn, "deftypemethodx", 14 }, /* TEXICMD_DEFTYPEMETHODX */
1.15 kristaps 153: { dodefn, "deftypevar", 10 }, /* TEXICMD_DEFTYPEVAR */
154: { dodefn, "deftypevarx", 11 }, /* TEXICMD_DEFTYPEVARX */
155: { dodefn, "deftypevr", 9 }, /* TEXICMD_DEFTYPEVR */
156: { dodefn, "deftypevrx", 10 }, /* TEXICMD_DEFTYPEVRX */
157: { dodefn, "defun", 5 }, /* TEXICMD_DEFUN */
158: { dodefn, "defunx", 6 }, /* TEXICMD_DEFUNX */
159: { dodefn, "defvar", 6 }, /* TEXICMD_DEFVAR */
160: { dodefn, "defvarx", 7 }, /* TEXICMD_DEFVARX */
161: { dodefn, "defvr", 5 }, /* TEXICMD_DEFVR */
162: { dodefn, "defvrx", 6 }, /* TEXICMD_DEFVRX */
1.68 kristaps 163: { doignblock, "detailmenu", 10 }, /* TEXICMD_DETAILMENU */
1.21 kristaps 164: { doinline, "dfn", 3 }, /* TEXICMD_DFN */
1.42 kristaps 165: { dosymbol, "DH", 2 }, /* TEXICMD_DH */
166: { dosymbol, "dh", 2 }, /* TEXICMD_DHSMALL */
1.1 kristaps 167: { doignline, "dircategory", 11 }, /* TEXICMD_DIRCATEGORY */
168: { doignblock, "direntry", 8 }, /* TEXICMD_DIRENTRY */
1.3 kristaps 169: { dodisplay, "display", 7 }, /* TEXICMD_DISPLAY */
1.28 kristaps 170: { doignbracket, "dmn", 3 }, /* TEXICMD_DMN */
1.40 kristaps 171: { doignblock, "documentdescription", 19 }, /* TEXICMD_DOCUMENTDESCRIPTION */
172: { doignline, "documentencoding", 16 }, /* TEXICMD_DOCUMENTENCODING */
1.44 kristaps 173: { doignline, "documentlanguage", 16 }, /* TEXICMD_DOCUMENTLANGUAGE */
1.42 kristaps 174: { doaccent, "dotaccent", 9 }, /* TEXICMD_DOTACCENT */
175: { doaccent, "dotless", 7 }, /* TEXICMD_DOTLESS */
1.2 kristaps 176: { dosymbol, "dots", 4 }, /* TEXICMD_DOTS */
1.8 kristaps 177: { dolink, "email", 5 }, /* TEXICMD_EMAIL */
1.21 kristaps 178: { doinline, "emph", 4 }, /* TEXICMD_EMPH */
1.44 kristaps 179: { doend, "end", 3 }, /* TEXICMD_END */
1.34 kristaps 180: { dosymbol, "enddots", 7 }, /* TEXICMD_ENDDOTS */
1.2 kristaps 181: { doenumerate, "enumerate", 9 }, /* TEXICMD_ENUMERATE */
1.12 kristaps 182: { doinline, "env", 3 }, /* TEXICMD_ENV */
1.28 kristaps 183: { dosymbol, "equiv", 5 }, /* TEXICMD_EQUIV */
1.15 kristaps 184: { dosymbol, "error", 5 }, /* TEXICMD_ERROR */
1.43 kristaps 185: { dosymbol, "euro", 4 }, /* TEXICMD_EURO */
1.1 kristaps 186: { doexample, "example", 7 }, /* TEXICMD_EXAMPLE */
1.42 kristaps 187: { dosymbol, "exclamdown", 10 }, /* TEXICMD_EXCLAMDOWN */
1.25 kristaps 188: { doignline, "exdent", 6 }, /* TEXICMD_EXDENT */
1.17 kristaps 189: { dosymbol, "expansion", 9 }, /* TEXICMD_EXPANSION */
1.12 kristaps 190: { doinline, "file", 4 }, /* TEXICMD_FILE */
1.17 kristaps 191: { doignline, "finalout", 8 }, /* TEXICMD_FINALOUT */
1.66 kristaps 192: { doindex, "findex", 6 }, /* TEXICMD_FINDEX */
1.44 kristaps 193: { doblock, "flushleft", 9 }, /* TEXICMD_FLUSHLEFT */
194: { doblock, "flushright", 10 }, /* TEXICMD_FLUSHRIGHT */
195: { doignline, "firstparagraphindent", 20 }, /* TEXICMD_FIRSTPARAGRAPHINDENT */
1.32 kristaps 196: { doignbracket, "footnote", 8 }, /* TEXICMD_FOOTNOTE */
1.44 kristaps 197: { doignline, "footnotestyle", 13 }, /* TEXICMD_FOOTNOTESTYLE */
1.20 kristaps 198: { dotable, "ftable", 6 }, /* TEXICMD_FTABLE */
199: { dodisplay, "format", 6 }, /* TEXICMD_FORMAT */
1.43 kristaps 200: { dosymbol, "geq", 3 }, /* TEXICMD_GEQ */
1.16 kristaps 201: { doaccent, "`", 1 }, /* TEXICMD_GRAVE */
1.3 kristaps 202: { doblock, "group", 5 }, /* TEXICMD_GROUP */
1.43 kristaps 203: { dosymbol, "guillemetleft", 13 }, /* TEXICMD_GUILLEMETLEFT */
204: { dosymbol, "guillemetright", 14 }, /* TEXICMD_GUILLEMETRIGHT */
205: { dosymbol, "guillemotleft", 13 }, /* TEXICMD_GUILLEMOTLEFT */
206: { dosymbol, "guillemotright", 14 }, /* TEXICMD_GUILLEMOTRIGHT */
207: { dosymbol, "guilsinglleft", 13 }, /* TEXICMD_GUILSINGLLEFT */
208: { dosymbol, "guilsinglright", 14 }, /* TEXICMD_GUILSINGLRIGHT */
1.42 kristaps 209: { doaccent, "H", 1 }, /* TEXICMD_H */
1.2 kristaps 210: { dosection, "heading", 7 }, /* TEXICMD_HEADING */
1.3 kristaps 211: { doignline, "headings", 8 }, /* TEXICMD_HEADINGS */
1.18 kristaps 212: { doitem, "headitem", 8 }, /* TEXICMD_HEADITEM */
1.25 kristaps 213: { doignblock, "html", 4 }, /* TEXICMD_HTML */
1.3 kristaps 214: { dosymbol, "-", 1 }, /* TEXICMD_HYPHEN */
1.21 kristaps 215: { doinline, "i", 1 }, /* TEXICMD_I */
1.24 kristaps 216: { dovalue, "ifclear", 7 }, /* TEXICMD_IFCLEAR */
1.14 kristaps 217: { doignblock, "ifdocbook", 9 }, /* TEXICMD_IFDOCBOOK */
1.1 kristaps 218: { doignblock, "ifhtml", 6 }, /* TEXICMD_IFHTML */
1.26 kristaps 219: { doblock, "ifinfo", 6 }, /* TEXICMD_IFINFO */
1.14 kristaps 220: { doblock, "ifnotdocbook", 12 }, /* TEXICMD_IFNOTDOCBOOK */
221: { doblock, "ifnothtml", 9 }, /* TEXICMD_IFNOTHTML */
222: { doblock, "ifnotinfo", 9 }, /* TEXICMD_IFNOTINFO */
223: { doignblock, "ifnotplaintext", 14 }, /* TEXICMD_IFNOTPLAINTEXT */
1.3 kristaps 224: { doblock, "ifnottex", 8 }, /* TEXICMD_IFNOTTEX */
1.14 kristaps 225: { doblock, "ifnotxml", 8 }, /* TEXICMD_IFNOTXML */
226: { doblock, "ifplaintext", 11 }, /* TEXICMD_IFPLAINTEXT */
1.1 kristaps 227: { doignblock, "iftex", 5 }, /* TEXICMD_IFTEX */
1.30 kristaps 228: { dovalue, "ifset", 5 }, /* TEXICMD_IFSET */
1.14 kristaps 229: { doignblock, "ifxml", 5 }, /* TEXICMD_IFXML */
1.17 kristaps 230: { doignblock, "ignore", 6 }, /* TEXICMD_IGNORE */
1.1 kristaps 231: { doignbracket, "image", 5 }, /* TEXICMD_IMAGE */
1.2 kristaps 232: { doinclude, "include", 7 }, /* TEXICMD_INCLUDE */
1.13 kristaps 233: { dodisplay, "indentblock", 11 }, /* TEXICMD_INDENTBLOCK */
1.44 kristaps 234: { dolink, "indicateurl", 11 }, /* TEXICMD_INDICATEURL */
235: { dolink, "inforef", 7 }, /* TEXICMD_INFOREF */
1.61 kristaps 236: { doinsertcopying, "insertcopying", 13 }, /* TEXICMD_INSERTCOPYING */
1.1 kristaps 237: { doitem, "item", 4 }, /* TEXICMD_ITEM */
238: { doitemize, "itemize", 7 }, /* TEXICMD_ITEMIZE */
1.20 kristaps 239: { doitem, "itemx", 5 }, /* TEXICMD_ITEMX */
1.21 kristaps 240: { doinline, "kbd", 3 }, /* TEXICMD_KBD */
1.18 kristaps 241: { dobracket, "key", 3 }, /* TEXICMD_KEY */
1.20 kristaps 242: { doignline, "kindex", 6 }, /* TEXICMD_KINDEX */
1.42 kristaps 243: { dosymbol, "L", 1 }, /* TEXICMD_L */
1.1 kristaps 244: { dosymbol, "LaTeX", 5 }, /* TEXICMD_LATEX */
1.43 kristaps 245: { dosymbol, "leq", 3 }, /* TEXICMD_LEQ */
1.23 kristaps 246: { dosecoffs, "lowersections", 13 }, /* TEXICMD_LOWERSECTIONS */
1.42 kristaps 247: { dosymbol, "l", 1 }, /* TEXICMD_LSMALL */
1.30 kristaps 248: { domacro, "macro", 5 }, /* TEXICMD_MACRO */
1.42 kristaps 249: { doaccent, "=", 1 }, /* TEXICMD_MACRON */
1.3 kristaps 250: { domath, "math", 4 }, /* TEXICMD_MATH */
1.65 kristaps 251: { domenu, "menu", 4 }, /* TEXICMD_MENU */
1.25 kristaps 252: { dosymbol, "minus", 5 }, /* TEXICMD_MINUS */
1.18 kristaps 253: { domultitable, "multitable", 10 }, /* TEXICMD_MULTITABLE */
1.15 kristaps 254: { doignline, "need", 4 }, /* TEXICMD_NEED */
1.3 kristaps 255: { dosymbol, "\n", 1 }, /* TEXICMD_NEWLINE */
1.65 kristaps 256: { donode, "node", 4 }, /* TEXICMD_NODE */
1.3 kristaps 257: { doignline, "noindent", 8 }, /* TEXICMD_NOINDENT */
1.42 kristaps 258: { dosymbol, "O", 1 }, /* TEXICMD_O */
259: { dosymbol, "OE", 2 }, /* TEXICMD_OE */
260: { dosymbol, "oe", 2 }, /* TEXICMD_OESMALL */
261: { doaccent, "ogonek", 6 }, /* TEXICMD_OGONEK */
1.16 kristaps 262: { doinline, "option", 6 }, /* TEXICMD_OPTION */
1.42 kristaps 263: { dosymbol, "ordf", 4 }, /* TEXICMD_ORDF */
264: { dosymbol, "ordm", 4 }, /* TEXICMD_ORDM */
265: { dosymbol, "o", 1 }, /* TEXICMD_OSMALL */
1.3 kristaps 266: { doignline, "page", 4 }, /* TEXICMD_PAGE */
1.25 kristaps 267: { doignline, "paragraphindent", 15 }, /* TEXICMD_PARINDENT */
268: { dosymbol, ".", 1 }, /* TEXICMD_PERIOD */
1.28 kristaps 269: { doignline, "pindex", 6 }, /* TEXICMD_PINDEX */
1.43 kristaps 270: { dosymbol, "pounds", 6 }, /* TEXICMD_POUNDS */
1.66 kristaps 271: { doprintindex, "printindex", 10 }, /* TEXICMD_PRINTINDEX */
1.42 kristaps 272: { dolink, "pxref", 5 }, /* TEXICMD_PXREF */
273: { dosymbol, "questiondown", 12 }, /* TEXICMD_QUESTIONDOWN */
274: { dosymbol, "?", 1 }, /* TEXICMD_QUESTIONMARK */
275: { doquotation, "quotation", 9 }, /* TEXICMD_QUOTATION */
1.43 kristaps 276: { dosymbol, "quotedblbase", 12 }, /* TEXICMD_QUOTEDBLBASE */
277: { dosymbol, "quotedblleft", 12 }, /* TEXICMD_QUOTEDBLLEFT */
278: { dosymbol, "quotedblright", 13 }, /* TEXICMD_QUOTEDBLRIGHT */
279: { dosymbol, "quotesinglbase", 14 }, /* TEXICMD_QUOTESINGLBASE */
280: { dosymbol, "quoteleft", 9 }, /* TEXICMD_QUOTELEFT */
281: { dosymbol, "quoteright", 10 }, /* TEXICMD_QUOTERIGHT */
1.21 kristaps 282: { doinline, "r", 1 }, /* TEXICMD_R */
1.23 kristaps 283: { dosecoffs, "raisesections", 13 }, /* TEXICMD_RAISESECTIONS */
1.1 kristaps 284: { dobracket, "ref", 3 }, /* TEXICMD_REF */
1.28 kristaps 285: { doignline, "refill", 6 }, /* TEXICMD_REFILL */
1.43 kristaps 286: { dosymbol, "registeredsymbol", 16 }, /* TEXICMD_REGISTEREDSYMBOL */
1.15 kristaps 287: { dosymbol, "result", 6 }, /* TEXICMD_RESULT */
1.42 kristaps 288: { doaccent, "ringaccent", 10 }, /* TEXICMD_RINGACCENT */
1.21 kristaps 289: { doinline, "samp", 4 }, /* TEXICMD_SAMP */
290: { doinline, "sansserif", 9 }, /* TEXICMD_SANSSERIF */
1.58 kristaps 291: { doinline, "sc", 2 }, /* TEXICMD_SC */
1.1 kristaps 292: { dosection, "section", 7 }, /* TEXICMD_SECTION */
1.24 kristaps 293: { dovalue, "set", 3 }, /* TEXICMD_SET */
1.1 kristaps 294: { doignline, "setchapternewpage", 17 }, /* TEXICMD_SETCHAPNEWPAGE */
1.35 kristaps 295: { doignline, "setcontentsaftertitlepage", 25 }, /* TEXICMD_SETCONTENTSAFTER */
1.1 kristaps 296: { doignline, "setfilename", 11 }, /* TEXICMD_SETFILENAME */
1.10 kristaps 297: { dotitle, "settitle", 8 }, /* TEXICMD_SETTITLE */
1.25 kristaps 298: { doignline, "shortcontents", 13 }, /* TEXICMD_SHORTCONTENTS */
1.21 kristaps 299: { doinline, "slanted", 7 }, /* TEXICMD_SLANTED */
1.34 kristaps 300: { dosymbol, "/", 1 }, /* TEXICMD_SLASH */
1.3 kristaps 301: { dosp, "sp", 2 }, /* TEXICMD_SP */
302: { dosymbol, " ", 1 }, /* TEXICMD_SPACE */
1.17 kristaps 303: { doignline, "smallbook", 9 }, /* TEXICMD_SMALLBOOK */
1.12 kristaps 304: { dodisplay, "smalldisplay", 12 }, /* TEXICMD_SMALLDISPLAY */
1.3 kristaps 305: { doexample, "smallexample", 12 }, /* TEXICMD_SMALLEXAMPLE */
1.20 kristaps 306: { dodisplay, "smallformat", 11 }, /* TEXICMD_SMALLFORMAT */
1.13 kristaps 307: { dodisplay, "smallindentblock", 16 }, /* TEXICMD_SMALLINDENTBLOCK */
1.3 kristaps 308: { dosymbol, "{", 1 }, /* TEXICMD_SQUIGGLE_LEFT */
309: { dosymbol, "}", 1 }, /* TEXICMD_SQUIGGLE_RIGHT */
1.35 kristaps 310: { dosymbol, "ss", 2 }, /* TEXICMD_SS */
1.21 kristaps 311: { doinline, "strong", 6 }, /* TEXICMD_STRONG */
1.66 kristaps 312: { dosection, "subheading", 10 }, /* TEXICMD_SUBHEADING */
313: { dosection, "subsection", 10 }, /* TEXICMD_SUBSECTION */
314: { dosection, "subsubheading", 13 }, /* TEXICMD_SUBSUBHEADING */
315: { dosection, "subsubsection", 13 }, /* TEXICMD_SUBSUBSECTION */
1.3 kristaps 316: { doignline, "subtitle", 8 }, /* TEXICMD_SUBTITLE */
1.25 kristaps 317: { doignline, "summarycontents", 15 }, /* TEXICMD_SUMMARYCONTENTS */
1.50 kristaps 318: { dodefindex, "synindex", 8 }, /* TEXICMD_SYNINDEX */
319: { dodefindex, "syncodeindex", 12 }, /* TEXICMD_SYNCODEINDEX */
1.21 kristaps 320: { doinline, "t", 1 }, /* TEXICMD_T */
1.18 kristaps 321: { dotab, "tab", 3 }, /* TEXICMD_TAB */
322: { dosymbol, "\t", 1 }, /* TEXICMD_TABSYM */
1.1 kristaps 323: { dotable, "table", 5 }, /* TEXICMD_TABLE */
324: { doignblock, "tex", 3 }, /* TEXICMD_TEX */
325: { dosymbol, "TeX", 3 }, /* TEXICMD_TEXSYM */
1.43 kristaps 326: { dosymbol, "textdegree", 10 }, /* TEXICMD_TEXTDEGREE */
1.42 kristaps 327: { dosymbol, "TH", 2 }, /* TEXICMD_TH */
328: { dosymbol, "th", 2 }, /* TEXICMD_THSMALL */
1.35 kristaps 329: { dosymbol, "tie", 3 }, /* TEXICMD_TIE */
1.42 kristaps 330: { doaccent, "tieaccent", 9 }, /* TEXICMD_TIEACCENT */
1.16 kristaps 331: { doaccent, "~", 1 }, /* TEXICMD_TILDE */
1.66 kristaps 332: { doindex, "tindex", 6 }, /* TEXICMD_TINDEX */
1.3 kristaps 333: { doignline, "title", 5 }, /* TEXICMD_TITLE */
1.1 kristaps 334: { dobracket, "titlefont", 9 }, /* TEXICMD_TITLEFONT */
335: { doignblock, "titlepage", 9 }, /* TEXICMD_TITLEPAGE */
1.67 kristaps 336: { dosection, "top", 3 }, /* TEXICMD_TOP */
1.66 kristaps 337: { doindex, "tpindex", 7 }, /* TEXICMD_TPINDEX */
1.42 kristaps 338: { doaccent, "u", 1 }, /* TEXICMD_U */
339: { doaccent, "ubaraccent", 10 }, /* TEXICMD_UBARACCENT */
340: { doaccent, "udotaccent", 10 }, /* TEXICMD_UDOTACCENT */
1.16 kristaps 341: { doaccent, "\"", 1 }, /* TEXICMD_UMLAUT */
1.12 kristaps 342: { dosection, "unnumbered", 10 }, /* TEXICMD_UNNUMBERED */
1.2 kristaps 343: { dosection, "unnumberedsec", 13 }, /* TEXICMD_UNNUMBEREDSEC */
1.66 kristaps 344: { dosection, "unnumberedsubsec", 16 }, /* TEXICMD_UNNUMBEREDSUBSEC */
345: { dosection, "unnumberedsubsubsec", 19 }, /* TEXICMD_UNNUMBEREDSUBSUBSEC */
1.8 kristaps 346: { dolink, "uref", 4 }, /* TEXICMD_UREF */
347: { dolink, "url", 3 }, /* TEXICMD_URL */
1.34 kristaps 348: { doignline, "", 0 }, /* TEXICMD_USER_INDEX */
1.42 kristaps 349: { doaccent, "v", 1 }, /* TEXICMD_V */
1.24 kristaps 350: { dovalue, "value", 5 }, /* TEXICMD_VALUE */
1.12 kristaps 351: { doinline, "var", 3 }, /* TEXICMD_VAR */
1.33 kristaps 352: { doverb, "verb", 4 }, /* TEXICMD_VERB */
353: { doverbatim, "verbatim", 8 }, /* TEXICMD_VERBATIM */
1.16 kristaps 354: { doverbinclude, "verbatiminclude", 15 }, /* TEXICMD_VERBATIMINCLUDE */
1.66 kristaps 355: { doindex, "vindex", 6 }, /* TEXICMD_VINDEX */
356: { doindex, "vrindex", 7 }, /* TEXICMD_VRINDEX */
1.9 kristaps 357: { dosp, "vskip", 5 }, /* TEXICMD_VSKIP */
1.20 kristaps 358: { dotable, "vtable", 6 }, /* TEXICMD_VTABLE */
1.3 kristaps 359: { dobracket, "w", 1 }, /* TEXICMD_W */
1.8 kristaps 360: { dolink, "xref", 4 }, /* TEXICMD_XREF */
1.20 kristaps 361: /* TEXICMD__END */
1.1 kristaps 362: };
363:
1.24 kristaps 364: const struct texitok *const texitoks = __texitoks;
1.18 kristaps 365:
1.60 kristaps 366: /*
1.66 kristaps 367: * Define new indexes either by assignment or aliasing (both of these
368: * accept the first argument as the new index).
1.60 kristaps 369: */
1.2 kristaps 370: static void
1.46 kristaps 371: dodefindex(struct texi *p, enum texicmd cmd, size_t *pos)
1.27 kristaps 372: {
1.66 kristaps 373: size_t start;
1.27 kristaps 374:
1.46 kristaps 375: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
376: advance(p, pos);
1.66 kristaps 377: start = *pos;
378: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
379: advance(p, pos);
380: if (*pos == BUFSZ(p)) {
381: texiwarn(p, "unexpected EOF");
1.27 kristaps 382: return;
1.71 schwarze 383: }
1.66 kristaps 384: if (0 == *pos - start)
385: texiwarn(p, "zero-length index definition");
386: else
387: texindex_add(p, &BUF(p)[start], *pos - start);
388: advance(p, pos);
1.27 kristaps 389: }
390:
1.66 kristaps 391: /*
392: * Handle both possible "define function" (type, etc.) classes: where
393: * we'll have a body and without one (suffixed with "x").
394: */
1.27 kristaps 395: static void
1.46 kristaps 396: dodefn(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 397: {
398: const char *blk;
399:
1.5 kristaps 400: blk = NULL;
1.3 kristaps 401: switch (cmd) {
1.15 kristaps 402: case (TEXICMD_DEFFN):
1.35 kristaps 403: case (TEXICMD_DEFMAC):
1.68 kristaps 404: case (TEXICMD_DEFOP):
405: case (TEXICMD_DEFOPT):
1.15 kristaps 406: case (TEXICMD_DEFTP):
1.3 kristaps 407: case (TEXICMD_DEFTYPEFN):
408: case (TEXICMD_DEFTYPEFUN):
1.34 kristaps 409: case (TEXICMD_DEFTYPEMETHOD):
1.15 kristaps 410: case (TEXICMD_DEFTYPEVAR):
411: case (TEXICMD_DEFTYPEVR):
412: case (TEXICMD_DEFUN):
413: case (TEXICMD_DEFVAR):
414: case (TEXICMD_DEFVR):
1.5 kristaps 415: blk = texitoks[cmd].tok;
1.3 kristaps 416: break;
1.5 kristaps 417: default:
1.3 kristaps 418: break;
419: }
420:
421: if (p->ign) {
1.15 kristaps 422: NULL != blk ?
1.46 kristaps 423: parseto(p, pos, blk) :
424: parseeoln(p, pos);
1.3 kristaps 425: return;
426: }
427:
1.66 kristaps 428: if (p->seenvs >= 0) {
429: teximacro(p, "Pp");
430: p->seenvs = -1;
431: }
1.15 kristaps 432:
1.3 kristaps 433: switch (cmd) {
1.34 kristaps 434: case (TEXICMD_DEFTYPEMETHOD):
435: case (TEXICMD_DEFTYPEMETHODX):
436: texiputchars(p, "Method");
437: break;
1.15 kristaps 438: case (TEXICMD_DEFMAC):
439: case (TEXICMD_DEFMACX):
440: texiputchars(p, "Macro");
441: break;
1.68 kristaps 442: case (TEXICMD_DEFOPT):
443: case (TEXICMD_DEFOPTX):
444: texiputchars(p, "User Option");
445: break;
1.15 kristaps 446: case (TEXICMD_DEFTYPEVAR):
447: case (TEXICMD_DEFTYPEVARX):
448: case (TEXICMD_DEFVAR):
449: case (TEXICMD_DEFVARX):
450: texiputchars(p, "Variable");
451: break;
1.3 kristaps 452: case (TEXICMD_DEFTYPEFUN):
1.15 kristaps 453: case (TEXICMD_DEFTYPEFUNX):
454: case (TEXICMD_DEFUN):
455: case (TEXICMD_DEFUNX):
456: texiputchars(p, "Function");
1.3 kristaps 457: break;
458: default:
1.46 kristaps 459: parselinearg(p, pos);
1.3 kristaps 460: break;
461: }
1.15 kristaps 462:
1.66 kristaps 463: p->seenvs = 0;
1.48 kristaps 464: texiputchar(p, ':');
465: texiputchar(p, '\n');
1.15 kristaps 466:
467: switch (cmd) {
468: case (TEXICMD_DEFMAC):
469: case (TEXICMD_DEFMACX):
470: teximacroopen(p, "Dv");
1.71 schwarze 471: while (parselinearg(p, pos))
1.15 kristaps 472: /* Spin. */ ;
473: teximacroclose(p);
474: break;
475: case (TEXICMD_DEFFN):
476: case (TEXICMD_DEFFNX):
477: case (TEXICMD_DEFUN):
478: case (TEXICMD_DEFUNX):
479: teximacroopen(p, "Fo");
1.46 kristaps 480: parselinearg(p, pos);
1.15 kristaps 481: teximacroclose(p);
482: teximacroopen(p, "Fa");
1.71 schwarze 483: while (parselinearg(p, pos))
1.15 kristaps 484: /* Spin. */ ;
485: teximacroclose(p);
486: teximacro(p, "Fc");
487: break;
1.68 kristaps 488: case (TEXICMD_DEFOP):
489: case (TEXICMD_DEFOPX):
1.15 kristaps 490: case (TEXICMD_DEFTYPEFUN):
491: case (TEXICMD_DEFTYPEFUNX):
492: case (TEXICMD_DEFTYPEFN):
493: case (TEXICMD_DEFTYPEFNX):
1.34 kristaps 494: case (TEXICMD_DEFTYPEMETHOD):
495: case (TEXICMD_DEFTYPEMETHODX):
1.15 kristaps 496: teximacroopen(p, "Ft");
1.46 kristaps 497: parselinearg(p, pos);
1.15 kristaps 498: teximacroclose(p);
499: teximacroopen(p, "Fo");
1.46 kristaps 500: parselinearg(p, pos);
1.15 kristaps 501: teximacroclose(p);
502: teximacroopen(p, "Fa");
1.71 schwarze 503: while (parselinearg(p, pos))
1.15 kristaps 504: /* Spin. */ ;
505: teximacroclose(p);
506: teximacro(p, "Fc");
507: break;
508: case (TEXICMD_DEFTP):
509: case (TEXICMD_DEFTPX):
510: case (TEXICMD_DEFTYPEVAR):
511: case (TEXICMD_DEFTYPEVARX):
512: case (TEXICMD_DEFTYPEVR):
513: case (TEXICMD_DEFTYPEVRX):
514: teximacroopen(p, "Vt");
1.71 schwarze 515: while (parselinearg(p, pos))
1.15 kristaps 516: /* Spin. */ ;
517: teximacroclose(p);
518: break;
1.68 kristaps 519: case (TEXICMD_DEFOPT):
520: case (TEXICMD_DEFOPTX):
1.15 kristaps 521: case (TEXICMD_DEFVAR):
522: case (TEXICMD_DEFVARX):
523: case (TEXICMD_DEFVR):
524: case (TEXICMD_DEFVRX):
525: teximacroopen(p, "Va");
1.71 schwarze 526: while (parselinearg(p, pos))
1.15 kristaps 527: /* Spin. */ ;
528: teximacroclose(p);
529: break;
530: default:
531: abort();
1.3 kristaps 532: }
1.15 kristaps 533:
1.54 kristaps 534: if (NULL == blk)
535: return;
536:
537: /*
538: * All "block" definitions have their block bodies indented
539: * unless they have the "x" form of the command following.
540: * E.g.,
541: * @deffn some function
542: * @deffnx another
543: * An explanation.
544: * @end deffn
545: * With this loop, we delay opening the indented block until we
546: * skipped past conformant macros.
547: */
548: for (;;) {
549: switch (peekcmd(p, *pos)) {
550: case (TEXICMD_DEFFNX):
551: case (TEXICMD_DEFMACX):
1.68 kristaps 552: case (TEXICMD_DEFOPX):
553: case (TEXICMD_DEFOPTX):
1.54 kristaps 554: case (TEXICMD_DEFTPX):
555: case (TEXICMD_DEFTYPEFNX):
556: case (TEXICMD_DEFTYPEFUNX):
557: case (TEXICMD_DEFTYPEMETHODX):
558: case (TEXICMD_DEFTYPEVARX):
559: case (TEXICMD_DEFTYPEVRX):
560: case (TEXICMD_DEFUNX):
561: case (TEXICMD_DEFVARX):
562: case (TEXICMD_DEFVRX):
563: texivspace(p);
564: parseeoln(p, pos);
565: continue;
566: default:
567: break;
568: }
569: break;
570: }
1.65 kristaps 571:
572: if (TEXICMD_END == peekcmd(p, *pos)) {
573: parseto(p, pos, blk);
574: return;
575: }
576:
1.66 kristaps 577: texivspace(p);
578: teximacro(p, "Bd -filled -offset indent -compact");
579: p->seenvs = -1;
1.54 kristaps 580: parseto(p, pos, blk);
1.66 kristaps 581: p->seenvs = 0;
1.54 kristaps 582: teximacro(p, "Ed");
1.66 kristaps 583: texivspace(p);
1.3 kristaps 584: }
585:
586: static void
1.46 kristaps 587: domacro(struct texi *p, enum texicmd cmd, size_t *pos)
1.30 kristaps 588: {
589: size_t start, end, endtoksz, len;
590: struct teximacro m;
591: const char *endtok, *blk;
592:
593: memset(&m, 0, sizeof(struct teximacro));
594:
1.46 kristaps 595: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
596: advance(p, pos);
1.30 kristaps 597:
1.46 kristaps 598: for (start = end = *pos; end < BUFSZ(p); end++)
599: if (ismspace(BUF(p)[end]) || '{' == BUF(p)[end])
1.30 kristaps 600: break;
601:
602: if (start == end)
603: texierr(p, "zero-length macro name");
604:
1.46 kristaps 605: advanceto(p, pos, end);
1.30 kristaps 606:
607: m.key = malloc(end - start + 1);
608: if (NULL == m.key)
609: texiabort(p, NULL);
1.46 kristaps 610: memcpy(m.key, &BUF(p)[start], end - start);
1.30 kristaps 611: m.key[end - start] = '\0';
612:
1.46 kristaps 613: m.args = argparse(p, pos, &m.argsz, 0);
1.69 kristaps 614: if (*pos == BUFSZ(p)) {
615: texiwarn(p, "unexpected EOF");
616: return;
617: }
1.30 kristaps 618:
1.46 kristaps 619: /* Note: we advance to the beginning of the macro. */
620: advanceeoln(p, pos, 1);
1.69 kristaps 621: if ((start = *pos) == BUFSZ(p)) {
622: texiwarn(p, "unexpected EOF");
623: return;
624: }
1.46 kristaps 625:
626: /*
627: * According to the Texinfo manual, the macro ends on the
628: * newline subsequent the @end macro.
629: * That's COMPLETELY FUCKING WRONG.
630: * It ends inclusive the newline, which is why so many macros
631: * say things like @r{hello}@c, where the subsequent @c swallows
632: * the newline.
633: * However, it does swallow the leading newline, so look for the
634: * @end macro without the leading newline else we might look
635: * past empty macros.
636: */
637: endtok = "@end macro\n";
1.30 kristaps 638: endtoksz = strlen(endtok);
1.46 kristaps 639: blk = memmem(&BUF(p)[start], BUFSZ(p) - start, endtok, endtoksz);
1.30 kristaps 640: if (NULL == blk)
641: texierr(p, "unterminated macro body");
1.46 kristaps 642: /* Roll us back one character. */
643: while (&BUF(p)[*pos] != blk)
644: advance(p, pos);
645: assert('@' == BUF(p)[*pos]);
1.71 schwarze 646: if ('\n' != BUF(p)[*pos - 1])
1.46 kristaps 647: texierr(p, "cannot handle @end macro in-line");
648:
649: len = blk - &BUF(p)[start];
1.30 kristaps 650: m.value = malloc(len + 1);
651: if (NULL == m.value)
652: texiabort(p, NULL);
1.46 kristaps 653: memcpy(m.value, &BUF(p)[start], len);
1.30 kristaps 654: m.value[len] = '\0';
655:
656: p->macros = realloc
657: (p->macros,
1.71 schwarze 658: (p->macrosz + 1) *
1.30 kristaps 659: sizeof(struct teximacro));
660: if (NULL == p->macros)
661: texiabort(p, NULL);
662:
663: p->macros[p->macrosz++] = m;
1.46 kristaps 664: advanceeoln(p, pos, 1);
1.30 kristaps 665: }
666:
667: static void
1.46 kristaps 668: doignblock(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 669: {
1.45 kristaps 670: char end[32], start[32];
671: const char *endt, *startt;
672: size_t esz, ssz, newpos, stack;
1.26 kristaps 673:
1.71 schwarze 674: /*
1.45 kristaps 675: * FIXME: this is cheating.
676: * These tokens are supposed to begin on a newline.
677: * However, if we do that, then we would need to check within
678: * the loop for trailer (or leading, as the case may be)
679: * newline, and that's just a bit too complicated right now.
680: * This is becasue
1.71 schwarze 681: * @ifset BAR
682: * @ifset FOO
683: * @end ifset
684: * @end ifset
1.45 kristaps 685: * won't work right now: we'd read after the first "@end ifset"
686: * to the next line, then look for the next line after that.
1.26 kristaps 687: */
1.71 schwarze 688: ssz = snprintf(start, sizeof(start),
1.45 kristaps 689: "@%s", texitoks[cmd].tok);
690: assert(ssz < sizeof(start));
1.71 schwarze 691: esz = snprintf(end, sizeof(end),
1.68 kristaps 692: "@end %s", texitoks[cmd].tok);
1.45 kristaps 693: assert(esz < sizeof(end));
694: stack = 1;
695:
696: /*
697: * Here we look for the end token "end" somewhere in the file in
698: * front of us.
699: * It's not that easy, of course: if we have a nested block,
700: * then there'll be an "end" token of the same kind between us.
701: * Thus, we keep track of scopes for matching "end" blocks.
1.26 kristaps 702: */
1.46 kristaps 703: while (stack > 0 && *pos < BUFSZ(p)) {
1.52 kristaps 704: if (stack > 64)
705: texierr(p, "run-away nested stack?");
1.46 kristaps 706: endt = memmem(&BUF(p)[*pos], BUFSZ(p) - *pos, end, esz);
707: startt = memmem(&BUF(p)[*pos], BUFSZ(p) - *pos, start, ssz);
1.45 kristaps 708: if (NULL == endt) {
709: texiwarn(p, "unterminated \"%s\" "
710: "block", texitoks[cmd].tok);
1.46 kristaps 711: *pos = BUFSZ(p);
1.45 kristaps 712: break;
1.71 schwarze 713: }
1.26 kristaps 714:
1.45 kristaps 715: newpos = *pos;
716: if (NULL == startt || startt > endt) {
1.46 kristaps 717: newpos += esz + (size_t)(endt - &BUF(p)[*pos]);
1.45 kristaps 718: stack--;
719: } else {
1.46 kristaps 720: newpos += ssz + (size_t)(startt - &BUF(p)[*pos]);
1.45 kristaps 721: stack++;
722: }
723:
1.46 kristaps 724: assert(newpos <= BUFSZ(p));
1.45 kristaps 725: while (*pos < newpos)
1.46 kristaps 726: advance(p, pos);
1.45 kristaps 727: }
1.1 kristaps 728: }
729:
730: static void
1.46 kristaps 731: doblock(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 732: {
1.71 schwarze 733:
1.46 kristaps 734: parseto(p, pos, texitoks[cmd].tok);
1.1 kristaps 735: }
736:
737: static void
1.46 kristaps 738: doinline(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 739: {
1.21 kristaps 740: const char *macro = NULL;
1.12 kristaps 741:
742: switch (cmd) {
1.21 kristaps 743: case (TEXICMD_CODE):
744: case (TEXICMD_KBD):
1.66 kristaps 745: /* FIXME: quote around @samp{} */
1.21 kristaps 746: case (TEXICMD_SAMP):
747: case (TEXICMD_T):
748: macro = "Li";
749: break;
750: case (TEXICMD_CITE):
751: case (TEXICMD_DFN):
752: case (TEXICMD_EMPH):
753: case (TEXICMD_I):
754: case (TEXICMD_SLANTED):
755: macro = "Em";
756: break;
757: case (TEXICMD_B):
758: case (TEXICMD_STRONG):
759: macro = "Sy";
760: break;
1.12 kristaps 761: case (TEXICMD_COMMAND):
762: macro = "Xr";
763: break;
764: case (TEXICMD_ENV):
765: macro = "Ev";
766: break;
767: case (TEXICMD_FILE):
768: macro = "Pa";
769: break;
1.16 kristaps 770: case (TEXICMD_OPTION):
771: macro = "Op";
772: break;
1.12 kristaps 773: case (TEXICMD_VAR):
774: macro = "Va";
775: break;
776: default:
1.22 kristaps 777: break;
1.12 kristaps 778: }
779:
1.25 kristaps 780: if (NULL == macro || p->literal || TEXILIST_TABLE == p->list) {
1.58 kristaps 781: if (TEXICMD_SC == cmd)
782: p->uppercase++;
1.53 kristaps 783: parsebracket(p, pos, 0);
1.58 kristaps 784: if (TEXICMD_SC == cmd)
785: p->uppercase--;
1.12 kristaps 786: return;
787: }
1.1 kristaps 788:
1.71 schwarze 789: /*
1.59 kristaps 790: * If we haven't seen any whitespace, then we don't want the
1.71 schwarze 791: * subsequent macro to insert any whitespace.
1.59 kristaps 792: */
793: if (p->outmacro && 0 == p->seenws) {
794: teximacroopen(p, "Ns");
795: teximacroclose(p);
796: }
797:
1.5 kristaps 798: teximacroopen(p, macro);
1.1 kristaps 799: p->seenws = 0;
1.63 kristaps 800: if (TEXICMD_CODE == cmd)
801: p->literal++;
1.58 kristaps 802: if (TEXICMD_SC == cmd)
803: p->uppercase++;
1.53 kristaps 804: parsebracket(p, pos, 0);
1.58 kristaps 805: if (TEXICMD_SC == cmd)
806: p->uppercase--;
1.63 kristaps 807: if (TEXICMD_CODE == cmd)
808: p->literal--;
1.46 kristaps 809: texipunctuate(p, pos);
1.5 kristaps 810: teximacroclose(p);
1.1 kristaps 811: }
812:
813: static void
1.46 kristaps 814: doverb(struct texi *p, enum texicmd cmd, size_t *pos)
1.33 kristaps 815: {
816: char delim;
1.34 kristaps 817: size_t start;
1.33 kristaps 818:
1.46 kristaps 819: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
820: advance(p, pos);
821: if (*pos == BUFSZ(p) || '{' != BUF(p)[*pos])
1.33 kristaps 822: return;
1.46 kristaps 823: advance(p, pos);
824: if (*pos == BUFSZ(p))
1.33 kristaps 825: return;
826:
1.46 kristaps 827: delim = BUF(p)[*pos];
828: advance(p, pos);
1.33 kristaps 829: /* Make sure we flush out our initial whitespace... */
830: if (p->seenws && p->outcol && 0 == p->literal)
831: texiputchar(p, ' ');
832: p->seenws = 0;
1.34 kristaps 833: start = *pos;
1.33 kristaps 834: /* Read until we see the delimiter then end-brace. */
1.46 kristaps 835: while (*pos < BUFSZ(p) - 1) {
1.71 schwarze 836: if (BUF(p)[*pos] == delim && BUF(p)[*pos + 1] == '}')
1.33 kristaps 837: break;
1.46 kristaps 838: advance(p, pos);
1.33 kristaps 839: }
1.51 kristaps 840: if (*pos >= BUFSZ(p) - 1)
1.33 kristaps 841: return;
1.46 kristaps 842: texiputbuf(p, start, *pos);
1.34 kristaps 843:
1.33 kristaps 844: /* Make sure we read after the end-brace. */
1.46 kristaps 845: assert(delim == BUF(p)[*pos]);
846: advance(p, pos);
847: assert('}' == BUF(p)[*pos]);
848: advance(p, pos);
1.33 kristaps 849: }
850:
851: static void
1.61 kristaps 852: doinsertcopying(struct texi *p, enum texicmd cmd, size_t *pos)
853: {
854:
855: advanceeoln(p, pos, 0);
1.66 kristaps 856: if (NULL != p->copying)
857: texisplice(p, p->copying, p->copyingsz, *pos);
1.61 kristaps 858: }
859:
860: static void
861: docopying(struct texi *p, enum texicmd cmd, size_t *pos)
862: {
863: const char *end, *term;
864: size_t endsz, endpos;
865:
866: /* We retain our starting (but not ending) newlines. */
867: end = "\n@end copying\n";
868: endsz = strlen(end);
869: advanceeoln(p, pos, 0);
870: if (*pos == BUFSZ(p)) {
871: texiwarn(p, "unterminated \"%s\"", texitoks[cmd].tok);
872: return;
873: }
874:
875: term = memmem(&BUF(p)[*pos], BUFSZ(p) - *pos, end, endsz);
1.68 kristaps 876: if (NULL == term)
877: texierr(p, "unterminated \"%s\"", texitoks[cmd].tok);
878: else
1.61 kristaps 879: endpos = *pos + (size_t)(term - &BUF(p)[*pos]);
880:
1.68 kristaps 881: if (endpos == *pos) {
882: advanceeoln(p, pos, 1);
883: return;
884: }
885:
886: assert(endpos < BUFSZ(p) && endpos > *pos);
1.61 kristaps 887: assert('\n' == BUF(p)[*pos]);
888: advance(p, pos);
889:
1.68 kristaps 890: if (*pos == BUFSZ(p)) {
891: texiwarn(p, "unterminated \"%s\"", texitoks[cmd].tok);
892: return;
893: }
894:
1.61 kristaps 895: p->copying = malloc(endpos - *pos + 1);
896: p->copyingsz = endpos - *pos;
897: memcpy(p->copying, &BUF(p)[*pos], p->copyingsz);
898: p->copying[endpos - *pos] = '\0';
899:
900: while (*pos < endpos)
901: advance(p, pos);
902: if (*pos < BUFSZ(p))
903: advanceto(p, pos, endpos + endsz);
904: }
905:
906: static void
1.46 kristaps 907: doverbatim(struct texi *p, enum texicmd cmd, size_t *pos)
1.25 kristaps 908: {
909: const char *end, *term;
910: size_t endsz, endpos;
911:
1.45 kristaps 912: /* We read from the @verbatim\n newline inclusive! */
1.25 kristaps 913: end = "\n@end verbatim\n";
914: endsz = strlen(end);
1.46 kristaps 915: advanceeoln(p, pos, 0);
916: if (*pos == BUFSZ(p)) {
1.61 kristaps 917: texiwarn(p, "unterminated \"%s\"", texitoks[cmd].tok);
1.45 kristaps 918: return;
919: }
1.25 kristaps 920:
1.46 kristaps 921: term = memmem(&BUF(p)[*pos], BUFSZ(p) - *pos, end, endsz);
1.45 kristaps 922: if (NULL == term) {
1.61 kristaps 923: texiwarn(p, "unterminated \"%s\"", texitoks[cmd].tok);
1.46 kristaps 924: endpos = BUFSZ(p);
1.45 kristaps 925: } else
1.46 kristaps 926: endpos = *pos + (size_t)(term - &BUF(p)[*pos]);
1.25 kristaps 927:
1.46 kristaps 928: assert(endpos <= BUFSZ(p));
929: assert('\n' == BUF(p)[*pos]);
930: advance(p, pos);
1.66 kristaps 931: texivspace(p);
932: teximacro(p, "Bd -literal -offset indent -compact");
933: p->seenvs = -1;
1.26 kristaps 934: while (*pos < endpos) {
1.46 kristaps 935: texiputchar(p, BUF(p)[*pos]);
936: advance(p, pos);
1.25 kristaps 937: }
1.66 kristaps 938: p->seenvs = 0;
1.25 kristaps 939: teximacro(p, "Ed");
1.66 kristaps 940: texivspace(p);
1.46 kristaps 941: if (*pos < BUFSZ(p))
942: advanceto(p, pos, endpos + endsz);
1.25 kristaps 943: }
944:
945: static void
1.46 kristaps 946: doverbinclude(struct texi *p, enum texicmd cmd, size_t *pos)
1.16 kristaps 947: {
1.71 schwarze 948: char fname[PATH_MAX], path[PATH_MAX];
949: int rc;
950: size_t i, end;
1.25 kristaps 951: const char *v;
952: enum texicmd type;
1.16 kristaps 953:
1.46 kristaps 954: while (*pos < BUFSZ(p) && ' ' == BUF(p)[*pos])
955: advance(p, pos);
1.16 kristaps 956:
1.46 kristaps 957: for (i = 0; *pos < BUFSZ(p) && '\n' != BUF(p)[*pos]; ) {
1.16 kristaps 958: if (i == sizeof(fname) - 1)
959: break;
1.46 kristaps 960: if ('@' != BUF(p)[*pos]) {
961: fname[i++] = BUF(p)[*pos];
962: advance(p, pos);
1.25 kristaps 963: continue;
964: }
1.46 kristaps 965: type = texicmd(p, *pos, &end, NULL);
966: advanceto(p, pos, end);
1.71 schwarze 967: if (TEXICMD_VALUE != type)
1.25 kristaps 968: texierr(p, "unknown verbatiminclude command");
1.46 kristaps 969: v = valueblookup(p, pos);
1.25 kristaps 970: if (NULL == v)
971: continue;
972: while ('\0' != *v) {
973: if (i == sizeof(fname) - 1)
974: break;
975: fname[i++] = *v++;
976: }
977: if ('\0' != *v)
978: break;
1.16 kristaps 979: }
980:
981: if (i == 0)
982: texierr(p, "path too short");
1.46 kristaps 983: else if ('\n' != BUF(p)[*pos])
1.16 kristaps 984: texierr(p, "path too long");
985: else if ('/' == fname[0])
986: texierr(p, "no absolute paths");
987: fname[i] = '\0';
988:
989: if (strstr(fname, "../") || strstr(fname, "/.."))
990: texierr(p, "insecure path");
991:
1.71 schwarze 992: rc = snprintf(path, sizeof(path),
1.16 kristaps 993: "%s/%s", p->dirs[0], fname);
1.71 schwarze 994: if (rc < 0)
1.16 kristaps 995: texierr(p, "couldn't format path");
996: else if ((size_t)rc >= sizeof(path))
997: texierr(p, "path too long");
998:
999: parsefile(p, path, 0);
1000: }
1001:
1002: static void
1.46 kristaps 1003: doinclude(struct texi *p, enum texicmd cmd, size_t *pos)
1.2 kristaps 1004: {
1.71 schwarze 1005: char fname[PATH_MAX], path[PATH_MAX];
1006: size_t i, end;
1007: int rc;
1.25 kristaps 1008: const char *v;
1009: enum texicmd type;
1.2 kristaps 1010:
1.46 kristaps 1011: while (*pos < BUFSZ(p) && ' ' == BUF(p)[*pos])
1012: advance(p, pos);
1.2 kristaps 1013:
1014: /* Read in the filename. */
1.46 kristaps 1015: for (i = 0; *pos < BUFSZ(p) && '\n' != BUF(p)[*pos]; ) {
1.2 kristaps 1016: if (i == sizeof(fname) - 1)
1017: break;
1.46 kristaps 1018: if ('@' != BUF(p)[*pos]) {
1019: fname[i++] = BUF(p)[*pos];
1020: advance(p, pos);
1.25 kristaps 1021: continue;
1022: }
1.46 kristaps 1023: type = texicmd(p, *pos, &end, NULL);
1024: advanceto(p, pos, end);
1.71 schwarze 1025: if (TEXICMD_VALUE != type)
1.25 kristaps 1026: texierr(p, "unknown include command");
1.46 kristaps 1027: v = valueblookup(p, pos);
1.25 kristaps 1028: if (NULL == v)
1029: continue;
1030: while ('\0' != *v) {
1031: if (i == sizeof(fname) - 1)
1032: break;
1033: fname[i++] = *v++;
1034: }
1035: if ('\0' != *v)
1036: break;
1.2 kristaps 1037: }
1038:
1039: if (i == 0)
1040: texierr(p, "path too short");
1.46 kristaps 1041: else if ('\n' != BUF(p)[*pos])
1.2 kristaps 1042: texierr(p, "path too long");
1043: else if ('/' == fname[0])
1044: texierr(p, "no absolute paths");
1045: fname[i] = '\0';
1046:
1047: if (strstr(fname, "../") || strstr(fname, "/.."))
1048: texierr(p, "insecure path");
1049:
1.5 kristaps 1050: for (i = 0; i < p->dirsz; i++) {
1.71 schwarze 1051: rc = snprintf(path, sizeof(path),
1.5 kristaps 1052: "%s/%s", p->dirs[i], fname);
1.71 schwarze 1053: if (rc < 0)
1.5 kristaps 1054: texierr(p, "couldn't format path");
1055: else if ((size_t)rc >= sizeof(path))
1056: texierr(p, "path too long");
1057: else if (-1 == access(path, R_OK))
1058: continue;
1059:
1.16 kristaps 1060: parsefile(p, path, 1);
1.5 kristaps 1061: return;
1062: }
1.2 kristaps 1063:
1.5 kristaps 1064: texierr(p, "couldn't find %s in includes", fname);
1.2 kristaps 1065: }
1066:
1067: static void
1.46 kristaps 1068: dobracket(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1069: {
1070:
1.53 kristaps 1071: parsebracket(p, pos, 0);
1.1 kristaps 1072: }
1073:
1074: static void
1.46 kristaps 1075: dodisplay(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 1076: {
1077:
1.57 kristaps 1078: advanceeoln(p, pos, 1);
1.66 kristaps 1079: texivspace(p);
1.57 kristaps 1080:
1.20 kristaps 1081: switch (cmd) {
1082: case (TEXICMD_FORMAT):
1083: case (TEXICMD_SMALLFORMAT):
1.66 kristaps 1084: teximacro(p, "Bd -filled -compact");
1.20 kristaps 1085: break;
1086: default:
1.66 kristaps 1087: teximacro(p, "Bd -filled -offset indent -compact");
1.20 kristaps 1088: break;
1089: }
1090:
1.66 kristaps 1091: p->seenvs = -1;
1.46 kristaps 1092: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 1093: p->seenvs = 0;
1.5 kristaps 1094: teximacro(p, "Ed");
1.66 kristaps 1095: texivspace(p);
1.3 kristaps 1096: }
1097:
1098: static void
1.46 kristaps 1099: doexample(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1100: {
1101:
1.57 kristaps 1102: advanceeoln(p, pos, 1);
1103:
1.66 kristaps 1104: texivspace(p);
1105: teximacro(p, "Bd -literal -offset indent -compact");
1.3 kristaps 1106: p->literal++;
1.46 kristaps 1107: parseto(p, pos, texitoks[cmd].tok);
1.3 kristaps 1108: p->literal--;
1.66 kristaps 1109: p->seenvs = 0;
1.5 kristaps 1110: teximacro(p, "Ed");
1.66 kristaps 1111: texivspace(p);
1.1 kristaps 1112: }
1113:
1114: static void
1.46 kristaps 1115: dobye(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1116: {
1117:
1118: texiexit(p);
1119: exit(EXIT_SUCCESS);
1120: }
1121:
1122: static void
1.46 kristaps 1123: dotitle(struct texi *p, enum texicmd cmd, size_t *pos)
1.10 kristaps 1124: {
1.57 kristaps 1125: size_t start;
1.10 kristaps 1126:
1.46 kristaps 1127: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1128: advance(p, pos);
1.57 kristaps 1129:
1130: /* We want to suck down the entire line, inclusive \n. */
1131: start = *pos;
1132: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) {
1133: if ('@' == BUF(p)[*pos])
1134: advance(p, pos);
1135: advance(p, pos);
1136: }
1137: if (*pos < BUFSZ(p))
1138: advance(p, pos);
1139:
1140: /* Copy this into a buffer. */
1.10 kristaps 1141: free(p->subtitle);
1.57 kristaps 1142: if (NULL == (p->subtitle = malloc(*pos - start + 1)))
1.27 kristaps 1143: texiabort(p, NULL);
1.57 kristaps 1144: memcpy(p->subtitle, &BUF(p)[start], *pos - start);
1145: p->subtitle[*pos - start] = '\0';
1.10 kristaps 1146: }
1147:
1148: static void
1.46 kristaps 1149: doaccent(struct texi *p, enum texicmd cmd, size_t *pos)
1.16 kristaps 1150: {
1.42 kristaps 1151: int brace = 0;
1.16 kristaps 1152:
1.46 kristaps 1153: if (*pos == BUFSZ(p)) {
1.42 kristaps 1154: texiwarn(p, "truncated: @%s", texitoks[cmd].tok);
1.16 kristaps 1155: return;
1.42 kristaps 1156: }
1157:
1158: /* Pad us with space, if necessary. */
1159: if (p->seenws && p->outcol && 0 == p->literal) {
1.34 kristaps 1160: texiputchar(p, ' ');
1.42 kristaps 1161: p->seenws = 0;
1162: }
1163:
1164: /*
1165: * If we're braced, then that's that.
1166: * Otherwise, in a special Texinfo case: if we're a non
1167: * alphabetic command of one letter, then the next character is
1168: * the critical one.
1169: * Otherwise, space can sit between us and our argument.
1170: */
1.46 kristaps 1171: if ('{' == BUF(p)[*pos]) {
1.42 kristaps 1172: brace = 1;
1.46 kristaps 1173: advance(p, pos);
1.71 schwarze 1174: } else if (isalpha((unsigned char)texitoks[cmd].tok[0]))
1.46 kristaps 1175: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1176: advance(p, pos);
1.42 kristaps 1177:
1.46 kristaps 1178: if (*pos == BUFSZ(p)) {
1.42 kristaps 1179: texiwarn(p, "truncated: @%s", texitoks[cmd].tok);
1180: return;
1181: }
1182:
1183: switch (cmd) {
1.16 kristaps 1184: case (TEXICMD_ACUTE):
1.46 kristaps 1185: switch (BUF(p)[*pos]) {
1.16 kristaps 1186: case ('a'): case ('A'):
1187: case ('e'): case ('E'):
1188: case ('i'): case ('I'):
1189: case ('o'): case ('O'):
1190: case ('u'): case ('U'):
1191: texiputchars(p, "\\(\'");
1192: break;
1193: default:
1.42 kristaps 1194: texiwarn(p, "ignoring accent");
1195: break;
1.16 kristaps 1196: }
1.46 kristaps 1197: texiputchar(p, BUF(p)[*pos]);
1198: advance(p, pos);
1.42 kristaps 1199: break;
1200: case (TEXICMD_CEDILLA):
1.46 kristaps 1201: if ('c' == BUF(p)[*pos] || 'C' == BUF(p)[*pos])
1.42 kristaps 1202: texiputchars(p, "\\(,");
1203: else
1204: texiwarn(p, "ignoring accent");
1.46 kristaps 1205: texiputchar(p, BUF(p)[*pos]);
1206: advance(p, pos);
1.16 kristaps 1207: break;
1208: case (TEXICMD_CIRCUMFLEX):
1.46 kristaps 1209: switch (BUF(p)[*pos]) {
1.16 kristaps 1210: case ('a'): case ('A'):
1211: case ('e'): case ('E'):
1212: case ('i'): case ('I'):
1213: case ('o'): case ('O'):
1214: case ('u'): case ('U'):
1215: texiputchars(p, "\\(^");
1216: break;
1217: default:
1.42 kristaps 1218: texiwarn(p, "ignoring accent");
1.34 kristaps 1219: break;
1.16 kristaps 1220: }
1.46 kristaps 1221: texiputchar(p, BUF(p)[*pos]);
1222: advance(p, pos);
1.42 kristaps 1223: break;
1224: case (TEXICMD_DOTLESS):
1.46 kristaps 1225: if ('i' == BUF(p)[*pos] || 'j' == BUF(p)[*pos])
1.42 kristaps 1226: texiputchars(p, "\\(.");
1227: else
1228: texiwarn(p, "ignoring accent");
1.46 kristaps 1229: texiputchar(p, BUF(p)[*pos]);
1230: advance(p, pos);
1.16 kristaps 1231: break;
1232: case (TEXICMD_GRAVE):
1.46 kristaps 1233: switch (BUF(p)[*pos]) {
1.16 kristaps 1234: case ('a'): case ('A'):
1235: case ('e'): case ('E'):
1236: case ('i'): case ('I'):
1237: case ('o'): case ('O'):
1238: case ('u'): case ('U'):
1239: texiputchars(p, "\\(`");
1240: break;
1241: default:
1.42 kristaps 1242: texiwarn(p, "ignoring accent");
1243: break;
1.16 kristaps 1244: }
1.46 kristaps 1245: texiputchar(p, BUF(p)[*pos]);
1246: advance(p, pos);
1.16 kristaps 1247: break;
1248: case (TEXICMD_TILDE):
1.46 kristaps 1249: switch (BUF(p)[*pos]) {
1.16 kristaps 1250: case ('a'): case ('A'):
1251: case ('n'): case ('N'):
1252: case ('o'): case ('O'):
1253: texiputchars(p, "\\(~");
1254: break;
1255: default:
1.42 kristaps 1256: texiwarn(p, "ignoring accent");
1.34 kristaps 1257: break;
1.16 kristaps 1258: }
1.46 kristaps 1259: texiputchar(p, BUF(p)[*pos]);
1260: advance(p, pos);
1.16 kristaps 1261: break;
1262: case (TEXICMD_UMLAUT):
1.46 kristaps 1263: switch (BUF(p)[*pos]) {
1.16 kristaps 1264: case ('a'): case ('A'):
1265: case ('e'): case ('E'):
1266: case ('i'): case ('I'):
1267: case ('o'): case ('O'):
1268: case ('u'): case ('U'):
1269: case ('y'):
1270: texiputchars(p, "\\(:");
1271: break;
1272: default:
1.42 kristaps 1273: texiwarn(p, "ignoring accent");
1.34 kristaps 1274: break;
1.16 kristaps 1275: }
1.46 kristaps 1276: texiputchar(p, BUF(p)[*pos]);
1277: advance(p, pos);
1.16 kristaps 1278: break;
1279: default:
1.46 kristaps 1280: texiputchar(p, BUF(p)[*pos]);
1281: advance(p, pos);
1.42 kristaps 1282: break;
1283: }
1284:
1285: if (brace) {
1.46 kristaps 1286: while (*pos < BUFSZ(p) && '}' != BUF(p)[*pos]) {
1287: texiputchar(p, BUF(p)[*pos]);
1288: advance(p, pos);
1.42 kristaps 1289: }
1.46 kristaps 1290: if (*pos < BUFSZ(p))
1291: advance(p, pos);
1.71 schwarze 1292: }
1.42 kristaps 1293:
1294: switch (cmd) {
1295: case (TEXICMD_TIEACCENT):
1296: texiputchar(p, ']');
1297: break;
1298: case (TEXICMD_DOTACCENT):
1299: texiputchar(p, '*');
1300: break;
1301: default:
1302: break;
1.16 kristaps 1303: }
1304: }
1305:
1306: static void
1.46 kristaps 1307: dosymbol(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1308: {
1309:
1.42 kristaps 1310: /* Remember to pad us. */
1.43 kristaps 1311: if (p->seenws && p->outcol && 0 == p->literal)
1.3 kristaps 1312: texiputchar(p, ' ');
1.43 kristaps 1313:
1314: p->seenws = 0;
1.3 kristaps 1315:
1.1 kristaps 1316: switch (cmd) {
1.42 kristaps 1317: case (TEXICMD_AA):
1318: texiputchars(p, "\\(oA");
1319: break;
1320: case (TEXICMD_AASMALL):
1321: texiputchars(p, "\\(oa");
1322: break;
1323: case (TEXICMD_AE):
1324: texiputchars(p, "\\(AE");
1325: break;
1326: case (TEXICMD_AESMALL):
1327: texiputchars(p, "\\(ae");
1328: break;
1.3 kristaps 1329: case (TEXICMD_ASTERISK):
1330: case (TEXICMD_NEWLINE):
1331: case (TEXICMD_SPACE):
1.18 kristaps 1332: case (TEXICMD_TABSYM):
1.3 kristaps 1333: texiputchar(p, ' ');
1334: break;
1.1 kristaps 1335: case (TEXICMD_AT):
1.3 kristaps 1336: texiputchar(p, '@');
1.59 kristaps 1337: break;
1338: case (TEXICMD_BACKSLASH):
1339: texiputchar(p, '\\');
1.3 kristaps 1340: break;
1341: case (TEXICMD_BANG):
1342: texiputchar(p, '!');
1.7 kristaps 1343: break;
1344: case (TEXICMD_BULLET):
1345: texiputchars(p, "\\(bu");
1.1 kristaps 1346: break;
1.35 kristaps 1347: case (TEXICMD_COMMA):
1348: texiputchar(p, ',');
1349: break;
1.1 kristaps 1350: case (TEXICMD_COPYRIGHT):
1351: texiputchars(p, "\\(co");
1352: break;
1.42 kristaps 1353: case (TEXICMD_DH):
1354: texiputchars(p, "\\(-D");
1355: break;
1356: case (TEXICMD_DHSMALL):
1357: texiputchars(p, "\\(Sd");
1358: break;
1.2 kristaps 1359: case (TEXICMD_DOTS):
1.34 kristaps 1360: case (TEXICMD_ENDDOTS):
1.2 kristaps 1361: texiputchars(p, "...");
1362: break;
1.28 kristaps 1363: case (TEXICMD_EQUIV):
1364: texiputchars(p, "\\(==");
1365: break;
1.15 kristaps 1366: case (TEXICMD_ERROR):
1367: texiputchars(p, "error\\(->");
1.17 kristaps 1368: break;
1.43 kristaps 1369: case (TEXICMD_EURO):
1370: texiputchars(p, "\\(Eu");
1371: break;
1.42 kristaps 1372: case (TEXICMD_EXCLAMDOWN):
1373: texiputchars(p, "\\(r!");
1374: break;
1.17 kristaps 1375: case (TEXICMD_EXPANSION):
1376: texiputchars(p, "\\(->");
1.15 kristaps 1377: break;
1.43 kristaps 1378: case (TEXICMD_GEQ):
1379: texiputchars(p, "\\(>=");
1380: break;
1381: case (TEXICMD_GUILLEMETLEFT):
1382: case (TEXICMD_GUILLEMOTLEFT):
1383: texiputchars(p, "\\(Fo");
1384: break;
1385: case (TEXICMD_GUILLEMETRIGHT):
1386: case (TEXICMD_GUILLEMOTRIGHT):
1387: texiputchars(p, "\\(Fc");
1388: break;
1389: case (TEXICMD_GUILSINGLLEFT):
1390: texiputchars(p, "\\(fo");
1391: break;
1392: case (TEXICMD_GUILSINGLRIGHT):
1393: texiputchars(p, "\\(fc");
1394: break;
1.42 kristaps 1395: case (TEXICMD_L):
1396: texiputchars(p, "\\(/L");
1397: break;
1.1 kristaps 1398: case (TEXICMD_LATEX):
1399: texiputchars(p, "LaTeX");
1400: break;
1.43 kristaps 1401: case (TEXICMD_LEQ):
1402: texiputchars(p, "\\(<=");
1403: break;
1.42 kristaps 1404: case (TEXICMD_LSMALL):
1405: texiputchars(p, "\\(/l");
1406: break;
1.25 kristaps 1407: case (TEXICMD_MINUS):
1408: texiputchars(p, "\\-");
1409: break;
1.42 kristaps 1410: case (TEXICMD_O):
1411: texiputchars(p, "\\(/O");
1412: break;
1413: case (TEXICMD_OE):
1414: texiputchars(p, "\\(OE");
1415: break;
1416: case (TEXICMD_OESMALL):
1417: texiputchars(p, "\\(oe");
1418: break;
1419: case (TEXICMD_ORDF):
1420: texiputchars(p, "a");
1421: break;
1422: case (TEXICMD_ORDM):
1423: texiputchars(p, "o");
1424: break;
1425: case (TEXICMD_OSMALL):
1426: texiputchars(p, "\\(/o");
1427: break;
1.25 kristaps 1428: case (TEXICMD_PERIOD):
1429: texiputchar(p, '.');
1430: break;
1.43 kristaps 1431: case (TEXICMD_POUNDS):
1432: texiputchars(p, "\\(Po");
1433: break;
1.42 kristaps 1434: case (TEXICMD_QUESTIONDOWN):
1435: texiputchars(p, "\\(r?");
1436: break;
1.3 kristaps 1437: case (TEXICMD_QUESTIONMARK):
1438: texiputchar(p, '?');
1.15 kristaps 1439: break;
1.43 kristaps 1440: case (TEXICMD_QUOTEDBLBASE):
1441: texiputchars(p, "\\(Bq");
1442: break;
1443: case (TEXICMD_QUOTEDBLLEFT):
1444: texiputchars(p, "\\(lq");
1445: break;
1446: case (TEXICMD_QUOTEDBLRIGHT):
1447: texiputchars(p, "\\(rq");
1448: break;
1449: case (TEXICMD_QUOTESINGLBASE):
1450: texiputchars(p, "\\(bq");
1451: break;
1452: case (TEXICMD_QUOTELEFT):
1453: texiputchars(p, "\\(oq");
1454: break;
1455: case (TEXICMD_QUOTERIGHT):
1456: texiputchars(p, "\\(cq");
1457: break;
1458: case (TEXICMD_REGISTEREDSYMBOL):
1459: texiputchars(p, "\\(rg");
1460: break;
1.15 kristaps 1461: case (TEXICMD_RESULT):
1462: texiputchars(p, "\\(rA");
1.3 kristaps 1463: break;
1.34 kristaps 1464: case (TEXICMD_SLASH):
1465: texiputchar(p, '/');
1466: break;
1.35 kristaps 1467: case (TEXICMD_SS):
1468: texiputchars(p, "\\(ss");
1469: break;
1.3 kristaps 1470: case (TEXICMD_SQUIGGLE_LEFT):
1471: texiputchars(p, "{");
1472: break;
1473: case (TEXICMD_SQUIGGLE_RIGHT):
1474: texiputchars(p, "}");
1475: break;
1.38 kristaps 1476: case (TEXICMD_TEXSYM):
1.35 kristaps 1477: texiputchars(p, "TeX");
1.43 kristaps 1478: break;
1479: case (TEXICMD_TEXTDEGREE):
1480: texiputchars(p, "\\(de");
1.35 kristaps 1481: break;
1.42 kristaps 1482: case (TEXICMD_TH):
1483: texiputchars(p, "\\(TP");
1484: break;
1485: case (TEXICMD_THSMALL):
1486: texiputchars(p, "\\(Tp");
1487: break;
1.38 kristaps 1488: case (TEXICMD_TIE):
1.35 kristaps 1489: texiputchars(p, "\\ ");
1.1 kristaps 1490: break;
1.3 kristaps 1491: case (TEXICMD_COLON):
1492: case (TEXICMD_HYPHEN):
1493: break;
1.1 kristaps 1494: default:
1495: abort();
1496: }
1497:
1.42 kristaps 1498: /* Alphabetic commands have braces we ignore. */
1.49 kristaps 1499: if (isalpha((unsigned char)texitoks[cmd].tok[0]))
1.46 kristaps 1500: doignbracket(p, cmd, pos);
1.1 kristaps 1501: }
1502:
1503: static void
1.46 kristaps 1504: doquotation(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1505: {
1.71 schwarze 1506:
1.5 kristaps 1507: teximacro(p, "Qo");
1.46 kristaps 1508: parseto(p, pos, "quotation");
1.5 kristaps 1509: teximacro(p, "Qc");
1.1 kristaps 1510: }
1511:
1.66 kristaps 1512: static int
1513: indexcmp(const void *p1, const void *p2)
1514: {
1.67 kristaps 1515: const struct texiterm *t1 = p1, *t2 = p2;
1.66 kristaps 1516:
1.67 kristaps 1517: return(strcasecmp(t1->term, t2->term));
1.66 kristaps 1518: }
1519:
1520: static void
1521: doprintindex(struct texi *p, enum texicmd cmd, size_t *pos)
1522: {
1.70 kristaps 1523: static size_t guard = 0;
1.71 schwarze 1524: size_t i, j, start, end, len;
1.66 kristaps 1525: #if HAVE_INDEX
1.70 kristaps 1526: char *cp;
1527: char buf[PATH_MAX];
1.66 kristaps 1528: #endif
1529:
1.70 kristaps 1530: if (guard++ > 8)
1531: texierr(p, "recursive @printindex");
1532:
1.66 kristaps 1533: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1534: advance(p, pos);
1535: start = *pos;
1536: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
1537: advance(p, pos);
1538: if ((end = *pos) == BUFSZ(p)) {
1539: texiwarn(p, "unexpected EOF");
1.70 kristaps 1540: guard--;
1.66 kristaps 1541: return;
1542: }
1543:
1544: advance(p, pos);
1.69 kristaps 1545: if (*pos == BUFSZ(p)) {
1546: texiwarn(p, "unexpected EOF");
1.70 kristaps 1547: guard--;
1.69 kristaps 1548: return;
1549: } else if (0 == (len = end - start)) {
1.66 kristaps 1550: texiwarn(p, "zero-length index");
1.70 kristaps 1551: guard--;
1.66 kristaps 1552: return;
1553: }
1554:
1555: /* Look for the index in our table. */
1556: for (i = 0; i < p->indexsz; i++) {
1557: if (strlen(p->indexs[i].name) != len)
1558: continue;
1559: if (strncmp(p->indexs[i].name, &BUF(p)[start], len))
1560: continue;
1561: break;
1562: }
1563:
1564: if (i == p->indexsz) {
1565: texiwarn(p, "cannot find index");
1.70 kristaps 1566: guard--;
1.66 kristaps 1567: return;
1.70 kristaps 1568: } else if (0 == p->indexs[i].indexsz) {
1569: guard--;
1.66 kristaps 1570: return;
1.70 kristaps 1571: }
1.66 kristaps 1572:
1573: /* Alphabetically sort our indices. */
1.71 schwarze 1574: qsort(p->indexs[i].index,
1575: p->indexs[i].indexsz,
1.67 kristaps 1576: sizeof(struct texiterm), indexcmp);
1.66 kristaps 1577:
1578: texivspace(p);
1579: teximacro(p, "Bl -tag -width Ds -compact");
1580: for (j = 0; j < p->indexs[i].indexsz; j++) {
1581: teximacroopen(p, "It");
1582: #if HAVE_INDEX
1.67 kristaps 1583: if (NULL == p->chapters) {
1584: teximacroopen(p, "Lkx");
1585: texiputchars(p, "\"idx");
1586: texiputchars(p, p->indexs[i].name);
1587: cp = p->indexs[i].index[j].term;
1.68 kristaps 1588: while ('\n' != *cp)
1.67 kristaps 1589: texiputchar(p, *cp++);
1590: texiputchars(p, "\" \"");
1591: p->literal++;
1592: } else {
1593: teximacroopen(p, "Xr");
1.68 kristaps 1594: snprintf(buf, sizeof(buf), "%s-%zd 7 \"idx",
1595: p->chapters, p->indexs[i].index[j].chapter);
1596: texiputchars(p, buf);
1.67 kristaps 1597: texiputchars(p, p->indexs[i].name);
1598: cp = p->indexs[i].index[j].term;
1.68 kristaps 1599: while ('\n' != *cp)
1.67 kristaps 1600: texiputchar(p, *cp++);
1601: texiputchars(p, "\" \"");
1602: p->literal++;
1.66 kristaps 1603: }
1604: #endif
1.71 schwarze 1605: texisplice(p, p->indexs[i].index[j].term,
1.67 kristaps 1606: strlen(p->indexs[i].index[j].term), *pos);
1.66 kristaps 1607: parseeoln(p, pos);
1608: #if HAVE_INDEX
1609: p->literal--;
1610: texiputchars(p, "\"");
1611: teximacroclose(p);
1612: #endif
1613: teximacroclose(p);
1614: }
1615: p->seenvs = 0;
1616: teximacro(p, "El");
1617: texivspace(p);
1.70 kristaps 1618: guard--;
1.66 kristaps 1619: }
1620:
1.64 kristaps 1621: static void
1.65 kristaps 1622: donode(struct texi *p, enum texicmd cmd, size_t *pos)
1623: {
1.66 kristaps 1624: int sv = p->seenvs;
1.68 kristaps 1625: char fname[PATH_MAX];
1626: size_t end, start;
1627:
1628: if (0 == p->nodesz++)
1629: p->ign--;
1630:
1631: /* Grab our node name. */
1632: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1633: advance(p, pos);
1634: start = *pos;
1635: while (*pos < BUFSZ(p)) {
1636: if (BUF(p)[*pos] == ',')
1637: break;
1638: else if (BUF(p)[*pos] == '\n')
1639: break;
1640: advance(p, pos);
1641: }
1642: if (*pos == BUFSZ(p)) {
1643: texiwarn(p, "unexpected EOF");
1644: return;
1645: }
1646: end = *pos;
1647: advanceeoln(p, pos, 1);
1648:
1649: if (NULL != p->chapters)
1650: teximdocclose(p, 0);
1651:
1652: /* Cache our node name. */
1653: p->nodecur = texicache(p, &BUF(p)[start], end - start);
1.66 kristaps 1654:
1655: if (NULL != p->chapters) {
1.71 schwarze 1656: snprintf(fname, sizeof(fname),
1.68 kristaps 1657: "%s-%zd.7", p->chapters, p->nodecur);
1658: p->outfile = fopen(fname, "w");
1659: if (NULL == p->outfile)
1660: texiabort(p, fname);
1.67 kristaps 1661: teximdocopen(p, pos);
1.68 kristaps 1662: } else if (p->nodesz > 1) {
1663: /* Otherwise, mark our index. */
1664: p->seenvs = -1;
1.66 kristaps 1665: #if HAVE_INDEX
1.67 kristaps 1666: teximacroopen(p, "Ix");
1667: texiputchars(p, "node");
1.68 kristaps 1668: texiputchars(p, p->nodecache[p->nodecur].name);
1.67 kristaps 1669: teximacroclose(p);
1670: #endif
1671: p->seenvs = sv;
1.68 kristaps 1672: } else
1673: teximdocopen(p, pos);
1.65 kristaps 1674: }
1675:
1.66 kristaps 1676: /*
1677: * This handles both menu and detailedmenu.
1678: * The syntax of these is fairly... unspecific, but what we do here
1679: * seems to work with most manuals.
1680: */
1.65 kristaps 1681: static void
1.64 kristaps 1682: domenu(struct texi *p, enum texicmd cmd, size_t *pos)
1683: {
1.68 kristaps 1684: size_t nodename, entryname;
1685: size_t nodenameend, entrynameend, i;
1.71 schwarze 1686: ssize_t ppos, lastppos;
1.68 kristaps 1687: char buf[PATH_MAX];
1688: enum texicmd tcmd;
1.64 kristaps 1689:
1690: advanceeoln(p, pos, 1);
1691:
1.71 schwarze 1692: /*
1693: * Parse past initial stuff.
1.66 kristaps 1694: * TODO: the manual says we're supposed to make this in bold or
1695: * something.
1696: */
1697: while (*pos < BUFSZ(p)) {
1698: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1699: advance(p, pos);
1.69 kristaps 1700: if (*pos < BUFSZ(p) && '*' != BUF(p)[*pos]) {
1.66 kristaps 1701: if (TEXICMD_END == peeklinecmd(p, *pos))
1702: break;
1703: parseeoln(p, pos);
1704: } else
1705: break;
1706: }
1707:
1.68 kristaps 1708: lastppos = -1;
1.65 kristaps 1709: texivspace(p);
1710: teximacro(p, "Bl -tag -width Ds -compact");
1.64 kristaps 1711: while (*pos < BUFSZ(p)) {
1.71 schwarze 1712: /*
1713: * Read to next menu item.
1.66 kristaps 1714: * We simply parse every line until we get a magic '*'.
1715: * These lines might occur interspersed OR as the
1716: * description of an entry.
1717: * Either way it's in the `It' block.
1718: */
1719: if (0 == p->seenws)
1720: p->seenws = *pos < BUFSZ(p) && isws(BUF(p)[*pos]);
1721: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1.64 kristaps 1722: advance(p, pos);
1.69 kristaps 1723: if (*pos == BUFSZ(p)) {
1724: texiwarn(p, "unexpected EOF");
1725: return;
1726: } else if ('*' != BUF(p)[*pos]) {
1.68 kristaps 1727: tcmd = peeklinecmd(p, *pos);
1728: if (TEXICMD_END == tcmd)
1.66 kristaps 1729: break;
1.71 schwarze 1730: else if (TEXICMD_COMMENT == tcmd)
1.68 kristaps 1731: advanceeoln(p, pos, 1);
1732: else
1733: parseeoln(p, pos);
1.66 kristaps 1734: continue;
1.71 schwarze 1735: }
1.64 kristaps 1736:
1.66 kristaps 1737: /* Now we're parsing a menu item. */
1.64 kristaps 1738: advance(p, pos);
1.66 kristaps 1739: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1.64 kristaps 1740: advance(p, pos);
1.68 kristaps 1741: entryname = *pos;
1.64 kristaps 1742: while (*pos < BUFSZ(p) && ':' != BUF(p)[*pos])
1743: advance(p, pos);
1.68 kristaps 1744: entrynameend = *pos;
1.69 kristaps 1745: if (*pos == BUFSZ(p)) {
1746: texiwarn(p, "unexpected EOF");
1747: return;
1748: }
1.66 kristaps 1749: advance(p, pos);
1.64 kristaps 1750:
1.68 kristaps 1751: p->seenvs = 0;
1752: teximacroopen(p, "It");
1.64 kristaps 1753: if (*pos == BUFSZ(p)) {
1754: texiwarn(p, "bad menu syntax");
1755: break;
1756: } else if (':' != BUF(p)[*pos]) {
1757: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1758: advance(p, pos);
1.68 kristaps 1759: nodename = *pos;
1.64 kristaps 1760: while (*pos < BUFSZ(p)) {
1761: switch (BUF(p)[*pos]) {
1762: case ('\t'):
1763: case ('\n'):
1764: case (','):
1765: break;
1766: case ('.'):
1767: if (*pos + 1 == BUFSZ(p)) {
1768: advance(p, pos);
1769: continue;
1.71 schwarze 1770: }
1.64 kristaps 1771: if (' ' == BUF(p)[*pos + 1]) {
1772: advance(p, pos);
1773: break;
1774: }
1775: /* FALLTHROUGH */
1776: default:
1777: advance(p, pos);
1778: continue;
1779: }
1780: advance(p, pos);
1781: break;
1782: }
1.68 kristaps 1783: nodenameend = *pos;
1.66 kristaps 1784: } else {
1.64 kristaps 1785: advance(p, pos);
1.68 kristaps 1786: nodename = entryname;
1787: nodenameend = entrynameend;
1788: }
1.71 schwarze 1789: ppos = texicache(p, &BUF(p)[nodename],
1.68 kristaps 1790: nodenameend - nodename);
1791: if (-1 != lastppos)
1792: p->nodecache[lastppos].next = ppos;
1793: p->nodecache[ppos].prev = lastppos;
1794: p->nodecache[ppos].up = p->nodecur;
1795: lastppos = ppos;
1.66 kristaps 1796: #ifdef HAVE_INDEX
1.68 kristaps 1797: if (NULL == p->chapters) {
1.66 kristaps 1798: teximacroopen(p, "Lkx");
1799: texiputchars(p, "\"node");
1.68 kristaps 1800: for (i = nodename; i < nodenameend; i++)
1801: texiputchar(p, BUF(p)[i]);
1802: texiputchars(p, "\" \"");
1803: for (i = entryname; i < entrynameend; i++)
1804: texiputchar(p, BUF(p)[i]);
1805: texiputchars(p, "\"");
1806: teximacroclose(p);
1807: } else {
1.71 schwarze 1808: snprintf(buf, sizeof(buf),
1.68 kristaps 1809: "%s-%zd 7 ", p->chapters, ppos);
1810: teximacroopen(p, "Xr");
1811: texiputchars(p, buf);
1812: texiputchars(p, "\"node");
1813: for (i = nodename; i < nodenameend; i++)
1814: texiputchar(p, BUF(p)[i]);
1.66 kristaps 1815: texiputchars(p, "\" \"");
1.68 kristaps 1816: for (i = entryname; i < entrynameend; i++)
1817: texiputchar(p, BUF(p)[i]);
1818: texiputchars(p, "\"");
1819: teximacroclose(p);
1.64 kristaps 1820: }
1.68 kristaps 1821: #else
1822: for (i = entryname; i < entrynameend; i++)
1823: texiputchar(p, BUF(p)[i]);
1.66 kristaps 1824: #endif
1825: teximacroclose(p);
1.64 kristaps 1826: }
1827:
1.66 kristaps 1828: advanceeoln(p, pos, 0);
1829: p->seenvs = 0;
1.64 kristaps 1830: teximacro(p, "El");
1.66 kristaps 1831: texivspace(p);
1.64 kristaps 1832: }
1833:
1.3 kristaps 1834: static void
1.46 kristaps 1835: domath(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 1836: {
1837:
1.53 kristaps 1838: parsebracket(p, pos, 1);
1.24 kristaps 1839: }
1840:
1841: static void
1.46 kristaps 1842: dovalue(struct texi *p, enum texicmd cmd, size_t *pos)
1.24 kristaps 1843: {
1.46 kristaps 1844: size_t start, end;
1.25 kristaps 1845: char *key, *val;
1846: const char *cp;
1.24 kristaps 1847:
1848: if (TEXICMD_SET == cmd) {
1.46 kristaps 1849: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1850: advance(p, pos);
1851: for (start = end = *pos; end < BUFSZ(p); end++)
1852: if (ismspace(BUF(p)[end]))
1.24 kristaps 1853: break;
1.25 kristaps 1854: /* We don't allow empty keys. */
1.24 kristaps 1855: if (start == end)
1856: return;
1.46 kristaps 1857: advanceto(p, pos, end);
1.24 kristaps 1858:
1859: key = malloc(end - start + 1);
1.27 kristaps 1860: if (NULL == key)
1861: texiabort(p, NULL);
1.46 kristaps 1862: memcpy(key, &BUF(p)[start], end - start);
1.24 kristaps 1863: key[end - start] = '\0';
1864:
1.46 kristaps 1865: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1866: advance(p, pos);
1867: for (start = end = *pos; end < BUFSZ(p); end++)
1868: if ('\n' == BUF(p)[end])
1.24 kristaps 1869: break;
1.25 kristaps 1870: /* We do allow empty values. */
1.46 kristaps 1871: advanceeoln(p, pos, 1);
1.24 kristaps 1872:
1873: val = malloc(end - start + 1);
1.27 kristaps 1874: if (NULL == val)
1875: texiabort(p, NULL);
1.46 kristaps 1876: memcpy(val, &BUF(p)[start], end - start);
1.24 kristaps 1877: val[end - start] = '\0';
1.25 kristaps 1878: valueadd(p, key, val);
1.24 kristaps 1879: } else if (TEXICMD_VALUE == cmd) {
1880: if (p->seenws)
1881: texiputchar(p, ' ');
1882: p->seenws = 0;
1.46 kristaps 1883: if (NULL != (cp = valueblookup(p, pos)))
1.56 kristaps 1884: texisplice(p, cp, strlen(cp), *pos);
1.46 kristaps 1885: else
1.25 kristaps 1886: texiputchars(p, "{No value}");
1.24 kristaps 1887: } else if (TEXICMD_IFCLEAR == cmd) {
1.46 kristaps 1888: if (NULL != valuellookup(p, pos))
1889: doignblock(p, cmd, pos);
1.26 kristaps 1890: else
1.46 kristaps 1891: parseto(p, pos, texitoks[cmd].tok);
1.30 kristaps 1892: } else if (TEXICMD_IFSET == cmd) {
1.46 kristaps 1893: if (NULL == valuellookup(p, pos))
1894: doignblock(p, cmd, pos);
1.30 kristaps 1895: else
1.46 kristaps 1896: parseto(p, pos, texitoks[cmd].tok);
1.25 kristaps 1897: } else if (TEXICMD_CLEAR == cmd)
1.46 kristaps 1898: valuelclear(p, pos);
1.3 kristaps 1899: }
1900:
1.1 kristaps 1901: static void
1.46 kristaps 1902: dolink(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1903: {
1.8 kristaps 1904: int c;
1.1 kristaps 1905:
1906: switch (cmd) {
1907: case (TEXICMD_EMAIL):
1.5 kristaps 1908: teximacroopen(p, "Mt");
1.1 kristaps 1909: break;
1.3 kristaps 1910: case (TEXICMD_UREF):
1.1 kristaps 1911: case (TEXICMD_URL):
1.44 kristaps 1912: case (TEXICMD_INDICATEURL):
1.5 kristaps 1913: teximacroopen(p, "Lk");
1.1 kristaps 1914: break;
1.8 kristaps 1915: case (TEXICMD_XREF):
1916: texiputchars(p, "See Section");
1.39 kristaps 1917: teximacroopen(p, "Dq");
1.8 kristaps 1918: break;
1919: case (TEXICMD_PXREF):
1920: texiputchars(p, "see Section");
1.39 kristaps 1921: teximacroopen(p, "Dq");
1.8 kristaps 1922: break;
1.34 kristaps 1923: case (TEXICMD_INFOREF):
1924: texiputchars(p, "See Info file node");
1.39 kristaps 1925: teximacroopen(p, "Dq");
1.34 kristaps 1926: break;
1.1 kristaps 1927: default:
1.8 kristaps 1928: abort();
1.1 kristaps 1929: }
1.8 kristaps 1930:
1.46 kristaps 1931: c = parsearg(p, pos, 0);
1.8 kristaps 1932: p->ign++;
1933: while (c > 0)
1.46 kristaps 1934: c = parsearg(p, pos, 1);
1.8 kristaps 1935: p->ign--;
1936:
1.46 kristaps 1937: texipunctuate(p, pos);
1.8 kristaps 1938: teximacroclose(p);
1939: }
1940:
1941: static void
1.46 kristaps 1942: doignargn(struct texi *p, enum texicmd cmd, size_t *pos)
1.8 kristaps 1943: {
1944: int c;
1945:
1.46 kristaps 1946: c = parsearg(p, pos, 0);
1.8 kristaps 1947: p->ign++;
1948: while (c > 0)
1.46 kristaps 1949: c = parsearg(p, pos, 1);
1.8 kristaps 1950: p->ign--;
1.1 kristaps 1951: }
1952:
1.23 kristaps 1953: /*
1954: * Sections can be made subsections and so on by way of the
1955: * @raiseections and @lowersections commands.
1956: * Perform this check here and return the actual section number adjusted
1957: * to the raise level.
1958: */
1959: static int
1960: sectioner(struct texi *p, int sec)
1961: {
1962:
1963: if ((sec -= p->secoffs) < 0) {
1964: texiwarn(p, "section below minimum, clamping");
1965: return(0);
1966: } else if (sec >= SECTSZ) {
1967: texiwarn(p, "section above maximum, clamping");
1968: return(SECTSZ - 1);
1969: }
1970: return(sec);
1971: }
1972:
1973: static void
1.46 kristaps 1974: dosecoffs(struct texi *p, enum texicmd cmd, size_t *pos)
1.23 kristaps 1975: {
1976:
1977: if (TEXICMD_RAISESECTIONS == cmd)
1978: p->secoffs++;
1979: else
1980: p->secoffs--;
1981: }
1982:
1983: static void
1.46 kristaps 1984: dosection(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1985: {
1.23 kristaps 1986: int sec;
1.12 kristaps 1987:
1988: switch (cmd) {
1.55 kristaps 1989: case (TEXICMD_TOP):
1990: sec = 0;
1991: break;
1.12 kristaps 1992: case (TEXICMD_APPENDIX):
1993: case (TEXICMD_CHAPTER):
1994: case (TEXICMD_UNNUMBERED):
1.23 kristaps 1995: sec = sectioner(p, 0);
1.12 kristaps 1996: break;
1997: case (TEXICMD_APPENDIXSEC):
1998: case (TEXICMD_HEADING):
1999: case (TEXICMD_SECTION):
2000: case (TEXICMD_UNNUMBEREDSEC):
1.23 kristaps 2001: sec = sectioner(p, 1);
1.12 kristaps 2002: break;
1.66 kristaps 2003: case (TEXICMD_APPENDIXSUBSEC):
2004: case (TEXICMD_SUBHEADING):
2005: case (TEXICMD_SUBSECTION):
2006: case (TEXICMD_UNNUMBEREDSUBSEC):
2007: sec = sectioner(p, 2);
2008: break;
2009: case (TEXICMD_APPENDIXSUBSUBSEC):
2010: case (TEXICMD_SUBSUBHEADING):
2011: case (TEXICMD_SUBSUBSECTION):
2012: case (TEXICMD_UNNUMBEREDSUBSUBSEC):
2013: sec = sectioner(p, 3);
2014: break;
1.12 kristaps 2015: default:
2016: abort();
2017: }
1.1 kristaps 2018:
1.3 kristaps 2019: if (p->outmacro)
1.23 kristaps 2020: texierr(p, "\"%s\" in open line scope!?", sects[sec]);
1.3 kristaps 2021: else if (p->literal)
1.23 kristaps 2022: texierr(p, "\"%s\" in a literal scope!?", sects[sec]);
1.3 kristaps 2023:
1.66 kristaps 2024: if (sec < 2)
2025: p->seenvs = -1;
1.71 schwarze 2026: else
1.66 kristaps 2027: texivspace(p);
2028:
1.23 kristaps 2029: teximacroopen(p, sects[sec]);
1.46 kristaps 2030: parseeoln(p, pos);
1.3 kristaps 2031: teximacroclose(p);
1.66 kristaps 2032:
2033: if (sec < 2)
2034: p->seenvs = -1;
2035: else
2036: texivspace(p);
1.3 kristaps 2037: }
2038:
2039: static void
1.46 kristaps 2040: dosp(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 2041: {
2042:
1.57 kristaps 2043: advanceeoln(p, pos, 1);
1.37 kristaps 2044: if (p->literal)
2045: texiputchar(p, '\n');
2046: else
2047: texivspace(p);
1.1 kristaps 2048: }
2049:
2050: static void
1.46 kristaps 2051: doitem(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2052: {
2053:
1.18 kristaps 2054: /* Multitable is using raw tbl(7). */
2055: if (TEXILIST_TABLE == p->list) {
1.64 kristaps 2056: if (p->outcol > 0)
2057: texiputchar(p, '\n');
1.18 kristaps 2058: return;
1.71 schwarze 2059: }
2060:
1.3 kristaps 2061: if (p->outmacro)
2062: texierr(p, "item in open line scope!?");
2063: else if (p->literal)
2064: texierr(p, "item in a literal scope!?");
2065:
2066: switch (p->list) {
2067: case (TEXILIST_ITEM):
1.66 kristaps 2068: p->seenvs = -1;
1.5 kristaps 2069: teximacroopen(p, "It");
1.3 kristaps 2070: break;
2071: case (TEXILIST_NOITEM):
1.66 kristaps 2072: p->seenvs = -1;
1.5 kristaps 2073: teximacro(p, "It");
1.3 kristaps 2074: break;
2075: default:
1.11 kristaps 2076: texivspace(p);
1.3 kristaps 2077: break;
2078: }
1.18 kristaps 2079:
2080: /* Trick so we don't start with Pp. */
1.46 kristaps 2081: parseeoln(p, pos);
1.1 kristaps 2082:
1.3 kristaps 2083: if (TEXILIST_ITEM == p->list)
2084: teximacroclose(p);
1.9 kristaps 2085: else if (p->outcol > 0)
1.1 kristaps 2086: texiputchar(p, '\n');
1.18 kristaps 2087: }
2088:
2089: static void
1.46 kristaps 2090: dotab(struct texi *p, enum texicmd cmd, size_t *pos)
1.18 kristaps 2091: {
2092:
2093: /* This command is only useful in @multitable. */
1.64 kristaps 2094: if (TEXILIST_TABLE == p->list && p->outcol)
1.18 kristaps 2095: texiputchar(p, '\t');
2096: }
2097:
2098: static void
1.46 kristaps 2099: domultitable(struct texi *p, enum texicmd cmd, size_t *pos)
1.18 kristaps 2100: {
2101: enum texilist sv = p->list;
1.32 kristaps 2102: int svliteral = p->literal;
1.18 kristaps 2103: enum texicmd type;
2104: size_t i, end, columns;
2105:
1.64 kristaps 2106: texivspace(p);
1.18 kristaps 2107: p->list = TEXILIST_TABLE;
1.71 schwarze 2108: /*
1.32 kristaps 2109: * TS/TE blocks aren't "in mdoc(7)", so we can disregard the
2110: * fact that we're in literal mode right now.
2111: */
2112: p->literal = 0;
1.18 kristaps 2113: teximacro(p, "TS");
2114: columns = 0;
2115:
2116: /* Advance to the first argument... */
1.46 kristaps 2117: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2118: advance(p, pos);
1.18 kristaps 2119:
2120: /* Make sure we don't print anything when scanning. */
2121: p->ign++;
1.57 kristaps 2122: if (*pos < BUFSZ(p) && '@' == BUF(p)[*pos]) {
1.71 schwarze 2123: /*
1.18 kristaps 2124: * Look for @columnfractions.
2125: * We ignore these, but we do use the number of
2126: * arguments to set the number of columns that we'll
2127: * have.
2128: */
1.46 kristaps 2129: type = texicmd(p, *pos, &end, NULL);
2130: advanceto(p, pos, end);
1.71 schwarze 2131: if (TEXICMD_COLUMNFRACTIONS != type)
1.25 kristaps 2132: texierr(p, "unknown multitable command");
1.46 kristaps 2133: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) {
2134: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2135: advance(p, pos);
2136: while (*pos < BUFSZ(p) && ! isws(BUF(p)[*pos])) {
2137: if ('\n' == BUF(p)[*pos])
1.18 kristaps 2138: break;
1.46 kristaps 2139: advance(p, pos);
1.18 kristaps 2140: }
2141: columns++;
2142: }
1.71 schwarze 2143: } else
1.18 kristaps 2144: /*
2145: * We have arguments.
2146: * We could parse these, but it's easier to just let
2147: * tbl(7) figure it out.
2148: * So use this only to count arguments.
2149: */
1.46 kristaps 2150: while (parselinearg(p, pos) > 0)
1.18 kristaps 2151: columns++;
2152: p->ign--;
2153:
2154: /* Left-justify each table entry. */
2155: for (i = 0; i < columns; i++) {
2156: if (i > 0)
2157: texiputchar(p, ' ');
2158: texiputchar(p, 'l');
2159: }
1.64 kristaps 2160:
2161: texiputchar(p, '.');
2162: texiputchar(p, '\n');
1.18 kristaps 2163: p->outmacro++;
1.46 kristaps 2164: parseto(p, pos, texitoks[cmd].tok);
1.18 kristaps 2165: p->outmacro--;
2166: teximacro(p, "TE");
1.32 kristaps 2167: p->literal = svliteral;
1.18 kristaps 2168: p->list = sv;
1.66 kristaps 2169: texivspace(p);
1.1 kristaps 2170: }
2171:
2172: static void
1.46 kristaps 2173: dotable(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2174: {
1.3 kristaps 2175: enum texilist sv = p->list;
2176:
1.57 kristaps 2177: advanceeoln(p, pos, 1);
2178:
1.3 kristaps 2179: p->list = TEXILIST_ITEM;
1.66 kristaps 2180: texivspace(p);
2181: teximacro(p, "Bl -tag -width Ds -compact");
1.46 kristaps 2182: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2183: p->seenvs = 0;
1.5 kristaps 2184: teximacro(p, "El");
1.66 kristaps 2185: texivspace(p);
1.3 kristaps 2186: p->list = sv;
1.44 kristaps 2187: }
2188:
2189: static void
1.46 kristaps 2190: doend(struct texi *p, enum texicmd cmd, size_t *pos)
1.44 kristaps 2191: {
2192: size_t start;
2193:
1.46 kristaps 2194: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2195: advance(p, pos);
1.44 kristaps 2196: start = *pos;
1.46 kristaps 2197: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
2198: advance(p, pos);
1.44 kristaps 2199:
1.71 schwarze 2200: texiwarn(p, "unexpected \"end\": %.*s",
1.56 kristaps 2201: (int)(*pos - start), &BUF(p)[start]);
1.46 kristaps 2202: advanceeoln(p, pos, 1);
1.1 kristaps 2203: }
2204:
2205: static void
1.46 kristaps 2206: doenumerate(struct texi *p, enum texicmd cmd, size_t *pos)
1.2 kristaps 2207: {
1.3 kristaps 2208: enum texilist sv = p->list;
1.2 kristaps 2209:
1.57 kristaps 2210: advanceeoln(p, pos, 1);
2211:
1.3 kristaps 2212: p->list = TEXILIST_NOITEM;
1.66 kristaps 2213: texivspace(p);
2214: teximacro(p, "Bl -enum -compact");
1.57 kristaps 2215: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2216: p->seenvs = 0;
1.5 kristaps 2217: teximacro(p, "El");
1.66 kristaps 2218: texivspace(p);
1.3 kristaps 2219: p->list = sv;
1.2 kristaps 2220: }
2221:
2222: static void
1.46 kristaps 2223: doitemize(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2224: {
1.3 kristaps 2225: enum texilist sv = p->list;
1.1 kristaps 2226:
1.57 kristaps 2227: advanceeoln(p, pos, 1);
2228:
1.21 kristaps 2229: p->list = TEXILIST_NOITEM;
1.66 kristaps 2230: texivspace(p);
2231: teximacro(p, "Bl -bullet -compact");
1.57 kristaps 2232: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2233: p->seenvs = 0;
1.5 kristaps 2234: teximacro(p, "El");
1.66 kristaps 2235: texivspace(p);
1.3 kristaps 2236: p->list = sv;
1.1 kristaps 2237: }
2238:
2239: static void
1.46 kristaps 2240: doignbracket(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2241: {
2242:
1.3 kristaps 2243: p->ign++;
1.53 kristaps 2244: parsebracket(p, pos, 0);
1.3 kristaps 2245: p->ign--;
1.1 kristaps 2246: }
2247:
2248: static void
1.66 kristaps 2249: doindex(struct texi *p, enum texicmd cmd, size_t *pos)
2250: {
2251: size_t start, end, len;
2252:
2253: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2254: advance(p, pos);
2255:
2256: start = *pos;
1.68 kristaps 2257: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
1.66 kristaps 2258: advance(p, pos);
2259:
2260: if (*pos == BUFSZ(p)) {
2261: texiwarn(p, "unexpected EOF");
2262: return;
2263: }
2264:
2265: advance(p, pos);
2266: end = *pos;
2267: if (0 == (len = end - start)) {
2268: texiwarn(p, "zero-length index");
2269: return;
2270: }
2271:
2272: /* Two-letter combos we can look up verbatim. */
2273: if (7 == texitoks[cmd].len) {
2274: texindex(p, texitoks[cmd].tok, 2, &BUF(p)[start], len);
2275: return;
2276: }
2277:
2278: assert(6 == texitoks[cmd].len);
2279: /* Newer one-letter combos need to be mapped. */
2280: switch (texitoks[cmd].tok[0]) {
2281: case ('c'):
2282: texindex(p, "cp", 2, &BUF(p)[start], len);
2283: break;
2284: case ('v'):
2285: texindex(p, "vr", 2, &BUF(p)[start], len);
2286: break;
2287: case ('f'):
2288: texindex(p, "fn", 2, &BUF(p)[start], len);
2289: break;
2290: case ('t'):
2291: texindex(p, "tp", 2, &BUF(p)[start], len);
2292: break;
2293: default:
2294: abort();
2295: }
2296: }
2297:
2298: static void
1.46 kristaps 2299: doignline(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2300: {
2301:
1.57 kristaps 2302: advanceeoln(p, pos, 1);
1.1 kristaps 2303: }
2304:
1.8 kristaps 2305: /*
2306: * Parse colon-separated directories from "cp" (if not NULL) and returns
2307: * the array of pointers.
1.40 kristaps 2308: * Prepends "base" to the array, if found.
1.8 kristaps 2309: * This does NOT sanitise the directories!
2310: */
1.5 kristaps 2311: static char **
1.27 kristaps 2312: parsedirs(struct texi *p, const char *base, const char *cp, size_t *sz)
1.5 kristaps 2313: {
1.71 schwarze 2314: char *tok, *str, *tofree;
2315: const char *cpp;
2316: size_t i = 0;
1.5 kristaps 2317: char **dirs;
2318:
1.40 kristaps 2319: /* Count up our expected arguments. */
2320: *sz = NULL != base;
2321: if (NULL != (cpp = cp))
2322: for ((*sz)++; NULL != (cpp = strchr(cpp, ':')); (*sz)++)
1.5 kristaps 2323: cpp++;
2324:
1.40 kristaps 2325: if (0 == *sz)
2326: return(NULL);
1.27 kristaps 2327: if (NULL == (dirs = calloc(*sz, sizeof(char *))))
2328: texiabort(p, NULL);
1.71 schwarze 2329: if (NULL != base && NULL == (dirs[i++] = strdup(base)))
1.27 kristaps 2330: texiabort(p, NULL);
1.5 kristaps 2331: if (NULL == cp)
2332: return(dirs);
1.27 kristaps 2333: if (NULL == (tofree = tok = str = strdup(cp)))
2334: texiabort(p, NULL);
1.5 kristaps 2335:
1.71 schwarze 2336: for ( ; NULL != (tok = strsep(&str, ":")); i++)
2337: if (NULL == (dirs[i] = strdup(tok)))
1.27 kristaps 2338: texiabort(p, NULL);
1.5 kristaps 2339:
2340: free(tofree);
2341: return(dirs);
2342: }
2343:
1.1 kristaps 2344: int
2345: main(int argc, char *argv[])
2346: {
2347: struct texi texi;
1.72 ! schwarze 2348: char date[32];
! 2349: struct stat st;
1.37 kristaps 2350: char *dirpath, *dir, *ccp;
1.10 kristaps 2351: const char *progname, *Idir, *cp;
1.72 ! schwarze 2352: time_t t;
! 2353: int c;
1.1 kristaps 2354:
2355: progname = strrchr(argv[0], '/');
2356: if (progname == NULL)
2357: progname = argv[0];
2358: else
2359: ++progname;
2360:
1.10 kristaps 2361: memset(&texi, 0, sizeof(struct texi));
1.40 kristaps 2362: texi.ign = 1;
1.55 kristaps 2363: texi.outfile = stdout;
1.66 kristaps 2364: texi.seenvs = -1;
1.5 kristaps 2365: Idir = NULL;
1.10 kristaps 2366:
1.72 ! schwarze 2367: while (-1 != (c = getopt(argc, argv, "C:d:I:")))
1.1 kristaps 2368: switch (c) {
1.55 kristaps 2369: case ('C'):
2370: texi.chapters = optarg;
2371: break;
1.72 ! schwarze 2372: case ('d'):
! 2373: texi.date = optarg;
! 2374: break;
1.5 kristaps 2375: case ('I'):
2376: Idir = optarg;
2377: break;
1.1 kristaps 2378: default:
2379: goto usage;
2380: }
2381:
2382: argv += optind;
1.40 kristaps 2383: argc -= optind;
1.66 kristaps 2384:
2385: /* Add the default Texinfo indices. */
2386: texindex_add(&texi, "cp", 2);
2387: texindex_add(&texi, "vr", 2);
2388: texindex_add(&texi, "tp", 2);
2389: texindex_add(&texi, "fn", 2);
1.1 kristaps 2390:
1.40 kristaps 2391: if (argc > 0) {
2392: if (NULL == (dirpath = strdup(argv[0])))
2393: texiabort(&texi, NULL);
2394: if (NULL == (dir = dirname(dirpath)))
2395: texiabort(&texi, NULL);
1.71 schwarze 2396: if (NULL != (cp = strrchr(argv[0], '/')))
1.40 kristaps 2397: texi.title = strdup(cp + 1);
2398: else
2399: texi.title = strdup(argv[0]);
2400: if (NULL == texi.title)
2401: texiabort(&texi, NULL);
2402: else if (NULL != (ccp = strchr(texi.title, '.')))
2403: *ccp = '\0';
2404: texi.dirs = parsedirs(&texi, dir, Idir, &texi.dirsz);
2405: free(dirpath);
1.72 ! schwarze 2406: if (NULL == texi.date) {
! 2407: t = stat(argv[0], &st) == 0 ? st.st_mtime : time(NULL);
! 2408: strftime(date, sizeof(date),
! 2409: "%B %e, %Y", localtime(&t));
! 2410: texi.date = date;
! 2411: }
1.40 kristaps 2412: parsefile(&texi, argv[0], 1);
2413: } else {
2414: texi.title = strdup("Unknown Manual");
2415: texi.dirs = parsedirs(&texi, NULL, Idir, &texi.dirsz);
1.72 ! schwarze 2416: if (NULL == texi.date) {
! 2417: t = time(NULL);
! 2418: strftime(date, sizeof(date),
! 2419: "%B %e, %Y", localtime(&t));
! 2420: texi.date = date;
! 2421: }
1.40 kristaps 2422: parsestdin(&texi);
2423: }
1.27 kristaps 2424:
1.2 kristaps 2425: texiexit(&texi);
1.56 kristaps 2426: exit(EXIT_SUCCESS);
1.1 kristaps 2427: usage:
1.72 ! schwarze 2428: fprintf(stderr, "usage: %s [-C dir] [-d date] [-I dirs] [file]\n",
! 2429: progname);
1.1 kristaps 2430: return(EXIT_FAILURE);
2431: }
CVSweb