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