Merge branch 'vendor/OPENSSH'
[dragonfly.git] / usr.bin / mandoc / mandoc.c
1 /*      $Id: mandoc.c,v 1.8 2009/11/05 10:16:01 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 #if defined(__linux__) || defined(__MINT__)
18 # define _GNU_SOURCE /* strptime() */
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 ('`'):
51                 /* FALLTHROUGH */
52         case ('q'):
53                 /* FALLTHROUGH */
54         case ('-'):
55                 /* FALLTHROUGH */
56         case ('~'):
57                 /* FALLTHROUGH */
58         case ('^'):
59                 /* FALLTHROUGH */
60         case ('%'):
61                 /* FALLTHROUGH */
62         case ('0'):
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 ('f'):
79                 if ('\0' == *++p || ! isgraph((u_char)*p))
80                         return(0);
81                 return(3);
82         case ('s'):
83                 if ('\0' == *++p)
84                         return(2);
85
86                 c = 2;
87                 terminator = 0;
88                 lim = 1;
89
90                 if (*p == '\'') {
91                         lim = 0;
92                         terminator = 1;
93                         ++p;
94                         ++c;
95                 } else if (*p == '[') {
96                         lim = 0;
97                         terminator = 2;
98                         ++p;
99                         ++c;
100                 } else if (*p == '(') {
101                         lim = 2;
102                         terminator = 3;
103                         ++p;
104                         ++c;
105                 }
106
107                 if (*p == '+' || *p == '-') {
108                         ++p;
109                         ++c;
110                 }
111
112                 if (*p == '\'') {
113                         if (terminator)
114                                 return(0);
115                         lim = 0;
116                         terminator = 1;
117                         ++p;
118                         ++c;
119                 } else if (*p == '[') {
120                         if (terminator)
121                                 return(0);
122                         lim = 0;
123                         terminator = 2;
124                         ++p;
125                         ++c;
126                 } else if (*p == '(') {
127                         if (terminator)
128                                 return(0);
129                         lim = 2;
130                         terminator = 3;
131                         ++p;
132                         ++c;
133                 }
134
135                 /* TODO: needs to handle floating point. */
136
137                 if ( ! isdigit((u_char)*p))
138                         return(0);
139
140                 for (i = 0; isdigit((u_char)*p); i++) {
141                         if (lim && i >= lim)
142                                 break;
143                         ++p;
144                         ++c;
145                 }
146
147                 if (terminator && terminator < 3) {
148                         if (1 == terminator && *p != '\'')
149                                 return(0);
150                         if (2 == terminator && *p != ']')
151                                 return(0);
152                         ++p;
153                         ++c;
154                 }
155
156                 return(c);
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 }