]> git.cameronkatri.com Git - mandoc.git/blob - out.c
Strip out the `\z' escape. This is the first recursive sequence,
[mandoc.git] / out.c
1 /* $Id: out.c,v 1.25 2010/08/24 12:18:49 kristaps Exp $ */
2 /*
3 * Copyright (c) 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 <sys/types.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29
30 #include "out.h"
31
32 /*
33 * Convert a `scaling unit' to a consistent form, or fail. Scaling
34 * units are documented in groff.7, mdoc.7, man.7.
35 */
36 int
37 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
38 {
39 char buf[BUFSIZ], hasd;
40 int i;
41 enum roffscale unit;
42
43 if ('\0' == *src)
44 return(0);
45
46 i = hasd = 0;
47
48 switch (*src) {
49 case ('+'):
50 src++;
51 break;
52 case ('-'):
53 buf[i++] = *src++;
54 break;
55 default:
56 break;
57 }
58
59 if ('\0' == *src)
60 return(0);
61
62 while (i < BUFSIZ) {
63 if ( ! isdigit((u_char)*src)) {
64 if ('.' != *src)
65 break;
66 else if (hasd)
67 break;
68 else
69 hasd = 1;
70 }
71 buf[i++] = *src++;
72 }
73
74 if (BUFSIZ == i || (*src && *(src + 1)))
75 return(0);
76
77 buf[i] = '\0';
78
79 switch (*src) {
80 case ('c'):
81 unit = SCALE_CM;
82 break;
83 case ('i'):
84 unit = SCALE_IN;
85 break;
86 case ('P'):
87 unit = SCALE_PC;
88 break;
89 case ('p'):
90 unit = SCALE_PT;
91 break;
92 case ('f'):
93 unit = SCALE_FS;
94 break;
95 case ('v'):
96 unit = SCALE_VS;
97 break;
98 case ('m'):
99 unit = SCALE_EM;
100 break;
101 case ('\0'):
102 if (SCALE_MAX == def)
103 return(0);
104 unit = SCALE_BU;
105 break;
106 case ('u'):
107 unit = SCALE_BU;
108 break;
109 case ('M'):
110 unit = SCALE_MM;
111 break;
112 case ('n'):
113 unit = SCALE_EN;
114 break;
115 default:
116 return(0);
117 }
118
119 /* FIXME: do this in the caller. */
120 if ((dst->scale = atof(buf)) < 0)
121 dst->scale = 0;
122 dst->unit = unit;
123 return(1);
124 }
125
126
127 /*
128 * Correctly writes the time in nroff form, which differs from standard
129 * form in that a space isn't printed in lieu of the extra %e field for
130 * single-digit dates.
131 */
132 void
133 time2a(time_t t, char *dst, size_t sz)
134 {
135 struct tm tm;
136 char buf[5];
137 char *p;
138 size_t nsz;
139
140 assert(sz > 1);
141 localtime_r(&t, &tm);
142
143 p = dst;
144 nsz = 0;
145
146 dst[0] = '\0';
147
148 if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
149 return;
150
151 p += (int)nsz;
152 sz -= nsz;
153
154 if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
155 return;
156
157 nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
158
159 if (nsz >= sz)
160 return;
161
162 p += (int)nsz;
163 sz -= nsz;
164
165 (void)strftime(p, sz, "%Y", &tm);
166 }
167
168
169 int
170 a2roffdeco(enum roffdeco *d, const char **word, size_t *sz)
171 {
172 int i, j, lim;
173 char term, c;
174 const char *wp;
175 enum roffdeco dd;
176
177 *d = DECO_NONE;
178 lim = i = 0;
179 term = '\0';
180 wp = *word;
181
182 switch ((c = wp[i++])) {
183 case ('('):
184 *d = DECO_SPECIAL;
185 lim = 2;
186 break;
187 case ('F'):
188 /* FALLTHROUGH */
189 case ('f'):
190 *d = 'F' == c ? DECO_FFONT : DECO_FONT;
191
192 switch (wp[i++]) {
193 case ('('):
194 lim = 2;
195 break;
196 case ('['):
197 term = ']';
198 break;
199 case ('3'):
200 /* FALLTHROUGH */
201 case ('B'):
202 *d = DECO_BOLD;
203 return(i);
204 case ('2'):
205 /* FALLTHROUGH */
206 case ('I'):
207 *d = DECO_ITALIC;
208 return(i);
209 case ('P'):
210 *d = DECO_PREVIOUS;
211 return(i);
212 case ('1'):
213 /* FALLTHROUGH */
214 case ('R'):
215 *d = DECO_ROMAN;
216 return(i);
217 default:
218 i--;
219 lim = 1;
220 break;
221 }
222 break;
223 case ('M'):
224 /* FALLTHROUGH */
225 case ('m'):
226 /* FALLTHROUGH */
227 case ('*'):
228 if ('*' == c)
229 *d = DECO_RESERVED;
230
231 switch (wp[i++]) {
232 case ('('):
233 lim = 2;
234 break;
235 case ('['):
236 term = ']';
237 break;
238 default:
239 i--;
240 lim = 1;
241 break;
242 }
243 break;
244 case ('h'):
245 /* FALLTHROUGH */
246 case ('v'):
247 /* FALLTHROUGH */
248 case ('s'):
249 j = 0;
250 if ('+' == wp[i] || '-' == wp[i]) {
251 i++;
252 j = 1;
253 }
254
255 switch (wp[i++]) {
256 case ('('):
257 lim = 2;
258 break;
259 case ('['):
260 term = ']';
261 break;
262 case ('\''):
263 term = '\'';
264 break;
265 case ('0'):
266 j = 1;
267 /* FALLTHROUGH */
268 default:
269 i--;
270 lim = 1;
271 break;
272 }
273
274 if ('+' == wp[i] || '-' == wp[i]) {
275 if (j)
276 return(i);
277 i++;
278 }
279
280 break;
281 case ('['):
282 *d = DECO_SPECIAL;
283 term = ']';
284 break;
285 case ('c'):
286 *d = DECO_NOSPACE;
287 return(i);
288 case ('z'):
289 *d = DECO_NONE;
290 if ('\\' == wp[i]) {
291 *word = &wp[++i];
292 return(i + a2roffdeco(&dd, word, sz));
293 } else
294 lim = 1;
295 break;
296 default:
297 *d = DECO_SSPECIAL;
298 i--;
299 lim = 1;
300 break;
301 }
302
303 assert(term || lim);
304 *word = &wp[i];
305
306 if (term) {
307 j = i;
308 while (wp[i] && wp[i] != term)
309 i++;
310 if ('\0' == wp[i]) {
311 *d = DECO_NONE;
312 return(i);
313 }
314
315 assert(i >= j);
316 *sz = (size_t)(i - j);
317
318 return(i + 1);
319 }
320
321 assert(lim > 0);
322 *sz = (size_t)lim;
323
324 for (j = 0; wp[i] && j < lim; j++)
325 i++;
326 if (j < lim)
327 *d = DECO_NONE;
328
329 return(i);
330 }