version 1.2, 2015/02/17 10:27:18 |
version 1.41, 2015/02/24 14:35:40 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
#include <sys/mman.h> |
#if defined(__linux__) || defined(__MINT__) |
#include <sys/stat.h> |
# define _GNU_SOURCE /* memmem */ |
|
#endif |
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
#include <fcntl.h> |
|
#include <getopt.h> |
#include <getopt.h> |
#include <libgen.h> |
#include <libgen.h> |
#include <limits.h> |
#include <limits.h> |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <time.h> |
|
|
/* |
#include "extern.h" |
* This defines each one of the Texinfo commands that we understand. |
|
* Obviously this only refers to native commands; overriden names are a |
|
* different story. |
|
*/ |
|
enum texicmd { |
|
TEXICMD_ACRONYM, |
|
TEXICMD_A4PAPER, |
|
TEXICMD_ANCHOR, |
|
TEXICMD_APPENDIX, |
|
TEXICMD_APPENDIXSEC, |
|
TEXICMD_AT, |
|
TEXICMD_BYE, |
|
TEXICMD_CHAPTER, |
|
TEXICMD_CINDEX, |
|
TEXICMD_CODE, |
|
TEXICMD_COMMAND, |
|
TEXICMD_COMMENT, |
|
TEXICMD_COMMENT_LONG, |
|
TEXICMD_CONTENTS, |
|
TEXICMD_COPYING, |
|
TEXICMD_COPYRIGHT, |
|
TEXICMD_DETAILMENU, |
|
TEXICMD_DIRCATEGORY, |
|
TEXICMD_DIRENTRY, |
|
TEXICMD_DOTS, |
|
TEXICMD_EMAIL, |
|
TEXICMD_EMPH, |
|
TEXICMD_END, |
|
TEXICMD_ENUMERATE, |
|
TEXICMD_EXAMPLE, |
|
TEXICMD_FILE, |
|
TEXICMD_HEADING, |
|
TEXICMD_I, |
|
TEXICMD_IFHTML, |
|
TEXICMD_IFNOTTEX, |
|
TEXICMD_IFTEX, |
|
TEXICMD_IMAGE, |
|
TEXICMD_INCLUDE, |
|
TEXICMD_ITEM, |
|
TEXICMD_ITEMIZE, |
|
TEXICMD_KBD, |
|
TEXICMD_LATEX, |
|
TEXICMD_MENU, |
|
TEXICMD_NODE, |
|
TEXICMD_QUOTATION, |
|
TEXICMD_PARINDENT, |
|
TEXICMD_PRINTINDEX, |
|
TEXICMD_REF, |
|
TEXICMD_SAMP, |
|
TEXICMD_SECTION, |
|
TEXICMD_SETCHAPNEWPAGE, |
|
TEXICMD_SETFILENAME, |
|
TEXICMD_SETTITLE, |
|
TEXICMD_SUBSECTION, |
|
TEXICMD_TABLE, |
|
TEXICMD_TEX, |
|
TEXICMD_TEXSYM, |
|
TEXICMD_TITLEFONT, |
|
TEXICMD_TITLEPAGE, |
|
TEXICMD_TOP, |
|
TEXICMD_UNNUMBERED, |
|
TEXICMD_UNNUMBEREDSEC, |
|
TEXICMD_URL, |
|
TEXICMD_VAR, |
|
TEXICMD__MAX |
|
}; |
|
|
|
/* |
#define SECTSZ 4 |
* The file currently being parsed. |
static const char *const sects[SECTSZ] = { |
* This keeps track of our location within that file. |
"Sh", |
*/ |
"Ss", |
struct texifile { |
"Em", |
const char *name; /* name of the file */ |
"No", |
size_t line; /* current line (from zero) */ |
|
size_t col; /* current column in line (from zero) */ |
|
char *map; /* mmap'd file */ |
|
size_t mapsz; /* size of mmap */ |
|
}; |
}; |
|
|
struct texi; |
static void doaccent(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doblock(struct texi *, enum texicmd, const char *, size_t, size_t *); |
/* |
|
* Callback for functions implementing texi commands. |
|
*/ |
|
typedef void (*texicmdfp)(struct texi *, |
|
enum texicmd, const char *, size_t, size_t *); |
|
|
|
/* |
|
* Describes Texinfo commands, whether native or overriden. |
|
*/ |
|
struct texitok { |
|
texicmdfp fp; /* callback (or NULL if none) */ |
|
const char *tok; /* name of the token */ |
|
size_t len; /* strlen(tok) */ |
|
}; |
|
|
|
/* |
|
* The main parse structure. |
|
* This keeps any necessary information handy. |
|
*/ |
|
struct texi { |
|
struct texifile files[64]; |
|
size_t filepos; |
|
unsigned flags; |
|
#define TEXI_IGN 0x01 /* don't print anything */ |
|
#define TEXI_HEADER (TEXI_IGN | 0x02) /* haven't seen @top yet */ |
|
#define TEXI_LITERAL 0x04 /* output all whitespace */ |
|
size_t outcol; /* column of output */ |
|
int outmacro; /* whether output is in line macro */ |
|
int seenws; /* whitespace has been ignored */ |
|
char *dir; /* texi directory */ |
|
}; |
|
|
|
/* FIXME: don't use this crap. */ |
|
#define ismpunct(_x) \ |
|
('.' == (_x) || \ |
|
',' == (_x) || \ |
|
';' == (_x)) |
|
#define isws(_x) \ |
|
(' ' == (_x) || '\t' == (_x)) |
|
|
|
static void doarg1(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dobracket(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dobracket(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dobye(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dobye(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void docommand(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dodefindex(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doemph(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dodefn(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dodisplay(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doenumerate(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doenumerate(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doexample(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doexample(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dofile(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignargn(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doifnottex(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doignblock(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignblock(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignbracket(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignbracket(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignline(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doignline(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doinline(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doinclude(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doinclude(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doitalic(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doitem(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doitem(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doitemize(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doitemize(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doliteral(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dolink(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void domacro(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void domath(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void domultitable(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doquotation(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void doquotation(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dotable(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dotable(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dotop(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dotop(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dosecoffs(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosection(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosection(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosh(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosp(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosubsection(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosubsection(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dosubsubsection(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosymbol(struct texi *, enum texicmd, const char *, size_t, size_t *); |
static void dosymbol(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dotab(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dotitle(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void dovalue(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doverb(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doverbatim(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
static void doverbinclude(struct texi *, enum texicmd, const char *, size_t, size_t *); |
|
|
static const struct texitok texitoks[TEXICMD__MAX] = { |
static const struct texitok __texitoks[TEXICMD__MAX] = { |
{ doarg1, "acronym", 7 }, /* TEXICMD_ACRONYM */ |
/* TEXICMD__BEGIN */ |
|
{ doignargn, "acronym", 7 }, /* TEXICMD_ACRONYM */ |
|
{ doaccent, "'", 1 }, /* TEXICMD_ACUTE */ |
{ doignline, "afourpaper", 10 }, /* TEXICMD_A4PAPER */ |
{ doignline, "afourpaper", 10 }, /* TEXICMD_A4PAPER */ |
{ doignbracket, "anchor", 6 }, /* TEXICMD_ANCHOR */ |
{ doignbracket, "anchor", 6 }, /* TEXICMD_ANCHOR */ |
{ dosh, "appendix", 8 }, /* TEXICMD_APPENDIX */ |
{ dosection, "appendix", 8 }, /* TEXICMD_APPENDIX */ |
{ dosh, "appendixsec", 11 }, /* TEXICMD_APPENDIXSEC */ |
{ dosection, "appendixsec", 11 }, /* TEXICMD_APPENDIXSEC */ |
|
{ dosubsection, "appendixsubsec", 14 }, /* TEXICMD_APPENDIXSUBSEC */ |
|
{ dosubsubsection, "appendixsubsubsec", 17 }, /* TEXICMD_APPENDIXSUBSUBSEC */ |
|
{ doinline, "asis", 4 }, /* TEXICMD_ASIS */ |
|
{ dosymbol, "*", 1 }, /* TEXICMD_ASTERISK */ |
{ dosymbol, "@", 1 }, /* TEXICMD_AT */ |
{ dosymbol, "@", 1 }, /* TEXICMD_AT */ |
|
{ doignline, "author", 6 }, /* TEXICMD_AUTHOR */ |
|
{ doinline, "b", 1 }, /* TEXICMD_BOLD */ |
|
{ dosymbol, "!", 1 }, /* TEXICMD_BANG */ |
|
{ dosymbol, "bullet", 6 }, /* TEXICMD_BULLET */ |
{ dobye, "bye", 3 }, /* TEXICMD_BYE */ |
{ dobye, "bye", 3 }, /* TEXICMD_BYE */ |
{ dosh, "chapter", 7 }, /* TEXICMD_CHAPTER */ |
{ doblock, "cartouche", 9 }, /* TEXICMD_CARTOUCHE */ |
|
{ doaccent, ",", 1 }, /* TEXICMD_CEDILLA */ |
|
{ doignline, "center", 6 }, /* TEXICMD_CENTER */ |
|
{ dosection, "chapter", 7 }, /* TEXICMD_CHAPTER */ |
{ doignline, "cindex", 6 }, /* TEXICMD_CINDEX */ |
{ doignline, "cindex", 6 }, /* TEXICMD_CINDEX */ |
{ doliteral, "code", 4 }, /* TEXICMD_CODE */ |
{ doaccent, "^", 1 }, /* TEXICMD_CIRCUMFLEX */ |
{ docommand, "command", 7 }, /* TEXICMD_COMMAND */ |
{ doinline, "cite", 4 }, /* TEXICMD_CITE */ |
|
{ dovalue, "clear", 5 }, /* TEXICMD_CLEAR */ |
|
{ doinline, "code", 4 }, /* TEXICMD_CODE */ |
|
{ dosymbol, ":", 1 }, /* TEXICMD_COLON */ |
|
{ NULL, "columnfractions", 15 }, /* TEXICMD_COLUMNFRACTIONS */ |
|
{ dosymbol, "comma", 5 }, /* TEXICMD_COMMA */ |
|
{ doinline, "command", 7 }, /* TEXICMD_COMMAND */ |
{ doignline, "c", 1 }, /* TEXICMD_COMMENT */ |
{ doignline, "c", 1 }, /* TEXICMD_COMMENT */ |
{ doignline, "comment", 7 }, /* TEXICMD_COMMENT_LONG */ |
{ doignline, "comment", 7 }, /* TEXICMD_COMMENT_LONG */ |
{ doignline, "contents", 8 }, /* TEXICMD_CONTENTS */ |
{ doignline, "contents", 8 }, /* TEXICMD_CONTENTS */ |
{ doignblock, "copying", 7 }, /* TEXICMD_COPYING */ |
{ doignblock, "copying", 7 }, /* TEXICMD_COPYING */ |
{ dosymbol, "copyright", 9 }, /* TEXICMD_COPYRIGHT */ |
{ dosymbol, "copyright", 9 }, /* TEXICMD_COPYRIGHT */ |
|
{ dodefindex, "defcodeindex", 12 }, /* TEXICMD_DEFCODEINDEX */ |
|
{ dodefn, "deffn", 5 }, /* TEXICMD_DEFFN */ |
|
{ dodefn, "deffnx", 6 }, /* TEXICMD_DEFFNX */ |
|
{ dodefindex, "defindex", 8 }, /* TEXICMD_DEFINDEX */ |
|
{ dodefn, "defmac", 6 }, /* TEXICMD_DEFMAC */ |
|
{ dodefn, "defmacx", 7 }, /* TEXICMD_DEFMACX */ |
|
{ dodefn, "deftp", 5 }, /* TEXICMD_DEFTP */ |
|
{ dodefn, "deftpx", 6 }, /* TEXICMD_DEFTPX */ |
|
{ dodefn, "deftypefn", 9 }, /* TEXICMD_DEFTYPEFN */ |
|
{ dodefn, "deftypefnx", 10 }, /* TEXICMD_DEFTYPEFNX */ |
|
{ dodefn, "deftypefun", 10 }, /* TEXICMD_DEFTYPEFUN */ |
|
{ dodefn, "deftypefunx", 11 }, /* TEXICMD_DEFTYPEFUNX */ |
|
{ dodefn, "deftypemethod", 13 }, /* TEXICMD_DEFTYPEMETHOD */ |
|
{ dodefn, "deftypemethodx", 14 }, /* TEXICMD_DEFTYPEMETHODX */ |
|
{ dodefn, "deftypevar", 10 }, /* TEXICMD_DEFTYPEVAR */ |
|
{ dodefn, "deftypevarx", 11 }, /* TEXICMD_DEFTYPEVARX */ |
|
{ dodefn, "deftypevr", 9 }, /* TEXICMD_DEFTYPEVR */ |
|
{ dodefn, "deftypevrx", 10 }, /* TEXICMD_DEFTYPEVRX */ |
|
{ dodefn, "defun", 5 }, /* TEXICMD_DEFUN */ |
|
{ dodefn, "defunx", 6 }, /* TEXICMD_DEFUNX */ |
|
{ dodefn, "defvar", 6 }, /* TEXICMD_DEFVAR */ |
|
{ dodefn, "defvarx", 7 }, /* TEXICMD_DEFVARX */ |
|
{ dodefn, "defvr", 5 }, /* TEXICMD_DEFVR */ |
|
{ dodefn, "defvrx", 6 }, /* TEXICMD_DEFVRX */ |
{ doignblock, "detailmenu", 10 }, /* TEXICMD_DETAILMENU */ |
{ doignblock, "detailmenu", 10 }, /* TEXICMD_DETAILMENU */ |
|
{ doinline, "dfn", 3 }, /* TEXICMD_DFN */ |
{ doignline, "dircategory", 11 }, /* TEXICMD_DIRCATEGORY */ |
{ doignline, "dircategory", 11 }, /* TEXICMD_DIRCATEGORY */ |
{ doignblock, "direntry", 8 }, /* TEXICMD_DIRENTRY */ |
{ doignblock, "direntry", 8 }, /* TEXICMD_DIRENTRY */ |
|
{ dodisplay, "display", 7 }, /* TEXICMD_DISPLAY */ |
|
{ doignbracket, "dmn", 3 }, /* TEXICMD_DMN */ |
|
{ doignblock, "documentdescription", 19 }, /* TEXICMD_DOCUMENTDESCRIPTION */ |
|
{ doignline, "documentencoding", 16 }, /* TEXICMD_DOCUMENTENCODING */ |
{ dosymbol, "dots", 4 }, /* TEXICMD_DOTS */ |
{ dosymbol, "dots", 4 }, /* TEXICMD_DOTS */ |
{ doarg1, "email", 5 }, /* TEXICMD_EMAIL */ |
{ dolink, "email", 5 }, /* TEXICMD_EMAIL */ |
{ doemph, "emph", 4 }, /* TEXICMD_EMPH */ |
{ doinline, "emph", 4 }, /* TEXICMD_EMPH */ |
{ NULL, "end", 3 }, /* TEXICMD_END */ |
{ NULL, "end", 3 }, /* TEXICMD_END */ |
|
{ dosymbol, "enddots", 7 }, /* TEXICMD_ENDDOTS */ |
{ doenumerate, "enumerate", 9 }, /* TEXICMD_ENUMERATE */ |
{ doenumerate, "enumerate", 9 }, /* TEXICMD_ENUMERATE */ |
|
{ doinline, "env", 3 }, /* TEXICMD_ENV */ |
|
{ dosymbol, "equiv", 5 }, /* TEXICMD_EQUIV */ |
|
{ dosymbol, "error", 5 }, /* TEXICMD_ERROR */ |
{ doexample, "example", 7 }, /* TEXICMD_EXAMPLE */ |
{ doexample, "example", 7 }, /* TEXICMD_EXAMPLE */ |
{ dofile, "file", 4 }, /* TEXICMD_FILE */ |
{ doignline, "exdent", 6 }, /* TEXICMD_EXDENT */ |
|
{ dosymbol, "expansion", 9 }, /* TEXICMD_EXPANSION */ |
|
{ doinline, "file", 4 }, /* TEXICMD_FILE */ |
|
{ doignline, "finalout", 8 }, /* TEXICMD_FINALOUT */ |
|
{ doignline, "findex", 6 }, /* TEXICMD_FINDEX */ |
|
{ doignbracket, "footnote", 8 }, /* TEXICMD_FOOTNOTE */ |
|
{ dotable, "ftable", 6 }, /* TEXICMD_FTABLE */ |
|
{ dodisplay, "format", 6 }, /* TEXICMD_FORMAT */ |
|
{ doaccent, "`", 1 }, /* TEXICMD_GRAVE */ |
|
{ doblock, "group", 5 }, /* TEXICMD_GROUP */ |
{ dosection, "heading", 7 }, /* TEXICMD_HEADING */ |
{ dosection, "heading", 7 }, /* TEXICMD_HEADING */ |
{ doitalic, "i", 1 }, /* TEXICMD_I */ |
{ doignline, "headings", 8 }, /* TEXICMD_HEADINGS */ |
|
{ doitem, "headitem", 8 }, /* TEXICMD_HEADITEM */ |
|
{ doignblock, "html", 4 }, /* TEXICMD_HTML */ |
|
{ dosymbol, "-", 1 }, /* TEXICMD_HYPHEN */ |
|
{ doinline, "i", 1 }, /* TEXICMD_I */ |
|
{ dovalue, "ifclear", 7 }, /* TEXICMD_IFCLEAR */ |
|
{ doignblock, "ifdocbook", 9 }, /* TEXICMD_IFDOCBOOK */ |
{ doignblock, "ifhtml", 6 }, /* TEXICMD_IFHTML */ |
{ doignblock, "ifhtml", 6 }, /* TEXICMD_IFHTML */ |
{ doifnottex, "ifnottex", 8 }, /* TEXICMD_IFNOTTEX */ |
{ doblock, "ifinfo", 6 }, /* TEXICMD_IFINFO */ |
|
{ doblock, "ifnotdocbook", 12 }, /* TEXICMD_IFNOTDOCBOOK */ |
|
{ doblock, "ifnothtml", 9 }, /* TEXICMD_IFNOTHTML */ |
|
{ doblock, "ifnotinfo", 9 }, /* TEXICMD_IFNOTINFO */ |
|
{ doignblock, "ifnotplaintext", 14 }, /* TEXICMD_IFNOTPLAINTEXT */ |
|
{ doblock, "ifnottex", 8 }, /* TEXICMD_IFNOTTEX */ |
|
{ doblock, "ifnotxml", 8 }, /* TEXICMD_IFNOTXML */ |
|
{ doblock, "ifplaintext", 11 }, /* TEXICMD_IFPLAINTEXT */ |
{ doignblock, "iftex", 5 }, /* TEXICMD_IFTEX */ |
{ doignblock, "iftex", 5 }, /* TEXICMD_IFTEX */ |
|
{ dovalue, "ifset", 5 }, /* TEXICMD_IFSET */ |
|
{ doignblock, "ifxml", 5 }, /* TEXICMD_IFXML */ |
|
{ doignblock, "ignore", 6 }, /* TEXICMD_IGNORE */ |
{ doignbracket, "image", 5 }, /* TEXICMD_IMAGE */ |
{ doignbracket, "image", 5 }, /* TEXICMD_IMAGE */ |
{ doinclude, "include", 7 }, /* TEXICMD_INCLUDE */ |
{ doinclude, "include", 7 }, /* TEXICMD_INCLUDE */ |
|
{ dodisplay, "indentblock", 11 }, /* TEXICMD_INDENTBLOCK */ |
|
{ dolink, "inforef", 7 }, /* TEXICMD_INDENTBLOCK */ |
|
{ doignline, "insertcopying", 13 }, /* TEXICMD_INSERTCOPYING */ |
{ doitem, "item", 4 }, /* TEXICMD_ITEM */ |
{ doitem, "item", 4 }, /* TEXICMD_ITEM */ |
{ doitemize, "itemize", 7 }, /* TEXICMD_ITEMIZE */ |
{ doitemize, "itemize", 7 }, /* TEXICMD_ITEMIZE */ |
{ doliteral, "kbd", 3 }, /* TEXICMD_KBD */ |
{ doitem, "itemx", 5 }, /* TEXICMD_ITEMX */ |
|
{ doinline, "kbd", 3 }, /* TEXICMD_KBD */ |
|
{ dobracket, "key", 3 }, /* TEXICMD_KEY */ |
|
{ doignline, "kindex", 6 }, /* TEXICMD_KINDEX */ |
{ dosymbol, "LaTeX", 5 }, /* TEXICMD_LATEX */ |
{ dosymbol, "LaTeX", 5 }, /* TEXICMD_LATEX */ |
|
{ dosecoffs, "lowersections", 13 }, /* TEXICMD_LOWERSECTIONS */ |
|
{ domacro, "macro", 5 }, /* TEXICMD_MACRO */ |
|
{ domath, "math", 4 }, /* TEXICMD_MATH */ |
{ doignblock, "menu", 4 }, /* TEXICMD_MENU */ |
{ doignblock, "menu", 4 }, /* TEXICMD_MENU */ |
|
{ dosymbol, "minus", 5 }, /* TEXICMD_MINUS */ |
|
{ domultitable, "multitable", 10 }, /* TEXICMD_MULTITABLE */ |
|
{ doignline, "need", 4 }, /* TEXICMD_NEED */ |
|
{ dosymbol, "\n", 1 }, /* TEXICMD_NEWLINE */ |
{ doignline, "node", 4 }, /* TEXICMD_NODE */ |
{ doignline, "node", 4 }, /* TEXICMD_NODE */ |
|
{ doignline, "noindent", 8 }, /* TEXICMD_NOINDENT */ |
|
{ doinline, "option", 6 }, /* TEXICMD_OPTION */ |
|
{ dolink, "pxref", 5 }, /* TEXICMD_PXREF */ |
|
{ dosymbol, "?", 1 }, /* TEXICMD_QUESTIONMARK */ |
{ doquotation, "quotation", 9 }, /* TEXICMD_QUOTATION */ |
{ doquotation, "quotation", 9 }, /* TEXICMD_QUOTATION */ |
|
{ doignline, "page", 4 }, /* TEXICMD_PAGE */ |
|
{ doignline, "paragraphindent", 15 }, /* TEXICMD_PARINDENT */ |
|
{ dosymbol, ".", 1 }, /* TEXICMD_PERIOD */ |
|
{ doignline, "pindex", 6 }, /* TEXICMD_PINDEX */ |
{ doignline, "printindex", 10 }, /* TEXICMD_PRINTINDEX */ |
{ doignline, "printindex", 10 }, /* TEXICMD_PRINTINDEX */ |
{ doignline, "paragraphindent", 14 }, /* TEXICMD_PARINDENT */ |
{ doinline, "r", 1 }, /* TEXICMD_R */ |
|
{ dosecoffs, "raisesections", 13 }, /* TEXICMD_RAISESECTIONS */ |
{ dobracket, "ref", 3 }, /* TEXICMD_REF */ |
{ dobracket, "ref", 3 }, /* TEXICMD_REF */ |
{ doliteral, "samp", 4 }, /* TEXICMD_SAMP */ |
{ doignline, "refill", 6 }, /* TEXICMD_REFILL */ |
|
{ dosymbol, "result", 6 }, /* TEXICMD_RESULT */ |
|
{ doinline, "samp", 4 }, /* TEXICMD_SAMP */ |
|
{ doinline, "sansserif", 9 }, /* TEXICMD_SANSSERIF */ |
|
{ dobracket, "sc", 2 }, /* TEXICMD_SC */ |
{ dosection, "section", 7 }, /* TEXICMD_SECTION */ |
{ dosection, "section", 7 }, /* TEXICMD_SECTION */ |
|
{ dovalue, "set", 3 }, /* TEXICMD_SET */ |
{ doignline, "setchapternewpage", 17 }, /* TEXICMD_SETCHAPNEWPAGE */ |
{ doignline, "setchapternewpage", 17 }, /* TEXICMD_SETCHAPNEWPAGE */ |
|
{ doignline, "setcontentsaftertitlepage", 25 }, /* TEXICMD_SETCONTENTSAFTER */ |
{ doignline, "setfilename", 11 }, /* TEXICMD_SETFILENAME */ |
{ doignline, "setfilename", 11 }, /* TEXICMD_SETFILENAME */ |
{ doignline, "settitle", 8 }, /* TEXICMD_SETTITLE */ |
{ dotitle, "settitle", 8 }, /* TEXICMD_SETTITLE */ |
|
{ doignline, "shortcontents", 13 }, /* TEXICMD_SHORTCONTENTS */ |
|
{ doinline, "slanted", 7 }, /* TEXICMD_SLANTED */ |
|
{ dosymbol, "/", 1 }, /* TEXICMD_SLASH */ |
|
{ dosp, "sp", 2 }, /* TEXICMD_SP */ |
|
{ dosymbol, " ", 1 }, /* TEXICMD_SPACE */ |
|
{ doignline, "smallbook", 9 }, /* TEXICMD_SMALLBOOK */ |
|
{ dodisplay, "smalldisplay", 12 }, /* TEXICMD_SMALLDISPLAY */ |
|
{ doexample, "smallexample", 12 }, /* TEXICMD_SMALLEXAMPLE */ |
|
{ dodisplay, "smallformat", 11 }, /* TEXICMD_SMALLFORMAT */ |
|
{ dodisplay, "smallindentblock", 16 }, /* TEXICMD_SMALLINDENTBLOCK */ |
|
{ dosymbol, "{", 1 }, /* TEXICMD_SQUIGGLE_LEFT */ |
|
{ dosymbol, "}", 1 }, /* TEXICMD_SQUIGGLE_RIGHT */ |
|
{ dosymbol, "ss", 2 }, /* TEXICMD_SS */ |
|
{ doinline, "strong", 6 }, /* TEXICMD_STRONG */ |
|
{ dosubsection, "subheading", 10 }, /* TEXICMD_SUBHEADING */ |
{ dosubsection, "subsection", 10 }, /* TEXICMD_SUBSECTION */ |
{ dosubsection, "subsection", 10 }, /* TEXICMD_SUBSECTION */ |
|
{ dosubsubsection, "subsubheading", 13 }, /* TEXICMD_SUBSUBHEADING */ |
|
{ dosubsubsection, "subsubsection", 13 }, /* TEXICMD_SUBSUBSECTION */ |
|
{ doignline, "subtitle", 8 }, /* TEXICMD_SUBTITLE */ |
|
{ doignline, "summarycontents", 15 }, /* TEXICMD_SUMMARYCONTENTS */ |
|
{ doignline, "synindex", 8 }, /* TEXICMD_SYNINDEX */ |
|
{ doignline, "syncodeindex", 12 }, /* TEXICMD_SYNCODEINDEX */ |
|
{ doinline, "t", 1 }, /* TEXICMD_T */ |
|
{ dotab, "tab", 3 }, /* TEXICMD_TAB */ |
|
{ dosymbol, "\t", 1 }, /* TEXICMD_TABSYM */ |
{ dotable, "table", 5 }, /* TEXICMD_TABLE */ |
{ dotable, "table", 5 }, /* TEXICMD_TABLE */ |
{ doignblock, "tex", 3 }, /* TEXICMD_TEX */ |
{ doignblock, "tex", 3 }, /* TEXICMD_TEX */ |
{ dosymbol, "TeX", 3 }, /* TEXICMD_TEXSYM */ |
{ dosymbol, "TeX", 3 }, /* TEXICMD_TEXSYM */ |
|
{ dosymbol, "tie", 3 }, /* TEXICMD_TIE */ |
|
{ doaccent, "~", 1 }, /* TEXICMD_TILDE */ |
|
{ doignline, "tindex", 6 }, /* TEXICMD_TINDEX */ |
|
{ doignline, "title", 5 }, /* TEXICMD_TITLE */ |
{ dobracket, "titlefont", 9 }, /* TEXICMD_TITLEFONT */ |
{ dobracket, "titlefont", 9 }, /* TEXICMD_TITLEFONT */ |
{ doignblock, "titlepage", 9 }, /* TEXICMD_TITLEPAGE */ |
{ doignblock, "titlepage", 9 }, /* TEXICMD_TITLEPAGE */ |
{ dotop, "top", 3 }, /* TEXICMD_TOP */ |
{ dotop, "top", 3 }, /* TEXICMD_TOP */ |
{ dosh, "unnumbered", 10 }, /* TEXICMD_UNNUMBERED */ |
{ doaccent, "\"", 1 }, /* TEXICMD_UMLAUT */ |
|
{ dosection, "unnumbered", 10 }, /* TEXICMD_UNNUMBERED */ |
{ dosection, "unnumberedsec", 13 }, /* TEXICMD_UNNUMBEREDSEC */ |
{ dosection, "unnumberedsec", 13 }, /* TEXICMD_UNNUMBEREDSEC */ |
{ doarg1, "url", 3 }, /* TEXICMD_URL */ |
{ dosubsection, "unnumberedsubsec", 16 }, /* TEXICMD_UNNUMBEREDSUBSEC */ |
{ doliteral, "var", 3 }, /* TEXICMD_VAR */ |
{ dosubsubsection, "unnumberedsubsubsec", 19 }, /* TEXICMD_UNNUMBEREDSUBSUBSEC */ |
|
{ dolink, "uref", 4 }, /* TEXICMD_UREF */ |
|
{ dolink, "url", 3 }, /* TEXICMD_URL */ |
|
{ doignline, "", 0 }, /* TEXICMD_USER_INDEX */ |
|
{ dovalue, "value", 5 }, /* TEXICMD_VALUE */ |
|
{ doinline, "var", 3 }, /* TEXICMD_VAR */ |
|
{ doverb, "verb", 4 }, /* TEXICMD_VERB */ |
|
{ doverbatim, "verbatim", 8 }, /* TEXICMD_VERBATIM */ |
|
{ doverbinclude, "verbatiminclude", 15 }, /* TEXICMD_VERBATIMINCLUDE */ |
|
{ doignline, "vindex", 6 }, /* TEXICMD_VINDEX */ |
|
{ dosp, "vskip", 5 }, /* TEXICMD_VSKIP */ |
|
{ dotable, "vtable", 6 }, /* TEXICMD_VTABLE */ |
|
{ dobracket, "w", 1 }, /* TEXICMD_W */ |
|
{ dolink, "xref", 4 }, /* TEXICMD_XREF */ |
|
/* TEXICMD__END */ |
}; |
}; |
|
|
/* |
const struct texitok *const texitoks = __texitoks; |
* Unmap the top-most file that we're using. |
|
*/ |
|
static void |
|
texifilepop(struct texi *p) |
|
{ |
|
struct texifile *f; |
|
|
|
assert(p->filepos > 0); |
|
f = &p->files[--p->filepos]; |
|
munmap(f->map, f->mapsz); |
|
} |
|
|
|
/* |
|
* Unmap all files that we're currently using. |
|
* The utility should exit(...) after this is called. |
|
*/ |
|
static void |
static void |
texiexit(struct texi *p) |
dodefindex(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
size_t start, end; |
|
char *cp; |
|
|
while (p->filepos > 0) |
while (*pos < sz && isws(buf[*pos])) |
texifilepop(p); |
advance(p, buf, pos); |
free(p->dir); |
|
} |
|
|
|
/* |
start = end = *pos; |
* Fatal error: unmap all files and exit. |
while (end < sz && ! ismspace(buf[end])) |
* The "errstring" is passed to perror(3). |
end++; |
*/ |
|
static void |
|
texiabort(struct texi *p, const char *errstring) |
|
{ |
|
|
|
perror(errstring); |
if (start == end) { |
texiexit(p); |
advanceeoln(p, buf, sz, pos, 1); |
exit(EXIT_FAILURE); |
return; |
} |
} else if (NULL == (cp = malloc(end - start + 1))) |
|
texiabort(p, NULL); |
|
|
/* |
memcpy(cp, &buf[start], end - start); |
* Print a generic warning message (to stderr) tied to our current |
cp[end - start] = '\0'; |
* location in the parse sequence. |
|
*/ |
|
static void |
|
texiwarn(const struct texi *p, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
|
|
fprintf(stderr, "%s:%zu:%zu: warning: ", |
p->indexs = realloc(p->indexs, |
p->files[p->filepos - 1].name, |
sizeof(char *) * (p->indexsz + 1)); |
p->files[p->filepos - 1].line + 1, |
|
p->files[p->filepos - 1].col + 1); |
|
va_start(ap, fmt); |
|
vfprintf(stderr, fmt, ap); |
|
va_end(ap); |
|
fputc('\n', stderr); |
|
} |
|
|
|
static void |
if (NULL == p->indexs) |
texierr(struct texi *p, const char *fmt, ...) |
texiabort(p, NULL); |
{ |
p->indexs[p->indexsz++] = cp; |
va_list ap; |
|
|
|
fprintf(stderr, "%s:%zu:%zu: error: ", |
|
p->files[p->filepos - 1].name, |
|
p->files[p->filepos - 1].line + 1, |
|
p->files[p->filepos - 1].col + 1); |
|
va_start(ap, fmt); |
|
vfprintf(stderr, fmt, ap); |
|
va_end(ap); |
|
fputc('\n', stderr); |
|
texiexit(p); |
|
exit(EXIT_FAILURE); |
|
} |
} |
|
|
/* |
|
* Put a single data character. |
|
* This MUST NOT be a mdoc(7) command: it should be free text that's |
|
* outputted to the screen. |
|
*/ |
|
static void |
static void |
texiputchar(struct texi *p, char c) |
dodefn(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
const char *blk; |
|
|
if (TEXI_IGN & p->flags) |
blk = NULL; |
|
switch (cmd) { |
|
case (TEXICMD_DEFFN): |
|
case (TEXICMD_DEFMAC): |
|
case (TEXICMD_DEFTP): |
|
case (TEXICMD_DEFTYPEFN): |
|
case (TEXICMD_DEFTYPEFUN): |
|
case (TEXICMD_DEFTYPEMETHOD): |
|
case (TEXICMD_DEFTYPEVAR): |
|
case (TEXICMD_DEFTYPEVR): |
|
case (TEXICMD_DEFUN): |
|
case (TEXICMD_DEFVAR): |
|
case (TEXICMD_DEFVR): |
|
blk = texitoks[cmd].tok; |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
if (p->ign) { |
|
NULL != blk ? |
|
parseto(p, buf, sz, pos, blk) : |
|
parseeoln(p, buf, sz, pos); |
return; |
return; |
|
} |
|
|
putchar(c); |
if (NULL != blk) |
if ('\n' == c) { |
texivspace(p); |
p->outcol = 0; |
|
p->outmacro = 0; |
|
p->seenws = 0; |
|
} else |
|
p->outcol++; |
|
} |
|
|
|
/* |
switch (cmd) { |
* Put multiple characters (see texiputchar()). |
case (TEXICMD_DEFTYPEMETHOD): |
*/ |
case (TEXICMD_DEFTYPEMETHODX): |
static void |
texiputchars(p, "Method"); |
texiputchars(struct texi *p, const char *s) |
break; |
{ |
case (TEXICMD_DEFMAC): |
|
case (TEXICMD_DEFMACX): |
|
texiputchars(p, "Macro"); |
|
break; |
|
case (TEXICMD_DEFTYPEVAR): |
|
case (TEXICMD_DEFTYPEVARX): |
|
case (TEXICMD_DEFVAR): |
|
case (TEXICMD_DEFVARX): |
|
texiputchars(p, "Variable"); |
|
break; |
|
case (TEXICMD_DEFTYPEFUN): |
|
case (TEXICMD_DEFTYPEFUNX): |
|
case (TEXICMD_DEFUN): |
|
case (TEXICMD_DEFUNX): |
|
texiputchars(p, "Function"); |
|
break; |
|
default: |
|
parselinearg(p, buf, sz, pos); |
|
break; |
|
} |
|
|
while ('\0' != *s) |
texiputchars(p, ":\n"); |
texiputchar(p, *s++); |
|
} |
|
|
|
/* |
switch (cmd) { |
* Put an mdoc(7) command without the trailing newline. |
case (TEXICMD_DEFMAC): |
* This should ONLY be used for mdoc(7) commands! |
case (TEXICMD_DEFMACX): |
*/ |
teximacroopen(p, "Dv"); |
static void |
while (parselinearg(p, buf, sz, pos)) |
texifputs(struct texi *p, const char *s) |
/* Spin. */ ; |
{ |
teximacroclose(p); |
int rc; |
break; |
|
case (TEXICMD_DEFFN): |
|
case (TEXICMD_DEFFNX): |
|
case (TEXICMD_DEFUN): |
|
case (TEXICMD_DEFUNX): |
|
teximacroopen(p, "Fo"); |
|
parselinearg(p, buf, sz, pos); |
|
teximacroclose(p); |
|
teximacroopen(p, "Fa"); |
|
while (parselinearg(p, buf, sz, pos)) |
|
/* Spin. */ ; |
|
teximacroclose(p); |
|
teximacro(p, "Fc"); |
|
break; |
|
case (TEXICMD_DEFTYPEFUN): |
|
case (TEXICMD_DEFTYPEFUNX): |
|
case (TEXICMD_DEFTYPEFN): |
|
case (TEXICMD_DEFTYPEFNX): |
|
case (TEXICMD_DEFTYPEMETHOD): |
|
case (TEXICMD_DEFTYPEMETHODX): |
|
teximacroopen(p, "Ft"); |
|
parselinearg(p, buf, sz, pos); |
|
teximacroclose(p); |
|
teximacroopen(p, "Fo"); |
|
parselinearg(p, buf, sz, pos); |
|
teximacroclose(p); |
|
teximacroopen(p, "Fa"); |
|
while (parselinearg(p, buf, sz, pos)) |
|
/* Spin. */ ; |
|
teximacroclose(p); |
|
teximacro(p, "Fc"); |
|
break; |
|
case (TEXICMD_DEFTP): |
|
case (TEXICMD_DEFTPX): |
|
case (TEXICMD_DEFTYPEVAR): |
|
case (TEXICMD_DEFTYPEVARX): |
|
case (TEXICMD_DEFTYPEVR): |
|
case (TEXICMD_DEFTYPEVRX): |
|
teximacroopen(p, "Vt"); |
|
while (parselinearg(p, buf, sz, pos)) |
|
/* Spin. */ ; |
|
teximacroclose(p); |
|
break; |
|
case (TEXICMD_DEFVAR): |
|
case (TEXICMD_DEFVARX): |
|
case (TEXICMD_DEFVR): |
|
case (TEXICMD_DEFVRX): |
|
teximacroopen(p, "Va"); |
|
while (parselinearg(p, buf, sz, pos)) |
|
/* Spin. */ ; |
|
teximacroclose(p); |
|
break; |
|
default: |
|
abort(); |
|
} |
|
|
if (TEXI_IGN & p->flags) |
texivspace(p); |
return; |
if (NULL != blk) |
if (p->outcol) |
parseto(p, buf, sz, pos, blk); |
texiputchar(p, '\n'); |
|
if (EOF != (rc = fputs(s, stdout))) |
|
p->outcol += rc; |
|
} |
} |
|
|
/* |
|
* Put an mdoc(7) command with the trailing newline. |
|
* This should ONLY be used for mdoc(7) commands! |
|
*/ |
|
static void |
static void |
teximacro(struct texi *p, const char *s) |
domacro(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
size_t start, end, endtoksz, len; |
|
struct teximacro m; |
|
const char *endtok, *blk; |
|
|
if (TEXI_IGN & p->flags) |
memset(&m, 0, sizeof(struct teximacro)); |
return; |
|
if (p->outcol) |
|
texiputchar(p, '\n'); |
|
puts(s); |
|
p->outcol = 0; |
|
p->seenws = 0; |
|
} |
|
|
|
/* |
while (*pos < sz && isws(buf[*pos])) |
* Advance by a single byte in the input stream. |
advance(p, buf, pos); |
*/ |
|
static void |
|
advance(struct texi *p, const char *buf, size_t *pos) |
|
{ |
|
|
|
if ('\n' == buf[*pos]) { |
for (start = end = *pos; end < sz; end++) |
p->files[p->filepos - 1].line++; |
if (ismspace(buf[end]) || '{' == buf[end]) |
p->files[p->filepos - 1].col = 0; |
break; |
} else |
|
p->files[p->filepos - 1].col++; |
|
|
|
(*pos)++; |
if (start == end) |
} |
texierr(p, "zero-length macro name"); |
|
|
/* |
advanceto(p, buf, pos, end); |
* Advance to the next non-whitespace word in the input stream. |
|
* If we're in literal mode, then print all of the whitespace as we're |
|
* doing so. |
|
*/ |
|
static size_t |
|
advancenext(struct texi *p, const char *buf, size_t sz, size_t *pos) |
|
{ |
|
|
|
if (TEXI_LITERAL & p->flags) { |
|
while (*pos < sz && isspace(buf[*pos])) { |
|
texiputchar(p, buf[*pos]); |
|
advance(p, buf, pos); |
|
} |
|
return(*pos); |
|
} |
|
|
|
while (*pos < sz && isspace(buf[*pos])) { |
m.key = malloc(end - start + 1); |
p->seenws = 1; |
if (NULL == m.key) |
/* |
texiabort(p, NULL); |
* If it looks like we've printed a double-line, then |
memcpy(m.key, &buf[start], end - start); |
* output a paragraph. |
m.key[end - start] = '\0'; |
* FIXME: this is stupid. |
|
*/ |
|
if (*pos && '\n' == buf[*pos] && '\n' == buf[*pos - 1]) |
|
teximacro(p, ".Pp"); |
|
advance(p, buf, pos); |
|
} |
|
return(*pos); |
|
} |
|
|
|
/* |
m.args = argparse(p, buf, sz, pos, &m.argsz, 0); |
* Advance to the EOLN in the input stream. |
advanceeoln(p, buf, sz, pos, 0); |
*/ |
|
static size_t |
|
advanceeoln(struct texi *p, const char *buf, size_t sz, size_t *pos) |
|
{ |
|
|
|
while (*pos < sz && '\n' != buf[*pos]) |
start = *pos; |
|
endtok = "\n@end macro\n"; |
|
endtoksz = strlen(endtok); |
|
blk = memmem(&buf[start], sz, endtok, endtoksz); |
|
if (NULL == blk) |
|
texierr(p, "unterminated macro body"); |
|
while (&buf[*pos] != blk) |
advance(p, buf, pos); |
advance(p, buf, pos); |
return(*pos); |
assert('\n' == buf[*pos]); |
} |
advance(p, buf, pos); |
|
len = blk - &buf[start]; |
|
m.value = malloc(len + 1); |
|
if (NULL == m.value) |
|
texiabort(p, NULL); |
|
memcpy(m.value, &buf[start], len); |
|
m.value[len] = '\0'; |
|
|
/* |
p->macros = realloc |
* Advance to position "end", which is an absolute position in the |
(p->macros, |
* current buffer greater than or equal to the current position. |
(p->macrosz + 1) * |
*/ |
sizeof(struct teximacro)); |
static void |
if (NULL == p->macros) |
advanceto(struct texi *p, const char *buf, size_t *pos, size_t end) |
texiabort(p, NULL); |
{ |
|
|
|
assert(*pos <= end); |
p->macros[p->macrosz++] = m; |
while (*pos < end) |
advanceeoln(p, buf, sz, pos, 1); |
advance(p, buf, pos); |
|
} |
} |
|
|
/* |
|
* Output a free-form word in the input stream, progressing to the next |
|
* command or white-space. |
|
* This also will advance the input stream. |
|
*/ |
|
static void |
static void |
texiword(struct texi *p, const char *buf, size_t sz, size_t *pos) |
doignblock(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
char end[32]; |
|
const char *term; |
|
size_t endsz, endpos; |
|
|
/* |
/* |
* XXX: if we're in literal mode, then we shouldn't do any |
* We want to completely ignore everything in these blocks, so |
* reflowing of text here. |
* simply jump to the @end block. |
*/ |
*/ |
if (p->outcol > 72 && ! (TEXI_LITERAL & p->flags)) |
endsz = snprintf(end, sizeof(end), |
texiputchar(p, '\n'); |
"\n@end %s\n", texitoks[cmd].tok); |
|
assert(endsz < sizeof(end)); |
|
|
if (p->seenws && p->outcol && ! (TEXI_LITERAL & p->flags)) |
/* |
texiputchar(p, ' '); |
* Look up where our end token occurs. |
|
* Set our end position based on the relative offset of that |
p->seenws = 0; |
* from our current position, or the EOF if we don't have a |
|
* proper ending point. |
while (*pos < sz && ! isspace(buf[*pos])) { |
*/ |
switch (buf[*pos]) { |
term = memmem(&buf[*pos], sz, end, endsz); |
case ('@'): |
endpos = NULL == term ? sz : |
case ('}'): |
*pos + (size_t)(term - &buf[*pos]); |
case ('{'): |
assert(endpos <= sz); |
return; |
while (*pos < endpos) |
} |
|
if (*pos < sz - 1 && |
|
'`' == buf[*pos] && |
|
'`' == buf[*pos + 1]) { |
|
texiputchars(p, "\\(lq"); |
|
advance(p, buf, pos); |
|
} else if (*pos < sz - 1 && |
|
'\'' == buf[*pos] && |
|
'\'' == buf[*pos + 1]) { |
|
texiputchars(p, "\\(rq"); |
|
advance(p, buf, pos); |
|
} else |
|
texiputchar(p, buf[*pos]); |
|
advance(p, buf, pos); |
advance(p, buf, pos); |
} |
|
} |
|
|
|
static enum texicmd |
/* Only do this if we're not already at the end. */ |
texicmd(struct texi *p, const char *buf, |
if (endpos < sz) |
size_t pos, size_t sz, size_t *end) |
advanceto(p, buf, pos, endpos + endsz); |
{ |
|
size_t i, len; |
|
|
|
assert('@' == buf[pos]); |
|
for (*end = ++pos; *end < sz && ! isspace(buf[*end]); (*end)++) |
|
if ((*end > pos && '@' == buf[*end]) || '{' == buf[*end]) |
|
break; |
|
|
|
len = *end - pos; |
|
for (i = 0; i < TEXICMD__MAX; i++) { |
|
if (len != texitoks[i].len) |
|
continue; |
|
if (0 == strncmp(texitoks[i].tok, &buf[pos], len)) |
|
return(i); |
|
} |
|
|
|
texiwarn(p, "bad command: %.*s", (int)len, &buf[pos]); |
|
return(TEXICMD__MAX); |
|
} |
} |
|
|
static void |
static void |
parseeof(struct texi *p, const char *buf, size_t sz) |
doblock(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
size_t pos = 0; |
|
enum texicmd cmd; |
|
size_t end; |
|
|
|
while ((pos = advancenext(p, buf, sz, &pos)) < sz) { |
|
switch (buf[pos]) { |
|
case ('}'): |
|
texiwarn(p, "unexpected \"}\""); |
|
advance(p, buf, &pos); |
|
continue; |
|
case ('{'): |
|
texiwarn(p, "unexpected \"{\""); |
|
advance(p, buf, &pos); |
|
continue; |
|
case ('@'): |
|
break; |
|
default: |
|
texiword(p, buf, sz, &pos); |
|
continue; |
|
} |
|
|
|
cmd = texicmd(p, buf, pos, sz, &end); |
|
advanceto(p, buf, &pos, end); |
|
if (TEXICMD__MAX == cmd) |
|
continue; |
|
if (NULL != texitoks[cmd].fp) |
|
(*texitoks[cmd].fp)(p, cmd, buf, sz, &pos); |
|
} |
|
} |
|
|
|
static void |
|
parsebracket(struct texi *p, const char *buf, size_t sz, size_t *pos) |
|
{ |
|
size_t end; |
|
enum texicmd cmd; |
|
|
|
if (*pos == sz || '{' != buf[*pos]) |
|
return; |
|
advance(p, buf, pos); |
|
|
|
while ((*pos = advancenext(p, buf, sz, pos)) < sz) { |
|
switch (buf[*pos]) { |
|
case ('}'): |
|
advance(p, buf, pos); |
|
return; |
|
case ('{'): |
|
texiwarn(p, "unexpected \"{\""); |
|
advance(p, buf, pos); |
|
continue; |
|
case ('@'): |
|
break; |
|
default: |
|
texiword(p, buf, sz, pos); |
|
continue; |
|
} |
|
|
|
cmd = texicmd(p, buf, *pos, sz, &end); |
|
advanceto(p, buf, pos, end); |
|
if (TEXICMD__MAX == cmd) |
|
continue; |
|
if (NULL != texitoks[cmd].fp) |
|
(*texitoks[cmd].fp)(p, cmd, buf, sz, pos); |
|
} |
|
} |
|
|
|
static void |
|
parseto(struct texi *p, const char *buf, |
|
size_t sz, size_t *pos, const char *endtoken) |
|
{ |
|
size_t end; |
|
enum texicmd cmd; |
|
size_t endtoksz; |
|
|
|
endtoksz = strlen(endtoken); |
|
assert(endtoksz > 0); |
|
|
|
while ((*pos = advancenext(p, buf, sz, pos)) < sz) { |
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
switch (buf[*pos]) { |
|
case ('}'): |
|
texiwarn(p, "unexpected \"}\""); |
|
advance(p, buf, pos); |
|
continue; |
|
case ('{'): |
|
texiwarn(p, "unexpected \"{\""); |
|
advance(p, buf, pos); |
|
continue; |
|
case ('@'): |
|
break; |
|
default: |
|
texiword(p, buf, sz, pos); |
|
continue; |
|
} |
|
|
|
cmd = texicmd(p, buf, *pos, sz, &end); |
|
advanceto(p, buf, pos, end); |
|
if (TEXICMD_END == cmd) { |
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
/* |
|
* FIXME: skip tabs and also check the full |
|
* word, not just its initial substring! |
|
*/ |
|
if (sz - *pos >= endtoksz && 0 == strncmp |
|
(&buf[*pos], endtoken, endtoksz)) { |
|
advanceeoln(p, buf, sz, pos); |
|
break; |
|
} |
|
texiwarn(p, "unexpected \"end\""); |
|
advanceeoln(p, buf, sz, pos); |
|
continue; |
|
} else if (TEXICMD__MAX != cmd) |
|
if (NULL != texitoks[cmd].fp) |
|
(*texitoks[cmd].fp)(p, cmd, buf, sz, pos); |
|
} |
|
} |
} |
|
|
static void |
static void |
parsefile(struct texi *p, const char *fname) |
doinline(struct texi *p, enum texicmd cmd, |
{ |
|
struct texifile *f; |
|
int fd; |
|
struct stat st; |
|
|
|
assert(p->filepos < 64); |
|
f = &p->files[p->filepos]; |
|
memset(f, 0, sizeof(struct texifile)); |
|
|
|
f->name = fname; |
|
if (-1 == (fd = open(fname, O_RDONLY, 0))) { |
|
texiabort(p, fname); |
|
} else if (-1 == fstat(fd, &st)) { |
|
close(fd); |
|
texiabort(p, fname); |
|
} |
|
|
|
f->mapsz = st.st_size; |
|
f->map = mmap(NULL, f->mapsz, |
|
PROT_READ, MAP_SHARED, fd, 0); |
|
close(fd); |
|
|
|
if (MAP_FAILED == f->map) |
|
texiabort(p, fname); |
|
|
|
p->filepos++; |
|
parseeof(p, f->map, f->mapsz); |
|
texifilepop(p); |
|
} |
|
|
|
static void |
|
doignblock(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
unsigned int sv = p->flags; |
const char *macro = NULL; |
const char *blockname; |
|
|
|
p->flags |= TEXI_IGN; |
|
switch (cmd) { |
switch (cmd) { |
case (TEXICMD_COPYING): |
case (TEXICMD_CODE): |
blockname = "copying"; |
case (TEXICMD_KBD): |
|
case (TEXICMD_SAMP): |
|
case (TEXICMD_T): |
|
macro = "Li"; |
break; |
break; |
case (TEXICMD_DETAILMENU): |
case (TEXICMD_CITE): |
blockname = "detailmenu"; |
case (TEXICMD_DFN): |
|
case (TEXICMD_EMPH): |
|
case (TEXICMD_I): |
|
case (TEXICMD_SLANTED): |
|
macro = "Em"; |
break; |
break; |
case (TEXICMD_DIRENTRY): |
case (TEXICMD_B): |
blockname = "direntry"; |
case (TEXICMD_STRONG): |
|
macro = "Sy"; |
break; |
break; |
case (TEXICMD_IFHTML): |
case (TEXICMD_COMMAND): |
blockname = "ifhtml"; |
macro = "Xr"; |
break; |
break; |
case (TEXICMD_IFTEX): |
case (TEXICMD_ENV): |
blockname = "iftex"; |
macro = "Ev"; |
break; |
break; |
case (TEXICMD_MENU): |
case (TEXICMD_FILE): |
blockname = "menu"; |
macro = "Pa"; |
break; |
break; |
case (TEXICMD_TEX): |
case (TEXICMD_OPTION): |
blockname = "tex"; |
macro = "Op"; |
break; |
break; |
case (TEXICMD_TITLEPAGE): |
case (TEXICMD_VAR): |
blockname = "titlepage"; |
macro = "Va"; |
break; |
break; |
default: |
default: |
abort(); |
break; |
} |
} |
parseto(p, buf, sz, pos, blockname); |
|
p->flags = sv; |
if (NULL == macro || p->literal || TEXILIST_TABLE == p->list) { |
|
parsebracket(p, buf, sz, pos); |
|
return; |
|
} |
|
|
|
teximacroopen(p, macro); |
|
p->seenws = 0; |
|
parsebracket(p, buf, sz, pos); |
|
texipunctuate(p, buf, sz, pos); |
|
teximacroclose(p); |
} |
} |
|
|
static void |
static void |
doifnottex(struct texi *p, enum texicmd cmd, |
doverb(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
char delim; |
parseto(p, buf, sz, pos, "ifnottex"); |
size_t start; |
|
|
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
if (*pos == sz || '{' != buf[*pos]) |
|
return; |
|
advance(p, buf, pos); |
|
if (*pos == sz) |
|
return; |
|
|
|
delim = buf[*pos]; |
|
advance(p, buf, pos); |
|
/* Make sure we flush out our initial whitespace... */ |
|
if (p->seenws && p->outcol && 0 == p->literal) |
|
texiputchar(p, ' '); |
|
p->seenws = 0; |
|
start = *pos; |
|
/* Read until we see the delimiter then end-brace. */ |
|
while (*pos < sz - 1) { |
|
if (buf[*pos] == delim && buf[*pos + 1] == '}') |
|
break; |
|
advance(p, buf, pos); |
|
} |
|
if (*pos == sz - 1) |
|
return; |
|
texiputbuf(p, buf, start, *pos); |
|
|
|
/* Make sure we read after the end-brace. */ |
|
assert(delim == buf[*pos]); |
|
advance(p, buf, pos); |
|
assert('}' == buf[*pos]); |
|
advance(p, buf, pos); |
} |
} |
|
|
static void |
static void |
doinline(struct texi *p, const char *buf, |
doverbatim(struct texi *p, enum texicmd cmd, |
size_t sz, size_t *pos, const char *macro) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
const char *end, *term; |
|
size_t endsz, endpos; |
|
|
if ( ! p->outmacro) |
advanceeoln(p, buf, sz, pos, 1); |
texifputs(p, "."); |
|
texiputchars(p, macro); |
/* We end at exactly this token. */ |
texiputchar(p, ' '); |
end = "\n@end verbatim\n"; |
p->seenws = 0; |
endsz = strlen(end); |
p->outmacro++; |
|
parsebracket(p, buf, sz, pos); |
/* |
p->outmacro--; |
* Look up where our end token occurs. |
if (*pos < sz - 1 && |
* Set our end position based on the relative offset of that |
ismpunct(buf[*pos]) && |
* from our current position. |
isspace(buf[*pos + 1])) { |
*/ |
texiputchar(p, ' '); |
term = memmem(&buf[*pos], sz, end, endsz); |
|
endpos = NULL == term ? sz : |
|
*pos + (size_t)(term - &buf[*pos]); |
|
|
|
teximacro(p, "Bd -literal -offset indent"); |
|
assert(endpos <= sz); |
|
while (*pos < endpos) { |
texiputchar(p, buf[*pos]); |
texiputchar(p, buf[*pos]); |
advance(p, buf, pos); |
advance(p, buf, pos); |
} |
} |
if ( ! p->outmacro) |
teximacro(p, "Ed"); |
texiputchar(p, '\n'); |
advanceto(p, buf, pos, endpos + endsz); |
} |
} |
|
|
static void |
static void |
doinclude(struct texi *p, enum texicmd cmd, |
doverbinclude(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
char fname[PATH_MAX], path[PATH_MAX]; |
char fname[PATH_MAX], path[PATH_MAX]; |
size_t i; |
int rc; |
int rc; |
size_t i, end; |
|
const char *v; |
|
enum texicmd type; |
|
|
while (*pos < sz && ' ' == buf[*pos]) |
while (*pos < sz && ' ' == buf[*pos]) |
advance(p, buf, pos); |
advance(p, buf, pos); |
|
|
/* Read in the filename. */ |
for (i = 0; *pos < sz && '\n' != buf[*pos]; ) { |
for (i = 0; *pos < sz && '\n' != buf[*pos]; i++) { |
|
if (i == sizeof(fname) - 1) |
if (i == sizeof(fname) - 1) |
break; |
break; |
fname[i] = buf[*pos]; |
if ('@' != buf[*pos]) { |
advance(p, buf, pos); |
fname[i++] = buf[*pos]; |
|
advance(p, buf, pos); |
|
continue; |
|
} |
|
type = texicmd(p, buf, *pos, sz, &end, NULL); |
|
advanceto(p, buf, pos, end); |
|
if (TEXICMD_VALUE != type) |
|
texierr(p, "unknown verbatiminclude command"); |
|
v = valueblookup(p, buf, sz, pos); |
|
if (NULL == v) |
|
continue; |
|
while ('\0' != *v) { |
|
if (i == sizeof(fname) - 1) |
|
break; |
|
fname[i++] = *v++; |
|
} |
|
if ('\0' != *v) |
|
break; |
} |
} |
|
|
if (i == 0) |
if (i == 0) |
Line 770 doinclude(struct texi *p, enum texicmd cmd, |
|
Line 724 doinclude(struct texi *p, enum texicmd cmd, |
|
if (strstr(fname, "../") || strstr(fname, "/..")) |
if (strstr(fname, "../") || strstr(fname, "/..")) |
texierr(p, "insecure path"); |
texierr(p, "insecure path"); |
|
|
/* Append filename to original name's directory. */ |
rc = snprintf(path, sizeof(path), |
rc = snprintf(path, sizeof(path), "%s/%s", p->dir, fname); |
"%s/%s", p->dirs[0], fname); |
if (rc < 0) |
if (rc < 0) |
texierr(p, "couldn't format filename"); |
texierr(p, "couldn't format path"); |
else if ((size_t)rc >= sizeof(path)) |
else if ((size_t)rc >= sizeof(path)) |
texierr(p, "path too long"); |
texierr(p, "path too long"); |
|
|
/* Pump through to parser. */ |
parsefile(p, path, 0); |
parsefile(p, path); |
|
} |
} |
|
|
static void |
static void |
doitalic(struct texi *p, enum texicmd cmd, |
doinclude(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
char fname[PATH_MAX], path[PATH_MAX]; |
|
size_t i, end; |
|
int rc; |
|
const char *v; |
|
enum texicmd type; |
|
|
texiputchars(p, "\\fI"); |
while (*pos < sz && ' ' == buf[*pos]) |
parsebracket(p, buf, sz, pos); |
advance(p, buf, pos); |
texiputchars(p, "\\fP"); |
|
} |
|
|
|
static void |
/* Read in the filename. */ |
doliteral(struct texi *p, enum texicmd cmd, |
for (i = 0; *pos < sz && '\n' != buf[*pos]; ) { |
const char *buf, size_t sz, size_t *pos) |
if (i == sizeof(fname) - 1) |
{ |
break; |
|
if ('@' != buf[*pos]) { |
|
fname[i++] = buf[*pos]; |
|
advance(p, buf, pos); |
|
continue; |
|
} |
|
type = texicmd(p, buf, *pos, sz, &end, NULL); |
|
advanceto(p, buf, pos, end); |
|
if (TEXICMD_VALUE != type) |
|
texierr(p, "unknown include command"); |
|
v = valueblookup(p, buf, sz, pos); |
|
if (NULL == v) |
|
continue; |
|
while ('\0' != *v) { |
|
if (i == sizeof(fname) - 1) |
|
break; |
|
fname[i++] = *v++; |
|
} |
|
if ('\0' != *v) |
|
break; |
|
} |
|
|
if (TEXI_LITERAL & p->flags) |
if (i == 0) |
parsebracket(p, buf, sz, pos); |
texierr(p, "path too short"); |
else |
else if ('\n' != buf[*pos]) |
doinline(p, buf, sz, pos, "Li"); |
texierr(p, "path too long"); |
|
else if ('/' == fname[0]) |
|
texierr(p, "no absolute paths"); |
|
fname[i] = '\0'; |
|
|
|
if (strstr(fname, "../") || strstr(fname, "/..")) |
|
texierr(p, "insecure path"); |
|
|
|
for (i = 0; i < p->dirsz; i++) { |
|
rc = snprintf(path, sizeof(path), |
|
"%s/%s", p->dirs[i], fname); |
|
if (rc < 0) |
|
texierr(p, "couldn't format path"); |
|
else if ((size_t)rc >= sizeof(path)) |
|
texierr(p, "path too long"); |
|
else if (-1 == access(path, R_OK)) |
|
continue; |
|
|
|
parsefile(p, path, 1); |
|
return; |
|
} |
|
|
|
texierr(p, "couldn't find %s in includes", fname); |
} |
} |
|
|
static void |
static void |
doemph(struct texi *p, enum texicmd cmd, |
dobracket(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
if (TEXI_LITERAL & p->flags) |
parsebracket(p, buf, sz, pos); |
doitalic(p, cmd, buf, sz, pos); |
|
else |
|
doinline(p, buf, sz, pos, "Em"); |
|
} |
} |
|
|
static void |
static void |
docommand(struct texi *p, enum texicmd cmd, |
dodisplay(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
doinline(p, buf, sz, pos, "Xr"); |
switch (cmd) { |
|
case (TEXICMD_FORMAT): |
|
case (TEXICMD_SMALLFORMAT): |
|
teximacro(p, "Bd -filled"); |
|
break; |
|
default: |
|
teximacro(p, "Bd -filled -offset indent"); |
|
break; |
|
} |
|
|
|
p->seenvs = 1; |
|
/* FIXME: ignore and parseeoln. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
teximacro(p, "Ed"); |
} |
} |
|
|
static void |
static void |
dobracket(struct texi *p, enum texicmd cmd, |
doexample(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
parsebracket(p, buf, sz, pos); |
teximacro(p, "Bd -literal -offset indent"); |
|
/* FIXME: ignore and parseeoln. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
|
p->literal++; |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
p->literal--; |
|
teximacro(p, "Ed"); |
} |
} |
|
|
static void |
static void |
dofile(struct texi *p, enum texicmd cmd, |
dobye(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
if (TEXI_LITERAL & p->flags) |
texiexit(p); |
parsebracket(p, buf, sz, pos); |
exit(EXIT_SUCCESS); |
else |
|
doinline(p, buf, sz, pos, "Pa"); |
|
} |
} |
|
|
static void |
static void |
doexample(struct texi *p, enum texicmd cmd, |
dotitle(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
unsigned int sv; |
size_t start, end; |
|
|
teximacro(p, ".Bd -literal"); |
while (*pos < sz && isws(buf[*pos])) |
advanceeoln(p, buf, sz, pos); |
|
if ('\n' == buf[*pos]) |
|
advance(p, buf, pos); |
advance(p, buf, pos); |
sv = p->flags; |
start = end = *pos; |
p->flags |= TEXI_LITERAL; |
while (end < sz && '\n' != buf[end]) |
parseto(p, buf, sz, pos, "example"); |
end++; |
p->flags = sv; |
advanceeoln(p, buf, sz, pos, 1); |
teximacro(p, ".Ed"); |
free(p->subtitle); |
|
p->subtitle = malloc(end - start + 1); |
|
if (NULL == p->subtitle) |
|
texiabort(p, NULL); |
|
memcpy(p->subtitle, &buf[start], end - start); |
|
p->subtitle[end - start] = '\0'; |
} |
} |
|
|
static void |
static void |
dobye(struct texi *p, enum texicmd cmd, |
doaccent(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
texiexit(p); |
if (*pos == sz) |
exit(EXIT_SUCCESS); |
return; |
|
if (p->seenws && p->outcol && 0 == p->literal) |
|
texiputchar(p, ' '); |
|
p->seenws = 0; |
|
switch (cmd) { |
|
case (TEXICMD_CEDILLA): |
|
/* Strange rules... */ |
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
if (*pos == sz || '{' != buf[*pos]) |
|
return; |
|
advance(p, buf, pos); |
|
switch (buf[*pos]) { |
|
case ('c'): case ('C'): |
|
texiputchars(p, "\\(,"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
} |
|
advance(p, buf, pos); |
|
break; |
|
case (TEXICMD_ACUTE): |
|
switch (buf[*pos]) { |
|
case ('a'): case ('A'): |
|
case ('e'): case ('E'): |
|
case ('i'): case ('I'): |
|
case ('o'): case ('O'): |
|
case ('u'): case ('U'): |
|
texiputchars(p, "\\(\'"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
} |
|
break; |
|
case (TEXICMD_CIRCUMFLEX): |
|
switch (buf[*pos]) { |
|
case ('a'): case ('A'): |
|
case ('e'): case ('E'): |
|
case ('i'): case ('I'): |
|
case ('o'): case ('O'): |
|
case ('u'): case ('U'): |
|
texiputchars(p, "\\(^"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
} |
|
break; |
|
case (TEXICMD_GRAVE): |
|
switch (buf[*pos]) { |
|
case ('a'): case ('A'): |
|
case ('e'): case ('E'): |
|
case ('i'): case ('I'): |
|
case ('o'): case ('O'): |
|
case ('u'): case ('U'): |
|
texiputchars(p, "\\(`"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
} |
|
break; |
|
case (TEXICMD_TILDE): |
|
switch (buf[*pos]) { |
|
case ('a'): case ('A'): |
|
case ('n'): case ('N'): |
|
case ('o'): case ('O'): |
|
texiputchars(p, "\\(~"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
} |
|
break; |
|
case (TEXICMD_UMLAUT): |
|
switch (buf[*pos]) { |
|
case ('a'): case ('A'): |
|
case ('e'): case ('E'): |
|
case ('i'): case ('I'): |
|
case ('o'): case ('O'): |
|
case ('u'): case ('U'): |
|
case ('y'): |
|
texiputchars(p, "\\(:"); |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
default: |
|
texiputchar(p, buf[*pos]); |
|
break; |
|
} |
|
break; |
|
default: |
|
abort(); |
|
} |
|
advance(p, buf, pos); |
} |
} |
|
|
static void |
static void |
Line 871 dosymbol(struct texi *p, enum texicmd cmd, |
|
Line 985 dosymbol(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
|
if (p->seenws && p->outcol && 0 == p->literal) { |
|
texiputchar(p, ' '); |
|
p->seenws = 0; |
|
} |
|
|
switch (cmd) { |
switch (cmd) { |
|
case (TEXICMD_ASTERISK): |
|
case (TEXICMD_NEWLINE): |
|
case (TEXICMD_SPACE): |
|
case (TEXICMD_TABSYM): |
|
texiputchar(p, ' '); |
|
break; |
case (TEXICMD_AT): |
case (TEXICMD_AT): |
texiputchars(p, "@"); |
texiputchar(p, '@'); |
break; |
break; |
|
case (TEXICMD_BANG): |
|
texiputchar(p, '!'); |
|
break; |
|
case (TEXICMD_BULLET): |
|
texiputchars(p, "\\(bu"); |
|
break; |
|
case (TEXICMD_COMMA): |
|
texiputchar(p, ','); |
|
break; |
case (TEXICMD_COPYRIGHT): |
case (TEXICMD_COPYRIGHT): |
texiputchars(p, "\\(co"); |
texiputchars(p, "\\(co"); |
break; |
break; |
case (TEXICMD_DOTS): |
case (TEXICMD_DOTS): |
|
case (TEXICMD_ENDDOTS): |
texiputchars(p, "..."); |
texiputchars(p, "..."); |
break; |
break; |
|
case (TEXICMD_EQUIV): |
|
texiputchars(p, "\\(=="); |
|
break; |
|
case (TEXICMD_ERROR): |
|
texiputchars(p, "error\\(->"); |
|
break; |
|
case (TEXICMD_EXPANSION): |
|
texiputchars(p, "\\(->"); |
|
break; |
case (TEXICMD_LATEX): |
case (TEXICMD_LATEX): |
texiputchars(p, "LaTeX"); |
texiputchars(p, "LaTeX"); |
break; |
break; |
|
case (TEXICMD_MINUS): |
|
texiputchars(p, "\\-"); |
|
break; |
|
case (TEXICMD_PERIOD): |
|
texiputchar(p, '.'); |
|
break; |
|
case (TEXICMD_QUESTIONMARK): |
|
texiputchar(p, '?'); |
|
break; |
|
case (TEXICMD_RESULT): |
|
texiputchars(p, "\\(rA"); |
|
break; |
|
case (TEXICMD_SLASH): |
|
texiputchar(p, '/'); |
|
break; |
|
case (TEXICMD_SS): |
|
texiputchars(p, "\\(ss"); |
|
break; |
|
case (TEXICMD_SQUIGGLE_LEFT): |
|
texiputchars(p, "{"); |
|
break; |
|
case (TEXICMD_SQUIGGLE_RIGHT): |
|
texiputchars(p, "}"); |
|
break; |
case (TEXICMD_TEXSYM): |
case (TEXICMD_TEXSYM): |
texiputchars(p, "TeX"); |
texiputchars(p, "TeX"); |
break; |
break; |
|
case (TEXICMD_TIE): |
|
texiputchars(p, "\\ "); |
|
break; |
|
case (TEXICMD_COLON): |
|
case (TEXICMD_HYPHEN): |
|
break; |
default: |
default: |
abort(); |
abort(); |
} |
} |
|
|
doignbracket(p, cmd, buf, sz, pos); |
if (texitoks[cmd].len > 1) |
|
doignbracket(p, cmd, buf, sz, pos); |
} |
} |
|
|
static void |
static void |
Line 899 doquotation(struct texi *p, enum texicmd cmd, |
|
Line 1074 doquotation(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
teximacro(p, ".Qo"); |
teximacro(p, "Qo"); |
parseto(p, buf, sz, pos, "quotation"); |
parseto(p, buf, sz, pos, "quotation"); |
teximacro(p, ".Qc"); |
teximacro(p, "Qc"); |
} |
} |
|
|
static void |
static void |
doarg1(struct texi *p, enum texicmd cmd, |
domath(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
size_t nest, start; |
|
|
|
/* |
|
* Math handling is different from everything else. |
|
* We don't allow any subcomponents, and we ignore the rules in |
|
* terms of @-commands. |
|
* This departs from GNU's rules, but whatever. |
|
*/ |
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
if (*pos == sz || '{' != buf[*pos]) |
if (*pos == sz || '{' != buf[*pos]) |
return; |
return; |
advance(p, buf, pos); |
advance(p, buf, pos); |
if ( ! p->outmacro) |
if (p->seenws && p->outcol && 0 == p->literal) |
texifputs(p, "."); |
texiputchar(p, ' '); |
|
p->seenws = 0; |
|
for (nest = 1, start = *pos; *pos < sz && nest > 0; ) { |
|
if ('{' == buf[*pos]) |
|
nest++; |
|
else if ('}' == buf[*pos]) |
|
if (0 == --nest) |
|
continue; |
|
advance(p, buf, pos); |
|
} |
|
if (*pos == sz) |
|
return; |
|
assert('}' == buf[*pos]); |
|
texiputbuf(p, buf, start, *pos); |
|
advance(p, buf, pos); |
|
} |
|
|
|
static void |
|
dovalue(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
size_t start, end, i; |
|
char *key, *val; |
|
const char *cp; |
|
|
|
if (TEXICMD_SET == cmd) { |
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
for (start = end = *pos; end < sz; end++) |
|
if (ismspace(buf[end])) |
|
break; |
|
/* We don't allow empty keys. */ |
|
if (start == end) |
|
return; |
|
advanceto(p, buf, pos, end); |
|
|
|
key = malloc(end - start + 1); |
|
if (NULL == key) |
|
texiabort(p, NULL); |
|
memcpy(key, &buf[start], end - start); |
|
key[end - start] = '\0'; |
|
|
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
for (start = end = *pos; end < sz; end++) |
|
if ('\n' == buf[end]) |
|
break; |
|
/* We do allow empty values. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
|
|
|
val = malloc(end - start + 1); |
|
if (NULL == val) |
|
texiabort(p, NULL); |
|
memcpy(val, &buf[start], end - start); |
|
val[end - start] = '\0'; |
|
valueadd(p, key, val); |
|
} else if (TEXICMD_VALUE == cmd) { |
|
if (p->seenws) |
|
texiputchar(p, ' '); |
|
p->seenws = 0; |
|
if (NULL != (cp = valueblookup(p, buf, sz, pos))) { |
|
for (i = 0; i < p->valstackpos; i++) |
|
if (cp == p->valstack[i]) |
|
break; |
|
if (i < p->valstackpos) |
|
texierr(p, "recursive value"); |
|
if (64 == p->valstackpos) |
|
texierr(p, "too many nested values"); |
|
p->valstack[p->valstackpos++] = cp; |
|
parsemembuf(p, cp, strlen(cp)); |
|
p->valstackpos--; |
|
} else |
|
texiputchars(p, "{No value}"); |
|
} else if (TEXICMD_IFCLEAR == cmd) { |
|
if (NULL != valuellookup(p, buf, sz, pos)) |
|
doignblock(p, cmd, buf, sz, pos); |
|
else |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
} else if (TEXICMD_IFSET == cmd) { |
|
if (NULL == valuellookup(p, buf, sz, pos)) |
|
doignblock(p, cmd, buf, sz, pos); |
|
else |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
} else if (TEXICMD_CLEAR == cmd) |
|
valuelclear(p, buf, sz, pos); |
|
} |
|
|
|
static void |
|
dolink(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
int c; |
|
|
switch (cmd) { |
switch (cmd) { |
case (TEXICMD_EMAIL): |
case (TEXICMD_EMAIL): |
texiputchars(p, "Lk "); |
teximacroopen(p, "Mt"); |
break; |
break; |
|
case (TEXICMD_UREF): |
case (TEXICMD_URL): |
case (TEXICMD_URL): |
texiputchars(p, "Mt "); |
teximacroopen(p, "Lk"); |
break; |
break; |
|
case (TEXICMD_XREF): |
|
texiputchars(p, "See Section"); |
|
teximacroopen(p, "Dq"); |
|
break; |
|
case (TEXICMD_PXREF): |
|
texiputchars(p, "see Section"); |
|
teximacroopen(p, "Dq"); |
|
break; |
|
case (TEXICMD_INFOREF): |
|
texiputchars(p, "See Info file node"); |
|
teximacroopen(p, "Dq"); |
|
break; |
default: |
default: |
abort(); |
abort(); |
} |
} |
while (*pos < sz && '}' != buf[*pos] && ',' != buf[*pos]) { |
|
texiputchar(p, buf[*pos]); |
c = parsearg(p, buf, sz, pos, 0); |
advance(p, buf, pos); |
p->ign++; |
|
while (c > 0) |
|
c = parsearg(p, buf, sz, pos, 1); |
|
p->ign--; |
|
|
|
texipunctuate(p, buf, sz, pos); |
|
teximacroclose(p); |
|
} |
|
|
|
static void |
|
doignargn(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
int c; |
|
|
|
c = parsearg(p, buf, sz, pos, 0); |
|
p->ign++; |
|
while (c > 0) |
|
c = parsearg(p, buf, sz, pos, 1); |
|
p->ign--; |
|
} |
|
|
|
/* |
|
* Sections can be made subsections and so on by way of the |
|
* @raiseections and @lowersections commands. |
|
* Perform this check here and return the actual section number adjusted |
|
* to the raise level. |
|
*/ |
|
static int |
|
sectioner(struct texi *p, int sec) |
|
{ |
|
|
|
if ((sec -= p->secoffs) < 0) { |
|
texiwarn(p, "section below minimum, clamping"); |
|
return(0); |
|
} else if (sec >= SECTSZ) { |
|
texiwarn(p, "section above maximum, clamping"); |
|
return(SECTSZ - 1); |
} |
} |
while (*pos < sz && '}' != buf[*pos]) |
return(sec); |
advance(p, buf, pos); |
|
if (*pos < sz) |
|
advance(p, buf, pos); |
|
if (*pos < sz - 1 && |
|
ismpunct(buf[*pos]) && |
|
isspace(buf[*pos + 1])) { |
|
texiputchar(p, ' '); |
|
texiputchar(p, buf[*pos]); |
|
advance(p, buf, pos); |
|
} |
|
if ( ! p->outmacro) |
|
texiputchar(p, '\n'); |
|
} |
} |
|
|
static void |
static void |
|
dosubsubsection(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
int sec; |
|
|
|
sec = sectioner(p, 3); |
|
|
|
/* We don't have a subsubsubsection, so make one up. */ |
|
texivspace(p); |
|
teximacroopen(p, sects[sec]); |
|
parseeoln(p, buf, sz, pos); |
|
teximacroclose(p); |
|
texivspace(p); |
|
} |
|
|
|
static void |
dosubsection(struct texi *p, enum texicmd cmd, |
dosubsection(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
int sec; |
|
|
if (TEXI_IGN & p->flags) { |
sec = sectioner(p, 2); |
advanceeoln(p, buf, sz, pos); |
|
return; |
if (p->outmacro) |
} |
texierr(p, "\"%s\" in open line scope!?", sects[sec]); |
while (*pos < sz && ' ' == buf[*pos]) |
else if (p->literal) |
advance(p, buf, pos); |
texierr(p, "\"%s\" in a literal scope!?", sects[sec]); |
texifputs(p, ".Pp"); |
|
while (*pos < sz && '\n' != buf[*pos]) { |
/* We don't have a subsubsection, so make one up. */ |
texiputchar(p, buf[*pos]); |
if (sec > 1) |
advance(p, buf, pos); |
texivspace(p); |
} |
teximacroopen(p, sects[sec]); |
texifputs(p, ".Pp"); |
parseeoln(p, buf, sz, pos); |
|
teximacroclose(p); |
|
if (sec > 1) |
|
texivspace(p); |
} |
} |
|
|
static void |
static void |
|
dosecoffs(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
|
|
if (TEXICMD_RAISESECTIONS == cmd) |
|
p->secoffs++; |
|
else |
|
p->secoffs--; |
|
} |
|
|
|
static void |
dosection(struct texi *p, enum texicmd cmd, |
dosection(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
int sec; |
|
|
if (TEXI_IGN & p->flags) { |
switch (cmd) { |
advanceeoln(p, buf, sz, pos); |
case (TEXICMD_APPENDIX): |
return; |
case (TEXICMD_CHAPTER): |
|
case (TEXICMD_TOP): |
|
case (TEXICMD_UNNUMBERED): |
|
sec = sectioner(p, 0); |
|
break; |
|
case (TEXICMD_APPENDIXSEC): |
|
case (TEXICMD_HEADING): |
|
case (TEXICMD_SECTION): |
|
case (TEXICMD_UNNUMBEREDSEC): |
|
sec = sectioner(p, 1); |
|
break; |
|
default: |
|
abort(); |
} |
} |
while (*pos < sz && isws(buf[*pos]) ) |
|
advance(p, buf, pos); |
if (p->outmacro) |
texifputs(p, ".Ss "); |
texierr(p, "\"%s\" in open line scope!?", sects[sec]); |
while (*pos < sz && '\n' != buf[*pos]) { |
else if (p->literal) |
texiputchar(p, buf[*pos]); |
texierr(p, "\"%s\" in a literal scope!?", sects[sec]); |
advance(p, buf, pos); |
|
} |
teximacroopen(p, sects[sec]); |
texiputchar(p, '\n'); |
parseeoln(p, buf, sz, pos); |
|
teximacroclose(p); |
|
p->seenvs = 1; |
} |
} |
|
|
static void |
static void |
dosh(struct texi *p, enum texicmd cmd, |
dosp(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
if (TEXI_IGN & p->flags) { |
if (p->literal) |
advanceeoln(p, buf, sz, pos); |
texiputchar(p, '\n'); |
return; |
else |
} |
texivspace(p); |
while (*pos < sz && isws(buf[*pos])) |
/* FIXME: ignore and parseeoln. */ |
advance(p, buf, pos); |
advanceeoln(p, buf, sz, pos, 1); |
texifputs(p, ".Sh "); |
|
while (*pos < sz && '\n' != buf[*pos]) { |
|
texiputchar(p, toupper(buf[*pos])); |
|
advance(p, buf, pos); |
|
} |
|
texiputchar(p, '\n'); |
|
} |
} |
|
|
static void |
static void |
dotop(struct texi *p, enum texicmd cmd, |
dotop(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
const char *cp; |
|
time_t t; |
|
char date[32]; |
|
|
p->flags &= ~TEXI_HEADER; |
if (--p->ign) |
advanceeoln(p, buf, sz, pos); |
texierr(p, "@top command while ignoring (%d)", p->ign); |
teximacro(p, ".Dd $Mdocdate$"); |
|
teximacro(p, ".Dt SOMETHING 7"); |
/* |
teximacro(p, ".Os"); |
* Here we print our standard mdoc(7) prologue. |
teximacro(p, ".Sh NAME"); |
* We use the title set with @settitle for the `Nd' description |
teximacro(p, ".Nm Something"); |
* and the source document filename (the first one as invoked on |
teximacro(p, ".Nd Something"); |
* the command line) for the title. |
|
* The date is set to the current date. |
|
*/ |
|
t = time(NULL); |
|
strftime(date, sizeof(date), "%F", localtime(&t)); |
|
|
|
teximacroopen(p, "Dd"); |
|
texiputchars(p, date); |
|
teximacroclose(p); |
|
teximacroopen(p, "Dt"); |
|
for (cp = p->title; '\0' != *cp; cp++) |
|
texiputchar(p, toupper(*cp)); |
|
texiputchars(p, " 7"); |
|
teximacroclose(p); |
|
teximacro(p, "Os"); |
|
teximacro(p, "Sh NAME"); |
|
teximacroopen(p, "Nm"); |
|
for (cp = p->title; '\0' != *cp; cp++) |
|
texiputchar(p, *cp); |
|
teximacroclose(p); |
|
teximacroopen(p, "Nd"); |
|
if (NULL != p->subtitle) |
|
for (cp = p->subtitle; '\0' != *cp; cp++) |
|
texiputchar(p, *cp); |
|
else |
|
texiputchars(p, "Unknown description"); |
|
teximacroclose(p); |
|
p->seenvs = 1; |
|
dosection(p, cmd, buf, sz, pos); |
} |
} |
|
|
static void |
static void |
doitem(struct texi *p, enum texicmd cmd, |
doitem(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
size_t end; |
|
|
|
/* See if we have arguments... */ |
/* Multitable is using raw tbl(7). */ |
for (end = *pos; end < sz; end++) |
if (TEXILIST_TABLE == p->list) { |
if ( ! isws(buf[end])) |
texiputchar(p, '\n'); |
break; |
return; |
|
} |
|
|
|
if (p->outmacro) |
|
texierr(p, "item in open line scope!?"); |
|
else if (p->literal) |
|
texierr(p, "item in a literal scope!?"); |
|
|
/* If we have arguments, print them too. */ |
switch (p->list) { |
if ('\n' != buf[end]) { |
case (TEXILIST_ITEM): |
texifputs(p, ".It"); |
teximacroopen(p, "It"); |
/* FIXME: process commands. */ |
break; |
|
case (TEXILIST_NOITEM): |
|
teximacro(p, "It"); |
|
break; |
|
default: |
|
texivspace(p); |
|
break; |
|
} |
|
|
|
/* Trick so we don't start with Pp. */ |
|
p->seenvs = 1; |
|
parseeoln(p, buf, sz, pos); |
|
|
|
if (TEXILIST_ITEM == p->list) |
|
teximacroclose(p); |
|
else if (p->outcol > 0) |
|
texiputchar(p, '\n'); |
|
} |
|
|
|
static void |
|
dotab(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
|
|
/* This command is only useful in @multitable. */ |
|
if (TEXILIST_TABLE == p->list) |
|
texiputchar(p, '\t'); |
|
} |
|
|
|
static void |
|
domultitable(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
|
{ |
|
enum texilist sv = p->list; |
|
int svliteral = p->literal; |
|
enum texicmd type; |
|
size_t i, end, columns; |
|
|
|
p->list = TEXILIST_TABLE; |
|
/* |
|
* TS/TE blocks aren't "in mdoc(7)", so we can disregard the |
|
* fact that we're in literal mode right now. |
|
*/ |
|
p->literal = 0; |
|
teximacro(p, "TS"); |
|
columns = 0; |
|
|
|
/* Advance to the first argument... */ |
|
while (*pos < sz && isws(buf[*pos])) |
|
advance(p, buf, pos); |
|
|
|
/* Make sure we don't print anything when scanning. */ |
|
p->ign++; |
|
if ('@' == buf[*pos]) { |
|
/* |
|
* Look for @columnfractions. |
|
* We ignore these, but we do use the number of |
|
* arguments to set the number of columns that we'll |
|
* have. |
|
*/ |
|
type = texicmd(p, buf, *pos, sz, &end, NULL); |
|
advanceto(p, buf, pos, end); |
|
if (TEXICMD_COLUMNFRACTIONS != type) |
|
texierr(p, "unknown multitable command"); |
while (*pos < sz && '\n' != buf[*pos]) { |
while (*pos < sz && '\n' != buf[*pos]) { |
texiputchar(p, buf[*pos]); |
while (*pos < sz && isws(buf[*pos])) |
advance(p, buf, pos); |
advance(p, buf, pos); |
|
while (*pos < sz && ! isws(buf[*pos])) { |
|
if ('\n' == buf[*pos]) |
|
break; |
|
advance(p, buf, pos); |
|
} |
|
columns++; |
} |
} |
texiputchar(p, '\n'); |
} else |
} else |
/* |
teximacro(p, ".It"); |
* We have arguments. |
|
* We could parse these, but it's easier to just let |
|
* tbl(7) figure it out. |
|
* So use this only to count arguments. |
|
*/ |
|
while (parselinearg(p, buf, sz, pos) > 0) |
|
columns++; |
|
p->ign--; |
|
|
|
/* Left-justify each table entry. */ |
|
for (i = 0; i < columns; i++) { |
|
if (i > 0) |
|
texiputchar(p, ' '); |
|
texiputchar(p, 'l'); |
|
} |
|
texiputchars(p, ".\n"); |
|
p->outmacro++; |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
p->outmacro--; |
|
teximacro(p, "TE"); |
|
p->literal = svliteral; |
|
p->list = sv; |
} |
} |
|
|
static void |
static void |
dotable(struct texi *p, enum texicmd cmd, |
dotable(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
enum texilist sv = p->list; |
|
|
teximacro(p, ".Bl -tag -width Ds"); |
p->list = TEXILIST_ITEM; |
parseto(p, buf, sz, pos, "table"); |
teximacro(p, "Bl -tag -width Ds"); |
teximacro(p, ".El"); |
/* FIXME: ignore and parseeoln. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
|
p->seenvs = 1; |
|
parseto(p, buf, sz, pos, texitoks[cmd].tok); |
|
teximacro(p, "El"); |
|
p->list = sv; |
} |
} |
|
|
static void |
static void |
doenumerate(struct texi *p, enum texicmd cmd, |
doenumerate(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
enum texilist sv = p->list; |
|
|
teximacro(p, ".Bl -enum"); |
p->list = TEXILIST_NOITEM; |
|
teximacro(p, "Bl -enum"); |
|
p->seenvs = 1; |
|
/* FIXME: ignore and parseeoln. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
parseto(p, buf, sz, pos, "enumerate"); |
parseto(p, buf, sz, pos, "enumerate"); |
teximacro(p, ".El"); |
teximacro(p, "El"); |
|
p->list = sv; |
} |
} |
|
|
static void |
static void |
doitemize(struct texi *p, enum texicmd cmd, |
doitemize(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
enum texilist sv = p->list; |
|
|
teximacro(p, ".Bl -bullet"); |
p->list = TEXILIST_NOITEM; |
|
teximacro(p, "Bl -bullet"); |
|
p->seenvs = 1; |
|
/* FIXME: ignore and parseeoln. */ |
|
advanceeoln(p, buf, sz, pos, 1); |
parseto(p, buf, sz, pos, "itemize"); |
parseto(p, buf, sz, pos, "itemize"); |
teximacro(p, ".El"); |
teximacro(p, "El"); |
|
p->list = sv; |
} |
} |
|
|
static void |
static void |
doignbracket(struct texi *p, enum texicmd cmd, |
doignbracket(struct texi *p, enum texicmd cmd, |
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
unsigned int sv = p->flags; |
|
|
|
p->flags |= TEXI_IGN; |
p->ign++; |
parsebracket(p, buf, sz, pos); |
parsebracket(p, buf, sz, pos); |
p->flags = sv; |
p->ign--; |
} |
} |
|
|
static void |
static void |
Line 1085 doignline(struct texi *p, enum texicmd cmd, |
|
Line 1582 doignline(struct texi *p, enum texicmd cmd, |
|
const char *buf, size_t sz, size_t *pos) |
const char *buf, size_t sz, size_t *pos) |
{ |
{ |
|
|
advanceeoln(p, buf, sz, pos); |
/* FIXME: ignore and parseeoln. */ |
if (*pos < sz) |
advanceeoln(p, buf, sz, pos, 1); |
advance(p, buf, pos); |
|
} |
} |
|
|
|
/* |
|
* Parse colon-separated directories from "cp" (if not NULL) and returns |
|
* the array of pointers. |
|
* Prepends "base" to the array, if found. |
|
* This does NOT sanitise the directories! |
|
*/ |
|
static char ** |
|
parsedirs(struct texi *p, const char *base, const char *cp, size_t *sz) |
|
{ |
|
char *tok, *str, *tofree; |
|
const char *cpp; |
|
size_t i = 0; |
|
char **dirs; |
|
|
|
/* Count up our expected arguments. */ |
|
*sz = NULL != base; |
|
if (NULL != (cpp = cp)) |
|
for ((*sz)++; NULL != (cpp = strchr(cpp, ':')); (*sz)++) |
|
cpp++; |
|
|
|
if (0 == *sz) |
|
return(NULL); |
|
if (NULL == (dirs = calloc(*sz, sizeof(char *)))) |
|
texiabort(p, NULL); |
|
if (NULL != base && NULL == (dirs[i++] = strdup(base))) |
|
texiabort(p, NULL); |
|
if (NULL == cp) |
|
return(dirs); |
|
if (NULL == (tofree = tok = str = strdup(cp))) |
|
texiabort(p, NULL); |
|
|
|
for ( ; NULL != (tok = strsep(&str, ":")); i++) |
|
if (NULL == (dirs[i] = strdup(tok))) |
|
texiabort(p, NULL); |
|
|
|
free(tofree); |
|
return(dirs); |
|
} |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
{ |
{ |
struct texi texi; |
struct texi texi; |
int c; |
int c; |
char *path, *dir; |
char *dirpath, *dir, *ccp; |
const char *progname; |
const char *progname, *Idir, *cp; |
|
|
progname = strrchr(argv[0], '/'); |
progname = strrchr(argv[0], '/'); |
if (progname == NULL) |
if (progname == NULL) |
Line 1104 main(int argc, char *argv[]) |
|
Line 1639 main(int argc, char *argv[]) |
|
else |
else |
++progname; |
++progname; |
|
|
while (-1 != (c = getopt(argc, argv, ""))) |
memset(&texi, 0, sizeof(struct texi)); |
|
texi.ign = 1; |
|
Idir = NULL; |
|
|
|
while (-1 != (c = getopt(argc, argv, "I:"))) |
switch (c) { |
switch (c) { |
|
case ('I'): |
|
Idir = optarg; |
|
break; |
default: |
default: |
goto usage; |
goto usage; |
} |
} |
|
|
argv += optind; |
argv += optind; |
if (0 == (argc -= optind)) |
argc -= optind; |
goto usage; |
|
|
|
if (NULL == (path = strdup(argv[0]))) { |
if (argc > 0) { |
perror(NULL); |
if (NULL == (dirpath = strdup(argv[0]))) |
exit(EXIT_FAILURE); |
texiabort(&texi, NULL); |
} else if (NULL == (dir = dirname(path))) { |
if (NULL == (dir = dirname(dirpath))) |
perror(argv[0]); |
texiabort(&texi, NULL); |
free(path); |
if (NULL != (cp = strrchr(argv[0], '/'))) |
exit(EXIT_FAILURE); |
texi.title = strdup(cp + 1); |
|
else |
|
texi.title = strdup(argv[0]); |
|
if (NULL == texi.title) |
|
texiabort(&texi, NULL); |
|
else if (NULL != (ccp = strchr(texi.title, '.'))) |
|
*ccp = '\0'; |
|
texi.dirs = parsedirs(&texi, dir, Idir, &texi.dirsz); |
|
free(dirpath); |
|
parsefile(&texi, argv[0], 1); |
|
} else { |
|
texi.title = strdup("Unknown Manual"); |
|
texi.dirs = parsedirs(&texi, NULL, Idir, &texi.dirsz); |
|
parsestdin(&texi); |
} |
} |
free(path); |
|
|
|
memset(&texi, 0, sizeof(struct texi)); |
|
texi.flags = TEXI_HEADER; |
|
texi.dir = strdup(dir); |
|
parsefile(&texi, argv[0]); |
|
texiexit(&texi); |
texiexit(&texi); |
return(EXIT_FAILURE); |
return(EXIT_FAILURE); |
usage: |
usage: |
fprintf(stderr, "usage: %s file\n", progname); |
fprintf(stderr, "usage: %s [-Idirs] [file]\n", progname); |
return(EXIT_FAILURE); |
return(EXIT_FAILURE); |
} |
} |