xref: /openbsd-src/usr.bin/mandoc/mandoc.c (revision cd1eb269cafb12c415be1749cd4a4b5422710415)
1 /*	$Id: mandoc.c,v 1.8 2010/04/07 23:15:05 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 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 <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <time.h>
25 
26 #include "libmandoc.h"
27 
28 static int	 a2time(time_t *, const char *, const char *);
29 
30 
31 int
32 mandoc_special(const char *p)
33 {
34 	int		 terminator;	/* Terminator for \s. */
35 	int		 lim;		/* Limit for N in \s. */
36 	int		 c, i;
37 
38 	if ('\\' != *p++)
39 		return(0);
40 
41 	switch (*p) {
42 	case ('\''):
43 		/* FALLTHROUGH */
44 	case ('`'):
45 		/* FALLTHROUGH */
46 	case ('q'):
47 		/* FALLTHROUGH */
48 	case ('-'):
49 		/* FALLTHROUGH */
50 	case ('~'):
51 		/* FALLTHROUGH */
52 	case ('^'):
53 		/* FALLTHROUGH */
54 	case ('%'):
55 		/* FALLTHROUGH */
56 	case ('0'):
57 		/* FALLTHROUGH */
58 	case (' '):
59 		/* FALLTHROUGH */
60 	case ('|'):
61 		/* FALLTHROUGH */
62 	case ('&'):
63 		/* FALLTHROUGH */
64 	case ('.'):
65 		/* FALLTHROUGH */
66 	case (':'):
67 		/* FALLTHROUGH */
68 	case ('c'):
69 		return(2);
70 	case ('e'):
71 		return(2);
72 	case ('s'):
73 		if ('\0' == *++p)
74 			return(2);
75 
76 		c = 2;
77 		terminator = 0;
78 		lim = 1;
79 
80 		if (*p == '\'') {
81 			lim = 0;
82 			terminator = 1;
83 			++p;
84 			++c;
85 		} else if (*p == '[') {
86 			lim = 0;
87 			terminator = 2;
88 			++p;
89 			++c;
90 		} else if (*p == '(') {
91 			lim = 2;
92 			terminator = 3;
93 			++p;
94 			++c;
95 		}
96 
97 		if (*p == '+' || *p == '-') {
98 			++p;
99 			++c;
100 		}
101 
102 		if (*p == '\'') {
103 			if (terminator)
104 				return(0);
105 			lim = 0;
106 			terminator = 1;
107 			++p;
108 			++c;
109 		} else if (*p == '[') {
110 			if (terminator)
111 				return(0);
112 			lim = 0;
113 			terminator = 2;
114 			++p;
115 			++c;
116 		} else if (*p == '(') {
117 			if (terminator)
118 				return(0);
119 			lim = 2;
120 			terminator = 3;
121 			++p;
122 			++c;
123 		}
124 
125 		/* TODO: needs to handle floating point. */
126 
127 		if ( ! isdigit((u_char)*p))
128 			return(0);
129 
130 		for (i = 0; isdigit((u_char)*p); i++) {
131 			if (lim && i >= lim)
132 				break;
133 			++p;
134 			++c;
135 		}
136 
137 		if (terminator && terminator < 3) {
138 			if (1 == terminator && *p != '\'')
139 				return(0);
140 			if (2 == terminator && *p != ']')
141 				return(0);
142 			++p;
143 			++c;
144 		}
145 
146 		return(c);
147 	case ('f'):
148 		/* FALLTHROUGH */
149 	case ('F'):
150 		/* FALLTHROUGH */
151 	case ('*'):
152 		if (0 == *++p || ! isgraph((u_char)*p))
153 			return(0);
154 		switch (*p) {
155 		case ('('):
156 			if (0 == *++p || ! isgraph((u_char)*p))
157 				return(0);
158 			return(4);
159 		case ('['):
160 			for (c = 3, p++; *p && ']' != *p; p++, c++)
161 				if ( ! isgraph((u_char)*p))
162 					break;
163 			return(*p == ']' ? c : 0);
164 		default:
165 			break;
166 		}
167 		return(3);
168 	case ('('):
169 		if (0 == *++p || ! isgraph((u_char)*p))
170 			return(0);
171 		if (0 == *++p || ! isgraph((u_char)*p))
172 			return(0);
173 		return(4);
174 	case ('['):
175 		break;
176 	default:
177 		return(0);
178 	}
179 
180 	for (c = 3, p++; *p && ']' != *p; p++, c++)
181 		if ( ! isgraph((u_char)*p))
182 			break;
183 
184 	return(*p == ']' ? c : 0);
185 }
186 
187 
188 void *
189 mandoc_calloc(size_t num, size_t size)
190 {
191 	void		*ptr;
192 
193 	ptr = calloc(num, size);
194 	if (NULL == ptr) {
195 		perror(NULL);
196 		exit(EXIT_FAILURE);
197 	}
198 
199 	return(ptr);
200 }
201 
202 
203 void *
204 mandoc_malloc(size_t size)
205 {
206 	void		*ptr;
207 
208 	ptr = malloc(size);
209 	if (NULL == ptr) {
210 		perror(NULL);
211 		exit(EXIT_FAILURE);
212 	}
213 
214 	return(ptr);
215 }
216 
217 
218 void *
219 mandoc_realloc(void *ptr, size_t size)
220 {
221 
222 	ptr = realloc(ptr, size);
223 	if (NULL == ptr) {
224 		perror(NULL);
225 		exit(EXIT_FAILURE);
226 	}
227 
228 	return(ptr);
229 }
230 
231 
232 char *
233 mandoc_strdup(const char *ptr)
234 {
235 	char		*p;
236 
237 	p = strdup(ptr);
238 	if (NULL == p) {
239 		perror(NULL);
240 		exit(EXIT_FAILURE);
241 	}
242 
243 	return(p);
244 }
245 
246 
247 static int
248 a2time(time_t *t, const char *fmt, const char *p)
249 {
250 	struct tm	 tm;
251 	char		*pp;
252 
253 	memset(&tm, 0, sizeof(struct tm));
254 
255 	pp = strptime(p, fmt, &tm);
256 	if (NULL != pp && '\0' == *pp) {
257 		*t = mktime(&tm);
258 		return(1);
259 	}
260 
261 	return(0);
262 }
263 
264 
265 /*
266  * Convert from a manual date string (see mdoc(7) and man(7)) into a
267  * date according to the stipulated date type.
268  */
269 time_t
270 mandoc_a2time(int flags, const char *p)
271 {
272 	time_t		 t;
273 
274 	if (MTIME_MDOCDATE & flags) {
275 		if (0 == strcmp(p, "$" "Mdocdate$"))
276 			return(time(NULL));
277 		if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
278 			return(t);
279 	}
280 
281 	if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
282 		if (a2time(&t, "%b %d, %Y", p))
283 			return(t);
284 
285 	if (MTIME_ISO_8601 & flags)
286 		if (a2time(&t, "%Y-%m-%d", p))
287 			return(t);
288 
289 	if (MTIME_REDUCED & flags) {
290 		if (a2time(&t, "%d, %Y", p))
291 			return(t);
292 		if (a2time(&t, "%Y", p))
293 			return(t);
294 	}
295 
296 	return(0);
297 }
298 
299