Merge branch 'vendor/OPENSSL' into HEAD
[dragonfly.git] / usr.bin / mandoc / mandoc.c
1 /*      $Id: mandoc.c,v 1.10 2010/01/05 19:51:10 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
18 #include <sys/types.h>
19
20 #include <assert.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26
27 #include "libmandoc.h"
28
29 static int       a2time(time_t *, const char *, const char *);
30
31
32 int
33 mandoc_special(const char *p)
34 {
35         int              terminator;    /* Terminator for \s. */
36         int              lim;           /* Limit for N in \s. */
37         int              c, i;
38
39         if ('\\' != *p++)
40                 return(0);
41
42         switch (*p) {
43         case ('\''):
44                 /* FALLTHROUGH */
45         case ('`'):
46                 /* FALLTHROUGH */
47         case ('q'):
48                 /* FALLTHROUGH */
49         case ('-'):
50                 /* FALLTHROUGH */
51         case ('~'):
52                 /* FALLTHROUGH */
53         case ('^'):
54                 /* FALLTHROUGH */
55         case ('%'):
56                 /* FALLTHROUGH */
57         case ('0'):
58                 /* FALLTHROUGH */
59         case (' '):
60                 /* FALLTHROUGH */
61         case ('|'):
62                 /* FALLTHROUGH */
63         case ('&'):
64                 /* FALLTHROUGH */
65         case ('.'):
66                 /* FALLTHROUGH */
67         case (':'):
68                 /* FALLTHROUGH */
69         case ('c'):
70                 return(2);
71         case ('e'):
72                 return(2);
73         case ('f'):
74                 if ('\0' == *++p || ! isgraph((u_char)*p))
75                         return(0);
76                 return(3);
77         case ('s'):
78                 if ('\0' == *++p)
79                         return(2);
80
81                 c = 2;
82                 terminator = 0;
83                 lim = 1;
84
85                 if (*p == '\'') {
86                         lim = 0;
87                         terminator = 1;
88                         ++p;
89                         ++c;
90                 } else if (*p == '[') {
91                         lim = 0;
92                         terminator = 2;
93                         ++p;
94                         ++c;
95                 } else if (*p == '(') {
96                         lim = 2;
97                         terminator = 3;
98                         ++p;
99                         ++c;
100                 }
101
102                 if (*p == '+' || *p == '-') {
103                         ++p;
104                         ++c;
105                 }
106
107                 if (*p == '\'') {
108                         if (terminator)
109                                 return(0);
110                         lim = 0;
111                         terminator = 1;
112                         ++p;
113                         ++c;
114                 } else if (*p == '[') {
115                         if (terminator)
116                                 return(0);
117                         lim = 0;
118                         terminator = 2;
119                         ++p;
120                         ++c;
121                 } else if (*p == '(') {
122                         if (terminator)
123                                 return(0);
124                         lim = 2;
125                         terminator = 3;
126                         ++p;
127                         ++c;
128                 }
129
130                 /* TODO: needs to handle floating point. */
131
132                 if ( ! isdigit((u_char)*p))
133                         return(0);
134
135                 for (i = 0; isdigit((u_char)*p); i++) {
136                         if (lim && i >= lim)
137                                 break;
138                         ++p;
139                         ++c;
140                 }
141
142                 if (terminator && terminator < 3) {
143                         if (1 == terminator && *p != '\'')
144                                 return(0);
145                         if (2 == terminator && *p != ']')
146                                 return(0);
147                         ++p;
148                         ++c;
149                 }
150
151                 return(c);
152         case ('*'):
153                 if (0 == *++p || ! isgraph((u_char)*p))
154                         return(0);
155                 switch (*p) {
156                 case ('('):
157                         if (0 == *++p || ! isgraph((u_char)*p))
158                                 return(0);
159                         return(4);
160                 case ('['):
161                         for (c = 3, p++; *p && ']' != *p; p++, c++)
162                                 if ( ! isgraph((u_char)*p))
163                                         break;
164                         return(*p == ']' ? c : 0);
165                 default:
166                         break;
167                 }
168                 return(3);
169         case ('('):
170                 if (0 == *++p || ! isgraph((u_char)*p))
171                         return(0);
172                 if (0 == *++p || ! isgraph((u_char)*p))
173                         return(0);
174                 return(4);
175         case ('['):
176                 break;
177         default:
178                 return(0);
179         }
180
181         for (c = 3, p++; *p && ']' != *p; p++, c++)
182                 if ( ! isgraph((u_char)*p))
183                         break;
184
185         return(*p == ']' ? c : 0);
186 }
187
188
189 void *
190 mandoc_calloc(size_t num, size_t size)
191 {
192         void            *ptr;
193
194         ptr = calloc(num, size);
195         if (NULL == ptr) {
196                 perror(NULL);
197                 exit(EXIT_FAILURE);
198         }
199
200         return(ptr);
201 }
202
203
204 void *
205 mandoc_malloc(size_t size)
206 {
207         void            *ptr;
208
209         ptr = malloc(size);
210         if (NULL == ptr) {
211                 perror(NULL);
212                 exit(EXIT_FAILURE);
213         }
214
215         return(ptr);
216 }
217
218
219 void *
220 mandoc_realloc(void *ptr, size_t size)
221 {
222
223         ptr = realloc(ptr, size);
224         if (NULL == ptr) {
225                 perror(NULL);
226                 exit(EXIT_FAILURE);
227         }
228
229         return(ptr);
230 }
231
232
233 char *
234 mandoc_strdup(const char *ptr)
235 {
236         char            *p;
237
238         p = strdup(ptr);
239         if (NULL == p) {
240                 perror(NULL);
241                 exit(EXIT_FAILURE);
242         }
243
244         return(p);
245 }
246
247
248 static int
249 a2time(time_t *t, const char *fmt, const char *p)
250 {
251         struct tm        tm;
252         char            *pp;
253
254         memset(&tm, 0, sizeof(struct tm));
255
256         pp = strptime(p, fmt, &tm);
257         if (NULL != pp && '\0' == *pp) {
258                 *t = mktime(&tm);
259                 return(1);
260         }
261
262         return(0);
263 }
264
265
266 /*
267  * Convert from a manual date string (see mdoc(7) and man(7)) into a
268  * date according to the stipulated date type.
269  */
270 time_t
271 mandoc_a2time(int flags, const char *p)
272 {
273         time_t           t;
274
275         if (MTIME_MDOCDATE & flags) {
276                 if (0 == strcmp(p, "$" "Mdocdate$"))
277                         return(time(NULL));
278                 if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
279                         return(t);
280         }
281
282         if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
283                 if (a2time(&t, "%b %d, %Y", p))
284                         return(t);
285
286         if (MTIME_ISO_8601 & flags)
287                 if (a2time(&t, "%Y-%m-%d", p))
288                         return(t);
289
290         if (MTIME_REDUCED & flags) {
291                 if (a2time(&t, "%d, %Y", p))
292                         return(t);
293                 if (a2time(&t, "%Y", p))
294                         return(t);
295         }
296
297         return(0);
298 }