Annotation of mandoc/mandoc.c, Revision 1.29
1.29 ! schwarze 1: /* $Id: mandoc.c,v 1.28 2010/08/16 09:37:58 kristaps Exp $ */
1.1 kristaps 2: /*
1.22 kristaps 3: * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 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: */
1.9 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
1.7 kristaps 19: #endif
20:
1.2 kristaps 21: #include <sys/types.h>
22:
1.1 kristaps 23: #include <assert.h>
24: #include <ctype.h>
25: #include <stdlib.h>
1.4 kristaps 26: #include <stdio.h>
27: #include <string.h>
1.7 kristaps 28: #include <time.h>
1.1 kristaps 29:
1.18 kristaps 30: #include "mandoc.h"
1.1 kristaps 31: #include "libmandoc.h"
32:
1.18 kristaps 33: static int a2time(time_t *, const char *, const char *);
1.7 kristaps 34:
35:
1.1 kristaps 36: int
1.18 kristaps 37: mandoc_special(char *p)
1.1 kristaps 38: {
1.22 kristaps 39: int len, i;
40: char term;
1.18 kristaps 41: char *sv;
1.1 kristaps 42:
1.22 kristaps 43: len = 0;
44: term = '\0';
1.18 kristaps 45: sv = p;
46:
1.22 kristaps 47: assert('\\' == *p);
48: p++;
1.1 kristaps 49:
1.22 kristaps 50: switch (*p++) {
1.24 kristaps 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
1.28 kristaps 92: case ('h'):
93: /* FALLTHROUGH */
94: case ('v'):
95: /* FALLTHROUGH */
1.8 kristaps 96: case ('s'):
1.22 kristaps 97: if (ASCII_HYPH == *p)
98: *p = '-';
1.28 kristaps 99:
100: i = 0;
101: if ('+' == *p || '-' == *p) {
1.22 kristaps 102: p++;
1.28 kristaps 103: i = 1;
104: }
1.8 kristaps 105:
1.22 kristaps 106: switch (*p++) {
107: case ('('):
108: len = 2;
109: break;
110: case ('['):
111: term = ']';
112: break;
113: case ('\''):
114: term = '\'';
115: break;
1.26 kristaps 116: case ('0'):
1.28 kristaps 117: i = 1;
1.26 kristaps 118: /* FALLTHROUGH */
1.22 kristaps 119: default:
120: len = 1;
121: p--;
122: break;
1.8 kristaps 123: }
124:
1.22 kristaps 125: if (ASCII_HYPH == *p)
126: *p = '-';
127: if ('+' == *p || '-' == *p) {
1.28 kristaps 128: if (i)
1.22 kristaps 129: return(0);
130: p++;
131: }
132:
133: break;
1.24 kristaps 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 */
1.11 kristaps 150: case ('f'):
151: /* FALLTHROUGH */
152: case ('F'):
153: /* FALLTHROUGH */
1.1 kristaps 154: case ('*'):
1.22 kristaps 155: switch (*p++) {
1.1 kristaps 156: case ('('):
1.22 kristaps 157: len = 2;
158: break;
1.1 kristaps 159: case ('['):
1.22 kristaps 160: term = ']';
161: break;
1.1 kristaps 162: default:
1.22 kristaps 163: len = 1;
164: p--;
1.1 kristaps 165: break;
166: }
1.22 kristaps 167: break;
1.1 kristaps 168: case ('('):
1.22 kristaps 169: len = 2;
170: break;
1.1 kristaps 171: case ('['):
1.22 kristaps 172: term = ']';
1.1 kristaps 173: break;
174: default:
1.22 kristaps 175: len = 1;
176: p--;
177: break;
1.1 kristaps 178: }
179:
1.22 kristaps 180: if (term) {
181: for ( ; *p && term != *p; p++)
182: if (ASCII_HYPH == *p)
183: *p = '-';
1.24 kristaps 184: return(*p ? (int)(p - sv) : 0);
1.22 kristaps 185: }
1.1 kristaps 186:
1.22 kristaps 187: for (i = 0; *p && i < len; i++, p++)
188: if (ASCII_HYPH == *p)
189: *p = '-';
1.24 kristaps 190: return(i == len ? (int)(p - sv) : 0);
1.1 kristaps 191: }
192:
1.4 kristaps 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) {
1.6 kristaps 201: perror(NULL);
1.29 ! schwarze 202: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 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) {
1.6 kristaps 216: perror(NULL);
1.29 ! schwarze 217: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 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) {
1.6 kristaps 230: perror(NULL);
1.29 ! schwarze 231: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 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) {
1.6 kristaps 245: perror(NULL);
1.29 ! schwarze 246: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 247: }
248:
249: return(p);
250: }
1.7 kristaps 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:
1.12 kristaps 305:
306: int
1.23 schwarze 307: mandoc_eos(const char *p, size_t sz, int enclosed)
1.12 kristaps 308: {
1.23 schwarze 309: const char *q;
310: int found;
1.12 kristaps 311:
1.13 kristaps 312: if (0 == sz)
313: return(0);
1.12 kristaps 314:
1.14 kristaps 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:
1.23 schwarze 321: found = 0;
1.25 kristaps 322: for (q = p + (int)sz - 1; q >= p; q--) {
1.23 schwarze 323: switch (*q) {
1.14 kristaps 324: case ('\"'):
325: /* FALLTHROUGH */
326: case ('\''):
1.15 kristaps 327: /* FALLTHROUGH */
328: case (']'):
1.14 kristaps 329: /* FALLTHROUGH */
330: case (')'):
1.23 schwarze 331: if (0 == found)
332: enclosed = 1;
1.14 kristaps 333: break;
334: case ('.'):
335: /* FALLTHROUGH */
336: case ('!'):
337: /* FALLTHROUGH */
338: case ('?'):
1.23 schwarze 339: found = 1;
340: break;
1.14 kristaps 341: default:
1.27 joerg 342: return(found && (!enclosed || isalnum((unsigned char)*q)));
1.14 kristaps 343: }
1.12 kristaps 344: }
345:
1.23 schwarze 346: return(found && !enclosed);
1.16 kristaps 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);
1.12 kristaps 375: }
CVSweb