]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
Actions in place for prologue parsing.
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.7 2009/03/25 16:07:36 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
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 <err.h> /* XXX */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "libman.h"
27
28 static int man_args(struct man *, int,
29 int *, char *, char **);
30
31
32 int
33 man_macro(struct man *man, int tok, int line,
34 int ppos, int *pos, char *buf)
35 {
36 int w, la;
37 char *p;
38 struct man_node *n;
39
40 if ( ! man_elem_alloc(man, line, ppos, tok))
41 return(0);
42 n = man->last;
43 man->next = MAN_NEXT_CHILD;
44
45 for (;;) {
46 la = *pos;
47 w = man_args(man, line, pos, buf, &p);
48
49 if (-1 == w)
50 return(0);
51 if (0 == w)
52 break;
53
54 if ( ! man_word_alloc(man, line, la, p))
55 return(0);
56 man->next = MAN_NEXT_SIBLING;
57 }
58
59 /*
60 * Note that when TH is pruned, we'll be back at the root, so
61 * make sure that we don't clobber as its sibling.
62 */
63
64 for ( ; man->last; man->last = man->last->parent) {
65 if (man->last == n)
66 break;
67 if (man->last->type == MAN_ROOT)
68 break;
69 if ( ! man_valid_post(man))
70 return(0);
71 if ( ! man_action_post(man))
72 return(0);
73 }
74
75 assert(man->last);
76
77 /*
78 * Same here regarding whether we're back at the root.
79 */
80
81 if (man->last->type != MAN_ROOT && ! man_valid_post(man))
82 return(0);
83 if (man->last->type != MAN_ROOT && ! man_action_post(man))
84 return(0);
85 if (man->last->type != MAN_ROOT)
86 man->next = MAN_NEXT_SIBLING;
87
88 return(1);
89 }
90
91
92 int
93 man_macroend(struct man *m)
94 {
95
96 for ( ; m->last && m->last != m->first;
97 m->last = m->last->parent) {
98 if ( ! man_valid_post(m))
99 return(0);
100 if ( ! man_action_post(m))
101 return(0);
102 }
103 assert(m->last == m->first);
104
105 if ( ! man_valid_post(m))
106 return(0);
107 if ( ! man_action_post(m))
108 return(0);
109
110 return(1);
111 }
112
113
114 /* ARGSUSED */
115 static int
116 man_args(struct man *man, int line,
117 int *pos, char *buf, char **v)
118 {
119
120 if (0 == buf[*pos])
121 return(0);
122
123 /* First parse non-quoted strings. */
124
125 if ('\"' != buf[*pos]) {
126 *v = &buf[*pos];
127
128 while (buf[*pos]) {
129 if (' ' == buf[*pos])
130 if ('\\' != buf[*pos - 1])
131 break;
132 (*pos)++;
133 }
134
135 if (0 == buf[*pos])
136 return(1);
137
138 buf[(*pos)++] = 0;
139
140 if (0 == buf[*pos])
141 return(1);
142
143 while (buf[*pos] && ' ' == buf[*pos])
144 (*pos)++;
145
146 if (buf[*pos])
147 return(1);
148
149 warnx("tail whitespace");
150 return(-1);
151 }
152
153 /*
154 * If we're a quoted string (and quoted strings are allowed),
155 * then parse ahead to the next quote. If none's found, it's an
156 * error. After, parse to the next word.
157 */
158
159 *v = &buf[++(*pos)];
160
161 while (buf[*pos] && '\"' != buf[*pos])
162 (*pos)++;
163
164 if (0 == buf[*pos]) {
165 warnx("unterminated quotation");
166 return(-1);
167 }
168
169 buf[(*pos)++] = 0;
170 if (0 == buf[*pos])
171 return(1);
172
173 while (buf[*pos] && ' ' == buf[*pos])
174 (*pos)++;
175
176 if (buf[*pos])
177 return(1);
178
179 warnx("tail whitespace");
180 return(-1);
181 }