Annotation of mandoc/mandoc.c, Revision 1.30
1.30 ! kristaps 1: /* $Id: mandoc.c,v 1.29 2010/08/20 01:02:07 schwarze 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.30 ! kristaps 173: break;
! 174: case ('z'):
! 175: len = 1;
! 176: if ('\\' == *p) {
! 177: p += mandoc_special(p);
! 178: return(*p ? (int)(p - sv) : 0);
! 179: }
1.1 kristaps 180: break;
181: default:
1.22 kristaps 182: len = 1;
183: p--;
184: break;
1.1 kristaps 185: }
186:
1.22 kristaps 187: if (term) {
188: for ( ; *p && term != *p; p++)
189: if (ASCII_HYPH == *p)
190: *p = '-';
1.24 kristaps 191: return(*p ? (int)(p - sv) : 0);
1.22 kristaps 192: }
1.1 kristaps 193:
1.22 kristaps 194: for (i = 0; *p && i < len; i++, p++)
195: if (ASCII_HYPH == *p)
196: *p = '-';
1.24 kristaps 197: return(i == len ? (int)(p - sv) : 0);
1.1 kristaps 198: }
199:
1.4 kristaps 200:
201: void *
202: mandoc_calloc(size_t num, size_t size)
203: {
204: void *ptr;
205:
206: ptr = calloc(num, size);
207: if (NULL == ptr) {
1.6 kristaps 208: perror(NULL);
1.29 schwarze 209: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 210: }
211:
212: return(ptr);
213: }
214:
215:
216: void *
217: mandoc_malloc(size_t size)
218: {
219: void *ptr;
220:
221: ptr = malloc(size);
222: if (NULL == ptr) {
1.6 kristaps 223: perror(NULL);
1.29 schwarze 224: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 225: }
226:
227: return(ptr);
228: }
229:
230:
231: void *
232: mandoc_realloc(void *ptr, size_t size)
233: {
234:
235: ptr = realloc(ptr, size);
236: if (NULL == ptr) {
1.6 kristaps 237: perror(NULL);
1.29 schwarze 238: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 239: }
240:
241: return(ptr);
242: }
243:
244:
245: char *
246: mandoc_strdup(const char *ptr)
247: {
248: char *p;
249:
250: p = strdup(ptr);
251: if (NULL == p) {
1.6 kristaps 252: perror(NULL);
1.29 schwarze 253: exit(MANDOCLEVEL_SYSERR);
1.4 kristaps 254: }
255:
256: return(p);
257: }
1.7 kristaps 258:
259:
260: static int
261: a2time(time_t *t, const char *fmt, const char *p)
262: {
263: struct tm tm;
264: char *pp;
265:
266: memset(&tm, 0, sizeof(struct tm));
267:
268: pp = strptime(p, fmt, &tm);
269: if (NULL != pp && '\0' == *pp) {
270: *t = mktime(&tm);
271: return(1);
272: }
273:
274: return(0);
275: }
276:
277:
278: /*
279: * Convert from a manual date string (see mdoc(7) and man(7)) into a
280: * date according to the stipulated date type.
281: */
282: time_t
283: mandoc_a2time(int flags, const char *p)
284: {
285: time_t t;
286:
287: if (MTIME_MDOCDATE & flags) {
288: if (0 == strcmp(p, "$" "Mdocdate$"))
289: return(time(NULL));
290: if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
291: return(t);
292: }
293:
294: if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
295: if (a2time(&t, "%b %d, %Y", p))
296: return(t);
297:
298: if (MTIME_ISO_8601 & flags)
299: if (a2time(&t, "%Y-%m-%d", p))
300: return(t);
301:
302: if (MTIME_REDUCED & flags) {
303: if (a2time(&t, "%d, %Y", p))
304: return(t);
305: if (a2time(&t, "%Y", p))
306: return(t);
307: }
308:
309: return(0);
310: }
311:
1.12 kristaps 312:
313: int
1.23 schwarze 314: mandoc_eos(const char *p, size_t sz, int enclosed)
1.12 kristaps 315: {
1.23 schwarze 316: const char *q;
317: int found;
1.12 kristaps 318:
1.13 kristaps 319: if (0 == sz)
320: return(0);
1.12 kristaps 321:
1.14 kristaps 322: /*
323: * End-of-sentence recognition must include situations where
324: * some symbols, such as `)', allow prior EOS punctuation to
325: * propogate outward.
326: */
327:
1.23 schwarze 328: found = 0;
1.25 kristaps 329: for (q = p + (int)sz - 1; q >= p; q--) {
1.23 schwarze 330: switch (*q) {
1.14 kristaps 331: case ('\"'):
332: /* FALLTHROUGH */
333: case ('\''):
1.15 kristaps 334: /* FALLTHROUGH */
335: case (']'):
1.14 kristaps 336: /* FALLTHROUGH */
337: case (')'):
1.23 schwarze 338: if (0 == found)
339: enclosed = 1;
1.14 kristaps 340: break;
341: case ('.'):
342: /* FALLTHROUGH */
343: case ('!'):
344: /* FALLTHROUGH */
345: case ('?'):
1.23 schwarze 346: found = 1;
347: break;
1.14 kristaps 348: default:
1.27 joerg 349: return(found && (!enclosed || isalnum((unsigned char)*q)));
1.14 kristaps 350: }
1.12 kristaps 351: }
352:
1.23 schwarze 353: return(found && !enclosed);
1.16 kristaps 354: }
355:
356:
357: int
358: mandoc_hyph(const char *start, const char *c)
359: {
360:
361: /*
362: * Choose whether to break at a hyphenated character. We only
363: * do this if it's free-standing within a word.
364: */
365:
366: /* Skip first/last character of buffer. */
367: if (c == start || '\0' == *(c + 1))
368: return(0);
369: /* Skip first/last character of word. */
370: if ('\t' == *(c + 1) || '\t' == *(c - 1))
371: return(0);
372: if (' ' == *(c + 1) || ' ' == *(c - 1))
373: return(0);
374: /* Skip double invocations. */
375: if ('-' == *(c + 1) || '-' == *(c - 1))
376: return(0);
377: /* Skip escapes. */
378: if ('\\' == *(c - 1))
379: return(0);
380:
381: return(1);
1.12 kristaps 382: }
CVSweb