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