Annotation of src/usr.bin/mandoc/mandoc.c, Revision 1.13
1.13 ! schwarze 1: /* $Id: mandoc.c,v 1.12 2010/05/26 02:39:58 schwarze Exp $ */
1.1 schwarze 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.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:
26: #include "libmandoc.h"
27:
1.5 schwarze 28: static int a2time(time_t *, const char *, const char *);
29:
30:
1.1 schwarze 31: int
32: mandoc_special(const char *p)
33: {
1.6 schwarze 34: int terminator; /* Terminator for \s. */
35: int lim; /* Limit for N in \s. */
36: int c, i;
1.1 schwarze 37:
38: if ('\\' != *p++)
39: return(0);
40:
41: switch (*p) {
42: case ('\''):
43: /* FALLTHROUGH */
44: case ('`'):
45: /* FALLTHROUGH */
46: case ('q'):
47: /* FALLTHROUGH */
48: case ('-'):
49: /* FALLTHROUGH */
50: case ('~'):
51: /* FALLTHROUGH */
52: case ('^'):
53: /* FALLTHROUGH */
54: case ('%'):
55: /* FALLTHROUGH */
56: case ('0'):
57: /* FALLTHROUGH */
58: case (' '):
1.13 ! schwarze 59: /* FALLTHROUGH */
! 60: case ('}'):
1.1 schwarze 61: /* FALLTHROUGH */
62: case ('|'):
63: /* FALLTHROUGH */
64: case ('&'):
65: /* FALLTHROUGH */
66: case ('.'):
67: /* FALLTHROUGH */
68: case (':'):
69: /* FALLTHROUGH */
1.3 schwarze 70: case ('c'):
71: return(2);
1.1 schwarze 72: case ('e'):
73: return(2);
1.6 schwarze 74: case ('s'):
75: if ('\0' == *++p)
76: return(2);
77:
78: c = 2;
79: terminator = 0;
80: lim = 1;
81:
82: if (*p == '\'') {
83: lim = 0;
84: terminator = 1;
85: ++p;
86: ++c;
87: } else if (*p == '[') {
88: lim = 0;
89: terminator = 2;
90: ++p;
91: ++c;
92: } else if (*p == '(') {
93: lim = 2;
94: terminator = 3;
95: ++p;
96: ++c;
97: }
98:
99: if (*p == '+' || *p == '-') {
100: ++p;
101: ++c;
102: }
103:
104: if (*p == '\'') {
105: if (terminator)
106: return(0);
107: lim = 0;
108: terminator = 1;
109: ++p;
110: ++c;
111: } else if (*p == '[') {
112: if (terminator)
113: return(0);
114: lim = 0;
115: terminator = 2;
116: ++p;
117: ++c;
118: } else if (*p == '(') {
119: if (terminator)
120: return(0);
121: lim = 2;
122: terminator = 3;
123: ++p;
124: ++c;
125: }
126:
127: /* TODO: needs to handle floating point. */
128:
129: if ( ! isdigit((u_char)*p))
130: return(0);
131:
132: for (i = 0; isdigit((u_char)*p); i++) {
133: if (lim && i >= lim)
134: break;
135: ++p;
136: ++c;
137: }
138:
139: if (terminator && terminator < 3) {
140: if (1 == terminator && *p != '\'')
141: return(0);
142: if (2 == terminator && *p != ']')
143: return(0);
144: ++p;
145: ++c;
146: }
147:
148: return(c);
1.8 schwarze 149: case ('f'):
150: /* FALLTHROUGH */
151: case ('F'):
152: /* FALLTHROUGH */
1.1 schwarze 153: case ('*'):
154: if (0 == *++p || ! isgraph((u_char)*p))
155: return(0);
156: switch (*p) {
157: case ('('):
158: if (0 == *++p || ! isgraph((u_char)*p))
159: return(0);
160: return(4);
161: case ('['):
162: for (c = 3, p++; *p && ']' != *p; p++, c++)
163: if ( ! isgraph((u_char)*p))
164: break;
165: return(*p == ']' ? c : 0);
166: default:
167: break;
168: }
169: return(3);
170: case ('('):
171: if (0 == *++p || ! isgraph((u_char)*p))
172: return(0);
173: if (0 == *++p || ! isgraph((u_char)*p))
174: return(0);
175: return(4);
176: case ('['):
177: break;
178: default:
179: return(0);
180: }
181:
182: for (c = 3, p++; *p && ']' != *p; p++, c++)
183: if ( ! isgraph((u_char)*p))
184: break;
185:
186: return(*p == ']' ? c : 0);
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);
198: exit(EXIT_FAILURE);
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);
213: exit(EXIT_FAILURE);
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);
227: exit(EXIT_FAILURE);
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);
242: exit(EXIT_FAILURE);
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
303: mandoc_eos(const char *p, size_t sz)
304: {
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:
315: for ( ; sz; sz--) {
316: switch (p[(int)sz - 1]) {
317: case ('\"'):
318: /* FALLTHROUGH */
319: case ('\''):
320: /* FALLTHROUGH */
321: case (']'):
322: /* FALLTHROUGH */
323: case (')'):
324: break;
325: case ('.'):
326: /* Escaped periods. */
327: if (sz > 1 && '\\' == p[(int)sz - 2])
328: return(0);
329: /* FALLTHROUGH */
330: case ('!'):
331: /* FALLTHROUGH */
332: case ('?'):
333: return(1);
334: default:
1.9 schwarze 335: return(0);
1.11 schwarze 336: }
1.9 schwarze 337: }
338:
1.11 schwarze 339: return(0);
1.12 schwarze 340: }
341:
342:
343: int
344: mandoc_hyph(const char *start, const char *c)
345: {
346:
347: /*
348: * Choose whether to break at a hyphenated character. We only
349: * do this if it's free-standing within a word.
350: */
351:
352: /* Skip first/last character of buffer. */
353: if (c == start || '\0' == *(c + 1))
354: return(0);
355: /* Skip first/last character of word. */
356: if ('\t' == *(c + 1) || '\t' == *(c - 1))
357: return(0);
358: if (' ' == *(c + 1) || ' ' == *(c - 1))
359: return(0);
360: /* Skip double invocations. */
361: if ('-' == *(c + 1) || '-' == *(c - 1))
362: return(0);
363: /* Skip escapes. */
364: if ('\\' == *(c - 1))
365: return(0);
366:
367: return(1);
1.9 schwarze 368: }