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