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