xref: /openbsd-src/usr.bin/mandoc/out.c (revision 7bbe964f6b7d22ad07ca46292495604f942eba4e)
1 /*	$Id: out.c,v 1.2 2009/10/27 21:40:07 schwarze Exp $ */
2 /*
3  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
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 #include <sys/types.h>
18 
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 
26 #include "out.h"
27 
28 /*
29  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
30  * units are documented in groff.7, mdoc.7, man.7.
31  */
32 int
33 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
34 {
35 	char		 buf[BUFSIZ], hasd;
36 	int		 i;
37 	enum roffscale	 unit;
38 
39 	if ('\0' == *src)
40 		return(0);
41 
42 	i = hasd = 0;
43 
44 	switch (*src) {
45 	case ('+'):
46 		src++;
47 		break;
48 	case ('-'):
49 		buf[i++] = *src++;
50 		break;
51 	default:
52 		break;
53 	}
54 
55 	if ('\0' == *src)
56 		return(0);
57 
58 	while (i < BUFSIZ) {
59 		if ( ! isdigit((u_char)*src)) {
60 			if ('.' != *src)
61 				break;
62 			else if (hasd)
63 				break;
64 			else
65 				hasd = 1;
66 		}
67 		buf[i++] = *src++;
68 	}
69 
70 	if (BUFSIZ == i || (*src && *(src + 1)))
71 		return(0);
72 
73 	buf[i] = '\0';
74 
75 	switch (*src) {
76 	case ('c'):
77 		unit = SCALE_CM;
78 		break;
79 	case ('i'):
80 		unit = SCALE_IN;
81 		break;
82 	case ('P'):
83 		unit = SCALE_PC;
84 		break;
85 	case ('p'):
86 		unit = SCALE_PT;
87 		break;
88 	case ('f'):
89 		unit = SCALE_FS;
90 		break;
91 	case ('v'):
92 		unit = SCALE_VS;
93 		break;
94 	case ('m'):
95 		unit = SCALE_EM;
96 		break;
97 	case ('\0'):
98 		if (SCALE_MAX == def)
99 			return(0);
100 		unit = SCALE_BU;
101 		break;
102 	case ('u'):
103 		unit = SCALE_BU;
104 		break;
105 	case ('M'):
106 		unit = SCALE_MM;
107 		break;
108 	case ('n'):
109 		unit = SCALE_EN;
110 		break;
111 	default:
112 		return(0);
113 	}
114 
115 	if ((dst->scale = atof(buf)) < 0)
116 		dst->scale = 0;
117 	dst->unit = unit;
118 	dst->pt = hasd;
119 
120 	return(1);
121 }
122 
123 
124 /*
125  * Correctly writes the time in nroff form, which differs from standard
126  * form in that a space isn't printed in lieu of the extra %e field for
127  * single-digit dates.
128  */
129 void
130 time2a(time_t t, char *dst, size_t sz)
131 {
132 	struct tm	 tm;
133 	char		 buf[5];
134 	char		*p;
135 	size_t		 nsz;
136 
137 	assert(sz > 1);
138 	localtime_r(&t, &tm);
139 
140 	p = dst;
141 	nsz = 0;
142 
143 	dst[0] = '\0';
144 
145 	if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
146 		return;
147 
148 	p += (int)nsz;
149 	sz -= nsz;
150 
151 	if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
152 		return;
153 
154 	nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
155 
156 	if (nsz >= sz)
157 		return;
158 
159 	p += (int)nsz;
160 	sz -= nsz;
161 
162 	(void)strftime(p, sz, "%Y", &tm);
163 }
164 
165