]> git.cameronkatri.com Git - mandoc.git/blob - mandoc.c
Added mail archive periodically generated by hypermail.
[mandoc.git] / mandoc.c
1 /* $Id: mandoc.c,v 1.28 2010/08/16 09:37:58 kristaps 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 ('S'):
61 /* FALLTHROUGH */
62 case ('R'):
63 /* FALLTHROUGH */
64 case ('o'):
65 /* FALLTHROUGH */
66 case ('N'):
67 /* FALLTHROUGH */
68 case ('l'):
69 /* FALLTHROUGH */
70 case ('L'):
71 /* FALLTHROUGH */
72 case ('H'):
73 /* FALLTHROUGH */
74 case ('h'):
75 /* FALLTHROUGH */
76 case ('D'):
77 /* FALLTHROUGH */
78 case ('C'):
79 /* FALLTHROUGH */
80 case ('b'):
81 /* FALLTHROUGH */
82 case ('B'):
83 /* FALLTHROUGH */
84 case ('a'):
85 /* FALLTHROUGH */
86 case ('A'):
87 if (*p++ != '\'')
88 return(0);
89 term = '\'';
90 break;
91 #endif
92 case ('h'):
93 /* FALLTHROUGH */
94 case ('v'):
95 /* FALLTHROUGH */
96 case ('s'):
97 if (ASCII_HYPH == *p)
98 *p = '-';
99
100 i = 0;
101 if ('+' == *p || '-' == *p) {
102 p++;
103 i = 1;
104 }
105
106 switch (*p++) {
107 case ('('):
108 len = 2;
109 break;
110 case ('['):
111 term = ']';
112 break;
113 case ('\''):
114 term = '\'';
115 break;
116 case ('0'):
117 i = 1;
118 /* FALLTHROUGH */
119 default:
120 len = 1;
121 p--;
122 break;
123 }
124
125 if (ASCII_HYPH == *p)
126 *p = '-';
127 if ('+' == *p || '-' == *p) {
128 if (i)
129 return(0);
130 p++;
131 }
132
133 break;
134 #if 0
135 case ('Y'):
136 /* FALLTHROUGH */
137 case ('V'):
138 /* FALLTHROUGH */
139 case ('$'):
140 /* FALLTHROUGH */
141 case ('n'):
142 /* FALLTHROUGH */
143 case ('k'):
144 /* FALLTHROUGH */
145 #endif
146 case ('M'):
147 /* FALLTHROUGH */
148 case ('m'):
149 /* FALLTHROUGH */
150 case ('f'):
151 /* FALLTHROUGH */
152 case ('F'):
153 /* FALLTHROUGH */
154 case ('*'):
155 switch (*p++) {
156 case ('('):
157 len = 2;
158 break;
159 case ('['):
160 term = ']';
161 break;
162 default:
163 len = 1;
164 p--;
165 break;
166 }
167 break;
168 case ('('):
169 len = 2;
170 break;
171 case ('['):
172 term = ']';
173 break;
174 default:
175 len = 1;
176 p--;
177 break;
178 }
179
180 if (term) {
181 for ( ; *p && term != *p; p++)
182 if (ASCII_HYPH == *p)
183 *p = '-';
184 return(*p ? (int)(p - sv) : 0);
185 }
186
187 for (i = 0; *p && i < len; i++, p++)
188 if (ASCII_HYPH == *p)
189 *p = '-';
190 return(i == len ? (int)(p - sv) : 0);
191 }
192
193
194 void *
195 mandoc_calloc(size_t num, size_t size)
196 {
197 void *ptr;
198
199 ptr = calloc(num, size);
200 if (NULL == ptr) {
201 perror(NULL);
202 exit(EXIT_FAILURE);
203 }
204
205 return(ptr);
206 }
207
208
209 void *
210 mandoc_malloc(size_t size)
211 {
212 void *ptr;
213
214 ptr = malloc(size);
215 if (NULL == ptr) {
216 perror(NULL);
217 exit(EXIT_FAILURE);
218 }
219
220 return(ptr);
221 }
222
223
224 void *
225 mandoc_realloc(void *ptr, size_t size)
226 {
227
228 ptr = realloc(ptr, size);
229 if (NULL == ptr) {
230 perror(NULL);
231 exit(EXIT_FAILURE);
232 }
233
234 return(ptr);
235 }
236
237
238 char *
239 mandoc_strdup(const char *ptr)
240 {
241 char *p;
242
243 p = strdup(ptr);
244 if (NULL == p) {
245 perror(NULL);
246 exit(EXIT_FAILURE);
247 }
248
249 return(p);
250 }
251
252
253 static int
254 a2time(time_t *t, const char *fmt, const char *p)
255 {
256 struct tm tm;
257 char *pp;
258
259 memset(&tm, 0, sizeof(struct tm));
260
261 pp = strptime(p, fmt, &tm);
262 if (NULL != pp && '\0' == *pp) {
263 *t = mktime(&tm);
264 return(1);
265 }
266
267 return(0);
268 }
269
270
271 /*
272 * Convert from a manual date string (see mdoc(7) and man(7)) into a
273 * date according to the stipulated date type.
274 */
275 time_t
276 mandoc_a2time(int flags, const char *p)
277 {
278 time_t t;
279
280 if (MTIME_MDOCDATE & flags) {
281 if (0 == strcmp(p, "$" "Mdocdate$"))
282 return(time(NULL));
283 if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
284 return(t);
285 }
286
287 if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
288 if (a2time(&t, "%b %d, %Y", p))
289 return(t);
290
291 if (MTIME_ISO_8601 & flags)
292 if (a2time(&t, "%Y-%m-%d", p))
293 return(t);
294
295 if (MTIME_REDUCED & flags) {
296 if (a2time(&t, "%d, %Y", p))
297 return(t);
298 if (a2time(&t, "%Y", p))
299 return(t);
300 }
301
302 return(0);
303 }
304
305
306 int
307 mandoc_eos(const char *p, size_t sz, int enclosed)
308 {
309 const char *q;
310 int found;
311
312 if (0 == sz)
313 return(0);
314
315 /*
316 * End-of-sentence recognition must include situations where
317 * some symbols, such as `)', allow prior EOS punctuation to
318 * propogate outward.
319 */
320
321 found = 0;
322 for (q = p + (int)sz - 1; q >= p; q--) {
323 switch (*q) {
324 case ('\"'):
325 /* FALLTHROUGH */
326 case ('\''):
327 /* FALLTHROUGH */
328 case (']'):
329 /* FALLTHROUGH */
330 case (')'):
331 if (0 == found)
332 enclosed = 1;
333 break;
334 case ('.'):
335 /* FALLTHROUGH */
336 case ('!'):
337 /* FALLTHROUGH */
338 case ('?'):
339 found = 1;
340 break;
341 default:
342 return(found && (!enclosed || isalnum((unsigned char)*q)));
343 }
344 }
345
346 return(found && !enclosed);
347 }
348
349
350 int
351 mandoc_hyph(const char *start, const char *c)
352 {
353
354 /*
355 * Choose whether to break at a hyphenated character. We only
356 * do this if it's free-standing within a word.
357 */
358
359 /* Skip first/last character of buffer. */
360 if (c == start || '\0' == *(c + 1))
361 return(0);
362 /* Skip first/last character of word. */
363 if ('\t' == *(c + 1) || '\t' == *(c - 1))
364 return(0);
365 if (' ' == *(c + 1) || ' ' == *(c - 1))
366 return(0);
367 /* Skip double invocations. */
368 if ('-' == *(c + 1) || '-' == *(c - 1))
369 return(0);
370 /* Skip escapes. */
371 if ('\\' == *(c - 1))
372 return(0);
373
374 return(1);
375 }