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