xref: /netbsd-src/external/bsd/mdocml/dist/out.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$Vendor-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 }
319