bd0ca99243680e0c43b0ad2f0a2fdf98b36b2a48
[dragonfly.git] / contrib / mdocml / man_macro.c
1 /*      $Id: man_macro.c,v 1.54 2010/12/08 10:58:22 kristaps Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2010 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 <assert.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "mandoc.h"
27 #include "libman.h"
28
29 enum    rew {
30         REW_REWIND,
31         REW_NOHALT,
32         REW_HALT
33 };
34
35 static  int              blk_close(MACRO_PROT_ARGS);
36 static  int              blk_exp(MACRO_PROT_ARGS);
37 static  int              blk_imp(MACRO_PROT_ARGS);
38 static  int              in_line_eoln(MACRO_PROT_ARGS);
39
40 static  int              rew_scope(enum man_type, 
41                                 struct man *, enum mant);
42 static  enum rew         rew_dohalt(enum mant, enum man_type, 
43                                 const struct man_node *);
44 static  enum rew         rew_block(enum mant, enum man_type, 
45                                 const struct man_node *);
46 static  int              rew_warn(struct man *, 
47                                 struct man_node *, enum mandocerr);
48
49 const   struct man_macro __man_macros[MAN_MAX] = {
50         { in_line_eoln, MAN_NSCOPED }, /* br */
51         { in_line_eoln, 0 }, /* TH */
52         { blk_imp, MAN_SCOPED }, /* SH */
53         { blk_imp, MAN_SCOPED }, /* SS */
54         { blk_imp, MAN_SCOPED | MAN_FSCOPED }, /* TP */
55         { blk_imp, 0 }, /* LP */
56         { blk_imp, 0 }, /* PP */
57         { blk_imp, 0 }, /* P */
58         { blk_imp, 0 }, /* IP */
59         { blk_imp, 0 }, /* HP */
60         { in_line_eoln, MAN_SCOPED }, /* SM */
61         { in_line_eoln, MAN_SCOPED }, /* SB */
62         { in_line_eoln, 0 }, /* BI */
63         { in_line_eoln, 0 }, /* IB */
64         { in_line_eoln, 0 }, /* BR */
65         { in_line_eoln, 0 }, /* RB */
66         { in_line_eoln, MAN_SCOPED }, /* R */
67         { in_line_eoln, MAN_SCOPED }, /* B */
68         { in_line_eoln, MAN_SCOPED }, /* I */
69         { in_line_eoln, 0 }, /* IR */
70         { in_line_eoln, 0 }, /* RI */
71         { in_line_eoln, MAN_NSCOPED }, /* na */
72         { in_line_eoln, MAN_NSCOPED }, /* sp */
73         { in_line_eoln, 0 }, /* nf */
74         { in_line_eoln, 0 }, /* fi */
75         { blk_close, 0 }, /* RE */
76         { blk_exp, MAN_EXPLICIT }, /* RS */
77         { in_line_eoln, 0 }, /* DT */
78         { in_line_eoln, 0 }, /* UC */
79         { in_line_eoln, 0 }, /* PD */
80         { in_line_eoln, 0 }, /* AT */
81         { in_line_eoln, 0 }, /* in */
82         { in_line_eoln, 0 }, /* ft */
83 };
84
85 const   struct man_macro * const man_macros = __man_macros;
86
87
88 /*
89  * Warn when "n" is an explicit non-roff macro.
90  */
91 static int
92 rew_warn(struct man *m, struct man_node *n, enum mandocerr er)
93 {
94
95         if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
96                 return(1);
97         if (MAN_VALID & n->flags)
98                 return(1);
99         if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
100                 return(1);
101         return(man_nmsg(m, n, er));
102 }
103
104
105 /*
106  * Rewind scope.  If a code "er" != MANDOCERR_MAX has been provided, it
107  * will be used if an explicit block scope is being closed out.
108  */
109 int
110 man_unscope(struct man *m, const struct man_node *n, 
111                 enum mandocerr er)
112 {
113
114         assert(n);
115
116         /* LINTED */
117         while (m->last != n) {
118                 if ( ! rew_warn(m, m->last, er))
119                         return(0);
120                 if ( ! man_valid_post(m))
121                         return(0);
122                 m->last = m->last->parent;
123                 assert(m->last);
124         }
125
126         if ( ! rew_warn(m, m->last, er))
127                 return(0);
128         if ( ! man_valid_post(m))
129                 return(0);
130
131         m->next = MAN_ROOT == m->last->type ? 
132                 MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
133
134         return(1);
135 }
136
137
138 static enum rew
139 rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
140 {
141
142         if (MAN_BLOCK == type && ntok == n->parent->tok && 
143                         MAN_BODY == n->parent->type)
144                 return(REW_REWIND);
145         return(ntok == n->tok ? REW_HALT : REW_NOHALT);
146 }
147
148
149 /*
150  * There are three scope levels: scoped to the root (all), scoped to the
151  * section (all less sections), and scoped to subsections (all less
152  * sections and subsections).
153  */
154 static enum rew 
155 rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
156 {
157         enum rew         c;
158
159         /* We cannot progress beyond the root ever. */
160         if (MAN_ROOT == n->type)
161                 return(REW_HALT);
162
163         assert(n->parent);
164
165         /* Normal nodes shouldn't go to the level of the root. */
166         if (MAN_ROOT == n->parent->type)
167                 return(REW_REWIND);
168
169         /* Already-validated nodes should be closed out. */
170         if (MAN_VALID & n->flags)
171                 return(REW_NOHALT);
172
173         /* First: rewind to ourselves. */
174         if (type == n->type && tok == n->tok)
175                 return(REW_REWIND);
176
177         /* 
178          * Next follow the implicit scope-smashings as defined by man.7:
179          * section, sub-section, etc.
180          */
181
182         switch (tok) {
183         case (MAN_SH):
184                 break;
185         case (MAN_SS):
186                 /* Rewind to a section, if a block. */
187                 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
188                         return(c);
189                 break;
190         case (MAN_RS):
191                 /* Rewind to a subsection, if a block. */
192                 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
193                         return(c);
194                 /* Rewind to a section, if a block. */
195                 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
196                         return(c);
197                 break;
198         default:
199                 /* Rewind to an offsetter, if a block. */
200                 if (REW_NOHALT != (c = rew_block(MAN_RS, type, n)))
201                         return(c);
202                 /* Rewind to a subsection, if a block. */
203                 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n)))
204                         return(c);
205                 /* Rewind to a section, if a block. */
206                 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
207                         return(c);
208                 break;
209         }
210
211         return(REW_NOHALT);
212 }
213
214
215 /*
216  * Rewinding entails ascending the parse tree until a coherent point,
217  * for example, the `SH' macro will close out any intervening `SS'
218  * scopes.  When a scope is closed, it must be validated and actioned.
219  */
220 static int
221 rew_scope(enum man_type type, struct man *m, enum mant tok)
222 {
223         struct man_node *n;
224         enum rew         c;
225
226         /* LINTED */
227         for (n = m->last; n; n = n->parent) {
228                 /* 
229                  * Whether we should stop immediately (REW_HALT), stop
230                  * and rewind until this point (REW_REWIND), or keep
231                  * rewinding (REW_NOHALT).
232                  */
233                 c = rew_dohalt(tok, type, n);
234                 if (REW_HALT == c)
235                         return(1);
236                 if (REW_REWIND == c)
237                         break;
238         }
239
240         /* 
241          * Rewind until the current point.  Warn if we're a roff
242          * instruction that's mowing over explicit scopes.
243          */
244         assert(n);
245
246         return(man_unscope(m, n, MANDOCERR_MAX));
247 }
248
249
250 /*
251  * Close out a generic explicit macro.
252  */
253 /* ARGSUSED */
254 int
255 blk_close(MACRO_PROT_ARGS)
256 {
257         enum mant                ntok;
258         const struct man_node   *nn;
259
260         switch (tok) {
261         case (MAN_RE):
262                 ntok = MAN_RS;
263                 break;
264         default:
265                 abort();
266                 /* NOTREACHED */
267         }
268
269         for (nn = m->last->parent; nn; nn = nn->parent)
270                 if (ntok == nn->tok)
271                         break;
272
273         if (NULL == nn)
274                 if ( ! man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE))
275                         return(0);
276
277         if ( ! rew_scope(MAN_BODY, m, ntok))
278                 return(0);
279         if ( ! rew_scope(MAN_BLOCK, m, ntok))
280                 return(0);
281
282         return(1);
283 }
284
285
286 /* ARGSUSED */
287 int
288 blk_exp(MACRO_PROT_ARGS)
289 {
290         int              w, la;
291         char            *p;
292
293         /* 
294          * Close out prior scopes.  "Regular" explicit macros cannot be
295          * nested, but we allow roff macros to be placed just about
296          * anywhere.
297          */
298
299         if ( ! rew_scope(MAN_BODY, m, tok))
300                 return(0);
301         if ( ! rew_scope(MAN_BLOCK, m, tok))
302                 return(0);
303
304         if ( ! man_block_alloc(m, line, ppos, tok))
305                 return(0);
306         if ( ! man_head_alloc(m, line, ppos, tok))
307                 return(0);
308
309         for (;;) {
310                 la = *pos;
311                 w = man_args(m, line, pos, buf, &p);
312
313                 if (-1 == w)
314                         return(0);
315                 if (0 == w)
316                         break;
317
318                 if ( ! man_word_alloc(m, line, la, p))
319                         return(0);
320         }
321
322         assert(m);
323         assert(tok != MAN_MAX);
324
325         if ( ! rew_scope(MAN_HEAD, m, tok))
326                 return(0);
327         return(man_body_alloc(m, line, ppos, tok));
328 }
329
330
331
332 /*
333  * Parse an implicit-block macro.  These contain a MAN_HEAD and a
334  * MAN_BODY contained within a MAN_BLOCK.  Rules for closing out other
335  * scopes, such as `SH' closing out an `SS', are defined in the rew
336  * routines.
337  */
338 /* ARGSUSED */
339 int
340 blk_imp(MACRO_PROT_ARGS)
341 {
342         int              w, la;
343         char            *p;
344         struct man_node *n;
345
346         /* Close out prior scopes. */
347
348         if ( ! rew_scope(MAN_BODY, m, tok))
349                 return(0);
350         if ( ! rew_scope(MAN_BLOCK, m, tok))
351                 return(0);
352
353         /* Allocate new block & head scope. */
354
355         if ( ! man_block_alloc(m, line, ppos, tok))
356                 return(0);
357         if ( ! man_head_alloc(m, line, ppos, tok))
358                 return(0);
359
360         n = m->last;
361
362         /* Add line arguments. */
363
364         for (;;) {
365                 la = *pos;
366                 w = man_args(m, line, pos, buf, &p);
367
368                 if (-1 == w)
369                         return(0);
370                 if (0 == w)
371                         break;
372
373                 if ( ! man_word_alloc(m, line, la, p))
374                         return(0);
375         }
376
377         /* Close out head and open body (unless MAN_SCOPE). */
378
379         if (MAN_SCOPED & man_macros[tok].flags) {
380                 /* If we're forcing scope (`TP'), keep it open. */
381                 if (MAN_FSCOPED & man_macros[tok].flags) {
382                         m->flags |= MAN_BLINE;
383                         return(1);
384                 } else if (n == m->last) {
385                         m->flags |= MAN_BLINE;
386                         return(1);
387                 }
388         }
389
390         if ( ! rew_scope(MAN_HEAD, m, tok))
391                 return(0);
392         return(man_body_alloc(m, line, ppos, tok));
393 }
394
395
396 /* ARGSUSED */
397 int
398 in_line_eoln(MACRO_PROT_ARGS)
399 {
400         int              w, la;
401         char            *p;
402         struct man_node *n;
403
404         if ( ! man_elem_alloc(m, line, ppos, tok))
405                 return(0);
406
407         n = m->last;
408
409         for (;;) {
410                 la = *pos;
411                 w = man_args(m, line, pos, buf, &p);
412
413                 if (-1 == w)
414                         return(0);
415                 if (0 == w)
416                         break;
417                 if ( ! man_word_alloc(m, line, la, p))
418                         return(0);
419         }
420
421         /*
422          * If no arguments are specified and this is MAN_SCOPED (i.e.,
423          * next-line scoped), then set our mode to indicate that we're
424          * waiting for terms to load into our context.
425          */
426
427         if (n == m->last && MAN_SCOPED & man_macros[tok].flags) {
428                 assert( ! (MAN_NSCOPED & man_macros[tok].flags));
429                 m->flags |= MAN_ELINE;
430                 return(1);
431         } 
432
433         /* Set ignorable context, if applicable. */
434
435         if (MAN_NSCOPED & man_macros[tok].flags) {
436                 assert( ! (MAN_SCOPED & man_macros[tok].flags));
437                 m->flags |= MAN_ILINE;
438         }
439         
440         /*
441          * Rewind our element scope.  Note that when TH is pruned, we'll
442          * be back at the root, so make sure that we don't clobber as
443          * its sibling.
444          */
445
446         for ( ; m->last; m->last = m->last->parent) {
447                 if (m->last == n)
448                         break;
449                 if (m->last->type == MAN_ROOT)
450                         break;
451                 if ( ! man_valid_post(m))
452                         return(0);
453         }
454
455         assert(m->last);
456
457         /*
458          * Same here regarding whether we're back at the root. 
459          */
460
461         if (m->last->type != MAN_ROOT && ! man_valid_post(m))
462                 return(0);
463
464         m->next = MAN_ROOT == m->last->type ?
465                 MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
466
467         return(1);
468 }
469
470
471 int
472 man_macroend(struct man *m)
473 {
474
475         return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT));
476 }
477