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