xref: /netbsd-src/external/bsd/mdocml/dist/mandoc.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$Vendor-Id: mandoc.c,v 1.27 2010/07/25 19:05:59 joerg Exp $ */
2 /*
3  * Copyright (c) 2008, 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 <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29 
30 #include "mandoc.h"
31 #include "libmandoc.h"
32 
33 static	int	 a2time(time_t *, const char *, const char *);
34 
35 
36 int
37 mandoc_special(char *p)
38 {
39 	int		 len, i;
40 	char		 term;
41 	char		*sv;
42 
43 	len = 0;
44 	term = '\0';
45 	sv = p;
46 
47 	assert('\\' == *p);
48 	p++;
49 
50 	switch (*p++) {
51 #if 0
52 	case ('Z'):
53 		/* FALLTHROUGH */
54 	case ('X'):
55 		/* FALLTHROUGH */
56 	case ('x'):
57 		/* FALLTHROUGH */
58 	case ('w'):
59 		/* FALLTHROUGH */
60 	case ('v'):
61 		/* FALLTHROUGH */
62 	case ('S'):
63 		/* FALLTHROUGH */
64 	case ('R'):
65 		/* FALLTHROUGH */
66 	case ('o'):
67 		/* FALLTHROUGH */
68 	case ('N'):
69 		/* FALLTHROUGH */
70 	case ('l'):
71 		/* FALLTHROUGH */
72 	case ('L'):
73 		/* FALLTHROUGH */
74 	case ('H'):
75 		/* FALLTHROUGH */
76 	case ('h'):
77 		/* FALLTHROUGH */
78 	case ('D'):
79 		/* FALLTHROUGH */
80 	case ('C'):
81 		/* FALLTHROUGH */
82 	case ('b'):
83 		/* FALLTHROUGH */
84 	case ('B'):
85 		/* FALLTHROUGH */
86 	case ('a'):
87 		/* FALLTHROUGH */
88 	case ('A'):
89 		if (*p++ != '\'')
90 			return(0);
91 		term = '\'';
92 		break;
93 #endif
94 	case ('s'):
95 		if (ASCII_HYPH == *p)
96 			*p = '-';
97 		if ('+' == *p || '-' == *p)
98 			p++;
99 
100 		i = ('s' != *(p - 1));
101 
102 		switch (*p++) {
103 		case ('('):
104 			len = 2;
105 			break;
106 		case ('['):
107 			term = ']';
108 			break;
109 		case ('\''):
110 			term = '\'';
111 			break;
112 		case ('0'):
113 			i++;
114 			/* FALLTHROUGH */
115 		default:
116 			len = 1;
117 			p--;
118 			break;
119 		}
120 
121 		if (ASCII_HYPH == *p)
122 			*p = '-';
123 		if ('+' == *p || '-' == *p) {
124 			if (i++)
125 				return(0);
126 			p++;
127 		}
128 
129 		if (0 == i)
130 			return(0);
131 		break;
132 #if 0
133 	case ('Y'):
134 		/* FALLTHROUGH */
135 	case ('V'):
136 		/* FALLTHROUGH */
137 	case ('$'):
138 		/* FALLTHROUGH */
139 	case ('n'):
140 		/* FALLTHROUGH */
141 	case ('k'):
142 		/* FALLTHROUGH */
143 #endif
144 	case ('M'):
145 		/* FALLTHROUGH */
146 	case ('m'):
147 		/* FALLTHROUGH */
148 	case ('f'):
149 		/* FALLTHROUGH */
150 	case ('F'):
151 		/* FALLTHROUGH */
152 	case ('*'):
153 		switch (*p++) {
154 		case ('('):
155 			len = 2;
156 			break;
157 		case ('['):
158 			term = ']';
159 			break;
160 		default:
161 			len = 1;
162 			p--;
163 			break;
164 		}
165 		break;
166 	case ('('):
167 		len = 2;
168 		break;
169 	case ('['):
170 		term = ']';
171 		break;
172 	default:
173 		len = 1;
174 		p--;
175 		break;
176 	}
177 
178 	if (term) {
179 		for ( ; *p && term != *p; p++)
180 			if (ASCII_HYPH == *p)
181 				*p = '-';
182 		return(*p ? (int)(p - sv) : 0);
183 	}
184 
185 	for (i = 0; *p && i < len; i++, p++)
186 		if (ASCII_HYPH == *p)
187 			*p = '-';
188 	return(i == len ? (int)(p - sv) : 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 
304 int
305 mandoc_eos(const char *p, size_t sz, int enclosed)
306 {
307 	const char *q;
308 	int found;
309 
310 	if (0 == sz)
311 		return(0);
312 
313 	/*
314 	 * End-of-sentence recognition must include situations where
315 	 * some symbols, such as `)', allow prior EOS punctuation to
316 	 * propogate outward.
317 	 */
318 
319 	found = 0;
320 	for (q = p + (int)sz - 1; q >= p; q--) {
321 		switch (*q) {
322 		case ('\"'):
323 			/* FALLTHROUGH */
324 		case ('\''):
325 			/* FALLTHROUGH */
326 		case (']'):
327 			/* FALLTHROUGH */
328 		case (')'):
329 			if (0 == found)
330 				enclosed = 1;
331 			break;
332 		case ('.'):
333 			/* FALLTHROUGH */
334 		case ('!'):
335 			/* FALLTHROUGH */
336 		case ('?'):
337 			found = 1;
338 			break;
339 		default:
340 			return(found && (!enclosed || isalnum((unsigned char)*q)));
341 		}
342 	}
343 
344 	return(found && !enclosed);
345 }
346 
347 
348 int
349 mandoc_hyph(const char *start, const char *c)
350 {
351 
352 	/*
353 	 * Choose whether to break at a hyphenated character.  We only
354 	 * do this if it's free-standing within a word.
355 	 */
356 
357 	/* Skip first/last character of buffer. */
358 	if (c == start || '\0' == *(c + 1))
359 		return(0);
360 	/* Skip first/last character of word. */
361 	if ('\t' == *(c + 1) || '\t' == *(c - 1))
362 		return(0);
363 	if (' ' == *(c + 1) || ' ' == *(c - 1))
364 		return(0);
365 	/* Skip double invocations. */
366 	if ('-' == *(c + 1) || '-' == *(c - 1))
367 		return(0);
368 	/* Skip escapes. */
369 	if ('\\' == *(c - 1))
370 		return(0);
371 
372 	return(1);
373 }
374