]> git.cameronkatri.com Git - mandoc.git/blob - mandoc.c
Add -Owidth=width option to mandoc -Tascii. Asked for by joerg@ about a
[mandoc.git] / mandoc.c
1 /* $Id: mandoc.c,v 1.17 2010/06/01 11:47:28 kristaps Exp $ */
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 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <sys/types.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29
30 #include "libmandoc.h"
31
32 static int a2time(time_t *, const char *, const char *);
33
34
35 int
36 mandoc_special(const char *p)
37 {
38 int terminator; /* Terminator for \s. */
39 int lim; /* Limit for N in \s. */
40 int c, i;
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 (' '):
63 /* FALLTHROUGH */
64 case ('}'):
65 /* FALLTHROUGH */
66 case ('|'):
67 /* FALLTHROUGH */
68 case ('&'):
69 /* FALLTHROUGH */
70 case ('.'):
71 /* FALLTHROUGH */
72 case (':'):
73 /* FALLTHROUGH */
74 case ('c'):
75 return(2);
76 case ('e'):
77 return(2);
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);
153 case ('f'):
154 /* FALLTHROUGH */
155 case ('F'):
156 /* FALLTHROUGH */
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
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) {
201 perror(NULL);
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) {
216 perror(NULL);
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) {
230 perror(NULL);
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) {
245 perror(NULL);
246 exit(EXIT_FAILURE);
247 }
248
249 return(p);
250 }
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
305
306 int
307 mandoc_eos(const char *p, size_t sz)
308 {
309
310 if (0 == sz)
311 return(0);
312
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 ('\''):
324 /* FALLTHROUGH */
325 case (']'):
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:
339 return(0);
340 }
341 }
342
343 return(0);
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);
372 }