]>
git.cameronkatri.com Git - mandoc.git/blob - macro.c
1 /* $Id: macro.c,v 1.6 2008/12/23 05:30:49 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.
27 #define _CC(p) ((const char **)p)
29 static int scope_rewind_exp(struct mdoc
*, int, int, int);
30 static int append_text(struct mdoc
*, int,
32 static int append_scoped(struct mdoc
*, int, int, int,
33 const char *[], int, const struct mdoc_arg
*);
34 static int args_next(struct mdoc
*, int,
35 int *, char *, char **);
36 static int argv_next(struct mdoc
*, int,
37 int *, char *, struct mdoc_arg
*);
38 static int args_next_quoted(struct mdoc
*, int,
39 int *, char *, char **);
43 args_next_quoted(struct mdoc
*mdoc
, int tok
,
44 int *pos
, char *buf
, char **v
)
50 assert( ! isspace(buf
[*pos
]));
52 if ('\"' != buf
[*pos
])
53 return(args_next(mdoc
, tok
, pos
, buf
, v
));
57 while (buf
[*pos
] && '\"' != buf
[*pos
])
61 (void)mdoc_err(mdoc
, tok
, *pos
, ERR_SYNTAX_UNQUOTE
);
69 while (buf
[*pos
] && isspace(buf
[*pos
]))
73 if ( ! mdoc_warn(mdoc
, tok
, *pos
, WARN_SYNTAX_WS_EOLN
))
81 scope_rewind_exp(struct mdoc
*mdoc
, int ppos
, int tok
, int dst
)
86 for (n
= mdoc
->last
; n
; n
= n
->parent
) {
87 if (MDOC_BLOCK
!= n
->type
)
89 if (dst
== n
->data
.block
.tok
)
91 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SCOPE_BREAK
));
94 if (NULL
== (mdoc
->last
= n
))
95 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SCOPE_NOCTX
));
97 mdoc_msg(mdoc
, ppos
, "scope: rewound `%s' to `%s'",
98 mdoc_macronames
[tok
], mdoc_macronames
[dst
]);
105 argv_next(struct mdoc
*mdoc
, int tok
,
106 int *pos
, char *buf
, struct mdoc_arg
*v
)
114 assert( ! isspace(buf
[*pos
]));
116 if ('-' != buf
[*pos
]) {
117 (void)mdoc_err(mdoc
, tok
, *pos
, ERR_SYNTAX_ARGS
);
122 argv
= &buf
[++(*pos
)];
124 while (buf
[*pos
] && ! isspace(buf
[*pos
]))
131 * XXX This is a little bit ugly. The mdoc_argv structure
132 * points to a pointer array, which we allocate on-the-fly in
133 * this function. If there's any failure, we need to release
134 * this memory, which is done by the caller of this function
135 * with mdoc_argv_free. Ew. This should be simpler.
138 if (MDOC_ARG_MAX
== (val
= mdoc_argv_lookup(tok
, argv
))) {
139 (void)mdoc_err(mdoc
, tok
, i
, ERR_SYNTAX_BADARG
);
143 while (buf
[*pos
] && isspace(buf
[*pos
]))
146 if ( ! mdoc_argv_parse(mdoc
, tok
, val
, v
, pos
, buf
))
154 args_next(struct mdoc
*mdoc
, int tok
,
155 int *pos
, char *buf
, char **v
)
161 assert( ! isspace(buf
[*pos
]));
163 if ('\"' == buf
[*pos
]) {
164 (void)mdoc_err(mdoc
, tok
, *pos
, ERR_SYNTAX_QUOTE
);
170 /* Scan ahead to end of token. */
172 while (buf
[*pos
] && ! isspace(buf
[*pos
]))
175 if (buf
[*pos
] && buf
[*pos
+ 1] && '\\' == buf
[*pos
]) {
176 (void)mdoc_err(mdoc
, tok
, *pos
, ERR_SYNTAX_WS
);
183 /* Scan ahead over trailing whitespace. */
186 while (buf
[*pos
] && isspace(buf
[*pos
]))
190 if ( ! mdoc_warn(mdoc
, tok
, *pos
, WARN_SYNTAX_WS_EOLN
))
198 append_scoped(struct mdoc
*mdoc
, int tok
, int pos
,
199 int sz
, const char *args
[],
200 int argc
, const struct mdoc_arg
*argv
)
205 /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
208 return(mdoc_err(mdoc
, tok
, pos
, ERR_ARGS_GE1
));
210 sec
= mdoc_atosec((size_t)sz
, _CC(args
));
211 if (SEC_CUSTOM
!= sec
&& sec
< mdoc
->sec_lastn
)
212 if ( ! mdoc_warn(mdoc
, tok
, pos
, WARN_SEC_OO
))
215 if (SEC_BODY
== mdoc
->sec_last
&& SEC_NAME
!= sec
)
216 return(mdoc_err(mdoc
, tok
, pos
, ERR_SEC_NAME
));
218 if (SEC_CUSTOM
!= sec
)
219 mdoc
->sec_lastn
= sec
;
220 mdoc
->sec_last
= sec
;
225 return(mdoc_err(mdoc
, tok
, pos
, ERR_ARGS_GE1
));
231 /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
237 mdoc_block_alloc(mdoc
, pos
, tok
, (size_t)argc
, argv
);
238 mdoc_head_alloc(mdoc
, pos
, tok
, (size_t)sz
, _CC(args
));
239 mdoc_body_alloc(mdoc
, pos
, tok
);
245 append_text(struct mdoc
*mdoc
, int tok
,
246 int pos
, int sz
, char *args
[])
253 /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
265 if ( ! mdoc_warn(mdoc
, tok
, pos
, WARN_ARGS_GE1
))
293 return(mdoc_err(mdoc
, tok
, pos
, ERR_ARGS_GE1
));
294 /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
300 mdoc_elem_alloc(mdoc
, pos
, tok
, 0,
301 NULL
, (size_t)sz
, _CC(args
));
307 macro_text(MACRO_PROT_ARGS
)
309 int lastarg
, c
, lasttok
, lastpunct
, j
;
310 char *args
[MDOC_LINEARG_MAX
], *p
;
316 if (SEC_PROLOGUE
== mdoc
->sec_lastn
)
317 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE
));
322 if (j
== MDOC_LINEARG_MAX
)
323 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
324 c
= args_next(mdoc
, tok
, pos
, buf
, &args
[j
]);
328 if (0 == c
&& ! lastpunct
)
329 return(append_text(mdoc
, tok
, lasttok
, j
, args
));
335 if (MDOC_MAX
!= (c
= mdoc_find(mdoc
, args
[j
]))) {
337 if ( ! append_text(mdoc
, tok
, lasttok
, j
, args
))
339 return(mdoc_macro(mdoc
, c
, lastarg
, pos
, buf
));
344 if ( ! mdoc_isdelim(args
[j
])) {
349 /* Punctuation found. */
351 p
= args
[j
]; /* Save argument (NULL-ified in append). */
354 if ( ! append_text(mdoc
, tok
, lasttok
, j
, args
))
359 mdoc_word_alloc(mdoc
, lastarg
, args
[j
]);
370 macro_prologue_dtitle(MACRO_PROT_ARGS
)
373 char *args
[MDOC_LINEARG_MAX
];
375 if (SEC_PROLOGUE
!= mdoc
->sec_lastn
)
376 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_NPROLOGUE
));
377 if (0 == mdoc
->meta
.date
)
378 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_OO
));
379 if (mdoc
->meta
.title
[0])
380 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_REP
));
387 if (j
== MDOC_LINEARG_MAX
)
388 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
389 c
= args_next(mdoc
, tok
, pos
, buf
, &args
[++j
]);
392 if (mdoc
->meta
.title
)
394 if ( ! mdoc_warn(mdoc
, tok
, ppos
, WARN_ARGS_GE1
))
396 (void)xstrlcpy(mdoc
->meta
.title
,
397 "UNTITLED", META_TITLE_SZ
);
402 if (MDOC_MAX
!= mdoc_find(mdoc
, args
[j
]) && ! mdoc_warn
403 (mdoc
, tok
, lastarg
, WARN_SYNTAX_MACLIKE
))
407 if (xstrlcpy(mdoc
->meta
.title
, args
[0], META_TITLE_SZ
))
409 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
412 mdoc
->meta
.msec
= mdoc_atomsec(args
[1]);
413 if (MSEC_DEFAULT
!= mdoc
->meta
.msec
)
415 return(mdoc_err(mdoc
, tok
, -1, ERR_SYNTAX_ARGS
));
418 mdoc
->meta
.vol
= mdoc_atovol(args
[2]);
419 if (VOL_DEFAULT
!= mdoc
->meta
.vol
)
421 mdoc
->meta
.arch
= mdoc_atoarch(args
[2]);
422 if (ARCH_DEFAULT
!= mdoc
->meta
.arch
)
424 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
427 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
432 macro_prologue_os(MACRO_PROT_ARGS
)
435 char *args
[MDOC_LINEARG_MAX
];
437 if (SEC_PROLOGUE
!= mdoc
->sec_lastn
)
438 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_NPROLOGUE
));
439 if (0 == mdoc
->meta
.title
[0])
440 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_OO
));
441 if (mdoc
->meta
.os
[0])
442 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_REP
));
449 if (j
== MDOC_LINEARG_MAX
)
450 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
451 c
= args_next_quoted(mdoc
, tok
, pos
, buf
, &args
[++j
]);
454 mdoc
->sec_lastn
= mdoc
->sec_last
= SEC_BODY
;
459 if ( ! xstrlcat(mdoc
->meta
.os
, args
[j
], sizeof(mdoc
->meta
.os
)))
460 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
461 if ( ! xstrlcat(mdoc
->meta
.os
, " ", sizeof(mdoc
->meta
.os
)))
462 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
470 macro_prologue_ddate(MACRO_PROT_ARGS
)
473 char *args
[MDOC_LINEARG_MAX
], date
[64];
475 if (SEC_PROLOGUE
!= mdoc
->sec_lastn
)
476 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_NPROLOGUE
));
477 if (mdoc
->meta
.title
[0])
478 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_OO
));
480 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE_REP
));
488 if (j
== MDOC_LINEARG_MAX
)
489 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
490 c
= args_next(mdoc
, tok
, pos
, buf
, &args
[++j
]);
495 mdoc
->meta
.date
= mdoc_atotime(date
);
498 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SYNTAX_ARGS
));
502 if (MDOC_MAX
!= mdoc_find(mdoc
, args
[j
]) && ! mdoc_warn
503 (mdoc
, tok
, lastarg
, WARN_SYNTAX_MACLIKE
))
507 if (xstrcmp("$Mdocdate: December 23 2008 $", args
[j
])) {
508 mdoc
->meta
.date
= time(NULL
);
510 } else if (xstrcmp("$Mdocdate:", args
[j
]))
513 if ( ! xstrcmp("$", args
[j
]))
516 if ( ! xstrlcat(date
, args
[j
], sizeof(date
)))
517 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
518 if ( ! xstrlcat(date
, " ", sizeof(date
)))
519 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_SYNTAX_ARGS
));
527 macro_scoped_explicit(MACRO_PROT_ARGS
)
530 struct mdoc_arg argv
[MDOC_LINEARG_MAX
];
532 if (SEC_PROLOGUE
== mdoc
->sec_lastn
)
533 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE
));
536 * First close out the explicit scope. The `end' tags (such as
537 * `.El' to `.Bl' don't cause anything to happen: we merely
538 * readjust our last parse point.
543 return(scope_rewind_exp(mdoc
, ppos
, tok
, MDOC_Bl
));
548 assert(MDOC_EXPLICIT
& mdoc_macros
[tok
].flags
);
552 for (j
= 0; j
< MDOC_LINEARG_MAX
; j
++) {
554 c
= argv_next(mdoc
, tok
, pos
, buf
, &argv
[j
]);
560 mdoc_argv_free(j
, argv
);
564 if (MDOC_LINEARG_MAX
== j
) {
565 mdoc_argv_free(j
, argv
);
566 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
569 c
= append_scoped(mdoc
, tok
, ppos
, 0, NULL
, j
, argv
);
570 mdoc_argv_free(j
, argv
);
576 macro_scoped_implicit(MACRO_PROT_ARGS
)
578 int t
, c
, lastarg
, j
;
579 char *args
[MDOC_LINEARG_MAX
];
582 assert( ! (MDOC_EXPLICIT
& mdoc_macros
[tok
].flags
));
584 if (SEC_PROLOGUE
== mdoc
->sec_lastn
)
585 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SEC_PROLOGUE
));
587 /* FIXME: put into scope_rewind_imp(). */
590 for (n
= mdoc
->last
; n
; n
= n
->parent
) {
591 if (MDOC_BLOCK
!= n
->type
)
593 if (tok
== (t
= n
->data
.block
.tok
))
595 if ( ! (MDOC_EXPLICIT
& mdoc_macros
[t
].flags
))
597 return(mdoc_err(mdoc
, tok
, ppos
, ERR_SCOPE_BREAK
));
602 mdoc_msg(mdoc
, ppos
, "scope: rewound `%s'",
603 mdoc_macronames
[tok
]);
605 mdoc_msg(mdoc
, ppos
, "scope: new `%s'",
606 mdoc_macronames
[tok
]);
613 if (j
== MDOC_LINEARG_MAX
)
614 return(mdoc_err(mdoc
, tok
, lastarg
, ERR_ARGS_MANY
));
615 c
= args_next(mdoc
, tok
, pos
, buf
, &args
[j
]);
620 return(append_scoped(mdoc
, tok
, ppos
,
621 j
, _CC(args
), 0, NULL
));
625 if (MDOC_MAX
!= (c
= mdoc_find(mdoc
, args
[j
])))
626 if ( ! mdoc_warn(mdoc
, tok
, lastarg
, WARN_SYNTAX_MACLIKE
))