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