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