]> git.cameronkatri.com Git - mandoc.git/blob - out.c
Remove the pod2man table entries. They can now be properly read and
[mandoc.git] / out.c
1 /* $Id: out.c,v 1.29 2010/08/29 11:28:09 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 ('k'):
224 /* FALLTHROUGH */
225 case ('M'):
226 /* FALLTHROUGH */
227 case ('m'):
228 /* FALLTHROUGH */
229 case ('*'):
230 if ('*' == c)
231 *d = DECO_RESERVED;
232
233 switch (wp[i++]) {
234 case ('('):
235 lim = 2;
236 break;
237 case ('['):
238 term = ']';
239 break;
240 default:
241 i--;
242 lim = 1;
243 break;
244 }
245 break;
246 case ('h'):
247 /* FALLTHROUGH */
248 case ('v'):
249 /* FALLTHROUGH */
250 case ('s'):
251 j = 0;
252 if ('+' == wp[i] || '-' == wp[i]) {
253 i++;
254 j = 1;
255 }
256
257 switch (wp[i++]) {
258 case ('('):
259 lim = 2;
260 break;
261 case ('['):
262 term = ']';
263 break;
264 case ('\''):
265 term = '\'';
266 break;
267 case ('0'):
268 j = 1;
269 /* FALLTHROUGH */
270 default:
271 i--;
272 lim = 1;
273 break;
274 }
275
276 if ('+' == wp[i] || '-' == wp[i]) {
277 if (j)
278 return(i);
279 i++;
280 }
281
282 /* Handle embedded numerical subexp or escape. */
283
284 if ('(' == wp[i]) {
285 while (wp[i] && ')' != wp[i])
286 if ('\\' == wp[i++]) {
287 /* Handle embedded escape. */
288 *word = &wp[i];
289 i += a2roffdeco(&dd, word, sz);
290 }
291
292 if (')' == wp[i++])
293 break;
294
295 *d = DECO_NONE;
296 return(i - 1);
297 } else if ('\\' == wp[i]) {
298 *word = &wp[++i];
299 i += a2roffdeco(&dd, word, sz);
300 }
301
302 break;
303 case ('['):
304 *d = DECO_SPECIAL;
305 term = ']';
306 break;
307 case ('c'):
308 *d = DECO_NOSPACE;
309 return(i);
310 case ('z'):
311 *d = DECO_NONE;
312 if ('\\' == wp[i]) {
313 *word = &wp[++i];
314 return(i + a2roffdeco(&dd, word, sz));
315 } else
316 lim = 1;
317 break;
318 case ('o'):
319 /* FALLTHROUGH */
320 case ('w'):
321 if ('\'' == wp[i++]) {
322 term = '\'';
323 break;
324 }
325 /* FALLTHROUGH */
326 default:
327 *d = DECO_SSPECIAL;
328 i--;
329 lim = 1;
330 break;
331 }
332
333 assert(term || lim);
334 *word = &wp[i];
335
336 if (term) {
337 j = i;
338 while (wp[i] && wp[i] != term)
339 i++;
340 if ('\0' == wp[i]) {
341 *d = DECO_NONE;
342 return(i);
343 }
344
345 assert(i >= j);
346 *sz = (size_t)(i - j);
347
348 return(i + 1);
349 }
350
351 assert(lim > 0);
352 *sz = (size_t)lim;
353
354 for (j = 0; wp[i] && j < lim; j++)
355 i++;
356 if (j < lim)
357 *d = DECO_NONE;
358
359 return(i);
360 }