1 /* $OpenBSD: man.c,v 1.135 2019/01/05 00:36:46 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> 5 * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include <sys/types.h> 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <stdarg.h> 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 28 #include "mandoc_aux.h" 29 #include "mandoc.h" 30 #include "roff.h" 31 #include "man.h" 32 #include "libmandoc.h" 33 #include "roff_int.h" 34 #include "libman.h" 35 36 static char *man_hasc(char *); 37 static int man_ptext(struct roff_man *, int, char *, int); 38 static int man_pmacro(struct roff_man *, int, char *, int); 39 40 41 int 42 man_parseln(struct roff_man *man, int ln, char *buf, int offs) 43 { 44 45 if (man->last->type != ROFFT_EQN || ln > man->last->line) 46 man->flags |= MAN_NEWLINE; 47 48 return roff_getcontrol(man->roff, buf, &offs) ? 49 man_pmacro(man, ln, buf, offs) : 50 man_ptext(man, ln, buf, offs); 51 } 52 53 /* 54 * If the string ends with \c, return a pointer to the backslash. 55 * Otherwise, return NULL. 56 */ 57 static char * 58 man_hasc(char *start) 59 { 60 char *cp, *ep; 61 62 ep = strchr(start, '\0') - 2; 63 if (ep < start || ep[0] != '\\' || ep[1] != 'c') 64 return NULL; 65 for (cp = ep; cp > start; cp--) 66 if (cp[-1] != '\\') 67 break; 68 return (ep - cp) % 2 ? NULL : ep; 69 } 70 71 void 72 man_descope(struct roff_man *man, int line, int offs, char *start) 73 { 74 /* Trailing \c keeps next-line scope open. */ 75 76 if (start != NULL && man_hasc(start) != NULL) 77 return; 78 79 /* 80 * Co-ordinate what happens with having a next-line scope open: 81 * first close out the element scopes (if applicable), 82 * then close out the block scope (also if applicable). 83 */ 84 85 if (man->flags & MAN_ELINE) { 86 while (man->last->parent->type != ROFFT_ROOT && 87 man_macro(man->last->parent->tok)->flags & MAN_ESCOPED) 88 man_unscope(man, man->last->parent); 89 man->flags &= ~MAN_ELINE; 90 } 91 if ( ! (man->flags & MAN_BLINE)) 92 return; 93 man_unscope(man, man->last->parent); 94 roff_body_alloc(man, line, offs, man->last->tok); 95 man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); 96 } 97 98 static int 99 man_ptext(struct roff_man *man, int line, char *buf, int offs) 100 { 101 int i; 102 char *ep; 103 104 /* In no-fill mode, whitespace is preserved on text lines. */ 105 106 if (man->flags & ROFF_NOFILL) { 107 roff_word_alloc(man, line, offs, buf + offs); 108 man_descope(man, line, offs, buf + offs); 109 return 1; 110 } 111 112 for (i = offs; buf[i] == ' '; i++) 113 /* Skip leading whitespace. */ ; 114 115 /* 116 * Blank lines are ignored in next line scope 117 * and right after headings and cancel preceding \c, 118 * but add a single vertical space elsewhere. 119 */ 120 121 if (buf[i] == '\0') { 122 if (man->flags & (MAN_ELINE | MAN_BLINE)) { 123 mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL); 124 return 1; 125 } 126 if (man->last->tok == MAN_SH || man->last->tok == MAN_SS) 127 return 1; 128 if (man->last->type == ROFFT_TEXT && 129 ((ep = man_hasc(man->last->string)) != NULL)) { 130 *ep = '\0'; 131 return 1; 132 } 133 roff_elem_alloc(man, line, offs, ROFF_sp); 134 man->next = ROFF_NEXT_SIBLING; 135 return 1; 136 } 137 138 /* 139 * Warn if the last un-escaped character is whitespace. Then 140 * strip away the remaining spaces (tabs stay!). 141 */ 142 143 i = (int)strlen(buf); 144 assert(i); 145 146 if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { 147 if (i > 1 && '\\' != buf[i - 2]) 148 mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL); 149 150 for (--i; i && ' ' == buf[i]; i--) 151 /* Spin back to non-space. */ ; 152 153 /* Jump ahead of escaped whitespace. */ 154 i += '\\' == buf[i] ? 2 : 1; 155 156 buf[i] = '\0'; 157 } 158 roff_word_alloc(man, line, offs, buf + offs); 159 160 /* 161 * End-of-sentence check. If the last character is an unescaped 162 * EOS character, then flag the node as being the end of a 163 * sentence. The front-end will know how to interpret this. 164 */ 165 166 assert(i); 167 if (mandoc_eos(buf, (size_t)i)) 168 man->last->flags |= NODE_EOS; 169 170 man_descope(man, line, offs, buf + offs); 171 return 1; 172 } 173 174 static int 175 man_pmacro(struct roff_man *man, int ln, char *buf, int offs) 176 { 177 struct roff_node *n; 178 const char *cp; 179 size_t sz; 180 enum roff_tok tok; 181 int ppos; 182 int bline; 183 184 /* Determine the line macro. */ 185 186 ppos = offs; 187 tok = TOKEN_NONE; 188 for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++) 189 offs++; 190 if (sz > 0 && sz < 4) 191 tok = roffhash_find(man->manmac, buf + ppos, sz); 192 if (tok == TOKEN_NONE) { 193 mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1); 194 return 1; 195 } 196 197 /* Skip a leading escape sequence or tab. */ 198 199 switch (buf[offs]) { 200 case '\\': 201 cp = buf + offs + 1; 202 mandoc_escape(&cp, NULL, NULL); 203 offs = cp - buf; 204 break; 205 case '\t': 206 offs++; 207 break; 208 default: 209 break; 210 } 211 212 /* Jump to the next non-whitespace word. */ 213 214 while (buf[offs] == ' ') 215 offs++; 216 217 /* 218 * Trailing whitespace. Note that tabs are allowed to be passed 219 * into the parser as "text", so we only warn about spaces here. 220 */ 221 222 if (buf[offs] == '\0' && buf[offs - 1] == ' ') 223 mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL); 224 225 /* 226 * Some macros break next-line scopes; otherwise, remember 227 * whether we are in next-line scope for a block head. 228 */ 229 230 man_breakscope(man, tok); 231 bline = man->flags & MAN_BLINE; 232 233 /* 234 * If the line in next-line scope ends with \c, keep the 235 * next-line scope open for the subsequent input line. 236 * That is not at all portable, only groff >= 1.22.4 237 * does it, but *if* this weird idiom occurs in a manual 238 * page, that's very likely what the author intended. 239 */ 240 241 if (bline && man_hasc(buf + offs)) 242 bline = 0; 243 244 /* Call to handler... */ 245 246 (*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf); 247 248 /* In quick mode (for mandocdb), abort after the NAME section. */ 249 250 if (man->quick && tok == MAN_SH) { 251 n = man->last; 252 if (n->type == ROFFT_BODY && 253 strcmp(n->prev->child->string, "NAME")) 254 return 2; 255 } 256 257 /* 258 * If we are in a next-line scope for a block head, 259 * close it out now and switch to the body, 260 * unless the next-line scope is allowed to continue. 261 */ 262 263 if (bline == 0 || 264 (man->flags & MAN_BLINE) == 0 || 265 man->flags & MAN_ELINE || 266 man_macro(tok)->flags & MAN_NSCOPED) 267 return 1; 268 269 man_unscope(man, man->last->parent); 270 roff_body_alloc(man, ln, ppos, man->last->tok); 271 man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); 272 return 1; 273 } 274 275 void 276 man_breakscope(struct roff_man *man, int tok) 277 { 278 struct roff_node *n; 279 280 /* 281 * An element next line scope is open, 282 * and the new macro is not allowed inside elements. 283 * Delete the element that is being broken. 284 */ 285 286 if (man->flags & MAN_ELINE && (tok < MAN_TH || 287 (man_macro(tok)->flags & MAN_NSCOPED) == 0)) { 288 n = man->last; 289 if (n->type == ROFFT_TEXT) 290 n = n->parent; 291 if (n->tok < MAN_TH || 292 (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED)) 293 == MAN_NSCOPED) 294 n = n->parent; 295 296 mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, 297 "%s breaks %s", roff_name[tok], roff_name[n->tok]); 298 299 roff_node_delete(man, n); 300 man->flags &= ~MAN_ELINE; 301 } 302 303 /* 304 * Weird special case: 305 * Switching fill mode closes section headers. 306 */ 307 308 if (man->flags & MAN_BLINE && 309 (tok == ROFF_nf || tok == ROFF_fi) && 310 (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) { 311 n = man->last; 312 man_unscope(man, n); 313 roff_body_alloc(man, n->line, n->pos, n->tok); 314 man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); 315 } 316 317 /* 318 * A block header next line scope is open, 319 * and the new macro is not allowed inside block headers. 320 * Delete the block that is being broken. 321 */ 322 323 if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi && 324 (tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) { 325 n = man->last; 326 if (n->type == ROFFT_TEXT) 327 n = n->parent; 328 if (n->tok < MAN_TH || 329 (man_macro(n->tok)->flags & MAN_XSCOPE) == 0) 330 n = n->parent; 331 332 assert(n->type == ROFFT_HEAD); 333 n = n->parent; 334 assert(n->type == ROFFT_BLOCK); 335 assert(man_macro(n->tok)->flags & MAN_BSCOPED); 336 337 mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, 338 "%s breaks %s", roff_name[tok], roff_name[n->tok]); 339 340 roff_node_delete(man, n); 341 man->flags &= ~(MAN_BLINE | ROFF_NONOFILL); 342 } 343 } 344