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