]> git.cameronkatri.com Git - mandoc.git/blob - macro.c
*** empty log message ***
[mandoc.git] / macro.c
1 /* $Id: macro.c,v 1.7 2008/12/28 00:34:20 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
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.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "private.h"
26
27 #define _CC(p) ((const char **)p)
28
29 static int scope_rewind_exp(struct mdoc *, int, int, int);
30 static int scope_rewind_imp(struct mdoc *, int, int);
31 static int append_text(struct mdoc *, int,
32 int, int, char *[]);
33 static int append_scoped(struct mdoc *, int, int, int,
34 const char *[], int, const struct mdoc_arg *);
35 static int append_delims(struct mdoc *, int, int *, char *);
36
37
38 static int
39 append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
40 {
41 int c, lastarg;
42 char *p;
43
44 if (0 == buf[*pos])
45 return(1);
46
47 mdoc_msg(mdoc, *pos, "appending delimiters");
48
49 for (;;) {
50 lastarg = *pos;
51 c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
52 if (ARGS_ERROR == c)
53 return(0);
54 else if (ARGS_EOLN == c)
55 break;
56 assert(mdoc_isdelim(p));
57 mdoc_word_alloc(mdoc, lastarg, p);
58 }
59
60 return(1);
61 }
62
63
64 static int
65 scope_rewind_imp(struct mdoc *mdoc, int ppos, int tok)
66 {
67 struct mdoc_node *n;
68 int t;
69
70 n = mdoc->last ? mdoc->last->parent : NULL;
71
72 /* LINTED */
73 for ( ; n; n = n->parent) {
74 if (MDOC_BLOCK != n->type)
75 continue;
76 if (tok == (t = n->data.block.tok))
77 break;
78 if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
79 continue;
80 return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
81 }
82
83 if (n) {
84 mdoc->last = n;
85 mdoc_msg(mdoc, ppos, "scope: rewound implicit `%s'",
86 mdoc_macronames[tok]);
87 return(1);
88 }
89
90 mdoc_msg(mdoc, ppos, "scope: new implicit `%s'",
91 mdoc_macronames[tok]);
92 return(1);
93 }
94
95
96 static int
97 scope_rewind_exp(struct mdoc *mdoc, int ppos, int tok, int dst)
98 {
99 struct mdoc_node *n;
100
101 assert(mdoc->last);
102
103 /* LINTED */
104 for (n = mdoc->last->parent; n; n = n->parent) {
105 if (MDOC_BLOCK != n->type)
106 continue;
107 if (dst == n->data.block.tok)
108 break;
109 return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
110 }
111
112 if (NULL == (mdoc->last = n))
113 return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
114
115 mdoc_msg(mdoc, ppos, "scope: rewound explicit `%s' to `%s'",
116 mdoc_macronames[tok], mdoc_macronames[dst]);
117
118 return(1);
119 }
120
121
122 static int
123 append_scoped(struct mdoc *mdoc, int tok, int pos,
124 int sz, const char *args[],
125 int argc, const struct mdoc_arg *argv)
126 {
127 enum mdoc_sec sec;
128 struct mdoc_node *node;
129
130 switch (tok) {
131 /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
132 case (MDOC_Sh):
133 if (0 == sz)
134 return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
135
136 sec = mdoc_atosec((size_t)sz, _CC(args));
137 if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
138 if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
139 return(0);
140
141 if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
142 return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
143
144 if (SEC_CUSTOM != sec)
145 mdoc->sec_lastn = sec;
146 mdoc->sec_last = sec;
147 break;
148
149 case (MDOC_Ss):
150 if (0 == sz)
151 return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
152 break;
153
154 case (MDOC_Bd):
155 assert(mdoc->last);
156 for (node = mdoc->last->parent; node; node = node->parent) {
157 if (node->type != MDOC_BLOCK)
158 continue;
159 if (node->data.block.tok != MDOC_Bd)
160 continue;
161 return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NONEST));
162 }
163 break;
164
165 case (MDOC_Bl):
166 break;
167
168 /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
169 default:
170 abort();
171 /* NOTREACHED */
172 }
173
174 mdoc_block_alloc(mdoc, pos, tok, (size_t)argc, argv);
175 mdoc_head_alloc(mdoc, pos, tok, (size_t)sz, _CC(args));
176 mdoc_body_alloc(mdoc, pos, tok);
177 return(1);
178 }
179
180
181 static int
182 append_text(struct mdoc *mdoc, int tok,
183 int pos, int sz, char *args[])
184 {
185
186 assert(sz >= 0);
187 args[sz] = NULL;
188
189 switch (tok) {
190 /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
191 case (MDOC_Pp):
192 if (0 == sz)
193 break;
194 if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0))
195 return(0);
196 break;
197
198 case (MDOC_Ft):
199 /* FALLTHROUGH */
200 case (MDOC_Li):
201 /* FALLTHROUGH */
202 case (MDOC_Ms):
203 /* FALLTHROUGH */
204 case (MDOC_Pa):
205 /* FALLTHROUGH */
206 case (MDOC_Tn):
207 if (0 < sz)
208 break;
209 if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
210 return(0);
211 break;
212
213 case (MDOC_Ar):
214 /* FALLTHROUGH */
215 case (MDOC_Cm):
216 /* FALLTHROUGH */
217 case (MDOC_Fl):
218 /* These can have no arguments. */
219 break;
220
221 case (MDOC_Ad):
222 /* FALLTHROUGH */
223 case (MDOC_Em):
224 /* FALLTHROUGH */
225 case (MDOC_Er):
226 /* FALLTHROUGH */
227 case (MDOC_Ev):
228 /* FALLTHROUGH */
229 case (MDOC_Fa):
230 /* FALLTHROUGH */
231 case (MDOC_Dv):
232 /* FALLTHROUGH */
233 case (MDOC_Ic):
234 /* FALLTHROUGH */
235 case (MDOC_Va):
236 /* FALLTHROUGH */
237 case (MDOC_Vt):
238 if (0 < sz)
239 break;
240 return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
241 /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
242 default:
243 abort();
244 /* NOTREACHED */
245 }
246
247 mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
248 return(1);
249 }
250
251
252 int
253 macro_text(MACRO_PROT_ARGS)
254 {
255 int lastarg, lastpunct, c, j;
256 char *args[MDOC_LINEARG_MAX], *p;
257
258 if (SEC_PROLOGUE == mdoc->sec_lastn)
259 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
260
261 /* Token pre-processing. */
262
263 switch (tok) {
264 case (MDOC_Pp):
265 /* `.Pp' ignored when following `.Sh' or `.Ss'. */
266 assert(mdoc->last);
267 if (MDOC_BODY != mdoc->last->type)
268 break;
269 switch (mdoc->last->data.body.tok) {
270 case (MDOC_Ss):
271 /* FALLTHROUGH */
272 case (MDOC_Sh):
273 if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_AFTER_BLK))
274 return(0);
275 return(1);
276 default:
277 break;
278 }
279 break;
280 default:
281 break;
282 }
283
284 /* Process line parameters. */
285
286 j = 0;
287 lastarg = ppos;
288 lastpunct = 0;
289
290 again:
291 if (j == MDOC_LINEARG_MAX)
292 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
293
294 /*
295 * Parse out the next argument, unquoted and unescaped. If
296 * we're a word (which may be punctuation followed eventually by
297 * a real word), then fall into checking for callables. If
298 * only punctuation remains and we're the first, then flush
299 * arguments, punctuation and exit; else, return to the caller.
300 */
301
302 lastarg = *pos;
303
304 switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &args[j])) {
305 case (ARGS_ERROR):
306 return(0);
307 case (ARGS_WORD):
308 break;
309 case (ARGS_PUNCT):
310 if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
311 return(0);
312 return(append_delims(mdoc, tok, pos, buf));
313 case (ARGS_EOLN):
314 return(append_text(mdoc, tok, ppos, j, args));
315 default:
316 abort();
317 /* NOTREACHED */
318 }
319
320 /*
321 * Command found. First flush out arguments, then call the
322 * command. If we're the line macro when it exits, flush
323 * terminal punctuation.
324 */
325
326 if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
327 if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
328 return(0);
329 if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
330 return(0);
331 if (ppos > 1)
332 return(1);
333 return(append_delims(mdoc, tok, pos, buf));
334 }
335
336 /* Word/non-term-punctuation found. */
337
338 if ( ! mdoc_isdelim(args[j])) {
339 /* Words are appended to the array of arguments. */
340 j++;
341 lastpunct = 1;
342 goto again;
343 }
344
345 /*
346 * For punctuation, flush all collected words, then flush
347 * punctuation, then start collecting again. Of course, this
348 * is non-terminal punctuation.
349 */
350
351 p = args[j];
352 if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
353 return(0);
354
355 mdoc_word_alloc(mdoc, lastarg, p);
356 j = 0;
357 lastpunct = 1;
358
359 goto again;
360
361 /* NOTREACHED */
362 }
363
364
365 int
366 macro_prologue_dtitle(MACRO_PROT_ARGS)
367 {
368 int lastarg, j;
369 char *args[MDOC_LINEARG_MAX];
370
371 if (SEC_PROLOGUE != mdoc->sec_lastn)
372 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
373 if (0 == mdoc->meta.date)
374 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
375 if (mdoc->meta.title[0])
376 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
377
378 j = -1;
379 lastarg = ppos;
380
381 again:
382 if (j == MDOC_LINEARG_MAX)
383 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
384
385 lastarg = *pos;
386
387 switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
388 case (ARGS_EOLN):
389 if (mdoc->meta.title)
390 return(1);
391 if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1))
392 return(0);
393 (void)xstrlcpy(mdoc->meta.title,
394 "UNTITLED", META_TITLE_SZ);
395 return(1);
396 case (ARGS_ERROR):
397 return(0);
398 default:
399 break;
400 }
401
402 if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
403 (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
404 return(0);
405
406 if (0 == j) {
407 if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ))
408 goto again;
409 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
410
411 } else if (1 == j) {
412 mdoc->meta.msec = mdoc_atomsec(args[1]);
413 if (MSEC_DEFAULT != mdoc->meta.msec)
414 goto again;
415 return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGFORM));
416
417 } else if (2 == j) {
418 mdoc->meta.vol = mdoc_atovol(args[2]);
419 if (VOL_DEFAULT != mdoc->meta.vol)
420 goto again;
421 mdoc->meta.arch = mdoc_atoarch(args[2]);
422 if (ARCH_DEFAULT != mdoc->meta.arch)
423 goto again;
424 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
425 }
426
427 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
428 }
429
430
431 int
432 macro_prologue_os(MACRO_PROT_ARGS)
433 {
434 int lastarg, j;
435 char *args[MDOC_LINEARG_MAX];
436
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));
443
444 j = -1;
445 lastarg = ppos;
446
447 again:
448 if (j == MDOC_LINEARG_MAX)
449 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
450
451 lastarg = *pos;
452
453 switch (mdoc_args(mdoc, tok, pos, buf,
454 ARGS_QUOTED, &args[++j])) {
455 case (ARGS_EOLN):
456 mdoc->sec_lastn = mdoc->sec_last = SEC_BODY;
457 return(1);
458 case (ARGS_ERROR):
459 return(0);
460 default:
461 break;
462 }
463
464 if ( ! xstrlcat(mdoc->meta.os, args[j], sizeof(mdoc->meta.os)))
465 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
466 if ( ! xstrlcat(mdoc->meta.os, " ", sizeof(mdoc->meta.os)))
467 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
468
469 goto again;
470 /* NOTREACHED */
471 }
472
473
474 int
475 macro_prologue_ddate(MACRO_PROT_ARGS)
476 {
477 int lastarg, j;
478 char *args[MDOC_LINEARG_MAX], date[64];
479
480 if (SEC_PROLOGUE != mdoc->sec_lastn)
481 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
482 if (mdoc->meta.title[0])
483 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
484 if (mdoc->meta.date)
485 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
486
487 j = -1;
488 date[0] = 0;
489 lastarg = ppos;
490
491 again:
492 if (j == MDOC_LINEARG_MAX)
493 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
494
495 lastarg = *pos;
496 switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
497 case (ARGS_EOLN):
498 if (mdoc->meta.date)
499 return(1);
500 mdoc->meta.date = mdoc_atotime(date);
501 if (mdoc->meta.date)
502 return(1);
503 return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGFORM));
504 case (ARGS_ERROR):
505 return(0);
506 default:
507 break;
508 }
509
510 if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
511 (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
512 return(0);
513
514 if (0 == j) {
515 if (xstrcmp("$Mdocdate: December 28 2008 $", args[j])) {
516 mdoc->meta.date = time(NULL);
517 goto again;
518 } else if (xstrcmp("$Mdocdate:", args[j]))
519 goto again;
520 } else if (4 == j)
521 if ( ! xstrcmp("$", args[j]))
522 goto again;
523
524 if ( ! xstrlcat(date, args[j], sizeof(date)))
525 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
526 if ( ! xstrlcat(date, " ", sizeof(date)))
527 return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
528
529 goto again;
530 /* NOTREACHED */
531 }
532
533
534 int
535 macro_scoped_explicit(MACRO_PROT_ARGS)
536 {
537 int c, lastarg, j;
538 struct mdoc_arg argv[MDOC_LINEARG_MAX];
539 struct mdoc_node *n;
540
541 if (SEC_PROLOGUE == mdoc->sec_lastn)
542 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
543
544 /*
545 * First close out the explicit scope. The `end' tags (such as
546 * `.El' to `.Bl' don't cause anything to happen: we merely
547 * readjust our last parse point.
548 */
549
550 switch (tok) {
551 case (MDOC_El):
552 return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bl));
553 case (MDOC_Ed):
554 return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bd));
555 default:
556 break;
557 }
558
559 assert(MDOC_EXPLICIT & mdoc_macros[tok].flags);
560
561 /* Token pre-processing. */
562
563 switch (tok) {
564 case (MDOC_Bl):
565 /* FALLTHROUGH */
566 case (MDOC_Bd):
567 /* `.Pp' ignored when preceding `.Bl' or `.Bd'. */
568 assert(mdoc->last);
569 if (MDOC_ELEM != mdoc->last->type)
570 break;
571 if (MDOC_Pp != mdoc->last->data.elem.tok)
572 break;
573 if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
574 return(0);
575 assert(mdoc->last->prev);
576 n = mdoc->last;
577 mdoc->last = mdoc->last->prev;
578 mdoc->last->next = NULL;
579 mdoc_node_free(n);
580 break;
581 default:
582 break;
583 }
584
585 lastarg = *pos;
586
587 for (j = 0; j < MDOC_LINEARG_MAX; j++) {
588 lastarg = *pos;
589 c = mdoc_argv(mdoc, tok, &argv[j], pos, buf);
590 if (0 == c)
591 break;
592 else if (1 == c)
593 continue;
594
595 mdoc_argv_free(j, argv);
596 return(0);
597 }
598
599 if (MDOC_LINEARG_MAX == j) {
600 mdoc_argv_free(j, argv);
601 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
602 }
603
604 c = append_scoped(mdoc, tok, ppos, 0, NULL, j, argv);
605 mdoc_argv_free(j, argv);
606 return(c);
607 }
608
609
610 int
611 macro_scoped_implicit(MACRO_PROT_ARGS)
612 {
613 int lastarg, j;
614 char *args[MDOC_LINEARG_MAX];
615 struct mdoc_node *n;
616
617 assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
618
619 if (SEC_PROLOGUE == mdoc->sec_lastn)
620 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
621
622 /* Token pre-processing. */
623
624 switch (tok) {
625 case (MDOC_Ss):
626 /* FALLTHROUGH */
627 case (MDOC_Sh):
628 /* `.Pp' ignored when preceding `.Ss' or `.Sh'. */
629 if (NULL == mdoc->last)
630 break;
631 if (MDOC_ELEM != mdoc->last->type)
632 break;
633 if (MDOC_Pp != mdoc->last->data.elem.tok)
634 break;
635 if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
636 return(0);
637 assert(mdoc->last->prev);
638 n = mdoc->last;
639 mdoc->last = mdoc->last->prev;
640 mdoc->last->next = NULL;
641 mdoc_node_free(n);
642 break;
643 default:
644 break;
645 }
646
647 switch (tok) {
648 case (MDOC_Sh):
649 /* FALLTHROUGH */
650 case (MDOC_Ss):
651 if ( ! scope_rewind_imp(mdoc, ppos, tok))
652 return(0);
653 break;
654 default:
655 break;
656 }
657
658 j = 0;
659 lastarg = ppos;
660
661 again:
662 if (j == MDOC_LINEARG_MAX)
663 return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
664
665 lastarg = *pos;
666
667 switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[j])) {
668 case (ARGS_ERROR):
669 return(0);
670 case (ARGS_EOLN):
671 return(append_scoped(mdoc, tok, ppos, j, _CC(args), 0, NULL));
672 default:
673 break;
674 }
675
676 /* Command found. */
677
678 if (MDOC_MAX != mdoc_find(mdoc, args[j]))
679 if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
680 return(0);
681
682 /* Word found. */
683
684 j++;
685 goto again;
686
687 /* NOTREACHED */
688 }
689
690
691 int
692 macro_scoped_line(MACRO_PROT_ARGS)
693 {
694
695 return(1);
696 }