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