| File: | src/usr.bin/mandoc/mdoc_macro.c |
| Warning: | line 269, column 6 Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'to') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: mdoc_macro.c,v 1.191 2020/01/19 17:59:01 schwarze Exp $ */ | |||
| 2 | /* | |||
| 3 | * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> | |||
| 4 | * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org> | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 17 | */ | |||
| 18 | #include <sys/types.h> | |||
| 19 | ||||
| 20 | #include <assert.h> | |||
| 21 | #include <ctype.h> | |||
| 22 | #include <stdlib.h> | |||
| 23 | #include <stdio.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <time.h> | |||
| 26 | ||||
| 27 | #include "mandoc.h" | |||
| 28 | #include "roff.h" | |||
| 29 | #include "mdoc.h" | |||
| 30 | #include "libmandoc.h" | |||
| 31 | #include "roff_int.h" | |||
| 32 | #include "libmdoc.h" | |||
| 33 | ||||
| 34 | static void blk_full(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 35 | static void blk_exp_close(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 36 | static void blk_part_exp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 37 | static void blk_part_imp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 38 | static void ctx_synopsis(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 39 | static void in_line_eoln(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 40 | static void in_line_argn(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 41 | static void in_line(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 42 | static void phrase_ta(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
| 43 | ||||
| 44 | static void append_delims(struct roff_man *, int, int *, char *); | |||
| 45 | static void dword(struct roff_man *, int, int, const char *, | |||
| 46 | enum mdelim, int); | |||
| 47 | static int find_pending(struct roff_man *, enum roff_tok, | |||
| 48 | int, int, struct roff_node *); | |||
| 49 | static int lookup(struct roff_man *, int, int, int, const char *); | |||
| 50 | static int macro_or_word(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf, char *, int); | |||
| 51 | static void break_intermediate(struct roff_node *, | |||
| 52 | struct roff_node *); | |||
| 53 | static int parse_rest(struct roff_man *, enum roff_tok, | |||
| 54 | int, int *, char *); | |||
| 55 | static enum roff_tok rew_alt(enum roff_tok); | |||
| 56 | static void rew_elem(struct roff_man *, enum roff_tok); | |||
| 57 | static void rew_last(struct roff_man *, const struct roff_node *); | |||
| 58 | static void rew_pending(struct roff_man *, | |||
| 59 | const struct roff_node *); | |||
| 60 | ||||
| 61 | static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = { | |||
| 62 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) | MDOC_JOIN(1 << 5) }, /* Dd */ | |||
| 63 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) }, /* Dt */ | |||
| 64 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) }, /* Os */ | |||
| 65 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sh */ | |||
| 66 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ss */ | |||
| 67 | { in_line_eoln, 0 }, /* Pp */ | |||
| 68 | { blk_part_imp, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* D1 */ | |||
| 69 | { blk_part_imp, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Dl */ | |||
| 70 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bd */ | |||
| 71 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ed */ | |||
| 72 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bl */ | |||
| 73 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* El */ | |||
| 74 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* It */ | |||
| 75 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ad */ | |||
| 76 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* An */ | |||
| 77 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 78 | MDOC_IGNDELIM(1 << 4) | MDOC_JOIN(1 << 5) }, /* Ap */ | |||
| 79 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ar */ | |||
| 80 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Cd */ | |||
| 81 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Cm */ | |||
| 82 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Dv */ | |||
| 83 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Er */ | |||
| 84 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ev */ | |||
| 85 | { in_line_eoln, 0 }, /* Ex */ | |||
| 86 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fa */ | |||
| 87 | { in_line_eoln, 0 }, /* Fd */ | |||
| 88 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fl */ | |||
| 89 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fn */ | |||
| 90 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ft */ | |||
| 91 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ic */ | |||
| 92 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* In */ | |||
| 93 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Li */ | |||
| 94 | { blk_full, MDOC_JOIN(1 << 5) }, /* Nd */ | |||
| 95 | { ctx_synopsis, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Nm */ | |||
| 96 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Op */ | |||
| 97 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ot */ | |||
| 98 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Pa */ | |||
| 99 | { in_line_eoln, 0 }, /* Rv */ | |||
| 100 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* St */ | |||
| 101 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Va */ | |||
| 102 | { ctx_synopsis, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Vt */ | |||
| 103 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Xr */ | |||
| 104 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %A */ | |||
| 105 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %B */ | |||
| 106 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %D */ | |||
| 107 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %I */ | |||
| 108 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %J */ | |||
| 109 | { in_line_eoln, 0 }, /* %N */ | |||
| 110 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %O */ | |||
| 111 | { in_line_eoln, 0 }, /* %P */ | |||
| 112 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %R */ | |||
| 113 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %T */ | |||
| 114 | { in_line_eoln, 0 }, /* %V */ | |||
| 115 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 116 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ac */ | |||
| 117 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 118 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ao */ | |||
| 119 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Aq */ | |||
| 120 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* At */ | |||
| 121 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 122 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bc */ | |||
| 123 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bf */ | |||
| 124 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 125 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bo */ | |||
| 126 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Bq */ | |||
| 127 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Bsx */ | |||
| 128 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Bx */ | |||
| 129 | { in_line_eoln, 0 }, /* Db */ | |||
| 130 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 131 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Dc */ | |||
| 132 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 133 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Do */ | |||
| 134 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Dq */ | |||
| 135 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Ec */ | |||
| 136 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ef */ | |||
| 137 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Em */ | |||
| 138 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Eo */ | |||
| 139 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fx */ | |||
| 140 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ms */ | |||
| 141 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* No */ | |||
| 142 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 143 | MDOC_IGNDELIM(1 << 4) | MDOC_JOIN(1 << 5) }, /* Ns */ | |||
| 144 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Nx */ | |||
| 145 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ox */ | |||
| 146 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 147 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Pc */ | |||
| 148 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_IGNDELIM(1 << 4) }, /* Pf */ | |||
| 149 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 150 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Po */ | |||
| 151 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Pq */ | |||
| 152 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 153 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Qc */ | |||
| 154 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ql */ | |||
| 155 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 156 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Qo */ | |||
| 157 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Qq */ | |||
| 158 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Re */ | |||
| 159 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Rs */ | |||
| 160 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 161 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Sc */ | |||
| 162 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 163 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* So */ | |||
| 164 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sq */ | |||
| 165 | { in_line_argn, 0 }, /* Sm */ | |||
| 166 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sx */ | |||
| 167 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sy */ | |||
| 168 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Tn */ | |||
| 169 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ux */ | |||
| 170 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Xc */ | |||
| 171 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Xo */ | |||
| 172 | { blk_full, MDOC_EXPLICIT(1 << 2) | MDOC_CALLABLE(1 << 0) }, /* Fo */ | |||
| 173 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 174 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Fc */ | |||
| 175 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 176 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Oo */ | |||
| 177 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 178 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Oc */ | |||
| 179 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bk */ | |||
| 180 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ek */ | |||
| 181 | { in_line_eoln, 0 }, /* Bt */ | |||
| 182 | { in_line_eoln, 0 }, /* Hf */ | |||
| 183 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fr */ | |||
| 184 | { in_line_eoln, 0 }, /* Ud */ | |||
| 185 | { in_line, 0 }, /* Lb */ | |||
| 186 | { in_line_eoln, 0 }, /* Lp */ | |||
| 187 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Lk */ | |||
| 188 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Mt */ | |||
| 189 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Brq */ | |||
| 190 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 191 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bro */ | |||
| 192 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
| 193 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Brc */ | |||
| 194 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %C */ | |||
| 195 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Es */ | |||
| 196 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* En */ | |||
| 197 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Dx */ | |||
| 198 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %Q */ | |||
| 199 | { in_line_eoln, 0 }, /* %U */ | |||
| 200 | { phrase_ta, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ta */ | |||
| 201 | { in_line_eoln, 0 }, /* Tg */ | |||
| 202 | }; | |||
| 203 | ||||
| 204 | ||||
| 205 | const struct mdoc_macro * | |||
| 206 | mdoc_macro(enum roff_tok tok) | |||
| 207 | { | |||
| 208 | assert(tok >= MDOC_Dd && tok < MDOC_MAX)((tok >= MDOC_Dd && tok < MDOC_MAX) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c", 208, __func__ , "tok >= MDOC_Dd && tok < MDOC_MAX")); | |||
| 209 | return mdoc_macros + (tok - MDOC_Dd); | |||
| 210 | } | |||
| 211 | ||||
| 212 | /* | |||
| 213 | * This is called at the end of parsing. It must traverse up the tree, | |||
| 214 | * closing out open [implicit] scopes. Obviously, open explicit scopes | |||
| 215 | * are errors. | |||
| 216 | */ | |||
| 217 | void | |||
| 218 | mdoc_endparse(struct roff_man *mdoc) | |||
| 219 | { | |||
| 220 | struct roff_node *n; | |||
| 221 | ||||
| 222 | /* Scan for open explicit scopes. */ | |||
| 223 | ||||
| 224 | n = mdoc->last->flags & NODE_VALID(1 << 0) ? | |||
| 225 | mdoc->last->parent : mdoc->last; | |||
| 226 | ||||
| 227 | for ( ; n; n = n->parent) | |||
| 228 | if (n->type == ROFFT_BLOCK && | |||
| 229 | mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) | |||
| 230 | mandoc_msg(MANDOCERR_BLK_NOEND, | |||
| 231 | n->line, n->pos, "%s", roff_name[n->tok]); | |||
| 232 | ||||
| 233 | /* Rewind to the first. */ | |||
| 234 | ||||
| 235 | rew_last(mdoc, mdoc->meta.first); | |||
| 236 | } | |||
| 237 | ||||
| 238 | /* | |||
| 239 | * Look up the macro at *p called by "from", | |||
| 240 | * or as a line macro if from == TOKEN_NONE. | |||
| 241 | */ | |||
| 242 | static int | |||
| 243 | lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p) | |||
| 244 | { | |||
| 245 | enum roff_tok res; | |||
| 246 | ||||
| 247 | if (mdoc->flags & MDOC_PHRASEQF(1 << 13)) { | |||
| 248 | mdoc->flags &= ~MDOC_PHRASEQF(1 << 13); | |||
| 249 | return TOKEN_NONE; | |||
| 250 | } | |||
| 251 | if (from == TOKEN_NONE || mdoc_macro(from)->flags & MDOC_PARSED(1 << 1)) { | |||
| 252 | res = roffhash_find(mdoc->mdocmac, p, 0); | |||
| 253 | if (res != TOKEN_NONE) { | |||
| 254 | if (mdoc_macro(res)->flags & MDOC_CALLABLE(1 << 0)) | |||
| 255 | return res; | |||
| 256 | mandoc_msg(MANDOCERR_MACRO_CALL, line, ppos, "%s", p); | |||
| 257 | } | |||
| 258 | } | |||
| 259 | return TOKEN_NONE; | |||
| 260 | } | |||
| 261 | ||||
| 262 | /* | |||
| 263 | * Rewind up to and including a specific node. | |||
| 264 | */ | |||
| 265 | static void | |||
| 266 | rew_last(struct roff_man *mdoc, const struct roff_node *to) | |||
| 267 | { | |||
| 268 | ||||
| 269 | if (to->flags & NODE_VALID(1 << 0)) | |||
| ||||
| 270 | return; | |||
| 271 | ||||
| 272 | while (mdoc->last != to) { | |||
| 273 | mdoc_state(mdoc, mdoc->last); | |||
| 274 | mdoc->last->flags |= NODE_VALID(1 << 0) | NODE_ENDED(1 << 1); | |||
| 275 | mdoc->last = mdoc->last->parent; | |||
| 276 | } | |||
| 277 | mdoc_state(mdoc, mdoc->last); | |||
| 278 | mdoc->last->flags |= NODE_VALID(1 << 0) | NODE_ENDED(1 << 1); | |||
| 279 | mdoc->next = ROFF_NEXT_SIBLING; | |||
| 280 | } | |||
| 281 | ||||
| 282 | /* | |||
| 283 | * Rewind up to a specific block, including all blocks that broke it. | |||
| 284 | */ | |||
| 285 | static void | |||
| 286 | rew_pending(struct roff_man *mdoc, const struct roff_node *n) | |||
| 287 | { | |||
| 288 | ||||
| 289 | for (;;) { | |||
| 290 | rew_last(mdoc, n); | |||
| 291 | ||||
| 292 | if (mdoc->last == n) { | |||
| 293 | switch (n->type) { | |||
| 294 | case ROFFT_HEAD: | |||
| 295 | roff_body_alloc(mdoc, n->line, n->pos, | |||
| 296 | n->tok); | |||
| 297 | if (n->tok == MDOC_Ss) | |||
| 298 | mdoc->flags &= ~ROFF_NONOFILL(1 << 16); | |||
| 299 | break; | |||
| 300 | case ROFFT_BLOCK: | |||
| 301 | break; | |||
| 302 | default: | |||
| 303 | return; | |||
| 304 | } | |||
| 305 | if ( ! (n->flags & NODE_BROKEN(1 << 2))) | |||
| 306 | return; | |||
| 307 | } else | |||
| 308 | n = mdoc->last; | |||
| 309 | ||||
| 310 | for (;;) { | |||
| 311 | if ((n = n->parent) == NULL((void *)0)) | |||
| 312 | return; | |||
| 313 | ||||
| 314 | if (n->type == ROFFT_BLOCK || | |||
| 315 | n->type == ROFFT_HEAD) { | |||
| 316 | if (n->flags & NODE_ENDED(1 << 1)) | |||
| 317 | break; | |||
| 318 | else | |||
| 319 | return; | |||
| 320 | } | |||
| 321 | } | |||
| 322 | } | |||
| 323 | } | |||
| 324 | ||||
| 325 | /* | |||
| 326 | * For a block closing macro, return the corresponding opening one. | |||
| 327 | * Otherwise, return the macro itself. | |||
| 328 | */ | |||
| 329 | static enum roff_tok | |||
| 330 | rew_alt(enum roff_tok tok) | |||
| 331 | { | |||
| 332 | switch (tok) { | |||
| 333 | case MDOC_Ac: | |||
| 334 | return MDOC_Ao; | |||
| 335 | case MDOC_Bc: | |||
| 336 | return MDOC_Bo; | |||
| 337 | case MDOC_Brc: | |||
| 338 | return MDOC_Bro; | |||
| 339 | case MDOC_Dc: | |||
| 340 | return MDOC_Do; | |||
| 341 | case MDOC_Ec: | |||
| 342 | return MDOC_Eo; | |||
| 343 | case MDOC_Ed: | |||
| 344 | return MDOC_Bd; | |||
| 345 | case MDOC_Ef: | |||
| 346 | return MDOC_Bf; | |||
| 347 | case MDOC_Ek: | |||
| 348 | return MDOC_Bk; | |||
| 349 | case MDOC_El: | |||
| 350 | return MDOC_Bl; | |||
| 351 | case MDOC_Fc: | |||
| 352 | return MDOC_Fo; | |||
| 353 | case MDOC_Oc: | |||
| 354 | return MDOC_Oo; | |||
| 355 | case MDOC_Pc: | |||
| 356 | return MDOC_Po; | |||
| 357 | case MDOC_Qc: | |||
| 358 | return MDOC_Qo; | |||
| 359 | case MDOC_Re: | |||
| 360 | return MDOC_Rs; | |||
| 361 | case MDOC_Sc: | |||
| 362 | return MDOC_So; | |||
| 363 | case MDOC_Xc: | |||
| 364 | return MDOC_Xo; | |||
| 365 | default: | |||
| 366 | return tok; | |||
| 367 | } | |||
| 368 | } | |||
| 369 | ||||
| 370 | static void | |||
| 371 | rew_elem(struct roff_man *mdoc, enum roff_tok tok) | |||
| 372 | { | |||
| 373 | struct roff_node *n; | |||
| 374 | ||||
| 375 | n = mdoc->last; | |||
| 376 | if (n->type != ROFFT_ELEM) | |||
| 377 | n = n->parent; | |||
| 378 | assert(n->type == ROFFT_ELEM)((n->type == ROFFT_ELEM) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 378, __func__, "n->type == ROFFT_ELEM")); | |||
| 379 | assert(tok == n->tok)((tok == n->tok) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 379, __func__, "tok == n->tok")); | |||
| 380 | rew_last(mdoc, n); | |||
| 381 | } | |||
| 382 | ||||
| 383 | static void | |||
| 384 | break_intermediate(struct roff_node *n, struct roff_node *breaker) | |||
| 385 | { | |||
| 386 | if (n != breaker && | |||
| 387 | n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD && | |||
| 388 | (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) | |||
| 389 | n = n->parent; | |||
| 390 | while (n != breaker) { | |||
| 391 | if ( ! (n->flags & NODE_VALID(1 << 0))) | |||
| 392 | n->flags |= NODE_BROKEN(1 << 2); | |||
| 393 | n = n->parent; | |||
| 394 | } | |||
| 395 | } | |||
| 396 | ||||
| 397 | /* | |||
| 398 | * If there is an open sub-block of the target requiring | |||
| 399 | * explicit close-out, postpone closing out the target until | |||
| 400 | * the rew_pending() call closing out the sub-block. | |||
| 401 | */ | |||
| 402 | static int | |||
| 403 | find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos, | |||
| 404 | struct roff_node *target) | |||
| 405 | { | |||
| 406 | struct roff_node *n; | |||
| 407 | int irc; | |||
| 408 | ||||
| 409 | if (target->flags & NODE_VALID(1 << 0)) | |||
| 410 | return 0; | |||
| 411 | ||||
| 412 | irc = 0; | |||
| 413 | for (n = mdoc->last; n != NULL((void *)0) && n != target; n = n->parent) { | |||
| 414 | if (n->flags & NODE_ENDED(1 << 1)) | |||
| 415 | continue; | |||
| 416 | if (n->type == ROFFT_BLOCK && | |||
| 417 | mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) { | |||
| 418 | irc = 1; | |||
| 419 | break_intermediate(mdoc->last, target); | |||
| 420 | if (target->type == ROFFT_HEAD) | |||
| 421 | target->flags |= NODE_ENDED(1 << 1); | |||
| 422 | else if ( ! (target->flags & NODE_ENDED(1 << 1))) { | |||
| 423 | mandoc_msg(MANDOCERR_BLK_NEST, | |||
| 424 | line, ppos, "%s breaks %s", | |||
| 425 | roff_name[tok], roff_name[n->tok]); | |||
| 426 | mdoc_endbody_alloc(mdoc, line, ppos, | |||
| 427 | tok, target); | |||
| 428 | } | |||
| 429 | } | |||
| 430 | } | |||
| 431 | return irc; | |||
| 432 | } | |||
| 433 | ||||
| 434 | /* | |||
| 435 | * Allocate a word and check whether it's punctuation or not. | |||
| 436 | * Punctuation consists of those tokens found in mdoc_isdelim(). | |||
| 437 | */ | |||
| 438 | static void | |||
| 439 | dword(struct roff_man *mdoc, int line, int col, const char *p, | |||
| 440 | enum mdelim d, int may_append) | |||
| 441 | { | |||
| 442 | ||||
| 443 | if (d == DELIM_MAX) | |||
| 444 | d = mdoc_isdelim(p); | |||
| 445 | ||||
| 446 | if (may_append && | |||
| 447 | ! (mdoc->flags & (MDOC_SYNOPSIS(1 << 7) | MDOC_KEEP(1 << 8) | MDOC_SMOFF(1 << 9))) && | |||
| 448 | d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT && | |||
| 449 | mdoc_isdelim(mdoc->last->string) == DELIM_NONE) { | |||
| 450 | roff_word_append(mdoc, p); | |||
| 451 | return; | |||
| 452 | } | |||
| 453 | ||||
| 454 | roff_word_alloc(mdoc, line, col, p); | |||
| 455 | ||||
| 456 | /* | |||
| 457 | * If the word consists of a bare delimiter, | |||
| 458 | * flag the new node accordingly, | |||
| 459 | * unless doing so was vetoed by the invoking macro. | |||
| 460 | * Always clear the veto, it is only valid for one word. | |||
| 461 | */ | |||
| 462 | ||||
| 463 | if (d == DELIM_OPEN) | |||
| 464 | mdoc->last->flags |= NODE_DELIMO(1 << 4); | |||
| 465 | else if (d == DELIM_CLOSE && | |||
| 466 | ! (mdoc->flags & MDOC_NODELIMC(1 << 10)) && | |||
| 467 | mdoc->last->parent->tok != MDOC_Fd) | |||
| 468 | mdoc->last->flags |= NODE_DELIMC(1 << 5); | |||
| 469 | mdoc->flags &= ~MDOC_NODELIMC(1 << 10); | |||
| 470 | } | |||
| 471 | ||||
| 472 | static void | |||
| 473 | append_delims(struct roff_man *mdoc, int line, int *pos, char *buf) | |||
| 474 | { | |||
| 475 | char *p; | |||
| 476 | int la; | |||
| 477 | enum margserr ac; | |||
| 478 | ||||
| 479 | if (buf[*pos] == '\0') | |||
| 480 | return; | |||
| 481 | ||||
| 482 | for (;;) { | |||
| 483 | la = *pos; | |||
| 484 | ac = mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p); | |||
| 485 | if (ac == ARGS_EOLN) | |||
| 486 | break; | |||
| 487 | dword(mdoc, line, la, p, DELIM_MAX, 1); | |||
| 488 | ||||
| 489 | /* | |||
| 490 | * If we encounter end-of-sentence symbols, then trigger | |||
| 491 | * the double-space. | |||
| 492 | * | |||
| 493 | * XXX: it's easy to allow this to propagate outward to | |||
| 494 | * the last symbol, such that `. )' will cause the | |||
| 495 | * correct double-spacing. However, (1) groff isn't | |||
| 496 | * smart enough to do this and (2) it would require | |||
| 497 | * knowing which symbols break this behaviour, for | |||
| 498 | * example, `. ;' shouldn't propagate the double-space. | |||
| 499 | */ | |||
| 500 | ||||
| 501 | if (mandoc_eos(p, strlen(p))) | |||
| 502 | mdoc->last->flags |= NODE_EOS(1 << 6); | |||
| 503 | if (ac == ARGS_ALLOC) | |||
| 504 | free(p); | |||
| 505 | } | |||
| 506 | } | |||
| 507 | ||||
| 508 | /* | |||
| 509 | * Parse one word. | |||
| 510 | * If it is a macro, call it and return 1. | |||
| 511 | * Otherwise, allocate it and return 0. | |||
| 512 | */ | |||
| 513 | static int | |||
| 514 | macro_or_word(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf, char *p, int parsed) | |||
| 515 | { | |||
| 516 | int ntok; | |||
| 517 | ||||
| 518 | ntok = buf[ppos] == '"' || parsed == 0 || | |||
| 519 | mdoc->flags & MDOC_PHRASELIT(1 << 5) ? TOKEN_NONE : | |||
| 520 | lookup(mdoc, tok, line, ppos, p); | |||
| 521 | ||||
| 522 | if (ntok == TOKEN_NONE) { | |||
| 523 | dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE || | |||
| 524 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
| 525 | return 0; | |||
| 526 | } else { | |||
| 527 | if (tok != TOKEN_NONE && | |||
| 528 | mdoc_macro(tok)->fp == in_line_eoln) | |||
| 529 | rew_elem(mdoc, tok); | |||
| 530 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, ppos, pos, buf); | |||
| 531 | if (tok == TOKEN_NONE) | |||
| 532 | append_delims(mdoc, line, pos, buf); | |||
| 533 | return 1; | |||
| 534 | } | |||
| 535 | } | |||
| 536 | ||||
| 537 | /* | |||
| 538 | * Close out block partial/full explicit. | |||
| 539 | */ | |||
| 540 | static void | |||
| 541 | blk_exp_close(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 542 | { | |||
| 543 | struct roff_node *body; /* Our own body. */ | |||
| 544 | struct roff_node *endbody; /* Our own end marker. */ | |||
| 545 | struct roff_node *itblk; /* An It block starting later. */ | |||
| 546 | struct roff_node *later; /* A sub-block starting later. */ | |||
| 547 | struct roff_node *n; /* Search back to our block. */ | |||
| 548 | struct roff_node *target; /* For find_pending(). */ | |||
| 549 | ||||
| 550 | int j, lastarg, maxargs, nl, pending; | |||
| 551 | enum margserr ac; | |||
| 552 | enum roff_tok atok, ntok; | |||
| 553 | char *p; | |||
| 554 | ||||
| 555 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
| 556 | ||||
| 557 | switch (tok) { | |||
| 558 | case MDOC_Ec: | |||
| 559 | maxargs = 1; | |||
| 560 | break; | |||
| 561 | case MDOC_Ek: | |||
| 562 | mdoc->flags &= ~MDOC_KEEP(1 << 8); | |||
| 563 | /* FALLTHROUGH */ | |||
| 564 | default: | |||
| 565 | maxargs = 0; | |||
| 566 | break; | |||
| 567 | } | |||
| 568 | ||||
| 569 | /* Search backwards for the beginning of our own body. */ | |||
| 570 | ||||
| 571 | atok = rew_alt(tok); | |||
| 572 | body = NULL((void *)0); | |||
| 573 | for (n = mdoc->last; n; n = n->parent) { | |||
| 574 | if (n->flags & NODE_ENDED(1 << 1) || n->tok != atok || | |||
| 575 | n->type != ROFFT_BODY || n->end != ENDBODY_NOT) | |||
| 576 | continue; | |||
| 577 | body = n; | |||
| 578 | break; | |||
| 579 | } | |||
| 580 | ||||
| 581 | /* | |||
| 582 | * Search backwards for beginnings of blocks, | |||
| 583 | * both of our own and of pending sub-blocks. | |||
| 584 | */ | |||
| 585 | ||||
| 586 | endbody = itblk = later = NULL((void *)0); | |||
| 587 | for (n = mdoc->last; n; n = n->parent) { | |||
| 588 | if (n->flags & NODE_ENDED(1 << 1)) | |||
| 589 | continue; | |||
| 590 | ||||
| 591 | /* | |||
| 592 | * Mismatching end macros can never break anything | |||
| 593 | * and we only care about the breaking of BLOCKs. | |||
| 594 | */ | |||
| 595 | ||||
| 596 | if (body == NULL((void *)0) || n->type != ROFFT_BLOCK) | |||
| 597 | continue; | |||
| 598 | ||||
| 599 | /* | |||
| 600 | * SYNOPSIS name blocks can not be broken themselves, | |||
| 601 | * but they do get broken together with a broken child. | |||
| 602 | */ | |||
| 603 | ||||
| 604 | if (n->tok == MDOC_Nm) { | |||
| 605 | if (later != NULL((void *)0)) | |||
| 606 | n->flags |= NODE_BROKEN(1 << 2) | NODE_ENDED(1 << 1); | |||
| 607 | continue; | |||
| 608 | } | |||
| 609 | ||||
| 610 | if (n->tok == MDOC_It) { | |||
| 611 | itblk = n; | |||
| 612 | continue; | |||
| 613 | } | |||
| 614 | ||||
| 615 | if (atok == n->tok) { | |||
| 616 | ||||
| 617 | /* | |||
| 618 | * Found the start of our own block. | |||
| 619 | * When there is no pending sub block, | |||
| 620 | * just proceed to closing out. | |||
| 621 | */ | |||
| 622 | ||||
| 623 | if (later == NULL((void *)0) || | |||
| 624 | (tok == MDOC_El && itblk == NULL((void *)0))) | |||
| 625 | break; | |||
| 626 | ||||
| 627 | /* | |||
| 628 | * When there is a pending sub block, postpone | |||
| 629 | * closing out the current block until the | |||
| 630 | * rew_pending() closing out the sub-block. | |||
| 631 | * Mark the place where the formatting - but not | |||
| 632 | * the scope - of the current block ends. | |||
| 633 | */ | |||
| 634 | ||||
| 635 | mandoc_msg(MANDOCERR_BLK_NEST, | |||
| 636 | line, ppos, "%s breaks %s", | |||
| 637 | roff_name[atok], roff_name[later->tok]); | |||
| 638 | ||||
| 639 | endbody = mdoc_endbody_alloc(mdoc, line, ppos, | |||
| 640 | atok, body); | |||
| 641 | ||||
| 642 | if (tok == MDOC_El) | |||
| 643 | itblk->flags |= NODE_ENDED(1 << 1) | NODE_BROKEN(1 << 2); | |||
| 644 | ||||
| 645 | /* | |||
| 646 | * If a block closing macro taking arguments | |||
| 647 | * breaks another block, put the arguments | |||
| 648 | * into the end marker. | |||
| 649 | */ | |||
| 650 | ||||
| 651 | if (maxargs) | |||
| 652 | mdoc->next = ROFF_NEXT_CHILD; | |||
| 653 | break; | |||
| 654 | } | |||
| 655 | ||||
| 656 | /* | |||
| 657 | * Explicit blocks close out description lines, but | |||
| 658 | * even those can get broken together with a child. | |||
| 659 | */ | |||
| 660 | ||||
| 661 | if (n->tok == MDOC_Nd) { | |||
| 662 | if (later != NULL((void *)0)) | |||
| 663 | n->flags |= NODE_BROKEN(1 << 2) | NODE_ENDED(1 << 1); | |||
| 664 | else | |||
| 665 | rew_last(mdoc, n); | |||
| 666 | continue; | |||
| 667 | } | |||
| 668 | ||||
| 669 | /* Breaking an open sub block. */ | |||
| 670 | ||||
| 671 | break_intermediate(mdoc->last, body); | |||
| 672 | n->flags |= NODE_BROKEN(1 << 2); | |||
| 673 | if (later == NULL((void *)0)) | |||
| 674 | later = n; | |||
| 675 | } | |||
| 676 | ||||
| 677 | if (body == NULL((void *)0)) { | |||
| 678 | mandoc_msg(MANDOCERR_BLK_NOTOPEN, line, ppos, | |||
| 679 | "%s", roff_name[tok]); | |||
| 680 | if (maxargs && endbody == NULL((void *)0)) { | |||
| 681 | /* | |||
| 682 | * Stray .Ec without previous .Eo: | |||
| 683 | * Break the output line, keep the arguments. | |||
| 684 | */ | |||
| 685 | roff_elem_alloc(mdoc, line, ppos, ROFF_br); | |||
| 686 | rew_elem(mdoc, ROFF_br); | |||
| 687 | } | |||
| 688 | } else if (endbody == NULL((void *)0)) { | |||
| 689 | rew_last(mdoc, body); | |||
| 690 | if (maxargs) | |||
| 691 | mdoc_tail_alloc(mdoc, line, ppos, atok); | |||
| 692 | } | |||
| 693 | ||||
| 694 | if ((mdoc_macro(tok)->flags & MDOC_PARSED(1 << 1)) == 0) { | |||
| 695 | if (buf[*pos] != '\0') | |||
| 696 | mandoc_msg(MANDOCERR_ARG_SKIP, line, ppos, | |||
| 697 | "%s %s", roff_name[tok], buf + *pos); | |||
| 698 | if (endbody == NULL((void *)0) && n != NULL((void *)0)) | |||
| 699 | rew_pending(mdoc, n); | |||
| 700 | ||||
| 701 | /* | |||
| 702 | * Restore the fill mode that was set before the display. | |||
| 703 | * This needs to be done here rather than during validation | |||
| 704 | * such that subsequent nodes get the right flags. | |||
| 705 | */ | |||
| 706 | ||||
| 707 | if (tok == MDOC_Ed && body != NULL((void *)0)) { | |||
| 708 | if (body->flags & NODE_NOFILL(1 << 8)) | |||
| 709 | mdoc->flags |= ROFF_NOFILL(1 << 1); | |||
| 710 | else | |||
| 711 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
| 712 | } | |||
| 713 | return; | |||
| 714 | } | |||
| 715 | ||||
| 716 | if (endbody != NULL((void *)0)) | |||
| 717 | n = endbody; | |||
| 718 | ||||
| 719 | ntok = TOKEN_NONE; | |||
| 720 | for (j = 0; ; j++) { | |||
| 721 | lastarg = *pos; | |||
| 722 | ||||
| 723 | if (j == maxargs && n != NULL((void *)0)) | |||
| 724 | rew_last(mdoc, n); | |||
| 725 | ||||
| 726 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 727 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) | |||
| 728 | break; | |||
| 729 | ||||
| 730 | ntok = lookup(mdoc, tok, line, lastarg, p); | |||
| 731 | ||||
| 732 | if (ntok == TOKEN_NONE) { | |||
| 733 | dword(mdoc, line, lastarg, p, DELIM_MAX, | |||
| 734 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
| 735 | if (ac == ARGS_ALLOC) | |||
| 736 | free(p); | |||
| 737 | continue; | |||
| 738 | } | |||
| 739 | if (ac == ARGS_ALLOC) | |||
| 740 | free(p); | |||
| 741 | ||||
| 742 | if (n != NULL((void *)0)) | |||
| 743 | rew_last(mdoc, n); | |||
| 744 | mdoc->flags &= ~MDOC_NEWLINE(1 << 3); | |||
| 745 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, lastarg, pos, buf); | |||
| 746 | break; | |||
| 747 | } | |||
| 748 | ||||
| 749 | if (n != NULL((void *)0)) { | |||
| 750 | pending = 0; | |||
| 751 | if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN(1 << 2)) { | |||
| 752 | target = n; | |||
| 753 | do | |||
| 754 | target = target->parent; | |||
| 755 | while ( ! (target->flags & NODE_ENDED(1 << 1))); | |||
| 756 | pending = find_pending(mdoc, ntok, line, ppos, target); | |||
| 757 | } | |||
| 758 | if ( ! pending) | |||
| 759 | rew_pending(mdoc, n); | |||
| 760 | } | |||
| 761 | if (nl) | |||
| 762 | append_delims(mdoc, line, pos, buf); | |||
| 763 | } | |||
| 764 | ||||
| 765 | static void | |||
| 766 | in_line(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 767 | { | |||
| 768 | int la, scope, cnt, firstarg, mayopen, nc, nl; | |||
| 769 | enum roff_tok ntok; | |||
| 770 | enum margserr ac; | |||
| 771 | enum mdelim d; | |||
| 772 | struct mdoc_arg *arg; | |||
| 773 | char *p; | |||
| 774 | ||||
| 775 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
| 776 | ||||
| 777 | /* | |||
| 778 | * Whether we allow ignored elements (those without content, | |||
| 779 | * usually because of reserved words) to squeak by. | |||
| 780 | */ | |||
| 781 | ||||
| 782 | switch (tok) { | |||
| 783 | case MDOC_An: | |||
| 784 | case MDOC_Ar: | |||
| 785 | case MDOC_Fl: | |||
| 786 | case MDOC_Mt: | |||
| 787 | case MDOC_Nm: | |||
| 788 | case MDOC_Pa: | |||
| 789 | nc = 1; | |||
| 790 | break; | |||
| 791 | default: | |||
| 792 | nc = 0; | |||
| 793 | break; | |||
| 794 | } | |||
| 795 | ||||
| 796 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
| 797 | ||||
| 798 | d = DELIM_NONE; | |||
| 799 | firstarg = 1; | |||
| 800 | mayopen = 1; | |||
| 801 | for (cnt = scope = 0;; ) { | |||
| 802 | la = *pos; | |||
| 803 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 804 | ||||
| 805 | /* | |||
| 806 | * At the end of a macro line, | |||
| 807 | * opening delimiters do not suppress spacing. | |||
| 808 | */ | |||
| 809 | ||||
| 810 | if (ac == ARGS_EOLN) { | |||
| 811 | if (d == DELIM_OPEN) | |||
| 812 | mdoc->last->flags &= ~NODE_DELIMO(1 << 4); | |||
| 813 | break; | |||
| 814 | } | |||
| 815 | ||||
| 816 | /* | |||
| 817 | * The rest of the macro line is only punctuation, | |||
| 818 | * to be handled by append_delims(). | |||
| 819 | * If there were no other arguments, | |||
| 820 | * do not allow the first one to suppress spacing, | |||
| 821 | * even if it turns out to be a closing one. | |||
| 822 | */ | |||
| 823 | ||||
| 824 | if (ac == ARGS_PUNCT) { | |||
| 825 | if (cnt == 0 && (nc == 0 || tok == MDOC_An)) | |||
| 826 | mdoc->flags |= MDOC_NODELIMC(1 << 10); | |||
| 827 | break; | |||
| 828 | } | |||
| 829 | ||||
| 830 | ntok = (tok == MDOC_Fn && !cnt) ? | |||
| 831 | TOKEN_NONE : lookup(mdoc, tok, line, la, p); | |||
| 832 | ||||
| 833 | /* | |||
| 834 | * In this case, we've located a submacro and must | |||
| 835 | * execute it. Close out scope, if open. If no | |||
| 836 | * elements have been generated, either create one (nc) | |||
| 837 | * or raise a warning. | |||
| 838 | */ | |||
| 839 | ||||
| 840 | if (ntok != TOKEN_NONE) { | |||
| 841 | if (scope) | |||
| 842 | rew_elem(mdoc, tok); | |||
| 843 | if (nc && ! cnt) { | |||
| 844 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 845 | rew_last(mdoc, mdoc->last); | |||
| 846 | } else if ( ! nc && ! cnt) { | |||
| 847 | mdoc_argv_free(arg); | |||
| 848 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
| 849 | line, ppos, "%s", roff_name[tok]); | |||
| 850 | } | |||
| 851 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, | |||
| 852 | line, la, pos, buf); | |||
| 853 | if (nl) | |||
| 854 | append_delims(mdoc, line, pos, buf); | |||
| 855 | if (ac == ARGS_ALLOC) | |||
| 856 | free(p); | |||
| 857 | return; | |||
| 858 | } | |||
| 859 | ||||
| 860 | /* | |||
| 861 | * Handle punctuation. Set up our scope, if a word; | |||
| 862 | * rewind the scope, if a delimiter; then append the word. | |||
| 863 | */ | |||
| 864 | ||||
| 865 | if ((d = mdoc_isdelim(p)) != DELIM_NONE) { | |||
| 866 | /* | |||
| 867 | * If we encounter closing punctuation, no word | |||
| 868 | * has been emitted, no scope is open, and we're | |||
| 869 | * allowed to have an empty element, then start | |||
| 870 | * a new scope. | |||
| 871 | */ | |||
| 872 | if ((d == DELIM_CLOSE || | |||
| 873 | (d == DELIM_MIDDLE && tok == MDOC_Fl)) && | |||
| 874 | !cnt && !scope && nc && mayopen) { | |||
| 875 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 876 | scope = 1; | |||
| 877 | cnt++; | |||
| 878 | if (tok == MDOC_Nm) | |||
| 879 | mayopen = 0; | |||
| 880 | } | |||
| 881 | /* | |||
| 882 | * Close out our scope, if one is open, before | |||
| 883 | * any punctuation. | |||
| 884 | */ | |||
| 885 | if (scope && tok != MDOC_Lk) { | |||
| 886 | rew_elem(mdoc, tok); | |||
| 887 | scope = 0; | |||
| 888 | if (tok == MDOC_Fn) | |||
| 889 | mayopen = 0; | |||
| 890 | } | |||
| 891 | } else if (mayopen && !scope) { | |||
| 892 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 893 | scope = 1; | |||
| 894 | cnt++; | |||
| 895 | } | |||
| 896 | ||||
| 897 | dword(mdoc, line, la, p, d, | |||
| 898 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
| 899 | ||||
| 900 | if (ac == ARGS_ALLOC) | |||
| 901 | free(p); | |||
| 902 | ||||
| 903 | /* | |||
| 904 | * If the first argument is a closing delimiter, | |||
| 905 | * do not suppress spacing before it. | |||
| 906 | */ | |||
| 907 | ||||
| 908 | if (firstarg && d == DELIM_CLOSE && !nc) | |||
| 909 | mdoc->last->flags &= ~NODE_DELIMC(1 << 5); | |||
| 910 | firstarg = 0; | |||
| 911 | ||||
| 912 | /* | |||
| 913 | * `Fl' macros have their scope re-opened with each new | |||
| 914 | * word so that the `-' can be added to each one without | |||
| 915 | * having to parse out spaces. | |||
| 916 | */ | |||
| 917 | if (scope && tok == MDOC_Fl) { | |||
| 918 | rew_elem(mdoc, tok); | |||
| 919 | scope = 0; | |||
| 920 | } | |||
| 921 | } | |||
| 922 | ||||
| 923 | if (scope && tok != MDOC_Lk) { | |||
| 924 | rew_elem(mdoc, tok); | |||
| 925 | scope = 0; | |||
| 926 | } | |||
| 927 | ||||
| 928 | /* | |||
| 929 | * If no elements have been collected and we're allowed to have | |||
| 930 | * empties (nc), open a scope and close it out. Otherwise, | |||
| 931 | * raise a warning. | |||
| 932 | */ | |||
| 933 | ||||
| 934 | if ( ! cnt) { | |||
| 935 | if (nc) { | |||
| 936 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 937 | rew_last(mdoc, mdoc->last); | |||
| 938 | } else { | |||
| 939 | mdoc_argv_free(arg); | |||
| 940 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
| 941 | line, ppos, "%s", roff_name[tok]); | |||
| 942 | } | |||
| 943 | } | |||
| 944 | if (nl) | |||
| 945 | append_delims(mdoc, line, pos, buf); | |||
| 946 | if (scope) | |||
| 947 | rew_elem(mdoc, tok); | |||
| 948 | } | |||
| 949 | ||||
| 950 | static void | |||
| 951 | blk_full(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 952 | { | |||
| 953 | struct mdoc_arg *arg; | |||
| 954 | struct roff_node *blk; /* Our own or a broken block. */ | |||
| 955 | struct roff_node *head; /* Our own head. */ | |||
| 956 | struct roff_node *body; /* Our own body. */ | |||
| 957 | struct roff_node *n; | |||
| 958 | char *p; | |||
| 959 | size_t iarg; | |||
| 960 | int done, la, nl, parsed; | |||
| 961 | enum margserr ac, lac; | |||
| 962 | ||||
| 963 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
| 964 | ||||
| 965 | if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { | |||
| 966 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
| 967 | line, ppos, "%s", roff_name[tok]); | |||
| 968 | return; | |||
| 969 | } | |||
| 970 | ||||
| 971 | if ((mdoc_macro(tok)->flags & MDOC_EXPLICIT(1 << 2)) == 0) { | |||
| 972 | ||||
| 973 | /* Here, tok is one of Sh Ss Nm Nd It. */ | |||
| 974 | ||||
| 975 | blk = NULL((void *)0); | |||
| 976 | for (n = mdoc->last; n != NULL((void *)0); n = n->parent) { | |||
| 977 | if (n->flags & NODE_ENDED(1 << 1)) { | |||
| 978 | if ( ! (n->flags & NODE_VALID(1 << 0))) | |||
| 979 | n->flags |= NODE_BROKEN(1 << 2); | |||
| 980 | continue; | |||
| 981 | } | |||
| 982 | if (n->type != ROFFT_BLOCK) | |||
| 983 | continue; | |||
| 984 | ||||
| 985 | if (tok == MDOC_It && n->tok == MDOC_Bl) { | |||
| 986 | if (blk != NULL((void *)0)) { | |||
| 987 | mandoc_msg(MANDOCERR_BLK_BROKEN, | |||
| 988 | line, ppos, "It breaks %s", | |||
| 989 | roff_name[blk->tok]); | |||
| 990 | rew_pending(mdoc, blk); | |||
| 991 | } | |||
| 992 | break; | |||
| 993 | } | |||
| 994 | ||||
| 995 | if (mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) { | |||
| 996 | switch (tok) { | |||
| 997 | case MDOC_Sh: | |||
| 998 | case MDOC_Ss: | |||
| 999 | mandoc_msg(MANDOCERR_BLK_BROKEN, | |||
| 1000 | line, ppos, | |||
| 1001 | "%s breaks %s", roff_name[tok], | |||
| 1002 | roff_name[n->tok]); | |||
| 1003 | rew_pending(mdoc, n); | |||
| 1004 | n = mdoc->last; | |||
| 1005 | continue; | |||
| 1006 | case MDOC_It: | |||
| 1007 | /* Delay in case it's astray. */ | |||
| 1008 | blk = n; | |||
| 1009 | continue; | |||
| 1010 | default: | |||
| 1011 | break; | |||
| 1012 | } | |||
| 1013 | break; | |||
| 1014 | } | |||
| 1015 | ||||
| 1016 | /* Here, n is one of Sh Ss Nm Nd It. */ | |||
| 1017 | ||||
| 1018 | if (tok != MDOC_Sh && (n->tok == MDOC_Sh || | |||
| 1019 | (tok != MDOC_Ss && (n->tok == MDOC_Ss || | |||
| 1020 | (tok != MDOC_It && n->tok == MDOC_It))))) | |||
| 1021 | break; | |||
| 1022 | ||||
| 1023 | /* Item breaking an explicit block. */ | |||
| 1024 | ||||
| 1025 | if (blk != NULL((void *)0)) { | |||
| 1026 | mandoc_msg(MANDOCERR_BLK_BROKEN, line, ppos, | |||
| 1027 | "It breaks %s", roff_name[blk->tok]); | |||
| 1028 | rew_pending(mdoc, blk); | |||
| 1029 | blk = NULL((void *)0); | |||
| 1030 | } | |||
| 1031 | ||||
| 1032 | /* Close out prior implicit scopes. */ | |||
| 1033 | ||||
| 1034 | rew_pending(mdoc, n); | |||
| 1035 | } | |||
| 1036 | ||||
| 1037 | /* Skip items outside lists. */ | |||
| 1038 | ||||
| 1039 | if (tok == MDOC_It && (n == NULL((void *)0) || n->tok != MDOC_Bl)) { | |||
| 1040 | mandoc_msg(MANDOCERR_IT_STRAY, | |||
| 1041 | line, ppos, "It %s", buf + *pos); | |||
| 1042 | roff_elem_alloc(mdoc, line, ppos, ROFF_br); | |||
| 1043 | rew_elem(mdoc, ROFF_br); | |||
| 1044 | return; | |||
| 1045 | } | |||
| 1046 | } | |||
| 1047 | ||||
| 1048 | /* | |||
| 1049 | * This routine accommodates implicitly- and explicitly-scoped | |||
| 1050 | * macro openings. Implicit ones first close out prior scope | |||
| 1051 | * (seen above). Delay opening the head until necessary to | |||
| 1052 | * allow leading punctuation to print. Special consideration | |||
| 1053 | * for `It -column', which has phrase-part syntax instead of | |||
| 1054 | * regular child nodes. | |||
| 1055 | */ | |||
| 1056 | ||||
| 1057 | switch (tok) { | |||
| 1058 | case MDOC_Sh: | |||
| 1059 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
| 1060 | break; | |||
| 1061 | case MDOC_Ss: | |||
| 1062 | mdoc->flags |= ROFF_NONOFILL(1 << 16); | |||
| 1063 | break; | |||
| 1064 | default: | |||
| 1065 | break; | |||
| 1066 | } | |||
| 1067 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
| 1068 | blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg); | |||
| 1069 | head = body = NULL((void *)0); | |||
| 1070 | ||||
| 1071 | /* | |||
| 1072 | * Exception: Heads of `It' macros in `-diag' lists are not | |||
| 1073 | * parsed, even though `It' macros in general are parsed. | |||
| 1074 | */ | |||
| 1075 | ||||
| 1076 | parsed = tok != MDOC_It || | |||
| 1077 | mdoc->last->parent->tok != MDOC_Bl || | |||
| 1078 | mdoc->last->parent->norm->Bl.type != LIST_diag; | |||
| 1079 | ||||
| 1080 | /* | |||
| 1081 | * The `Nd' macro has all arguments in its body: it's a hybrid | |||
| 1082 | * of block partial-explicit and full-implicit. Stupid. | |||
| 1083 | */ | |||
| 1084 | ||||
| 1085 | if (tok == MDOC_Nd) { | |||
| 1086 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
| 1087 | rew_last(mdoc, head); | |||
| 1088 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1089 | } | |||
| 1090 | ||||
| 1091 | if (tok == MDOC_Bk) | |||
| 1092 | mdoc->flags |= MDOC_KEEP(1 << 8); | |||
| 1093 | ||||
| 1094 | ac = ARGS_EOLN; | |||
| 1095 | for (;;) { | |||
| 1096 | ||||
| 1097 | /* | |||
| 1098 | * If we are right after a tab character, | |||
| 1099 | * do not parse the first word for macros. | |||
| 1100 | */ | |||
| 1101 | ||||
| 1102 | if (mdoc->flags & MDOC_PHRASEQN(1 << 15)) { | |||
| 1103 | mdoc->flags &= ~MDOC_PHRASEQN(1 << 15); | |||
| 1104 | mdoc->flags |= MDOC_PHRASEQF(1 << 13); | |||
| 1105 | } | |||
| 1106 | ||||
| 1107 | la = *pos; | |||
| 1108 | lac = ac; | |||
| 1109 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 1110 | if (ac == ARGS_EOLN) { | |||
| 1111 | if (lac != ARGS_PHRASE || | |||
| 1112 | ! (mdoc->flags & MDOC_PHRASEQF(1 << 13))) | |||
| 1113 | break; | |||
| 1114 | ||||
| 1115 | /* | |||
| 1116 | * This line ends in a tab; start the next | |||
| 1117 | * column now, with a leading blank. | |||
| 1118 | */ | |||
| 1119 | ||||
| 1120 | if (body != NULL((void *)0)) | |||
| 1121 | rew_last(mdoc, body); | |||
| 1122 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1123 | roff_word_alloc(mdoc, line, ppos, "\\&"); | |||
| 1124 | break; | |||
| 1125 | } | |||
| 1126 | ||||
| 1127 | if (tok == MDOC_Bd || tok == MDOC_Bk) { | |||
| 1128 | mandoc_msg(MANDOCERR_ARG_EXCESS, line, la, | |||
| 1129 | "%s ... %s", roff_name[tok], buf + la); | |||
| 1130 | if (ac == ARGS_ALLOC) | |||
| 1131 | free(p); | |||
| 1132 | break; | |||
| 1133 | } | |||
| 1134 | if (tok == MDOC_Rs) { | |||
| 1135 | mandoc_msg(MANDOCERR_ARG_SKIP, | |||
| 1136 | line, la, "Rs %s", buf + la); | |||
| 1137 | if (ac == ARGS_ALLOC) | |||
| 1138 | free(p); | |||
| 1139 | break; | |||
| 1140 | } | |||
| 1141 | if (ac == ARGS_PUNCT) | |||
| 1142 | break; | |||
| 1143 | ||||
| 1144 | /* | |||
| 1145 | * Emit leading punctuation (i.e., punctuation before | |||
| 1146 | * the ROFFT_HEAD) for non-phrase types. | |||
| 1147 | */ | |||
| 1148 | ||||
| 1149 | if (head == NULL((void *)0) && | |||
| 1150 | ac != ARGS_PHRASE && | |||
| 1151 | mdoc_isdelim(p) == DELIM_OPEN) { | |||
| 1152 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
| 1153 | if (ac == ARGS_ALLOC) | |||
| 1154 | free(p); | |||
| 1155 | continue; | |||
| 1156 | } | |||
| 1157 | ||||
| 1158 | /* Open a head if one hasn't been opened. */ | |||
| 1159 | ||||
| 1160 | if (head == NULL((void *)0)) | |||
| 1161 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
| 1162 | ||||
| 1163 | if (ac == ARGS_PHRASE) { | |||
| 1164 | ||||
| 1165 | /* | |||
| 1166 | * If we haven't opened a body yet, rewind the | |||
| 1167 | * head; if we have, rewind that instead. | |||
| 1168 | */ | |||
| 1169 | ||||
| 1170 | rew_last(mdoc, body == NULL((void *)0) ? head : body); | |||
| 1171 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1172 | ||||
| 1173 | /* Process to the tab or to the end of the line. */ | |||
| 1174 | ||||
| 1175 | mdoc->flags |= MDOC_PHRASE(1 << 4); | |||
| 1176 | parse_rest(mdoc, TOKEN_NONE, line, &la, buf); | |||
| 1177 | mdoc->flags &= ~MDOC_PHRASE(1 << 4); | |||
| 1178 | ||||
| 1179 | /* There may have been `Ta' macros. */ | |||
| 1180 | ||||
| 1181 | while (body->next != NULL((void *)0)) | |||
| 1182 | body = body->next; | |||
| 1183 | continue; | |||
| 1184 | } | |||
| 1185 | ||||
| 1186 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, parsed); | |||
| 1187 | if (ac == ARGS_ALLOC) | |||
| 1188 | free(p); | |||
| 1189 | if (done) | |||
| 1190 | break; | |||
| 1191 | } | |||
| 1192 | ||||
| 1193 | if (blk->flags & NODE_VALID(1 << 0)) | |||
| 1194 | return; | |||
| 1195 | if (head == NULL((void *)0)) | |||
| 1196 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
| 1197 | if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs) | |||
| 1198 | append_delims(mdoc, line, pos, buf); | |||
| 1199 | if (body != NULL((void *)0)) | |||
| 1200 | goto out; | |||
| 1201 | if (find_pending(mdoc, tok, line, ppos, head)) | |||
| 1202 | return; | |||
| 1203 | ||||
| 1204 | /* Close out scopes to remain in a consistent state. */ | |||
| 1205 | ||||
| 1206 | rew_last(mdoc, head); | |||
| 1207 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1208 | if (tok == MDOC_Ss) | |||
| 1209 | mdoc->flags &= ~ROFF_NONOFILL(1 << 16); | |||
| 1210 | ||||
| 1211 | /* | |||
| 1212 | * Set up fill mode for display blocks. | |||
| 1213 | * This needs to be done here up front rather than during | |||
| 1214 | * validation such that child nodes get the right flags. | |||
| 1215 | */ | |||
| 1216 | ||||
| 1217 | if (tok == MDOC_Bd && arg != NULL((void *)0)) { | |||
| 1218 | for (iarg = 0; iarg < arg->argc; iarg++) { | |||
| 1219 | switch (arg->argv[iarg].arg) { | |||
| 1220 | case MDOC_Unfilled: | |||
| 1221 | case MDOC_Literal: | |||
| 1222 | mdoc->flags |= ROFF_NOFILL(1 << 1); | |||
| 1223 | break; | |||
| 1224 | case MDOC_Filled: | |||
| 1225 | case MDOC_Ragged: | |||
| 1226 | case MDOC_Centred: | |||
| 1227 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
| 1228 | break; | |||
| 1229 | default: | |||
| 1230 | continue; | |||
| 1231 | } | |||
| 1232 | break; | |||
| 1233 | } | |||
| 1234 | } | |||
| 1235 | out: | |||
| 1236 | if (mdoc->flags & MDOC_FREECOL(1 << 6)) { | |||
| 1237 | rew_last(mdoc, body); | |||
| 1238 | rew_last(mdoc, blk); | |||
| 1239 | mdoc->flags &= ~MDOC_FREECOL(1 << 6); | |||
| 1240 | } | |||
| 1241 | } | |||
| 1242 | ||||
| 1243 | static void | |||
| 1244 | blk_part_imp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1245 | { | |||
| 1246 | int done, la, nl; | |||
| 1247 | enum margserr ac; | |||
| 1248 | char *p; | |||
| 1249 | struct roff_node *blk; /* saved block context */ | |||
| 1250 | struct roff_node *body; /* saved body context */ | |||
| 1251 | struct roff_node *n; | |||
| 1252 | ||||
| 1253 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
| 1254 | ||||
| 1255 | /* | |||
| 1256 | * A macro that spans to the end of the line. This is generally | |||
| 1257 | * (but not necessarily) called as the first macro. The block | |||
| 1258 | * has a head as the immediate child, which is always empty, | |||
| 1259 | * followed by zero or more opening punctuation nodes, then the | |||
| 1260 | * body (which may be empty, depending on the macro), then zero | |||
| 1261 | * or more closing punctuation nodes. | |||
| 1262 | */ | |||
| 1263 | ||||
| 1264 | blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL((void *)0)); | |||
| 1265 | rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok)); | |||
| 1266 | ||||
| 1267 | /* | |||
| 1268 | * Open the body scope "on-demand", that is, after we've | |||
| 1269 | * processed all our the leading delimiters (open parenthesis, | |||
| 1270 | * etc.). | |||
| 1271 | */ | |||
| 1272 | ||||
| 1273 | for (body = NULL((void *)0); ; ) { | |||
| 1274 | la = *pos; | |||
| 1275 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 1276 | if (ac == ARGS_EOLN || ac == ARGS_PUNCT) | |||
| 1277 | break; | |||
| 1278 | ||||
| 1279 | if (body == NULL((void *)0) && mdoc_isdelim(p) == DELIM_OPEN) { | |||
| 1280 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
| 1281 | if (ac == ARGS_ALLOC) | |||
| 1282 | free(p); | |||
| 1283 | continue; | |||
| 1284 | } | |||
| 1285 | ||||
| 1286 | if (body == NULL((void *)0)) | |||
| 1287 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1288 | ||||
| 1289 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
| 1290 | if (ac == ARGS_ALLOC) | |||
| 1291 | free(p); | |||
| 1292 | if (done) | |||
| 1293 | break; | |||
| 1294 | } | |||
| 1295 | if (body == NULL((void *)0)) | |||
| 1296 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1297 | ||||
| 1298 | if (find_pending(mdoc, tok, line, ppos, body)) | |||
| 1299 | return; | |||
| 1300 | ||||
| 1301 | rew_last(mdoc, body); | |||
| 1302 | if (nl) | |||
| 1303 | append_delims(mdoc, line, pos, buf); | |||
| 1304 | rew_pending(mdoc, blk); | |||
| 1305 | ||||
| 1306 | /* Move trailing .Ns out of scope. */ | |||
| 1307 | ||||
| 1308 | for (n = body->child; n && n->next; n = n->next) | |||
| 1309 | /* Do nothing. */ ; | |||
| 1310 | if (n && n->tok == MDOC_Ns) | |||
| 1311 | roff_node_relink(mdoc, n); | |||
| 1312 | } | |||
| 1313 | ||||
| 1314 | static void | |||
| 1315 | blk_part_exp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1316 | { | |||
| 1317 | int done, la, nl; | |||
| 1318 | enum margserr ac; | |||
| 1319 | struct roff_node *head; /* keep track of head */ | |||
| 1320 | char *p; | |||
| 1321 | ||||
| 1322 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
| 1323 | ||||
| 1324 | /* | |||
| 1325 | * The opening of an explicit macro having zero or more leading | |||
| 1326 | * punctuation nodes; a head with optional single element (the | |||
| 1327 | * case of `Eo'); and a body that may be empty. | |||
| 1328 | */ | |||
| 1329 | ||||
| 1330 | roff_block_alloc(mdoc, line, ppos, tok); | |||
| 1331 | head = NULL((void *)0); | |||
| 1332 | for (;;) { | |||
| 1333 | la = *pos; | |||
| 1334 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 1335 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) | |||
| 1336 | break; | |||
| 1337 | ||||
| 1338 | /* Flush out leading punctuation. */ | |||
| 1339 | ||||
| 1340 | if (head == NULL((void *)0) && mdoc_isdelim(p) == DELIM_OPEN) { | |||
| 1341 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
| 1342 | if (ac == ARGS_ALLOC) | |||
| 1343 | free(p); | |||
| 1344 | continue; | |||
| 1345 | } | |||
| 1346 | ||||
| 1347 | if (head == NULL((void *)0)) { | |||
| 1348 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
| 1349 | if (tok == MDOC_Eo) /* Not parsed. */ | |||
| 1350 | dword(mdoc, line, la, p, DELIM_MAX, 0); | |||
| 1351 | rew_last(mdoc, head); | |||
| 1352 | roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1353 | if (tok == MDOC_Eo) { | |||
| 1354 | if (ac == ARGS_ALLOC) | |||
| 1355 | free(p); | |||
| 1356 | continue; | |||
| 1357 | } | |||
| 1358 | } | |||
| 1359 | ||||
| 1360 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
| 1361 | if (ac == ARGS_ALLOC) | |||
| 1362 | free(p); | |||
| 1363 | if (done) | |||
| 1364 | break; | |||
| 1365 | } | |||
| 1366 | ||||
| 1367 | /* Clean-up to leave in a consistent state. */ | |||
| 1368 | ||||
| 1369 | if (head == NULL((void *)0)) { | |||
| 1370 | rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok)); | |||
| 1371 | roff_body_alloc(mdoc, line, ppos, tok); | |||
| 1372 | } | |||
| 1373 | if (nl) | |||
| 1374 | append_delims(mdoc, line, pos, buf); | |||
| 1375 | } | |||
| 1376 | ||||
| 1377 | static void | |||
| 1378 | in_line_argn(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1379 | { | |||
| 1380 | struct mdoc_arg *arg; | |||
| 1381 | char *p; | |||
| 1382 | enum margserr ac; | |||
| 1383 | enum roff_tok ntok; | |||
| 1384 | int state; /* arg#; -1: not yet open; -2: closed */ | |||
| 1385 | int la, maxargs, nl; | |||
| 1386 | ||||
| 1387 | nl = mdoc->flags & MDOC_NEWLINE(1 << 3); | |||
| 1388 | ||||
| 1389 | /* | |||
| 1390 | * A line macro that has a fixed number of arguments (maxargs). | |||
| 1391 | * Only open the scope once the first non-leading-punctuation is | |||
| 1392 | * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then | |||
| 1393 | * keep it open until the maximum number of arguments are | |||
| 1394 | * exhausted. | |||
| 1395 | */ | |||
| 1396 | ||||
| 1397 | switch (tok) { | |||
| 1398 | case MDOC_Ap: | |||
| 1399 | case MDOC_Ns: | |||
| 1400 | case MDOC_Ux: | |||
| 1401 | maxargs = 0; | |||
| 1402 | break; | |||
| 1403 | case MDOC_Bx: | |||
| 1404 | case MDOC_Es: | |||
| 1405 | case MDOC_Xr: | |||
| 1406 | maxargs = 2; | |||
| 1407 | break; | |||
| 1408 | default: | |||
| 1409 | maxargs = 1; | |||
| 1410 | break; | |||
| 1411 | } | |||
| 1412 | ||||
| 1413 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
| 1414 | ||||
| 1415 | state = -1; | |||
| 1416 | p = NULL((void *)0); | |||
| 1417 | for (;;) { | |||
| 1418 | la = *pos; | |||
| 1419 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 1420 | ||||
| 1421 | if ((ac == ARGS_WORD || ac == ARGS_ALLOC) && state == -1 && | |||
| 1422 | (mdoc_macro(tok)->flags & MDOC_IGNDELIM(1 << 4)) == 0 && | |||
| 1423 | mdoc_isdelim(p) == DELIM_OPEN) { | |||
| 1424 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
| 1425 | if (ac == ARGS_ALLOC) | |||
| 1426 | free(p); | |||
| 1427 | continue; | |||
| 1428 | } | |||
| 1429 | ||||
| 1430 | if (state == -1 && tok != MDOC_In && | |||
| 1431 | tok != MDOC_St && tok != MDOC_Xr) { | |||
| 1432 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 1433 | state = 0; | |||
| 1434 | } | |||
| 1435 | ||||
| 1436 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) { | |||
| 1437 | if (abs(state) < 2 && tok == MDOC_Pf) | |||
| 1438 | mandoc_msg(MANDOCERR_PF_SKIP, | |||
| 1439 | line, ppos, "Pf %s", | |||
| 1440 | p == NULL((void *)0) ? "at eol" : p); | |||
| 1441 | break; | |||
| 1442 | } | |||
| 1443 | ||||
| 1444 | if (state == maxargs) { | |||
| 1445 | rew_elem(mdoc, tok); | |||
| 1446 | state = -2; | |||
| 1447 | } | |||
| 1448 | ||||
| 1449 | ntok = (tok == MDOC_Pf && state == 0) ? | |||
| 1450 | TOKEN_NONE : lookup(mdoc, tok, line, la, p); | |||
| 1451 | ||||
| 1452 | if (ntok != TOKEN_NONE) { | |||
| 1453 | if (state >= 0) { | |||
| 1454 | rew_elem(mdoc, tok); | |||
| 1455 | state = -2; | |||
| 1456 | } | |||
| 1457 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, | |||
| 1458 | line, la, pos, buf); | |||
| 1459 | if (ac == ARGS_ALLOC) | |||
| 1460 | free(p); | |||
| 1461 | break; | |||
| 1462 | } | |||
| 1463 | ||||
| 1464 | if (mdoc_macro(tok)->flags & MDOC_IGNDELIM(1 << 4) || | |||
| 1465 | mdoc_isdelim(p) == DELIM_NONE) { | |||
| 1466 | if (state == -1) { | |||
| 1467 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 1468 | state = 1; | |||
| 1469 | } else if (state >= 0) | |||
| 1470 | state++; | |||
| 1471 | } else if (state >= 0) { | |||
| 1472 | rew_elem(mdoc, tok); | |||
| 1473 | state = -2; | |||
| 1474 | } | |||
| 1475 | ||||
| 1476 | dword(mdoc, line, la, p, DELIM_MAX, | |||
| 1477 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
| 1478 | if (ac == ARGS_ALLOC) | |||
| 1479 | free(p); | |||
| 1480 | p = mdoc->last->string; | |||
| 1481 | } | |||
| 1482 | ||||
| 1483 | if (state == -1) { | |||
| 1484 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
| 1485 | line, ppos, "%s", roff_name[tok]); | |||
| 1486 | return; | |||
| 1487 | } | |||
| 1488 | ||||
| 1489 | if (state == 0 && tok == MDOC_Pf) | |||
| 1490 | append_delims(mdoc, line, pos, buf); | |||
| 1491 | if (state >= 0) | |||
| 1492 | rew_elem(mdoc, tok); | |||
| 1493 | if (nl) | |||
| 1494 | append_delims(mdoc, line, pos, buf); | |||
| 1495 | } | |||
| 1496 | ||||
| 1497 | static void | |||
| 1498 | in_line_eoln(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1499 | { | |||
| 1500 | struct roff_node *n; | |||
| 1501 | struct mdoc_arg *arg; | |||
| 1502 | ||||
| 1503 | if ((tok == MDOC_Pp || tok == MDOC_Lp) && | |||
| 1504 | ! (mdoc->flags & MDOC_SYNOPSIS(1 << 7))) { | |||
| 1505 | n = mdoc->last; | |||
| 1506 | if (mdoc->next == ROFF_NEXT_SIBLING) | |||
| 1507 | n = n->parent; | |||
| 1508 | if (n->tok == MDOC_Nm) | |||
| 1509 | rew_last(mdoc, n->parent); | |||
| 1510 | } | |||
| 1511 | ||||
| 1512 | if (buf[*pos] == '\0' && | |||
| 1513 | (tok == MDOC_Fd || *roff_name[tok] == '%')) { | |||
| 1514 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
| 1515 | line, ppos, "%s", roff_name[tok]); | |||
| 1516 | return; | |||
| 1517 | } | |||
| 1518 | ||||
| 1519 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
| 1520 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
| 1521 | if (parse_rest(mdoc, tok, line, pos, buf)) | |||
| 1522 | return; | |||
| 1523 | rew_elem(mdoc, tok); | |||
| 1524 | } | |||
| 1525 | ||||
| 1526 | /* | |||
| 1527 | * The simplest argument parser available: Parse the remaining | |||
| 1528 | * words until the end of the phrase or line and return 0 | |||
| 1529 | * or until the next macro, call that macro, and return 1. | |||
| 1530 | */ | |||
| 1531 | static int | |||
| 1532 | parse_rest(struct roff_man *mdoc, enum roff_tok tok, | |||
| 1533 | int line, int *pos, char *buf) | |||
| 1534 | { | |||
| 1535 | char *p; | |||
| 1536 | int done, la; | |||
| 1537 | enum margserr ac; | |||
| 1538 | ||||
| 1539 | for (;;) { | |||
| 1540 | la = *pos; | |||
| 1541 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
| 1542 | if (ac == ARGS_EOLN) | |||
| 1543 | return 0; | |||
| 1544 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
| 1545 | if (ac == ARGS_ALLOC) | |||
| 1546 | free(p); | |||
| 1547 | if (done) | |||
| 1548 | return 1; | |||
| 1549 | } | |||
| 1550 | } | |||
| 1551 | ||||
| 1552 | static void | |||
| 1553 | ctx_synopsis(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1554 | { | |||
| 1555 | ||||
| 1556 | if (~mdoc->flags & (MDOC_SYNOPSIS(1 << 7) | MDOC_NEWLINE(1 << 3))) | |||
| 1557 | in_line(mdoc, tok, line, ppos, pos, buf); | |||
| 1558 | else if (tok == MDOC_Nm) | |||
| 1559 | blk_full(mdoc, tok, line, ppos, pos, buf); | |||
| 1560 | else { | |||
| 1561 | assert(tok == MDOC_Vt)((tok == MDOC_Vt) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 1561, __func__, "tok == MDOC_Vt")); | |||
| 1562 | blk_part_imp(mdoc, tok, line, ppos, pos, buf); | |||
| 1563 | } | |||
| 1564 | } | |||
| 1565 | ||||
| 1566 | /* | |||
| 1567 | * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. | |||
| 1568 | * They're unusual because they're basically free-form text until a | |||
| 1569 | * macro is encountered. | |||
| 1570 | */ | |||
| 1571 | static void | |||
| 1572 | phrase_ta(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
| 1573 | { | |||
| 1574 | struct roff_node *body, *n; | |||
| 1575 | ||||
| 1576 | /* Make sure we are in a column list or ignore this macro. */ | |||
| 1577 | ||||
| 1578 | body = NULL((void *)0); | |||
| ||||
| 1579 | for (n = mdoc->last; n != NULL((void *)0); n = n->parent) { | |||
| 1580 | if (n->flags & NODE_ENDED(1 << 1)) | |||
| 1581 | continue; | |||
| 1582 | if (n->tok == MDOC_It && n->type == ROFFT_BODY) | |||
| 1583 | body = n; | |||
| 1584 | if (n->tok == MDOC_Bl && n->end == ENDBODY_NOT) | |||
| 1585 | break; | |||
| 1586 | } | |||
| 1587 | ||||
| 1588 | if (n
| |||
| 1589 | mandoc_msg(MANDOCERR_TA_STRAY, line, ppos, "Ta"); | |||
| 1590 | return; | |||
| 1591 | } | |||
| 1592 | ||||
| 1593 | /* Advance to the next column. */ | |||
| 1594 | ||||
| 1595 | rew_last(mdoc, body); | |||
| 1596 | roff_body_alloc(mdoc, line, ppos, MDOC_It); | |||
| 1597 | parse_rest(mdoc, TOKEN_NONE, line, pos, buf); | |||
| 1598 | } |