Annotation of mandoc/mandoc.c, Revision 1.17
1.17 ! kristaps 1: /* $Id: mandoc.c,v 1.16 2010/05/25 12:37:20 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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:
30: #include "libmandoc.h"
31:
1.7 kristaps 32: static int a2time(time_t *, const char *, const char *);
33:
34:
1.1 kristaps 35: int
36: mandoc_special(const char *p)
37: {
1.8 kristaps 38: int terminator; /* Terminator for \s. */
39: int lim; /* Limit for N in \s. */
40: int c, i;
1.1 kristaps 41:
42: if ('\\' != *p++)
43: return(0);
44:
45: switch (*p) {
46: case ('\''):
47: /* FALLTHROUGH */
48: case ('`'):
49: /* FALLTHROUGH */
50: case ('q'):
51: /* FALLTHROUGH */
52: case ('-'):
53: /* FALLTHROUGH */
54: case ('~'):
55: /* FALLTHROUGH */
56: case ('^'):
57: /* FALLTHROUGH */
58: case ('%'):
59: /* FALLTHROUGH */
60: case ('0'):
61: /* FALLTHROUGH */
62: case (' '):
1.17 ! kristaps 63: /* FALLTHROUGH */
! 64: case ('}'):
1.1 kristaps 65: /* FALLTHROUGH */
66: case ('|'):
67: /* FALLTHROUGH */
68: case ('&'):
69: /* FALLTHROUGH */
70: case ('.'):
71: /* FALLTHROUGH */
72: case (':'):
73: /* FALLTHROUGH */
1.3 kristaps 74: case ('c'):
75: return(2);
1.1 kristaps 76: case ('e'):
77: return(2);
1.8 kristaps 78: case ('s'):
79: if ('\0' == *++p)
80: return(2);
81:
82: c = 2;
83: terminator = 0;
84: lim = 1;
85:
86: if (*p == '\'') {
87: lim = 0;
88: terminator = 1;
89: ++p;
90: ++c;
91: } else if (*p == '[') {
92: lim = 0;
93: terminator = 2;
94: ++p;
95: ++c;
96: } else if (*p == '(') {
97: lim = 2;
98: terminator = 3;
99: ++p;
100: ++c;
101: }
102:
103: if (*p == '+' || *p == '-') {
104: ++p;
105: ++c;
106: }
107:
108: if (*p == '\'') {
109: if (terminator)
110: return(0);
111: lim = 0;
112: terminator = 1;
113: ++p;
114: ++c;
115: } else if (*p == '[') {
116: if (terminator)
117: return(0);
118: lim = 0;
119: terminator = 2;
120: ++p;
121: ++c;
122: } else if (*p == '(') {
123: if (terminator)
124: return(0);
125: lim = 2;
126: terminator = 3;
127: ++p;
128: ++c;
129: }
130:
131: /* TODO: needs to handle floating point. */
132:
133: if ( ! isdigit((u_char)*p))
134: return(0);
135:
136: for (i = 0; isdigit((u_char)*p); i++) {
137: if (lim && i >= lim)
138: break;
139: ++p;
140: ++c;
141: }
142:
143: if (terminator && terminator < 3) {
144: if (1 == terminator && *p != '\'')
145: return(0);
146: if (2 == terminator && *p != ']')
147: return(0);
148: ++p;
149: ++c;
150: }
151:
152: return(c);
1.11 kristaps 153: case ('f'):
154: /* FALLTHROUGH */
155: case ('F'):
156: /* FALLTHROUGH */
1.1 kristaps 157: case ('*'):
158: if (0 == *++p || ! isgraph((u_char)*p))
159: return(0);
160: switch (*p) {
161: case ('('):
162: if (0 == *++p || ! isgraph((u_char)*p))
163: return(0);
164: return(4);
165: case ('['):
166: for (c = 3, p++; *p && ']' != *p; p++, c++)
167: if ( ! isgraph((u_char)*p))
168: break;
169: return(*p == ']' ? c : 0);
170: default:
171: break;
172: }
173: return(3);
174: case ('('):
175: if (0 == *++p || ! isgraph((u_char)*p))
176: return(0);
177: if (0 == *++p || ! isgraph((u_char)*p))
178: return(0);
179: return(4);
180: case ('['):
181: break;
182: default:
183: return(0);
184: }
185:
186: for (c = 3, p++; *p && ']' != *p; p++, c++)
187: if ( ! isgraph((u_char)*p))
188: break;
189:
190: return(*p == ']' ? c : 0);
191: }
192:
1.4 kristaps 193:
194: void *
195: mandoc_calloc(size_t num, size_t size)
196: {
197: void *ptr;
198:
199: ptr = calloc(num, size);
200: if (NULL == ptr) {
1.6 kristaps 201: perror(NULL);
1.4 kristaps 202: exit(EXIT_FAILURE);
203: }
204:
205: return(ptr);
206: }
207:
208:
209: void *
210: mandoc_malloc(size_t size)
211: {
212: void *ptr;
213:
214: ptr = malloc(size);
215: if (NULL == ptr) {
1.6 kristaps 216: perror(NULL);
1.4 kristaps 217: exit(EXIT_FAILURE);
218: }
219:
220: return(ptr);
221: }
222:
223:
224: void *
225: mandoc_realloc(void *ptr, size_t size)
226: {
227:
228: ptr = realloc(ptr, size);
229: if (NULL == ptr) {
1.6 kristaps 230: perror(NULL);
1.4 kristaps 231: exit(EXIT_FAILURE);
232: }
233:
234: return(ptr);
235: }
236:
237:
238: char *
239: mandoc_strdup(const char *ptr)
240: {
241: char *p;
242:
243: p = strdup(ptr);
244: if (NULL == p) {
1.6 kristaps 245: perror(NULL);
1.4 kristaps 246: exit(EXIT_FAILURE);
247: }
248:
249: return(p);
250: }
1.7 kristaps 251:
252:
253: static int
254: a2time(time_t *t, const char *fmt, const char *p)
255: {
256: struct tm tm;
257: char *pp;
258:
259: memset(&tm, 0, sizeof(struct tm));
260:
261: pp = strptime(p, fmt, &tm);
262: if (NULL != pp && '\0' == *pp) {
263: *t = mktime(&tm);
264: return(1);
265: }
266:
267: return(0);
268: }
269:
270:
271: /*
272: * Convert from a manual date string (see mdoc(7) and man(7)) into a
273: * date according to the stipulated date type.
274: */
275: time_t
276: mandoc_a2time(int flags, const char *p)
277: {
278: time_t t;
279:
280: if (MTIME_MDOCDATE & flags) {
281: if (0 == strcmp(p, "$" "Mdocdate$"))
282: return(time(NULL));
283: if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
284: return(t);
285: }
286:
287: if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
288: if (a2time(&t, "%b %d, %Y", p))
289: return(t);
290:
291: if (MTIME_ISO_8601 & flags)
292: if (a2time(&t, "%Y-%m-%d", p))
293: return(t);
294:
295: if (MTIME_REDUCED & flags) {
296: if (a2time(&t, "%d, %Y", p))
297: return(t);
298: if (a2time(&t, "%Y", p))
299: return(t);
300: }
301:
302: return(0);
303: }
304:
1.12 kristaps 305:
306: int
307: mandoc_eos(const char *p, size_t sz)
308: {
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:
319: for ( ; sz; sz--) {
320: switch (p[(int)sz - 1]) {
321: case ('\"'):
322: /* FALLTHROUGH */
323: case ('\''):
1.15 kristaps 324: /* FALLTHROUGH */
325: case (']'):
1.14 kristaps 326: /* FALLTHROUGH */
327: case (')'):
328: break;
329: case ('.'):
330: /* Escaped periods. */
331: if (sz > 1 && '\\' == p[(int)sz - 2])
332: return(0);
333: /* FALLTHROUGH */
334: case ('!'):
335: /* FALLTHROUGH */
336: case ('?'):
337: return(1);
338: default:
1.12 kristaps 339: return(0);
1.14 kristaps 340: }
1.12 kristaps 341: }
342:
1.14 kristaps 343: return(0);
1.16 kristaps 344: }
345:
346:
347: int
348: mandoc_hyph(const char *start, const char *c)
349: {
350:
351: /*
352: * Choose whether to break at a hyphenated character. We only
353: * do this if it's free-standing within a word.
354: */
355:
356: /* Skip first/last character of buffer. */
357: if (c == start || '\0' == *(c + 1))
358: return(0);
359: /* Skip first/last character of word. */
360: if ('\t' == *(c + 1) || '\t' == *(c - 1))
361: return(0);
362: if (' ' == *(c + 1) || ' ' == *(c - 1))
363: return(0);
364: /* Skip double invocations. */
365: if ('-' == *(c + 1) || '-' == *(c - 1))
366: return(0);
367: /* Skip escapes. */
368: if ('\\' == *(c - 1))
369: return(0);
370:
371: return(1);
1.12 kristaps 372: }
CVSweb