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