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