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