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