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