]> git.cameronkatri.com Git - mandoc.git/blob - out.c
Correctly make quotes around `Lk' link-name argument. Noted by Aldis
[mandoc.git] / out.c
1 /* $Id: out.c,v 1.23 2010/07/22 23:03:15 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
176 *d = DECO_NONE;
177 lim = i = 0;
178 term = '\0';
179 wp = *word;
180
181 switch ((c = wp[i++])) {
182 case ('('):
183 *d = DECO_SPECIAL;
184 lim = 2;
185 break;
186 case ('F'):
187 /* FALLTHROUGH */
188 case ('f'):
189 *d = 'F' == c ? DECO_FFONT : DECO_FONT;
190
191 switch (wp[i++]) {
192 case ('('):
193 lim = 2;
194 break;
195 case ('['):
196 term = ']';
197 break;
198 case ('3'):
199 /* FALLTHROUGH */
200 case ('B'):
201 *d = DECO_BOLD;
202 return(i);
203 case ('2'):
204 /* FALLTHROUGH */
205 case ('I'):
206 *d = DECO_ITALIC;
207 return(i);
208 case ('P'):
209 *d = DECO_PREVIOUS;
210 return(i);
211 case ('1'):
212 /* FALLTHROUGH */
213 case ('R'):
214 *d = DECO_ROMAN;
215 return(i);
216 default:
217 i--;
218 lim = 1;
219 break;
220 }
221 break;
222 case ('M'):
223 /* FALLTHROUGH */
224 case ('m'):
225 /* FALLTHROUGH */
226 case ('*'):
227 if ('*' == c)
228 *d = DECO_RESERVED;
229
230 switch (wp[i++]) {
231 case ('('):
232 lim = 2;
233 break;
234 case ('['):
235 term = ']';
236 break;
237 default:
238 i--;
239 lim = 1;
240 break;
241 }
242 break;
243 case ('s'):
244 if ('+' == wp[i] || '-' == wp[i])
245 i++;
246
247 j = ('s' != wp[i - 1]);
248
249 switch (wp[i++]) {
250 case ('('):
251 lim = 2;
252 break;
253 case ('['):
254 term = ']';
255 break;
256 case ('\''):
257 term = '\'';
258 break;
259 case ('0'):
260 j++;
261 /* FALLTHROUGH */
262 default:
263 i--;
264 lim = 1;
265 break;
266 }
267
268 if ('+' == wp[i] || '-' == wp[i]) {
269 if (j++)
270 return(i);
271 i++;
272 }
273
274 if (0 == j)
275 return(i);
276 break;
277 case ('['):
278 *d = DECO_SPECIAL;
279 term = ']';
280 break;
281 case ('c'):
282 *d = DECO_NOSPACE;
283 return(i);
284 default:
285 *d = DECO_SSPECIAL;
286 i--;
287 lim = 1;
288 break;
289 }
290
291 assert(term || lim);
292 *word = &wp[i];
293
294 if (term) {
295 j = i;
296 while (wp[i] && wp[i] != term)
297 i++;
298 if ('\0' == wp[i]) {
299 *d = DECO_NONE;
300 return(i);
301 }
302
303 assert(i >= j);
304 *sz = (size_t)(i - j);
305
306 return(i + 1);
307 }
308
309 assert(lim > 0);
310 *sz = (size_t)lim;
311
312 for (j = 0; wp[i] && j < lim; j++)
313 i++;
314 if (j < lim)
315 *d = DECO_NONE;
316
317 return(i);
318 }