Annotation of texi2mdoc/main.c, Revision 1.71
1.71 ! schwarze 1: /* $Id: main.c,v 1.70 2015/03/13 08:13:21 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.71 ! schwarze 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.71 ! schwarze 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.71 ! schwarze 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.71 ! schwarze 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.71 ! schwarze 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.71 ! schwarze 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]);
1.71 ! schwarze 642: if ('\n' != BUF(p)[*pos - 1])
1.46 kristaps 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,
1.71 ! schwarze 654: (p->macrosz + 1) *
1.30 kristaps 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:
1.71 ! schwarze 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
1.71 ! schwarze 677: * @ifset BAR
! 678: * @ifset FOO
! 679: * @end ifset
! 680: * @end ifset
1.45 kristaps 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.71 ! schwarze 684: ssz = snprintf(start, sizeof(start),
1.45 kristaps 685: "@%s", texitoks[cmd].tok);
686: assert(ssz < sizeof(start));
1.71 ! schwarze 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;
1.71 ! schwarze 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: {
1.71 ! schwarze 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.71 ! schwarze 785: /*
1.59 kristaps 786: * If we haven't seen any whitespace, then we don't want the
1.71 ! schwarze 787: * subsequent macro to insert any whitespace.
1.59 kristaps 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) {
1.71 ! schwarze 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.71 ! schwarze 944: char fname[PATH_MAX], path[PATH_MAX];
! 945: int rc;
! 946: size_t i, end;
1.25 kristaps 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.71 ! schwarze 963: if (TEXICMD_VALUE != type)
1.25 kristaps 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:
1.71 ! schwarze 988: rc = snprintf(path, sizeof(path),
1.16 kristaps 989: "%s/%s", p->dirs[0], fname);
1.71 ! schwarze 990: if (rc < 0)
1.16 kristaps 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.71 ! schwarze 1001: char fname[PATH_MAX], path[PATH_MAX];
! 1002: size_t i, end;
! 1003: int rc;
1.25 kristaps 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.71 ! schwarze 1021: if (TEXICMD_VALUE != type)
1.25 kristaps 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++) {
1.71 ! schwarze 1047: rc = snprintf(path, sizeof(path),
1.5 kristaps 1048: "%s/%s", p->dirs[i], fname);
1.71 ! schwarze 1049: if (rc < 0)
1.5 kristaps 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.71 ! schwarze 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.71 ! schwarze 1288: }
1.42 kristaps 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: {
1.71 ! schwarze 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: {
1.70 kristaps 1519: static size_t guard = 0;
1.71 ! schwarze 1520: size_t i, j, start, end, len;
1.66 kristaps 1521: #if HAVE_INDEX
1.70 kristaps 1522: char *cp;
1523: char buf[PATH_MAX];
1.66 kristaps 1524: #endif
1525:
1.70 kristaps 1526: if (guard++ > 8)
1527: texierr(p, "recursive @printindex");
1528:
1.66 kristaps 1529: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1530: advance(p, pos);
1531: start = *pos;
1532: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
1533: advance(p, pos);
1534: if ((end = *pos) == BUFSZ(p)) {
1535: texiwarn(p, "unexpected EOF");
1.70 kristaps 1536: guard--;
1.66 kristaps 1537: return;
1538: }
1539:
1540: advance(p, pos);
1.69 kristaps 1541: if (*pos == BUFSZ(p)) {
1542: texiwarn(p, "unexpected EOF");
1.70 kristaps 1543: guard--;
1.69 kristaps 1544: return;
1545: } else if (0 == (len = end - start)) {
1.66 kristaps 1546: texiwarn(p, "zero-length index");
1.70 kristaps 1547: guard--;
1.66 kristaps 1548: return;
1549: }
1550:
1551: /* Look for the index in our table. */
1552: for (i = 0; i < p->indexsz; i++) {
1553: if (strlen(p->indexs[i].name) != len)
1554: continue;
1555: if (strncmp(p->indexs[i].name, &BUF(p)[start], len))
1556: continue;
1557: break;
1558: }
1559:
1560: if (i == p->indexsz) {
1561: texiwarn(p, "cannot find index");
1.70 kristaps 1562: guard--;
1.66 kristaps 1563: return;
1.70 kristaps 1564: } else if (0 == p->indexs[i].indexsz) {
1565: guard--;
1.66 kristaps 1566: return;
1.70 kristaps 1567: }
1.66 kristaps 1568:
1569: /* Alphabetically sort our indices. */
1.71 ! schwarze 1570: qsort(p->indexs[i].index,
! 1571: p->indexs[i].indexsz,
1.67 kristaps 1572: sizeof(struct texiterm), indexcmp);
1.66 kristaps 1573:
1574: texivspace(p);
1575: teximacro(p, "Bl -tag -width Ds -compact");
1576: for (j = 0; j < p->indexs[i].indexsz; j++) {
1577: teximacroopen(p, "It");
1578: #if HAVE_INDEX
1.67 kristaps 1579: if (NULL == p->chapters) {
1580: teximacroopen(p, "Lkx");
1581: texiputchars(p, "\"idx");
1582: texiputchars(p, p->indexs[i].name);
1583: cp = p->indexs[i].index[j].term;
1.68 kristaps 1584: while ('\n' != *cp)
1.67 kristaps 1585: texiputchar(p, *cp++);
1586: texiputchars(p, "\" \"");
1587: p->literal++;
1588: } else {
1589: teximacroopen(p, "Xr");
1.68 kristaps 1590: snprintf(buf, sizeof(buf), "%s-%zd 7 \"idx",
1591: p->chapters, p->indexs[i].index[j].chapter);
1592: texiputchars(p, buf);
1.67 kristaps 1593: texiputchars(p, p->indexs[i].name);
1594: cp = p->indexs[i].index[j].term;
1.68 kristaps 1595: while ('\n' != *cp)
1.67 kristaps 1596: texiputchar(p, *cp++);
1597: texiputchars(p, "\" \"");
1598: p->literal++;
1.66 kristaps 1599: }
1600: #endif
1.71 ! schwarze 1601: texisplice(p, p->indexs[i].index[j].term,
1.67 kristaps 1602: strlen(p->indexs[i].index[j].term), *pos);
1.66 kristaps 1603: parseeoln(p, pos);
1604: #if HAVE_INDEX
1605: p->literal--;
1606: texiputchars(p, "\"");
1607: teximacroclose(p);
1608: #endif
1609: teximacroclose(p);
1610: }
1611: p->seenvs = 0;
1612: teximacro(p, "El");
1613: texivspace(p);
1.70 kristaps 1614: guard--;
1.66 kristaps 1615: }
1616:
1.64 kristaps 1617: static void
1.65 kristaps 1618: donode(struct texi *p, enum texicmd cmd, size_t *pos)
1619: {
1.66 kristaps 1620: int sv = p->seenvs;
1.68 kristaps 1621: char fname[PATH_MAX];
1622: size_t end, start;
1623:
1624: if (0 == p->nodesz++)
1625: p->ign--;
1626:
1627: /* Grab our node name. */
1628: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1629: advance(p, pos);
1630: start = *pos;
1631: while (*pos < BUFSZ(p)) {
1632: if (BUF(p)[*pos] == ',')
1633: break;
1634: else if (BUF(p)[*pos] == '\n')
1635: break;
1636: advance(p, pos);
1637: }
1638: if (*pos == BUFSZ(p)) {
1639: texiwarn(p, "unexpected EOF");
1640: return;
1641: }
1642: end = *pos;
1643: advanceeoln(p, pos, 1);
1644:
1645: if (NULL != p->chapters)
1646: teximdocclose(p, 0);
1647:
1648: /* Cache our node name. */
1649: p->nodecur = texicache(p, &BUF(p)[start], end - start);
1.66 kristaps 1650:
1651: if (NULL != p->chapters) {
1.71 ! schwarze 1652: snprintf(fname, sizeof(fname),
1.68 kristaps 1653: "%s-%zd.7", p->chapters, p->nodecur);
1654: p->outfile = fopen(fname, "w");
1655: if (NULL == p->outfile)
1656: texiabort(p, fname);
1.67 kristaps 1657: teximdocopen(p, pos);
1.68 kristaps 1658: } else if (p->nodesz > 1) {
1659: /* Otherwise, mark our index. */
1660: p->seenvs = -1;
1.66 kristaps 1661: #if HAVE_INDEX
1.67 kristaps 1662: teximacroopen(p, "Ix");
1663: texiputchars(p, "node");
1.68 kristaps 1664: texiputchars(p, p->nodecache[p->nodecur].name);
1.67 kristaps 1665: teximacroclose(p);
1666: #endif
1667: p->seenvs = sv;
1.68 kristaps 1668: } else
1669: teximdocopen(p, pos);
1.65 kristaps 1670: }
1671:
1.66 kristaps 1672: /*
1673: * This handles both menu and detailedmenu.
1674: * The syntax of these is fairly... unspecific, but what we do here
1675: * seems to work with most manuals.
1676: */
1.65 kristaps 1677: static void
1.64 kristaps 1678: domenu(struct texi *p, enum texicmd cmd, size_t *pos)
1679: {
1.68 kristaps 1680: size_t nodename, entryname;
1681: size_t nodenameend, entrynameend, i;
1.71 ! schwarze 1682: ssize_t ppos, lastppos;
1.68 kristaps 1683: char buf[PATH_MAX];
1684: enum texicmd tcmd;
1.64 kristaps 1685:
1686: advanceeoln(p, pos, 1);
1687:
1.71 ! schwarze 1688: /*
! 1689: * Parse past initial stuff.
1.66 kristaps 1690: * TODO: the manual says we're supposed to make this in bold or
1691: * something.
1692: */
1693: while (*pos < BUFSZ(p)) {
1694: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1695: advance(p, pos);
1.69 kristaps 1696: if (*pos < BUFSZ(p) && '*' != BUF(p)[*pos]) {
1.66 kristaps 1697: if (TEXICMD_END == peeklinecmd(p, *pos))
1698: break;
1699: parseeoln(p, pos);
1700: } else
1701: break;
1702: }
1703:
1.68 kristaps 1704: lastppos = -1;
1.65 kristaps 1705: texivspace(p);
1706: teximacro(p, "Bl -tag -width Ds -compact");
1.64 kristaps 1707: while (*pos < BUFSZ(p)) {
1.71 ! schwarze 1708: /*
! 1709: * Read to next menu item.
1.66 kristaps 1710: * We simply parse every line until we get a magic '*'.
1711: * These lines might occur interspersed OR as the
1712: * description of an entry.
1713: * Either way it's in the `It' block.
1714: */
1715: if (0 == p->seenws)
1716: p->seenws = *pos < BUFSZ(p) && isws(BUF(p)[*pos]);
1717: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1.64 kristaps 1718: advance(p, pos);
1.69 kristaps 1719: if (*pos == BUFSZ(p)) {
1720: texiwarn(p, "unexpected EOF");
1721: return;
1722: } else if ('*' != BUF(p)[*pos]) {
1.68 kristaps 1723: tcmd = peeklinecmd(p, *pos);
1724: if (TEXICMD_END == tcmd)
1.66 kristaps 1725: break;
1.71 ! schwarze 1726: else if (TEXICMD_COMMENT == tcmd)
1.68 kristaps 1727: advanceeoln(p, pos, 1);
1728: else
1729: parseeoln(p, pos);
1.66 kristaps 1730: continue;
1.71 ! schwarze 1731: }
1.64 kristaps 1732:
1.66 kristaps 1733: /* Now we're parsing a menu item. */
1.64 kristaps 1734: advance(p, pos);
1.66 kristaps 1735: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1.64 kristaps 1736: advance(p, pos);
1.68 kristaps 1737: entryname = *pos;
1.64 kristaps 1738: while (*pos < BUFSZ(p) && ':' != BUF(p)[*pos])
1739: advance(p, pos);
1.68 kristaps 1740: entrynameend = *pos;
1.69 kristaps 1741: if (*pos == BUFSZ(p)) {
1742: texiwarn(p, "unexpected EOF");
1743: return;
1744: }
1.66 kristaps 1745: advance(p, pos);
1.64 kristaps 1746:
1.68 kristaps 1747: p->seenvs = 0;
1748: teximacroopen(p, "It");
1.64 kristaps 1749: if (*pos == BUFSZ(p)) {
1750: texiwarn(p, "bad menu syntax");
1751: break;
1752: } else if (':' != BUF(p)[*pos]) {
1753: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1754: advance(p, pos);
1.68 kristaps 1755: nodename = *pos;
1.64 kristaps 1756: while (*pos < BUFSZ(p)) {
1757: switch (BUF(p)[*pos]) {
1758: case ('\t'):
1759: case ('\n'):
1760: case (','):
1761: break;
1762: case ('.'):
1763: if (*pos + 1 == BUFSZ(p)) {
1764: advance(p, pos);
1765: continue;
1.71 ! schwarze 1766: }
1.64 kristaps 1767: if (' ' == BUF(p)[*pos + 1]) {
1768: advance(p, pos);
1769: break;
1770: }
1771: /* FALLTHROUGH */
1772: default:
1773: advance(p, pos);
1774: continue;
1775: }
1776: advance(p, pos);
1777: break;
1778: }
1.68 kristaps 1779: nodenameend = *pos;
1.66 kristaps 1780: } else {
1.64 kristaps 1781: advance(p, pos);
1.68 kristaps 1782: nodename = entryname;
1783: nodenameend = entrynameend;
1784: }
1.71 ! schwarze 1785: ppos = texicache(p, &BUF(p)[nodename],
1.68 kristaps 1786: nodenameend - nodename);
1787: if (-1 != lastppos)
1788: p->nodecache[lastppos].next = ppos;
1789: p->nodecache[ppos].prev = lastppos;
1790: p->nodecache[ppos].up = p->nodecur;
1791: lastppos = ppos;
1.66 kristaps 1792: #ifdef HAVE_INDEX
1.68 kristaps 1793: if (NULL == p->chapters) {
1.66 kristaps 1794: teximacroopen(p, "Lkx");
1795: texiputchars(p, "\"node");
1.68 kristaps 1796: for (i = nodename; i < nodenameend; i++)
1797: texiputchar(p, BUF(p)[i]);
1798: texiputchars(p, "\" \"");
1799: for (i = entryname; i < entrynameend; i++)
1800: texiputchar(p, BUF(p)[i]);
1801: texiputchars(p, "\"");
1802: teximacroclose(p);
1803: } else {
1.71 ! schwarze 1804: snprintf(buf, sizeof(buf),
1.68 kristaps 1805: "%s-%zd 7 ", p->chapters, ppos);
1806: teximacroopen(p, "Xr");
1807: texiputchars(p, buf);
1808: texiputchars(p, "\"node");
1809: for (i = nodename; i < nodenameend; i++)
1810: texiputchar(p, BUF(p)[i]);
1.66 kristaps 1811: texiputchars(p, "\" \"");
1.68 kristaps 1812: for (i = entryname; i < entrynameend; i++)
1813: texiputchar(p, BUF(p)[i]);
1814: texiputchars(p, "\"");
1815: teximacroclose(p);
1.64 kristaps 1816: }
1.68 kristaps 1817: #else
1818: for (i = entryname; i < entrynameend; i++)
1819: texiputchar(p, BUF(p)[i]);
1.66 kristaps 1820: #endif
1821: teximacroclose(p);
1.64 kristaps 1822: }
1823:
1.66 kristaps 1824: advanceeoln(p, pos, 0);
1825: p->seenvs = 0;
1.64 kristaps 1826: teximacro(p, "El");
1.66 kristaps 1827: texivspace(p);
1.64 kristaps 1828: }
1829:
1.3 kristaps 1830: static void
1.46 kristaps 1831: domath(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 1832: {
1833:
1.53 kristaps 1834: parsebracket(p, pos, 1);
1.24 kristaps 1835: }
1836:
1837: static void
1.46 kristaps 1838: dovalue(struct texi *p, enum texicmd cmd, size_t *pos)
1.24 kristaps 1839: {
1.46 kristaps 1840: size_t start, end;
1.25 kristaps 1841: char *key, *val;
1842: const char *cp;
1.24 kristaps 1843:
1844: if (TEXICMD_SET == cmd) {
1.46 kristaps 1845: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1846: advance(p, pos);
1847: for (start = end = *pos; end < BUFSZ(p); end++)
1848: if (ismspace(BUF(p)[end]))
1.24 kristaps 1849: break;
1.25 kristaps 1850: /* We don't allow empty keys. */
1.24 kristaps 1851: if (start == end)
1852: return;
1.46 kristaps 1853: advanceto(p, pos, end);
1.24 kristaps 1854:
1855: key = malloc(end - start + 1);
1.27 kristaps 1856: if (NULL == key)
1857: texiabort(p, NULL);
1.46 kristaps 1858: memcpy(key, &BUF(p)[start], end - start);
1.24 kristaps 1859: key[end - start] = '\0';
1860:
1.46 kristaps 1861: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
1862: advance(p, pos);
1863: for (start = end = *pos; end < BUFSZ(p); end++)
1864: if ('\n' == BUF(p)[end])
1.24 kristaps 1865: break;
1.25 kristaps 1866: /* We do allow empty values. */
1.46 kristaps 1867: advanceeoln(p, pos, 1);
1.24 kristaps 1868:
1869: val = malloc(end - start + 1);
1.27 kristaps 1870: if (NULL == val)
1871: texiabort(p, NULL);
1.46 kristaps 1872: memcpy(val, &BUF(p)[start], end - start);
1.24 kristaps 1873: val[end - start] = '\0';
1.25 kristaps 1874: valueadd(p, key, val);
1.24 kristaps 1875: } else if (TEXICMD_VALUE == cmd) {
1876: if (p->seenws)
1877: texiputchar(p, ' ');
1878: p->seenws = 0;
1.46 kristaps 1879: if (NULL != (cp = valueblookup(p, pos)))
1.56 kristaps 1880: texisplice(p, cp, strlen(cp), *pos);
1.46 kristaps 1881: else
1.25 kristaps 1882: texiputchars(p, "{No value}");
1.24 kristaps 1883: } else if (TEXICMD_IFCLEAR == cmd) {
1.46 kristaps 1884: if (NULL != valuellookup(p, pos))
1885: doignblock(p, cmd, pos);
1.26 kristaps 1886: else
1.46 kristaps 1887: parseto(p, pos, texitoks[cmd].tok);
1.30 kristaps 1888: } else if (TEXICMD_IFSET == cmd) {
1.46 kristaps 1889: if (NULL == valuellookup(p, pos))
1890: doignblock(p, cmd, pos);
1.30 kristaps 1891: else
1.46 kristaps 1892: parseto(p, pos, texitoks[cmd].tok);
1.25 kristaps 1893: } else if (TEXICMD_CLEAR == cmd)
1.46 kristaps 1894: valuelclear(p, pos);
1.3 kristaps 1895: }
1896:
1.1 kristaps 1897: static void
1.46 kristaps 1898: dolink(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1899: {
1.8 kristaps 1900: int c;
1.1 kristaps 1901:
1902: switch (cmd) {
1903: case (TEXICMD_EMAIL):
1.5 kristaps 1904: teximacroopen(p, "Mt");
1.1 kristaps 1905: break;
1.3 kristaps 1906: case (TEXICMD_UREF):
1.1 kristaps 1907: case (TEXICMD_URL):
1.44 kristaps 1908: case (TEXICMD_INDICATEURL):
1.5 kristaps 1909: teximacroopen(p, "Lk");
1.1 kristaps 1910: break;
1.8 kristaps 1911: case (TEXICMD_XREF):
1912: texiputchars(p, "See Section");
1.39 kristaps 1913: teximacroopen(p, "Dq");
1.8 kristaps 1914: break;
1915: case (TEXICMD_PXREF):
1916: texiputchars(p, "see Section");
1.39 kristaps 1917: teximacroopen(p, "Dq");
1.8 kristaps 1918: break;
1.34 kristaps 1919: case (TEXICMD_INFOREF):
1920: texiputchars(p, "See Info file node");
1.39 kristaps 1921: teximacroopen(p, "Dq");
1.34 kristaps 1922: break;
1.1 kristaps 1923: default:
1.8 kristaps 1924: abort();
1.1 kristaps 1925: }
1.8 kristaps 1926:
1.46 kristaps 1927: c = parsearg(p, pos, 0);
1.8 kristaps 1928: p->ign++;
1929: while (c > 0)
1.46 kristaps 1930: c = parsearg(p, pos, 1);
1.8 kristaps 1931: p->ign--;
1932:
1.46 kristaps 1933: texipunctuate(p, pos);
1.8 kristaps 1934: teximacroclose(p);
1935: }
1936:
1937: static void
1.46 kristaps 1938: doignargn(struct texi *p, enum texicmd cmd, size_t *pos)
1.8 kristaps 1939: {
1940: int c;
1941:
1.46 kristaps 1942: c = parsearg(p, pos, 0);
1.8 kristaps 1943: p->ign++;
1944: while (c > 0)
1.46 kristaps 1945: c = parsearg(p, pos, 1);
1.8 kristaps 1946: p->ign--;
1.1 kristaps 1947: }
1948:
1.23 kristaps 1949: /*
1950: * Sections can be made subsections and so on by way of the
1951: * @raiseections and @lowersections commands.
1952: * Perform this check here and return the actual section number adjusted
1953: * to the raise level.
1954: */
1955: static int
1956: sectioner(struct texi *p, int sec)
1957: {
1958:
1959: if ((sec -= p->secoffs) < 0) {
1960: texiwarn(p, "section below minimum, clamping");
1961: return(0);
1962: } else if (sec >= SECTSZ) {
1963: texiwarn(p, "section above maximum, clamping");
1964: return(SECTSZ - 1);
1965: }
1966: return(sec);
1967: }
1968:
1969: static void
1.46 kristaps 1970: dosecoffs(struct texi *p, enum texicmd cmd, size_t *pos)
1.23 kristaps 1971: {
1972:
1973: if (TEXICMD_RAISESECTIONS == cmd)
1974: p->secoffs++;
1975: else
1976: p->secoffs--;
1977: }
1978:
1979: static void
1.46 kristaps 1980: dosection(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 1981: {
1.23 kristaps 1982: int sec;
1.12 kristaps 1983:
1984: switch (cmd) {
1.55 kristaps 1985: case (TEXICMD_TOP):
1986: sec = 0;
1987: break;
1.12 kristaps 1988: case (TEXICMD_APPENDIX):
1989: case (TEXICMD_CHAPTER):
1990: case (TEXICMD_UNNUMBERED):
1.23 kristaps 1991: sec = sectioner(p, 0);
1.12 kristaps 1992: break;
1993: case (TEXICMD_APPENDIXSEC):
1994: case (TEXICMD_HEADING):
1995: case (TEXICMD_SECTION):
1996: case (TEXICMD_UNNUMBEREDSEC):
1.23 kristaps 1997: sec = sectioner(p, 1);
1.12 kristaps 1998: break;
1.66 kristaps 1999: case (TEXICMD_APPENDIXSUBSEC):
2000: case (TEXICMD_SUBHEADING):
2001: case (TEXICMD_SUBSECTION):
2002: case (TEXICMD_UNNUMBEREDSUBSEC):
2003: sec = sectioner(p, 2);
2004: break;
2005: case (TEXICMD_APPENDIXSUBSUBSEC):
2006: case (TEXICMD_SUBSUBHEADING):
2007: case (TEXICMD_SUBSUBSECTION):
2008: case (TEXICMD_UNNUMBEREDSUBSUBSEC):
2009: sec = sectioner(p, 3);
2010: break;
1.12 kristaps 2011: default:
2012: abort();
2013: }
1.1 kristaps 2014:
1.3 kristaps 2015: if (p->outmacro)
1.23 kristaps 2016: texierr(p, "\"%s\" in open line scope!?", sects[sec]);
1.3 kristaps 2017: else if (p->literal)
1.23 kristaps 2018: texierr(p, "\"%s\" in a literal scope!?", sects[sec]);
1.3 kristaps 2019:
1.66 kristaps 2020: if (sec < 2)
2021: p->seenvs = -1;
1.71 ! schwarze 2022: else
1.66 kristaps 2023: texivspace(p);
2024:
1.23 kristaps 2025: teximacroopen(p, sects[sec]);
1.46 kristaps 2026: parseeoln(p, pos);
1.3 kristaps 2027: teximacroclose(p);
1.66 kristaps 2028:
2029: if (sec < 2)
2030: p->seenvs = -1;
2031: else
2032: texivspace(p);
1.3 kristaps 2033: }
2034:
2035: static void
1.46 kristaps 2036: dosp(struct texi *p, enum texicmd cmd, size_t *pos)
1.3 kristaps 2037: {
2038:
1.57 kristaps 2039: advanceeoln(p, pos, 1);
1.37 kristaps 2040: if (p->literal)
2041: texiputchar(p, '\n');
2042: else
2043: texivspace(p);
1.1 kristaps 2044: }
2045:
2046: static void
1.46 kristaps 2047: doitem(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2048: {
2049:
1.18 kristaps 2050: /* Multitable is using raw tbl(7). */
2051: if (TEXILIST_TABLE == p->list) {
1.64 kristaps 2052: if (p->outcol > 0)
2053: texiputchar(p, '\n');
1.18 kristaps 2054: return;
1.71 ! schwarze 2055: }
! 2056:
1.3 kristaps 2057: if (p->outmacro)
2058: texierr(p, "item in open line scope!?");
2059: else if (p->literal)
2060: texierr(p, "item in a literal scope!?");
2061:
2062: switch (p->list) {
2063: case (TEXILIST_ITEM):
1.66 kristaps 2064: p->seenvs = -1;
1.5 kristaps 2065: teximacroopen(p, "It");
1.3 kristaps 2066: break;
2067: case (TEXILIST_NOITEM):
1.66 kristaps 2068: p->seenvs = -1;
1.5 kristaps 2069: teximacro(p, "It");
1.3 kristaps 2070: break;
2071: default:
1.11 kristaps 2072: texivspace(p);
1.3 kristaps 2073: break;
2074: }
1.18 kristaps 2075:
2076: /* Trick so we don't start with Pp. */
1.46 kristaps 2077: parseeoln(p, pos);
1.1 kristaps 2078:
1.3 kristaps 2079: if (TEXILIST_ITEM == p->list)
2080: teximacroclose(p);
1.9 kristaps 2081: else if (p->outcol > 0)
1.1 kristaps 2082: texiputchar(p, '\n');
1.18 kristaps 2083: }
2084:
2085: static void
1.46 kristaps 2086: dotab(struct texi *p, enum texicmd cmd, size_t *pos)
1.18 kristaps 2087: {
2088:
2089: /* This command is only useful in @multitable. */
1.64 kristaps 2090: if (TEXILIST_TABLE == p->list && p->outcol)
1.18 kristaps 2091: texiputchar(p, '\t');
2092: }
2093:
2094: static void
1.46 kristaps 2095: domultitable(struct texi *p, enum texicmd cmd, size_t *pos)
1.18 kristaps 2096: {
2097: enum texilist sv = p->list;
1.32 kristaps 2098: int svliteral = p->literal;
1.18 kristaps 2099: enum texicmd type;
2100: size_t i, end, columns;
2101:
1.64 kristaps 2102: texivspace(p);
1.18 kristaps 2103: p->list = TEXILIST_TABLE;
1.71 ! schwarze 2104: /*
1.32 kristaps 2105: * TS/TE blocks aren't "in mdoc(7)", so we can disregard the
2106: * fact that we're in literal mode right now.
2107: */
2108: p->literal = 0;
1.18 kristaps 2109: teximacro(p, "TS");
2110: columns = 0;
2111:
2112: /* Advance to the first argument... */
1.46 kristaps 2113: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2114: advance(p, pos);
1.18 kristaps 2115:
2116: /* Make sure we don't print anything when scanning. */
2117: p->ign++;
1.57 kristaps 2118: if (*pos < BUFSZ(p) && '@' == BUF(p)[*pos]) {
1.71 ! schwarze 2119: /*
1.18 kristaps 2120: * Look for @columnfractions.
2121: * We ignore these, but we do use the number of
2122: * arguments to set the number of columns that we'll
2123: * have.
2124: */
1.46 kristaps 2125: type = texicmd(p, *pos, &end, NULL);
2126: advanceto(p, pos, end);
1.71 ! schwarze 2127: if (TEXICMD_COLUMNFRACTIONS != type)
1.25 kristaps 2128: texierr(p, "unknown multitable command");
1.46 kristaps 2129: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) {
2130: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2131: advance(p, pos);
2132: while (*pos < BUFSZ(p) && ! isws(BUF(p)[*pos])) {
2133: if ('\n' == BUF(p)[*pos])
1.18 kristaps 2134: break;
1.46 kristaps 2135: advance(p, pos);
1.18 kristaps 2136: }
2137: columns++;
2138: }
1.71 ! schwarze 2139: } else
1.18 kristaps 2140: /*
2141: * We have arguments.
2142: * We could parse these, but it's easier to just let
2143: * tbl(7) figure it out.
2144: * So use this only to count arguments.
2145: */
1.46 kristaps 2146: while (parselinearg(p, pos) > 0)
1.18 kristaps 2147: columns++;
2148: p->ign--;
2149:
2150: /* Left-justify each table entry. */
2151: for (i = 0; i < columns; i++) {
2152: if (i > 0)
2153: texiputchar(p, ' ');
2154: texiputchar(p, 'l');
2155: }
1.64 kristaps 2156:
2157: texiputchar(p, '.');
2158: texiputchar(p, '\n');
1.18 kristaps 2159: p->outmacro++;
1.46 kristaps 2160: parseto(p, pos, texitoks[cmd].tok);
1.18 kristaps 2161: p->outmacro--;
2162: teximacro(p, "TE");
1.32 kristaps 2163: p->literal = svliteral;
1.18 kristaps 2164: p->list = sv;
1.66 kristaps 2165: texivspace(p);
1.1 kristaps 2166: }
2167:
2168: static void
1.46 kristaps 2169: dotable(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2170: {
1.3 kristaps 2171: enum texilist sv = p->list;
2172:
1.57 kristaps 2173: advanceeoln(p, pos, 1);
2174:
1.3 kristaps 2175: p->list = TEXILIST_ITEM;
1.66 kristaps 2176: texivspace(p);
2177: teximacro(p, "Bl -tag -width Ds -compact");
1.46 kristaps 2178: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2179: p->seenvs = 0;
1.5 kristaps 2180: teximacro(p, "El");
1.66 kristaps 2181: texivspace(p);
1.3 kristaps 2182: p->list = sv;
1.44 kristaps 2183: }
2184:
2185: static void
1.46 kristaps 2186: doend(struct texi *p, enum texicmd cmd, size_t *pos)
1.44 kristaps 2187: {
2188: size_t start;
2189:
1.46 kristaps 2190: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2191: advance(p, pos);
1.44 kristaps 2192: start = *pos;
1.46 kristaps 2193: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
2194: advance(p, pos);
1.44 kristaps 2195:
1.71 ! schwarze 2196: texiwarn(p, "unexpected \"end\": %.*s",
1.56 kristaps 2197: (int)(*pos - start), &BUF(p)[start]);
1.46 kristaps 2198: advanceeoln(p, pos, 1);
1.1 kristaps 2199: }
2200:
2201: static void
1.46 kristaps 2202: doenumerate(struct texi *p, enum texicmd cmd, size_t *pos)
1.2 kristaps 2203: {
1.3 kristaps 2204: enum texilist sv = p->list;
1.2 kristaps 2205:
1.57 kristaps 2206: advanceeoln(p, pos, 1);
2207:
1.3 kristaps 2208: p->list = TEXILIST_NOITEM;
1.66 kristaps 2209: texivspace(p);
2210: teximacro(p, "Bl -enum -compact");
1.57 kristaps 2211: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2212: p->seenvs = 0;
1.5 kristaps 2213: teximacro(p, "El");
1.66 kristaps 2214: texivspace(p);
1.3 kristaps 2215: p->list = sv;
1.2 kristaps 2216: }
2217:
2218: static void
1.46 kristaps 2219: doitemize(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2220: {
1.3 kristaps 2221: enum texilist sv = p->list;
1.1 kristaps 2222:
1.57 kristaps 2223: advanceeoln(p, pos, 1);
2224:
1.21 kristaps 2225: p->list = TEXILIST_NOITEM;
1.66 kristaps 2226: texivspace(p);
2227: teximacro(p, "Bl -bullet -compact");
1.57 kristaps 2228: parseto(p, pos, texitoks[cmd].tok);
1.66 kristaps 2229: p->seenvs = 0;
1.5 kristaps 2230: teximacro(p, "El");
1.66 kristaps 2231: texivspace(p);
1.3 kristaps 2232: p->list = sv;
1.1 kristaps 2233: }
2234:
2235: static void
1.46 kristaps 2236: doignbracket(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2237: {
2238:
1.3 kristaps 2239: p->ign++;
1.53 kristaps 2240: parsebracket(p, pos, 0);
1.3 kristaps 2241: p->ign--;
1.1 kristaps 2242: }
2243:
2244: static void
1.66 kristaps 2245: doindex(struct texi *p, enum texicmd cmd, size_t *pos)
2246: {
2247: size_t start, end, len;
2248:
2249: while (*pos < BUFSZ(p) && isws(BUF(p)[*pos]))
2250: advance(p, pos);
2251:
2252: start = *pos;
1.68 kristaps 2253: while (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos])
1.66 kristaps 2254: advance(p, pos);
2255:
2256: if (*pos == BUFSZ(p)) {
2257: texiwarn(p, "unexpected EOF");
2258: return;
2259: }
2260:
2261: advance(p, pos);
2262: end = *pos;
2263: if (0 == (len = end - start)) {
2264: texiwarn(p, "zero-length index");
2265: return;
2266: }
2267:
2268: /* Two-letter combos we can look up verbatim. */
2269: if (7 == texitoks[cmd].len) {
2270: texindex(p, texitoks[cmd].tok, 2, &BUF(p)[start], len);
2271: return;
2272: }
2273:
2274: assert(6 == texitoks[cmd].len);
2275: /* Newer one-letter combos need to be mapped. */
2276: switch (texitoks[cmd].tok[0]) {
2277: case ('c'):
2278: texindex(p, "cp", 2, &BUF(p)[start], len);
2279: break;
2280: case ('v'):
2281: texindex(p, "vr", 2, &BUF(p)[start], len);
2282: break;
2283: case ('f'):
2284: texindex(p, "fn", 2, &BUF(p)[start], len);
2285: break;
2286: case ('t'):
2287: texindex(p, "tp", 2, &BUF(p)[start], len);
2288: break;
2289: default:
2290: abort();
2291: }
2292: }
2293:
2294: static void
1.46 kristaps 2295: doignline(struct texi *p, enum texicmd cmd, size_t *pos)
1.1 kristaps 2296: {
2297:
1.57 kristaps 2298: advanceeoln(p, pos, 1);
1.1 kristaps 2299: }
2300:
1.8 kristaps 2301: /*
2302: * Parse colon-separated directories from "cp" (if not NULL) and returns
2303: * the array of pointers.
1.40 kristaps 2304: * Prepends "base" to the array, if found.
1.8 kristaps 2305: * This does NOT sanitise the directories!
2306: */
1.5 kristaps 2307: static char **
1.27 kristaps 2308: parsedirs(struct texi *p, const char *base, const char *cp, size_t *sz)
1.5 kristaps 2309: {
1.71 ! schwarze 2310: char *tok, *str, *tofree;
! 2311: const char *cpp;
! 2312: size_t i = 0;
1.5 kristaps 2313: char **dirs;
2314:
1.40 kristaps 2315: /* Count up our expected arguments. */
2316: *sz = NULL != base;
2317: if (NULL != (cpp = cp))
2318: for ((*sz)++; NULL != (cpp = strchr(cpp, ':')); (*sz)++)
1.5 kristaps 2319: cpp++;
2320:
1.40 kristaps 2321: if (0 == *sz)
2322: return(NULL);
1.27 kristaps 2323: if (NULL == (dirs = calloc(*sz, sizeof(char *))))
2324: texiabort(p, NULL);
1.71 ! schwarze 2325: if (NULL != base && NULL == (dirs[i++] = strdup(base)))
1.27 kristaps 2326: texiabort(p, NULL);
1.5 kristaps 2327: if (NULL == cp)
2328: return(dirs);
1.27 kristaps 2329: if (NULL == (tofree = tok = str = strdup(cp)))
2330: texiabort(p, NULL);
1.5 kristaps 2331:
1.71 ! schwarze 2332: for ( ; NULL != (tok = strsep(&str, ":")); i++)
! 2333: if (NULL == (dirs[i] = strdup(tok)))
1.27 kristaps 2334: texiabort(p, NULL);
1.5 kristaps 2335:
2336: free(tofree);
2337: return(dirs);
2338: }
2339:
1.1 kristaps 2340: int
2341: main(int argc, char *argv[])
2342: {
2343: struct texi texi;
1.2 kristaps 2344: int c;
1.37 kristaps 2345: char *dirpath, *dir, *ccp;
1.10 kristaps 2346: const char *progname, *Idir, *cp;
1.1 kristaps 2347:
2348: progname = strrchr(argv[0], '/');
2349: if (progname == NULL)
2350: progname = argv[0];
2351: else
2352: ++progname;
2353:
1.10 kristaps 2354: memset(&texi, 0, sizeof(struct texi));
1.40 kristaps 2355: texi.ign = 1;
1.55 kristaps 2356: texi.outfile = stdout;
1.66 kristaps 2357: texi.seenvs = -1;
1.5 kristaps 2358: Idir = NULL;
1.10 kristaps 2359:
1.71 ! schwarze 2360: while (-1 != (c = getopt(argc, argv, "C:I:")))
1.1 kristaps 2361: switch (c) {
1.55 kristaps 2362: case ('C'):
2363: texi.chapters = optarg;
2364: break;
1.5 kristaps 2365: case ('I'):
2366: Idir = optarg;
2367: break;
1.1 kristaps 2368: default:
2369: goto usage;
2370: }
2371:
2372: argv += optind;
1.40 kristaps 2373: argc -= optind;
1.66 kristaps 2374:
2375: /* Add the default Texinfo indices. */
2376: texindex_add(&texi, "cp", 2);
2377: texindex_add(&texi, "vr", 2);
2378: texindex_add(&texi, "tp", 2);
2379: texindex_add(&texi, "fn", 2);
1.1 kristaps 2380:
1.40 kristaps 2381: if (argc > 0) {
2382: if (NULL == (dirpath = strdup(argv[0])))
2383: texiabort(&texi, NULL);
2384: if (NULL == (dir = dirname(dirpath)))
2385: texiabort(&texi, NULL);
1.71 ! schwarze 2386: if (NULL != (cp = strrchr(argv[0], '/')))
1.40 kristaps 2387: texi.title = strdup(cp + 1);
2388: else
2389: texi.title = strdup(argv[0]);
2390: if (NULL == texi.title)
2391: texiabort(&texi, NULL);
2392: else if (NULL != (ccp = strchr(texi.title, '.')))
2393: *ccp = '\0';
2394: texi.dirs = parsedirs(&texi, dir, Idir, &texi.dirsz);
2395: free(dirpath);
2396: parsefile(&texi, argv[0], 1);
2397: } else {
2398: texi.title = strdup("Unknown Manual");
2399: texi.dirs = parsedirs(&texi, NULL, Idir, &texi.dirsz);
2400: parsestdin(&texi);
2401: }
1.27 kristaps 2402:
1.2 kristaps 2403: texiexit(&texi);
1.56 kristaps 2404: exit(EXIT_SUCCESS);
1.1 kristaps 2405: usage:
1.55 kristaps 2406: fprintf(stderr, "usage: %s [-Cdir] [-Idirs] [file]\n", progname);
1.1 kristaps 2407: return(EXIT_FAILURE);
2408: }
CVSweb