1 /* $Id: mdoc_argv.c,v 1.52 2014/07/06 19:08:56 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2012 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 AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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 <stdlib.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 #include "mdoc.h" 26 #include "mandoc.h" 27 #include "mandoc_aux.h" 28 #include "libmdoc.h" 29 #include "libmandoc.h" 30 31 #define MULTI_STEP 5 /* pre-allocate argument values */ 32 #define DELIMSZ 6 /* max possible size of a delimiter */ 33 34 enum argsflag { 35 ARGSFL_NONE = 0, 36 ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */ 37 ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */ 38 }; 39 40 enum argvflag { 41 ARGV_NONE, /* no args to flag (e.g., -split) */ 42 ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */ 43 ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */ 44 }; 45 46 struct mdocarg { 47 enum argsflag flags; 48 const enum mdocargt *argvs; 49 }; 50 51 static void argn_free(struct mdoc_arg *, int); 52 static enum margserr args(struct mdoc *, int, int *, 53 char *, enum argsflag, char **); 54 static int args_checkpunct(const char *, int); 55 static int argv_multi(struct mdoc *, int, 56 struct mdoc_argv *, int *, char *); 57 static int argv_single(struct mdoc *, int, 58 struct mdoc_argv *, int *, char *); 59 60 static const enum argvflag argvflags[MDOC_ARG_MAX] = { 61 ARGV_NONE, /* MDOC_Split */ 62 ARGV_NONE, /* MDOC_Nosplit */ 63 ARGV_NONE, /* MDOC_Ragged */ 64 ARGV_NONE, /* MDOC_Unfilled */ 65 ARGV_NONE, /* MDOC_Literal */ 66 ARGV_SINGLE, /* MDOC_File */ 67 ARGV_SINGLE, /* MDOC_Offset */ 68 ARGV_NONE, /* MDOC_Bullet */ 69 ARGV_NONE, /* MDOC_Dash */ 70 ARGV_NONE, /* MDOC_Hyphen */ 71 ARGV_NONE, /* MDOC_Item */ 72 ARGV_NONE, /* MDOC_Enum */ 73 ARGV_NONE, /* MDOC_Tag */ 74 ARGV_NONE, /* MDOC_Diag */ 75 ARGV_NONE, /* MDOC_Hang */ 76 ARGV_NONE, /* MDOC_Ohang */ 77 ARGV_NONE, /* MDOC_Inset */ 78 ARGV_MULTI, /* MDOC_Column */ 79 ARGV_SINGLE, /* MDOC_Width */ 80 ARGV_NONE, /* MDOC_Compact */ 81 ARGV_NONE, /* MDOC_Std */ 82 ARGV_NONE, /* MDOC_Filled */ 83 ARGV_NONE, /* MDOC_Words */ 84 ARGV_NONE, /* MDOC_Emphasis */ 85 ARGV_NONE, /* MDOC_Symbolic */ 86 ARGV_NONE /* MDOC_Symbolic */ 87 }; 88 89 static const enum mdocargt args_Ex[] = { 90 MDOC_Std, 91 MDOC_ARG_MAX 92 }; 93 94 static const enum mdocargt args_An[] = { 95 MDOC_Split, 96 MDOC_Nosplit, 97 MDOC_ARG_MAX 98 }; 99 100 static const enum mdocargt args_Bd[] = { 101 MDOC_Ragged, 102 MDOC_Unfilled, 103 MDOC_Filled, 104 MDOC_Literal, 105 MDOC_File, 106 MDOC_Offset, 107 MDOC_Compact, 108 MDOC_Centred, 109 MDOC_ARG_MAX 110 }; 111 112 static const enum mdocargt args_Bf[] = { 113 MDOC_Emphasis, 114 MDOC_Literal, 115 MDOC_Symbolic, 116 MDOC_ARG_MAX 117 }; 118 119 static const enum mdocargt args_Bk[] = { 120 MDOC_Words, 121 MDOC_ARG_MAX 122 }; 123 124 static const enum mdocargt args_Bl[] = { 125 MDOC_Bullet, 126 MDOC_Dash, 127 MDOC_Hyphen, 128 MDOC_Item, 129 MDOC_Enum, 130 MDOC_Tag, 131 MDOC_Diag, 132 MDOC_Hang, 133 MDOC_Ohang, 134 MDOC_Inset, 135 MDOC_Column, 136 MDOC_Width, 137 MDOC_Offset, 138 MDOC_Compact, 139 MDOC_Nested, 140 MDOC_ARG_MAX 141 }; 142 143 static const struct mdocarg mdocargs[MDOC_MAX] = { 144 { ARGSFL_DELIM, NULL }, /* Ap */ 145 { ARGSFL_NONE, NULL }, /* Dd */ 146 { ARGSFL_NONE, NULL }, /* Dt */ 147 { ARGSFL_NONE, NULL }, /* Os */ 148 { ARGSFL_NONE, NULL }, /* Sh */ 149 { ARGSFL_NONE, NULL }, /* Ss */ 150 { ARGSFL_NONE, NULL }, /* Pp */ 151 { ARGSFL_DELIM, NULL }, /* D1 */ 152 { ARGSFL_DELIM, NULL }, /* Dl */ 153 { ARGSFL_NONE, args_Bd }, /* Bd */ 154 { ARGSFL_NONE, NULL }, /* Ed */ 155 { ARGSFL_NONE, args_Bl }, /* Bl */ 156 { ARGSFL_NONE, NULL }, /* El */ 157 { ARGSFL_NONE, NULL }, /* It */ 158 { ARGSFL_DELIM, NULL }, /* Ad */ 159 { ARGSFL_DELIM, args_An }, /* An */ 160 { ARGSFL_DELIM, NULL }, /* Ar */ 161 { ARGSFL_DELIM, NULL }, /* Cd */ 162 { ARGSFL_DELIM, NULL }, /* Cm */ 163 { ARGSFL_DELIM, NULL }, /* Dv */ 164 { ARGSFL_DELIM, NULL }, /* Er */ 165 { ARGSFL_DELIM, NULL }, /* Ev */ 166 { ARGSFL_NONE, args_Ex }, /* Ex */ 167 { ARGSFL_DELIM, NULL }, /* Fa */ 168 { ARGSFL_NONE, NULL }, /* Fd */ 169 { ARGSFL_DELIM, NULL }, /* Fl */ 170 { ARGSFL_DELIM, NULL }, /* Fn */ 171 { ARGSFL_DELIM, NULL }, /* Ft */ 172 { ARGSFL_DELIM, NULL }, /* Ic */ 173 { ARGSFL_DELIM, NULL }, /* In */ 174 { ARGSFL_DELIM, NULL }, /* Li */ 175 { ARGSFL_NONE, NULL }, /* Nd */ 176 { ARGSFL_DELIM, NULL }, /* Nm */ 177 { ARGSFL_DELIM, NULL }, /* Op */ 178 { ARGSFL_DELIM, NULL }, /* Ot */ 179 { ARGSFL_DELIM, NULL }, /* Pa */ 180 { ARGSFL_NONE, args_Ex }, /* Rv */ 181 { ARGSFL_DELIM, NULL }, /* St */ 182 { ARGSFL_DELIM, NULL }, /* Va */ 183 { ARGSFL_DELIM, NULL }, /* Vt */ 184 { ARGSFL_DELIM, NULL }, /* Xr */ 185 { ARGSFL_NONE, NULL }, /* %A */ 186 { ARGSFL_NONE, NULL }, /* %B */ 187 { ARGSFL_NONE, NULL }, /* %D */ 188 { ARGSFL_NONE, NULL }, /* %I */ 189 { ARGSFL_NONE, NULL }, /* %J */ 190 { ARGSFL_NONE, NULL }, /* %N */ 191 { ARGSFL_NONE, NULL }, /* %O */ 192 { ARGSFL_NONE, NULL }, /* %P */ 193 { ARGSFL_NONE, NULL }, /* %R */ 194 { ARGSFL_NONE, NULL }, /* %T */ 195 { ARGSFL_NONE, NULL }, /* %V */ 196 { ARGSFL_DELIM, NULL }, /* Ac */ 197 { ARGSFL_NONE, NULL }, /* Ao */ 198 { ARGSFL_DELIM, NULL }, /* Aq */ 199 { ARGSFL_DELIM, NULL }, /* At */ 200 { ARGSFL_DELIM, NULL }, /* Bc */ 201 { ARGSFL_NONE, args_Bf }, /* Bf */ 202 { ARGSFL_NONE, NULL }, /* Bo */ 203 { ARGSFL_DELIM, NULL }, /* Bq */ 204 { ARGSFL_DELIM, NULL }, /* Bsx */ 205 { ARGSFL_DELIM, NULL }, /* Bx */ 206 { ARGSFL_NONE, NULL }, /* Db */ 207 { ARGSFL_DELIM, NULL }, /* Dc */ 208 { ARGSFL_NONE, NULL }, /* Do */ 209 { ARGSFL_DELIM, NULL }, /* Dq */ 210 { ARGSFL_DELIM, NULL }, /* Ec */ 211 { ARGSFL_NONE, NULL }, /* Ef */ 212 { ARGSFL_DELIM, NULL }, /* Em */ 213 { ARGSFL_NONE, NULL }, /* Eo */ 214 { ARGSFL_DELIM, NULL }, /* Fx */ 215 { ARGSFL_DELIM, NULL }, /* Ms */ 216 { ARGSFL_DELIM, NULL }, /* No */ 217 { ARGSFL_DELIM, NULL }, /* Ns */ 218 { ARGSFL_DELIM, NULL }, /* Nx */ 219 { ARGSFL_DELIM, NULL }, /* Ox */ 220 { ARGSFL_DELIM, NULL }, /* Pc */ 221 { ARGSFL_DELIM, NULL }, /* Pf */ 222 { ARGSFL_NONE, NULL }, /* Po */ 223 { ARGSFL_DELIM, NULL }, /* Pq */ 224 { ARGSFL_DELIM, NULL }, /* Qc */ 225 { ARGSFL_DELIM, NULL }, /* Ql */ 226 { ARGSFL_NONE, NULL }, /* Qo */ 227 { ARGSFL_DELIM, NULL }, /* Qq */ 228 { ARGSFL_NONE, NULL }, /* Re */ 229 { ARGSFL_NONE, NULL }, /* Rs */ 230 { ARGSFL_DELIM, NULL }, /* Sc */ 231 { ARGSFL_NONE, NULL }, /* So */ 232 { ARGSFL_DELIM, NULL }, /* Sq */ 233 { ARGSFL_NONE, NULL }, /* Sm */ 234 { ARGSFL_DELIM, NULL }, /* Sx */ 235 { ARGSFL_DELIM, NULL }, /* Sy */ 236 { ARGSFL_DELIM, NULL }, /* Tn */ 237 { ARGSFL_DELIM, NULL }, /* Ux */ 238 { ARGSFL_DELIM, NULL }, /* Xc */ 239 { ARGSFL_NONE, NULL }, /* Xo */ 240 { ARGSFL_NONE, NULL }, /* Fo */ 241 { ARGSFL_DELIM, NULL }, /* Fc */ 242 { ARGSFL_NONE, NULL }, /* Oo */ 243 { ARGSFL_DELIM, NULL }, /* Oc */ 244 { ARGSFL_NONE, args_Bk }, /* Bk */ 245 { ARGSFL_NONE, NULL }, /* Ek */ 246 { ARGSFL_NONE, NULL }, /* Bt */ 247 { ARGSFL_NONE, NULL }, /* Hf */ 248 { ARGSFL_DELIM, NULL }, /* Fr */ 249 { ARGSFL_NONE, NULL }, /* Ud */ 250 { ARGSFL_DELIM, NULL }, /* Lb */ 251 { ARGSFL_NONE, NULL }, /* Lp */ 252 { ARGSFL_DELIM, NULL }, /* Lk */ 253 { ARGSFL_DELIM, NULL }, /* Mt */ 254 { ARGSFL_DELIM, NULL }, /* Brq */ 255 { ARGSFL_NONE, NULL }, /* Bro */ 256 { ARGSFL_DELIM, NULL }, /* Brc */ 257 { ARGSFL_NONE, NULL }, /* %C */ 258 { ARGSFL_NONE, NULL }, /* Es */ 259 { ARGSFL_DELIM, NULL }, /* En */ 260 { ARGSFL_DELIM, NULL }, /* Dx */ 261 { ARGSFL_NONE, NULL }, /* %Q */ 262 { ARGSFL_NONE, NULL }, /* br */ 263 { ARGSFL_NONE, NULL }, /* sp */ 264 { ARGSFL_NONE, NULL }, /* %U */ 265 { ARGSFL_NONE, NULL }, /* Ta */ 266 { ARGSFL_NONE, NULL }, /* ll */ 267 }; 268 269 270 /* 271 * Parse an argument from line text. This comes in the form of -key 272 * [value0...], which may either have a single mandatory value, at least 273 * one mandatory value, an optional single value, or no value. 274 */ 275 enum margverr 276 mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok, 277 struct mdoc_arg **v, int *pos, char *buf) 278 { 279 char *p, sv; 280 struct mdoc_argv tmp; 281 struct mdoc_arg *arg; 282 const enum mdocargt *ap; 283 284 if ('\0' == buf[*pos]) 285 return(ARGV_EOLN); 286 else if (NULL == (ap = mdocargs[tok].argvs)) 287 return(ARGV_WORD); 288 else if ('-' != buf[*pos]) 289 return(ARGV_WORD); 290 291 /* Seek to the first unescaped space. */ 292 293 p = &buf[++(*pos)]; 294 295 assert(*pos > 0); 296 297 for ( ; buf[*pos] ; (*pos)++) 298 if (' ' == buf[*pos] && '\\' != buf[*pos - 1]) 299 break; 300 301 /* 302 * We want to nil-terminate the word to look it up (it's easier 303 * that way). But we may not have a flag, in which case we need 304 * to restore the line as-is. So keep around the stray byte, 305 * which we'll reset upon exiting (if necessary). 306 */ 307 308 if ('\0' != (sv = buf[*pos])) 309 buf[(*pos)++] = '\0'; 310 311 /* 312 * Now look up the word as a flag. Use temporary storage that 313 * we'll copy into the node's flags, if necessary. 314 */ 315 316 memset(&tmp, 0, sizeof(struct mdoc_argv)); 317 318 tmp.line = line; 319 tmp.pos = *pos; 320 tmp.arg = MDOC_ARG_MAX; 321 322 while (MDOC_ARG_MAX != (tmp.arg = *ap++)) 323 if (0 == strcmp(p, mdoc_argnames[tmp.arg])) 324 break; 325 326 if (MDOC_ARG_MAX == tmp.arg) { 327 /* 328 * The flag was not found. 329 * Restore saved zeroed byte and return as a word. 330 */ 331 if (sv) 332 buf[*pos - 1] = sv; 333 return(ARGV_WORD); 334 } 335 336 /* Read to the next word (the argument). */ 337 338 while (buf[*pos] && ' ' == buf[*pos]) 339 (*pos)++; 340 341 switch (argvflags[tmp.arg]) { 342 case ARGV_SINGLE: 343 if ( ! argv_single(mdoc, line, &tmp, pos, buf)) 344 return(ARGV_ERROR); 345 break; 346 case ARGV_MULTI: 347 if ( ! argv_multi(mdoc, line, &tmp, pos, buf)) 348 return(ARGV_ERROR); 349 break; 350 case ARGV_NONE: 351 break; 352 } 353 354 if (NULL == (arg = *v)) 355 arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg)); 356 357 arg->argc++; 358 arg->argv = mandoc_reallocarray(arg->argv, 359 arg->argc, sizeof(struct mdoc_argv)); 360 361 memcpy(&arg->argv[(int)arg->argc - 1], &tmp, 362 sizeof(struct mdoc_argv)); 363 364 return(ARGV_ARG); 365 } 366 367 void 368 mdoc_argv_free(struct mdoc_arg *p) 369 { 370 int i; 371 372 if (NULL == p) 373 return; 374 375 if (p->refcnt) { 376 --(p->refcnt); 377 if (p->refcnt) 378 return; 379 } 380 assert(p->argc); 381 382 for (i = (int)p->argc - 1; i >= 0; i--) 383 argn_free(p, i); 384 385 free(p->argv); 386 free(p); 387 } 388 389 static void 390 argn_free(struct mdoc_arg *p, int iarg) 391 { 392 struct mdoc_argv *arg; 393 int j; 394 395 arg = &p->argv[iarg]; 396 397 if (arg->sz && arg->value) { 398 for (j = (int)arg->sz - 1; j >= 0; j--) 399 free(arg->value[j]); 400 free(arg->value); 401 } 402 403 for (--p->argc; iarg < (int)p->argc; iarg++) 404 p->argv[iarg] = p->argv[iarg+1]; 405 } 406 407 enum margserr 408 mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v) 409 { 410 411 return(args(mdoc, line, pos, buf, ARGSFL_NONE, v)); 412 } 413 414 enum margserr 415 mdoc_args(struct mdoc *mdoc, int line, int *pos, 416 char *buf, enum mdoct tok, char **v) 417 { 418 enum argsflag fl; 419 struct mdoc_node *n; 420 421 fl = mdocargs[tok].flags; 422 423 if (MDOC_It != tok) 424 return(args(mdoc, line, pos, buf, fl, v)); 425 426 /* 427 * We know that we're in an `It', so it's reasonable to expect 428 * us to be sitting in a `Bl'. Someday this may not be the case 429 * (if we allow random `It's sitting out there), so provide a 430 * safe fall-back into the default behaviour. 431 */ 432 433 for (n = mdoc->last; n; n = n->parent) 434 if (MDOC_Bl == n->tok) 435 if (LIST_column == n->norm->Bl.type) { 436 fl = ARGSFL_TABSEP; 437 break; 438 } 439 440 return(args(mdoc, line, pos, buf, fl, v)); 441 } 442 443 static enum margserr 444 args(struct mdoc *mdoc, int line, int *pos, 445 char *buf, enum argsflag fl, char **v) 446 { 447 char *p, *pp; 448 int pairs; 449 enum margserr rc; 450 451 if ('\0' == buf[*pos]) { 452 if (MDOC_PPHRASE & mdoc->flags) 453 return(ARGS_EOLN); 454 /* 455 * If we're not in a partial phrase and the flag for 456 * being a phrase literal is still set, the punctuation 457 * is unterminated. 458 */ 459 if (MDOC_PHRASELIT & mdoc->flags) 460 mandoc_msg(MANDOCERR_ARG_QUOTE, 461 mdoc->parse, line, *pos, NULL); 462 463 mdoc->flags &= ~MDOC_PHRASELIT; 464 return(ARGS_EOLN); 465 } 466 467 *v = &buf[*pos]; 468 469 if (ARGSFL_DELIM == fl) 470 if (args_checkpunct(buf, *pos)) 471 return(ARGS_PUNCT); 472 473 /* 474 * First handle TABSEP items, restricted to `Bl -column'. This 475 * ignores conventional token parsing and instead uses tabs or 476 * `Ta' macros to separate phrases. Phrases are parsed again 477 * for arguments at a later phase. 478 */ 479 480 if (ARGSFL_TABSEP == fl) { 481 /* Scan ahead to tab (can't be escaped). */ 482 p = strchr(*v, '\t'); 483 pp = NULL; 484 485 /* Scan ahead to unescaped `Ta'. */ 486 if ( ! (MDOC_PHRASELIT & mdoc->flags)) 487 for (pp = *v; ; pp++) { 488 if (NULL == (pp = strstr(pp, "Ta"))) 489 break; 490 if (pp > *v && ' ' != *(pp - 1)) 491 continue; 492 if (' ' == *(pp + 2) || '\0' == *(pp + 2)) 493 break; 494 } 495 496 /* By default, assume a phrase. */ 497 rc = ARGS_PHRASE; 498 499 /* 500 * Adjust new-buffer position to be beyond delimiter 501 * mark (e.g., Ta -> end + 2). 502 */ 503 if (p && pp) { 504 *pos += pp < p ? 2 : 1; 505 rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE; 506 p = pp < p ? pp : p; 507 } else if (p && ! pp) { 508 rc = ARGS_PPHRASE; 509 *pos += 1; 510 } else if (pp && ! p) { 511 p = pp; 512 *pos += 2; 513 } else { 514 rc = ARGS_PEND; 515 p = strchr(*v, 0); 516 } 517 518 /* Whitespace check for eoln case... */ 519 if ('\0' == *p && ' ' == *(p - 1)) 520 mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, 521 line, *pos, NULL); 522 523 *pos += (int)(p - *v); 524 525 /* Strip delimiter's preceding whitespace. */ 526 pp = p - 1; 527 while (pp > *v && ' ' == *pp) { 528 if (pp > *v && '\\' == *(pp - 1)) 529 break; 530 pp--; 531 } 532 *(pp + 1) = 0; 533 534 /* Strip delimiter's proceeding whitespace. */ 535 for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++) 536 /* Skip ahead. */ ; 537 538 return(rc); 539 } 540 541 /* 542 * Process a quoted literal. A quote begins with a double-quote 543 * and ends with a double-quote NOT preceded by a double-quote. 544 * NUL-terminate the literal in place. 545 * Collapse pairs of quotes inside quoted literals. 546 * Whitespace is NOT involved in literal termination. 547 */ 548 549 if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) { 550 if ( ! (MDOC_PHRASELIT & mdoc->flags)) 551 *v = &buf[++(*pos)]; 552 553 if (MDOC_PPHRASE & mdoc->flags) 554 mdoc->flags |= MDOC_PHRASELIT; 555 556 pairs = 0; 557 for ( ; buf[*pos]; (*pos)++) { 558 /* Move following text left after quoted quotes. */ 559 if (pairs) 560 buf[*pos - pairs] = buf[*pos]; 561 if ('\"' != buf[*pos]) 562 continue; 563 /* Unquoted quotes end quoted args. */ 564 if ('\"' != buf[*pos + 1]) 565 break; 566 /* Quoted quotes collapse. */ 567 pairs++; 568 (*pos)++; 569 } 570 if (pairs) 571 buf[*pos - pairs] = '\0'; 572 573 if ('\0' == buf[*pos]) { 574 if (MDOC_PPHRASE & mdoc->flags) 575 return(ARGS_QWORD); 576 mandoc_msg(MANDOCERR_ARG_QUOTE, 577 mdoc->parse, line, *pos, NULL); 578 return(ARGS_QWORD); 579 } 580 581 mdoc->flags &= ~MDOC_PHRASELIT; 582 buf[(*pos)++] = '\0'; 583 584 if ('\0' == buf[*pos]) 585 return(ARGS_QWORD); 586 587 while (' ' == buf[*pos]) 588 (*pos)++; 589 590 if ('\0' == buf[*pos]) 591 mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, 592 line, *pos, NULL); 593 594 return(ARGS_QWORD); 595 } 596 597 p = &buf[*pos]; 598 *v = mandoc_getarg(mdoc->parse, &p, line, pos); 599 600 return(ARGS_WORD); 601 } 602 603 /* 604 * Check if the string consists only of space-separated closing 605 * delimiters. This is a bit of a dance: the first must be a close 606 * delimiter, but it may be followed by middle delimiters. Arbitrary 607 * whitespace may separate these tokens. 608 */ 609 static int 610 args_checkpunct(const char *buf, int i) 611 { 612 int j; 613 char dbuf[DELIMSZ]; 614 enum mdelim d; 615 616 /* First token must be a close-delimiter. */ 617 618 for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++) 619 dbuf[j] = buf[i]; 620 621 if (DELIMSZ == j) 622 return(0); 623 624 dbuf[j] = '\0'; 625 if (DELIM_CLOSE != mdoc_isdelim(dbuf)) 626 return(0); 627 628 while (' ' == buf[i]) 629 i++; 630 631 /* Remaining must NOT be open/none. */ 632 633 while (buf[i]) { 634 j = 0; 635 while (buf[i] && ' ' != buf[i] && j < DELIMSZ) 636 dbuf[j++] = buf[i++]; 637 638 if (DELIMSZ == j) 639 return(0); 640 641 dbuf[j] = '\0'; 642 d = mdoc_isdelim(dbuf); 643 if (DELIM_NONE == d || DELIM_OPEN == d) 644 return(0); 645 646 while (' ' == buf[i]) 647 i++; 648 } 649 650 return('\0' == buf[i]); 651 } 652 653 static int 654 argv_multi(struct mdoc *mdoc, int line, 655 struct mdoc_argv *v, int *pos, char *buf) 656 { 657 enum margserr ac; 658 char *p; 659 660 for (v->sz = 0; ; v->sz++) { 661 if ('-' == buf[*pos]) 662 break; 663 ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); 664 if (ARGS_ERROR == ac) 665 return(0); 666 else if (ARGS_EOLN == ac) 667 break; 668 669 if (0 == v->sz % MULTI_STEP) 670 v->value = mandoc_reallocarray(v->value, 671 v->sz + MULTI_STEP, sizeof(char *)); 672 673 v->value[(int)v->sz] = mandoc_strdup(p); 674 } 675 676 return(1); 677 } 678 679 static int 680 argv_single(struct mdoc *mdoc, int line, 681 struct mdoc_argv *v, int *pos, char *buf) 682 { 683 enum margserr ac; 684 char *p; 685 686 ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); 687 if (ARGS_ERROR == ac) 688 return(0); 689 if (ARGS_EOLN == ac) 690 return(1); 691 692 v->sz = 1; 693 v->value = mandoc_malloc(sizeof(char *)); 694 v->value[0] = mandoc_strdup(p); 695 696 return(1); 697 } 698