]>
git.cameronkatri.com Git - mandoc.git/blob - argv.c
1 /* $Id: argv.c,v 1.26 2009/01/22 14:56:21 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 * Parse arguments and parameters of macros. Arguments follow the
30 * syntax of `-arg [val [valN...]]', while parameters are free-form text
31 * following arguments (if any). This file must correctly handle the
32 * strange punctuation rules dictated by groff.
35 #define ARGS_QUOTED (1 << 0)
36 #define ARGS_DELIM (1 << 1)
37 #define ARGS_TABSEP (1 << 2)
39 static int lookup(int, const char *);
40 static int args(struct mdoc
*, int, int *,
41 char *, int, char **);
42 static int argv(struct mdoc
*, int,
43 struct mdoc_arg
*, int *, char *);
44 static int argv_single(struct mdoc
*, int,
45 struct mdoc_arg
*, int *, char *);
46 static int argv_multi(struct mdoc
*, int,
47 struct mdoc_arg
*, int *, char *);
48 static int postargv(struct mdoc
*, int,
49 const struct mdoc_arg
*, int);
50 static int pwarn(struct mdoc
*, int, int, int);
51 static int perr(struct mdoc
*, int, int, int);
53 /* Warning messages. */
67 static int mdoc_argflags
[MDOC_MAX
] = {
91 ARGS_DELIM
| ARGS_QUOTED
, /* Fa */
94 ARGS_DELIM
| ARGS_QUOTED
, /* Fn */
95 ARGS_DELIM
| ARGS_QUOTED
, /* Ft */
109 ARGS_QUOTED
, /* %A */
110 ARGS_QUOTED
, /* %B */
111 ARGS_QUOTED
, /* %D */
112 ARGS_QUOTED
, /* %I */
113 ARGS_QUOTED
, /* %J */
114 ARGS_QUOTED
, /* %N */
115 ARGS_QUOTED
, /* %O */
116 ARGS_QUOTED
, /* %P */
117 ARGS_QUOTED
, /* %R */
118 ARGS_QUOTED
, /* %T */
119 ARGS_QUOTED
, /* %V */
128 ARGS_DELIM
, /* Bsx */
178 perr(struct mdoc
*mdoc
, int line
, int pos
, int code
)
184 c
= mdoc_perr(mdoc
, line
, pos
,
185 "unterminated quoted parameter");
188 c
= mdoc_perr(mdoc
, line
, pos
,
189 "invalid value for offset argument");
192 c
= mdoc_perr(mdoc
, line
, pos
,
193 "argument requires a value");
196 c
= mdoc_perr(mdoc
, line
, pos
,
197 "too many values for argument");
208 pwarn(struct mdoc
*mdoc
, int line
, int pos
, int code
)
214 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
215 "unexpected quoted parameter");
218 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
219 "argument-like parameter");
222 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_SYNTAX
,
223 "last list column is empty");
226 c
= mdoc_pwarn(mdoc
, line
, pos
, WARN_COMPAT
,
227 "trailing whitespace");
238 mdoc_args(struct mdoc
*mdoc
, int line
,
239 int *pos
, char *buf
, int tok
, char **v
)
244 fl
= (0 == tok
) ? 0 : mdoc_argflags
[tok
];
247 * First see if we should use TABSEP (Bl -column). This
248 * invalidates the use of ARGS_DELIM.
251 if (MDOC_It
== tok
) {
252 for (n
= mdoc
->last
; n
; n
= n
->parent
)
253 if (MDOC_BLOCK
== n
->type
)
254 if (MDOC_Bl
== n
->tok
)
257 c
= (int)n
->data
.block
.argc
;
261 for (i
= 0; i
< c
; i
++) {
262 if (MDOC_Column
!= n
->data
.block
.argv
[i
].arg
)
270 return(args(mdoc
, line
, pos
, buf
, fl
, v
));
275 args(struct mdoc
*mdoc
, int line
,
276 int *pos
, char *buf
, int fl
, char **v
)
286 if ('\"' == buf
[*pos
] && ! (fl
& ARGS_QUOTED
))
287 if ( ! pwarn(mdoc
, line
, *pos
, WQUOTPARM
))
290 if ('-' == buf
[*pos
])
291 if ( ! pwarn(mdoc
, line
, *pos
, WARGVPARM
))
295 * If the first character is a delimiter and we're to look for
296 * delimited strings, then pass down the buffer seeing if it
297 * follows the pattern of [[::delim::][ ]+]+.
300 if ((fl
& ARGS_DELIM
) && mdoc_iscdelim(buf
[*pos
])) {
301 for (i
= *pos
; (c
= buf
[i
]); ) {
302 if ( ! mdoc_iscdelim(c
))
305 if (0 == buf
[i
] || ! isspace(c
))
308 while (buf
[i
] && isspace(c
))
317 /* First parse non-quoted strings. */
319 if ('\"' != buf
[*pos
] || ! (ARGS_QUOTED
& fl
)) {
323 * Thar be dragons here! If we're tab-separated, search
324 * ahead for either a tab or the `Ta' macro. If a tab
325 * is detected, it mustn't be escaped; if a `Ta' is
326 * detected, it must be space-buffered before and after.
327 * If either of these hold true, then prune out the
328 * extra spaces and call it an argument.
331 if (ARGS_TABSEP
& fl
) {
332 /* Scan ahead to unescaped tab. */
334 for (p
= *v
; ; p
++) {
335 if (NULL
== (p
= strchr(p
, '\t')))
339 if ('\\' != *(p
- 1))
343 /* Scan ahead to unescaped `Ta'. */
345 for (pp
= *v
; ; pp
++) {
346 if (NULL
== (pp
= strstr(pp
, "Ta")))
348 if (pp
> *v
&& ' ' != *(pp
- 1))
350 if (' ' == *(pp
+ 2) || 0 == *(pp
+ 2))
354 /* Choose delimiter tab/Ta. */
357 p
= (p
< pp
? p
: pp
);
361 /* Strip delimiter's preceding whitespace. */
365 while (pp
> *v
&& ' ' == *pp
)
367 if (pp
== *v
&& ' ' == *pp
)
373 /* ...in- and proceding whitespace. */
375 if (p
&& ('\t' != *p
)) {
390 if ( ! pwarn(mdoc
, line
, *pos
, WCOLEMPTY
))
392 if (p
&& 0 == *p
&& p
> *v
&& ' ' == *(p
- 1))
393 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
399 /* Configure the eoln case, too. */
404 if (p
> *v
&& ' ' == *(p
- 1))
405 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
412 /* Do non-tabsep look-ahead here. */
414 if ( ! (ARGS_TABSEP
& fl
))
415 while ((c
= buf
[*pos
])) {
417 if ('\\' != buf
[*pos
- 1])
430 if ( ! (ARGS_TABSEP
& fl
))
431 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
437 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
444 * If we're a quoted string (and quoted strings are allowed),
445 * then parse ahead to the next quote. If none's found, it's an
446 * error. After, parse to the next word.
451 while (buf
[*pos
] && '\"' != buf
[*pos
])
454 if (0 == buf
[*pos
]) {
455 (void)perr(mdoc
, line
, *pos
, EQUOTTERM
);
463 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
469 if ( ! pwarn(mdoc
, line
, *pos
, WTAILWS
))
477 lookup(int tok
, const char *argv
)
482 if (xstrcmp(argv
, "split"))
484 else if (xstrcmp(argv
, "nosplit"))
485 return(MDOC_Nosplit
);
489 if (xstrcmp(argv
, "ragged"))
491 else if (xstrcmp(argv
, "unfilled"))
492 return(MDOC_Unfilled
);
493 else if (xstrcmp(argv
, "filled"))
495 else if (xstrcmp(argv
, "literal"))
496 return(MDOC_Literal
);
497 else if (xstrcmp(argv
, "file"))
499 else if (xstrcmp(argv
, "offset"))
504 if (xstrcmp(argv
, "emphasis"))
505 return(MDOC_Emphasis
);
506 else if (xstrcmp(argv
, "literal"))
507 return(MDOC_Literal
);
508 else if (xstrcmp(argv
, "symbolic"))
509 return(MDOC_Symbolic
);
513 if (xstrcmp(argv
, "words"))
518 if (xstrcmp(argv
, "bullet"))
520 else if (xstrcmp(argv
, "dash"))
522 else if (xstrcmp(argv
, "hyphen"))
524 else if (xstrcmp(argv
, "item"))
526 else if (xstrcmp(argv
, "enum"))
528 else if (xstrcmp(argv
, "tag"))
530 else if (xstrcmp(argv
, "diag"))
532 else if (xstrcmp(argv
, "hang"))
534 else if (xstrcmp(argv
, "ohang"))
536 else if (xstrcmp(argv
, "inset"))
538 else if (xstrcmp(argv
, "column"))
540 else if (xstrcmp(argv
, "width"))
542 else if (xstrcmp(argv
, "offset"))
544 else if (xstrcmp(argv
, "compact"))
545 return(MDOC_Compact
);
551 if (xstrcmp(argv
, "std"))
556 if (xstrcmp(argv
, "p1003.1-88"))
557 return(MDOC_p1003_1_88
);
558 else if (xstrcmp(argv
, "p1003.1-90"))
559 return(MDOC_p1003_1_90
);
560 else if (xstrcmp(argv
, "p1003.1-96"))
561 return(MDOC_p1003_1_96
);
562 else if (xstrcmp(argv
, "p1003.1-2001"))
563 return(MDOC_p1003_1_2001
);
564 else if (xstrcmp(argv
, "p1003.1-2004"))
565 return(MDOC_p1003_1_2004
);
566 else if (xstrcmp(argv
, "p1003.1"))
567 return(MDOC_p1003_1
);
568 else if (xstrcmp(argv
, "p1003.1b"))
569 return(MDOC_p1003_1b
);
570 else if (xstrcmp(argv
, "p1003.1b-93"))
571 return(MDOC_p1003_1b_93
);
572 else if (xstrcmp(argv
, "p1003.1c-95"))
573 return(MDOC_p1003_1c_95
);
574 else if (xstrcmp(argv
, "p1003.1g-2000"))
575 return(MDOC_p1003_1g_2000
);
576 else if (xstrcmp(argv
, "p1003.2-92"))
577 return(MDOC_p1003_2_92
);
578 else if (xstrcmp(argv
, "p1003.2-95"))
579 return(MDOC_p1387_2_95
);
580 else if (xstrcmp(argv
, "p1003.2"))
581 return(MDOC_p1003_2
);
582 else if (xstrcmp(argv
, "p1387.2-95"))
583 return(MDOC_p1387_2
);
584 else if (xstrcmp(argv
, "isoC-90"))
585 return(MDOC_isoC_90
);
586 else if (xstrcmp(argv
, "isoC-amd1"))
587 return(MDOC_isoC_amd1
);
588 else if (xstrcmp(argv
, "isoC-tcor1"))
589 return(MDOC_isoC_tcor1
);
590 else if (xstrcmp(argv
, "isoC-tcor2"))
591 return(MDOC_isoC_tcor2
);
592 else if (xstrcmp(argv
, "isoC-99"))
593 return(MDOC_isoC_99
);
594 else if (xstrcmp(argv
, "ansiC"))
596 else if (xstrcmp(argv
, "ansiC-89"))
597 return(MDOC_ansiC_89
);
598 else if (xstrcmp(argv
, "ansiC-99"))
599 return(MDOC_ansiC_99
);
600 else if (xstrcmp(argv
, "ieee754"))
601 return(MDOC_ieee754
);
602 else if (xstrcmp(argv
, "iso8802-3"))
603 return(MDOC_iso8802_3
);
604 else if (xstrcmp(argv
, "xpg3"))
606 else if (xstrcmp(argv
, "xpg4"))
608 else if (xstrcmp(argv
, "xpg4.2"))
610 else if (xstrcmp(argv
, "xpg4.3"))
612 else if (xstrcmp(argv
, "xbd5"))
614 else if (xstrcmp(argv
, "xcu5"))
616 else if (xstrcmp(argv
, "xsh5"))
618 else if (xstrcmp(argv
, "xns5"))
620 else if (xstrcmp(argv
, "xns5.2d2.0"))
621 return(MDOC_xns5_2d2_0
);
622 else if (xstrcmp(argv
, "xcurses4.2"))
623 return(MDOC_xcurses4_2
);
624 else if (xstrcmp(argv
, "susv2"))
626 else if (xstrcmp(argv
, "susv3"))
628 else if (xstrcmp(argv
, "svid4"))
636 return(MDOC_ARG_MAX
);
641 postargv(struct mdoc
*mdoc
, int line
, const struct mdoc_arg
*v
, int pos
)
648 if (xstrcmp(v
->value
[0], "left"))
650 if (xstrcmp(v
->value
[0], "right"))
652 if (xstrcmp(v
->value
[0], "center"))
654 if (xstrcmp(v
->value
[0], "indent"))
656 if (xstrcmp(v
->value
[0], "indent-two"))
658 return(perr(mdoc
, line
, pos
, EOFFSET
));
668 argv_multi(struct mdoc
*mdoc
, int line
,
669 struct mdoc_arg
*v
, int *pos
, char *buf
)
675 v
->value
= xcalloc(MDOC_LINEARG_MAX
, sizeof(char *));
679 for (v
->sz
= 0; v
->sz
< MDOC_LINEARG_MAX
; v
->sz
++) {
680 if ('-' == buf
[*pos
])
682 c
= args(mdoc
, line
, pos
, buf
, ARGS_QUOTED
, &p
);
683 if (ARGS_ERROR
== c
) {
686 } else if (ARGS_EOLN
== c
)
691 if (0 < v
->sz
&& v
->sz
< MDOC_LINEARG_MAX
)
696 return(perr(mdoc
, line
, ppos
, EARGVAL
));
698 return(perr(mdoc
, line
, ppos
, EARGMANY
));
703 argv_single(struct mdoc
*mdoc
, int line
,
704 struct mdoc_arg
*v
, int *pos
, char *buf
)
711 c
= args(mdoc
, line
, pos
, buf
, ARGS_QUOTED
, &p
);
715 return(perr(mdoc
, line
, ppos
, EARGVAL
));
718 v
->value
= xcalloc(1, sizeof(char *));
725 argv(struct mdoc
*mdoc
, int line
,
726 struct mdoc_arg
*v
, int *pos
, char *buf
)
738 return(argv_single(mdoc
, line
, v
, pos
, buf
));
740 return(argv_multi(mdoc
, line
, v
, pos
, buf
));
750 mdoc_argv(struct mdoc
*mdoc
, int line
, int tok
,
751 struct mdoc_arg
*v
, int *pos
, char *buf
)
756 (void)memset(v
, 0, sizeof(struct mdoc_arg
));
761 assert( ! isspace((int)buf
[*pos
]));
763 if ('-' != buf
[*pos
])
776 if (isspace((int)buf
[*pos
]))
777 if ('\\' != buf
[*pos
- 1])
785 if (MDOC_ARG_MAX
== (v
->arg
= lookup(tok
, p
))) {
786 if ( ! pwarn(mdoc
, line
, i
, WARGVPARM
))
791 while (buf
[*pos
] && isspace((int)buf
[*pos
]))
794 /* FIXME: whitespace if no value. */
797 if ( ! argv(mdoc
, line
, v
, pos
, buf
))
799 if ( ! postargv(mdoc
, line
, v
, ppos
))
807 mdoc_argv_free(int sz
, struct mdoc_arg
*arg
)
811 for (i
= 0; i
< sz
; i
++) {
812 if (0 == arg
[i
].sz
) {
813 assert(NULL
== arg
[i
].value
);
816 assert(arg
[i
].value
);