]>
git.cameronkatri.com Git - mandoc.git/blob - argv.c
8ad5d662ff223b4d3e4b395cbfdcd3be45bec86c
1 /* $Id: argv.c,v 1.34 2009/02/28 12:16:02 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
29 * Routines to parse arguments of macros. Arguments follow the syntax
30 * of `-arg [val [valN...]]'. Arguments come in all types: quoted
31 * arguments, multiple arguments per value, no-value arguments, etc.
34 #define ARGS_QUOTED (1 << 0)
35 #define ARGS_DELIM (1 << 1)
36 #define ARGS_TABSEP (1 << 2)
38 static int argv_a2arg(int, const char *);
39 static int args(struct mdoc
*, int, int *,
40 char *, int, char **);
41 static int argv(struct mdoc
*, int,
42 struct mdoc_arg
*, int *, char *);
43 static int argv_single(struct mdoc
*, int,
44 struct mdoc_arg
*, int *, char *);
45 static int argv_multi(struct mdoc
*, int,
46 struct mdoc_arg
*, int *, char *);
47 static int pwarn(struct mdoc
*, int, int, int);
48 static int perr(struct mdoc
*, int, int, int);
50 /* Warning messages. */
63 static int mdoc_argflags
[MDOC_MAX
] = {
87 ARGS_DELIM
| ARGS_QUOTED
, /* Fa */
90 ARGS_DELIM
| ARGS_QUOTED
, /* Fn */
91 ARGS_DELIM
| ARGS_QUOTED
, /* Ft */
105 ARGS_QUOTED
, /* %A */
106 ARGS_QUOTED
, /* %B */
107 ARGS_QUOTED
, /* %D */
108 ARGS_QUOTED
, /* %I */
109 ARGS_QUOTED
, /* %J */
110 ARGS_QUOTED
, /* %N */
111 ARGS_QUOTED
, /* %O */
112 ARGS_QUOTED
, /* %P */
113 ARGS_QUOTED
, /* %R */
114 ARGS_QUOTED
, /* %T */
115 ARGS_QUOTED
, /* %V */
124 ARGS_DELIM
, /* Bsx */
174 perr(struct mdoc
*mdoc
, int line
, int pos
, int code
)
180 c
= mdoc_perr(mdoc
, line
, pos
,
181 "unterminated quoted parameter");
184 c
= mdoc_perr(mdoc
, line
, pos
,
185 "argument requires a value");
188 c
= mdoc_perr(mdoc
, line
, pos
,
189 "too many values for argument");
200 pwarn(struct mdoc
*mdoc
, int line
, int pos
, int code
)
206 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
207 "unexpected quoted parameter");
210 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
211 "argument-like parameter");
214 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
215 "last list column is empty");
218 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_COMPAT
,
219 "trailing whitespace");
230 mdoc_args(struct mdoc
*mdoc
, int line
,
231 int *pos
, char *buf
, int tok
, char **v
)
236 fl
= (0 == tok
) ? 0 : mdoc_argflags
[tok
];
239 * First see if we should use TABSEP (Bl -column). This
240 * invalidates the use of ARGS_DELIM.
243 if (MDOC_It
== tok
) {
244 for (n
= mdoc
->last
; n
; n
= n
->parent
)
245 if (MDOC_BLOCK
== n
->type
)
246 if (MDOC_Bl
== n
->tok
)
249 c
= (int)n
->data
.block
.argc
;
253 for (i
= 0; i
< c
; i
++) {
254 if (MDOC_Column
!= n
->data
.block
.argv
[i
].arg
)
262 return(args(mdoc
, line
, pos
, buf
, fl
, v
));
267 args(struct mdoc
*mdoc
, int line
,
268 int *pos
, char *buf
, int fl
, char **v
)
278 if ('\"' == buf
[*pos
] && ! (fl
& ARGS_QUOTED
))
279 if ( ! pwarn(mdoc
, line
, *pos
, WQUOTPARM
))
282 if ('-' == buf
[*pos
])
283 if ( ! pwarn(mdoc
, line
, *pos
, WARGVPARM
))
287 * If the first character is a delimiter and we're to look for
288 * delimited strings, then pass down the buffer seeing if it
289 * follows the pattern of [[::delim::][ ]+]+.
292 if ((fl
& ARGS_DELIM
) && mdoc_iscdelim(buf
[*pos
])) {
293 for (i
= *pos
; buf
[i
]; ) {
294 if ( ! mdoc_iscdelim(buf
[i
]))
297 /* There must be at least one space... */
298 if (0 == buf
[i
] || ! isspace((int)buf
[i
]))
301 while (buf
[i
] && isspace((int)buf
[i
]))
310 /* First parse non-quoted strings. */
312 if ('\"' != buf
[*pos
] || ! (ARGS_QUOTED
& fl
)) {
316 * Thar be dragons here! If we're tab-separated, search
317 * ahead for either a tab or the `Ta' macro. If a tab
318 * is detected, it mustn't be escaped; if a `Ta' is
319 * detected, it must be space-buffered before and after.
320 * If either of these hold true, then prune out the
321 * extra spaces and call it an argument.
324 if (ARGS_TABSEP
& fl
) {
325 /* Scan ahead to unescaped tab. */
327 for (p
= *v
; ; p
++) {
328 if (NULL
== (p
= strchr(p
, '\t')))
332 if ('\\' != *(p
- 1))
336 /* Scan ahead to unescaped `Ta'. */
338 for (pp
= *v
; ; pp
++) {
339 if (NULL
== (pp
= strstr(pp
, "Ta")))
341 if (pp
> *v
&& ' ' != *(pp
- 1))
343 if (' ' == *(pp
+ 2) || 0 == *(pp
+ 2))
347 /* Choose delimiter tab/Ta. */
350 p
= (p
< pp
? p
: pp
);
354 /* Strip delimiter's preceding whitespace. */
358 while (pp
> *v
&& ' ' == *pp
)
360 if (pp
== *v
&& ' ' == *pp
)
366 /* ...in- and proceding whitespace. */
368 if (p
&& ('\t' != *p
)) {
379 *pos
+= (int)(p
- *v
);
383 if ( ! pwarn(mdoc
, line
, *pos
, WCOLEMPTY
))
385 if (p
&& 0 == *p
&& p
> *v
&& ' ' == *(p
- 1))
386 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
392 /* Configure the eoln case, too. */
397 if (p
> *v
&& ' ' == *(p
- 1))
398 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
400 *pos
+= (int)(p
- *v
);
405 /* Do non-tabsep look-ahead here. */
407 if ( ! (ARGS_TABSEP
& fl
))
409 if (isspace((int)buf
[*pos
]))
410 if ('\\' != buf
[*pos
- 1])
423 if ( ! (ARGS_TABSEP
& fl
))
424 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
430 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
437 * If we're a quoted string (and quoted strings are allowed),
438 * then parse ahead to the next quote. If none's found, it's an
439 * error. After, parse to the next word.
444 while (buf
[*pos
] && '\"' != buf
[*pos
])
447 if (0 == buf
[*pos
]) {
448 (void)perr(mdoc
, line
, *pos
, EQUOTTERM
);
456 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
462 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
470 argv_a2arg(int tok
, const char *argv
)
475 if (xstrcmp(argv
, "split"))
477 else if (xstrcmp(argv
, "nosplit"))
478 return(MDOC_Nosplit
);
482 if (xstrcmp(argv
, "ragged"))
484 else if (xstrcmp(argv
, "unfilled"))
485 return(MDOC_Unfilled
);
486 else if (xstrcmp(argv
, "filled"))
488 else if (xstrcmp(argv
, "literal"))
489 return(MDOC_Literal
);
490 else if (xstrcmp(argv
, "file"))
492 else if (xstrcmp(argv
, "offset"))
497 if (xstrcmp(argv
, "emphasis"))
498 return(MDOC_Emphasis
);
499 else if (xstrcmp(argv
, "literal"))
500 return(MDOC_Literal
);
501 else if (xstrcmp(argv
, "symbolic"))
502 return(MDOC_Symbolic
);
506 if (xstrcmp(argv
, "words"))
511 if (xstrcmp(argv
, "bullet"))
513 else if (xstrcmp(argv
, "dash"))
515 else if (xstrcmp(argv
, "hyphen"))
517 else if (xstrcmp(argv
, "item"))
519 else if (xstrcmp(argv
, "enum"))
521 else if (xstrcmp(argv
, "tag"))
523 else if (xstrcmp(argv
, "diag"))
525 else if (xstrcmp(argv
, "hang"))
527 else if (xstrcmp(argv
, "ohang"))
529 else if (xstrcmp(argv
, "inset"))
531 else if (xstrcmp(argv
, "column"))
533 else if (xstrcmp(argv
, "width"))
535 else if (xstrcmp(argv
, "offset"))
537 else if (xstrcmp(argv
, "compact"))
538 return(MDOC_Compact
);
544 if (xstrcmp(argv
, "std"))
549 if (xstrcmp(argv
, "p1003.1-88"))
550 return(MDOC_p1003_1_88
);
551 else if (xstrcmp(argv
, "p1003.1-90"))
552 return(MDOC_p1003_1_90
);
553 else if (xstrcmp(argv
, "p1003.1-96"))
554 return(MDOC_p1003_1_96
);
555 else if (xstrcmp(argv
, "p1003.1-2001"))
556 return(MDOC_p1003_1_2001
);
557 else if (xstrcmp(argv
, "p1003.1-2004"))
558 return(MDOC_p1003_1_2004
);
559 else if (xstrcmp(argv
, "p1003.1"))
560 return(MDOC_p1003_1
);
561 else if (xstrcmp(argv
, "p1003.1b"))
562 return(MDOC_p1003_1b
);
563 else if (xstrcmp(argv
, "p1003.1b-93"))
564 return(MDOC_p1003_1b_93
);
565 else if (xstrcmp(argv
, "p1003.1c-95"))
566 return(MDOC_p1003_1c_95
);
567 else if (xstrcmp(argv
, "p1003.1g-2000"))
568 return(MDOC_p1003_1g_2000
);
569 else if (xstrcmp(argv
, "p1003.2-92"))
570 return(MDOC_p1003_2_92
);
571 else if (xstrcmp(argv
, "p1003.2-95"))
572 return(MDOC_p1387_2_95
);
573 else if (xstrcmp(argv
, "p1003.2"))
574 return(MDOC_p1003_2
);
575 else if (xstrcmp(argv
, "p1387.2-95"))
576 return(MDOC_p1387_2
);
577 else if (xstrcmp(argv
, "isoC-90"))
578 return(MDOC_isoC_90
);
579 else if (xstrcmp(argv
, "isoC-amd1"))
580 return(MDOC_isoC_amd1
);
581 else if (xstrcmp(argv
, "isoC-tcor1"))
582 return(MDOC_isoC_tcor1
);
583 else if (xstrcmp(argv
, "isoC-tcor2"))
584 return(MDOC_isoC_tcor2
);
585 else if (xstrcmp(argv
, "isoC-99"))
586 return(MDOC_isoC_99
);
587 else if (xstrcmp(argv
, "ansiC"))
589 else if (xstrcmp(argv
, "ansiC-89"))
590 return(MDOC_ansiC_89
);
591 else if (xstrcmp(argv
, "ansiC-99"))
592 return(MDOC_ansiC_99
);
593 else if (xstrcmp(argv
, "ieee754"))
594 return(MDOC_ieee754
);
595 else if (xstrcmp(argv
, "iso8802-3"))
596 return(MDOC_iso8802_3
);
597 else if (xstrcmp(argv
, "xpg3"))
599 else if (xstrcmp(argv
, "xpg4"))
601 else if (xstrcmp(argv
, "xpg4.2"))
603 else if (xstrcmp(argv
, "xpg4.3"))
605 else if (xstrcmp(argv
, "xbd5"))
607 else if (xstrcmp(argv
, "xcu5"))
609 else if (xstrcmp(argv
, "xsh5"))
611 else if (xstrcmp(argv
, "xns5"))
613 else if (xstrcmp(argv
, "xns5.2d2.0"))
614 return(MDOC_xns5_2d2_0
);
615 else if (xstrcmp(argv
, "xcurses4.2"))
616 return(MDOC_xcurses4_2
);
617 else if (xstrcmp(argv
, "susv2"))
619 else if (xstrcmp(argv
, "susv3"))
621 else if (xstrcmp(argv
, "svid4"))
629 return(MDOC_ARG_MAX
);
634 argv_multi(struct mdoc
*mdoc
, int line
,
635 struct mdoc_arg
*v
, int *pos
, char *buf
)
641 v
->value
= xcalloc(MDOC_LINEARG_MAX
, sizeof(char *));
645 for (v
->sz
= 0; v
->sz
< MDOC_LINEARG_MAX
; v
->sz
++) {
646 if ('-' == buf
[*pos
])
648 c
= args(mdoc
, line
, pos
, buf
, ARGS_QUOTED
, &p
);
649 if (ARGS_ERROR
== c
) {
652 } else if (ARGS_EOLN
== c
)
654 v
->value
[(int)v
->sz
] = p
;
657 if (0 < v
->sz
&& v
->sz
< MDOC_LINEARG_MAX
)
662 return(perr(mdoc
, line
, ppos
, EARGVAL
));
664 return(perr(mdoc
, line
, ppos
, EARGMANY
));
669 argv_single(struct mdoc
*mdoc
, int line
,
670 struct mdoc_arg
*v
, int *pos
, char *buf
)
677 c
= args(mdoc
, line
, pos
, buf
, ARGS_QUOTED
, &p
);
681 return(perr(mdoc
, line
, ppos
, EARGVAL
));
684 v
->value
= xcalloc(1, sizeof(char *));
691 argv(struct mdoc
*mdoc
, int line
,
692 struct mdoc_arg
*v
, int *pos
, char *buf
)
704 return(argv_single(mdoc
, line
, v
, pos
, buf
));
706 return(argv_multi(mdoc
, line
, v
, pos
, buf
));
716 mdoc_argv(struct mdoc
*mdoc
, int line
, int tok
,
717 struct mdoc_arg
*v
, int *pos
, char *buf
)
722 (void)memset(v
, 0, sizeof(struct mdoc_arg
));
727 assert( ! isspace((int)buf
[*pos
]));
729 if ('-' != buf
[*pos
])
742 if (isspace((int)buf
[*pos
]))
743 if ('\\' != buf
[*pos
- 1])
751 if (MDOC_ARG_MAX
== (v
->arg
= argv_a2arg(tok
, p
))) {
752 if ( ! pwarn(mdoc
, line
, i
, WARGVPARM
))
757 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
760 /* FIXME: whitespace if no value. */
762 if ( ! argv(mdoc
, line
, v
, pos
, buf
))
770 mdoc_argv_free(int sz
, struct mdoc_arg
*arg
)
774 for (i
= 0; i
< sz
; i
++) {
775 if (0 == arg
[i
].sz
) {
776 assert(NULL
== arg
[i
].value
);
779 assert(arg
[i
].value
);