1 /* $Vendor-Id: mandoc.c,v 1.11 2010/04/07 11:25:38 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 ('c'): 73 return(2); 74 case ('e'): 75 return(2); 76 case ('s'): 77 if ('\0' == *++p) 78 return(2); 79 80 c = 2; 81 terminator = 0; 82 lim = 1; 83 84 if (*p == '\'') { 85 lim = 0; 86 terminator = 1; 87 ++p; 88 ++c; 89 } else if (*p == '[') { 90 lim = 0; 91 terminator = 2; 92 ++p; 93 ++c; 94 } else if (*p == '(') { 95 lim = 2; 96 terminator = 3; 97 ++p; 98 ++c; 99 } 100 101 if (*p == '+' || *p == '-') { 102 ++p; 103 ++c; 104 } 105 106 if (*p == '\'') { 107 if (terminator) 108 return(0); 109 lim = 0; 110 terminator = 1; 111 ++p; 112 ++c; 113 } else if (*p == '[') { 114 if (terminator) 115 return(0); 116 lim = 0; 117 terminator = 2; 118 ++p; 119 ++c; 120 } else if (*p == '(') { 121 if (terminator) 122 return(0); 123 lim = 2; 124 terminator = 3; 125 ++p; 126 ++c; 127 } 128 129 /* TODO: needs to handle floating point. */ 130 131 if ( ! isdigit((u_char)*p)) 132 return(0); 133 134 for (i = 0; isdigit((u_char)*p); i++) { 135 if (lim && i >= lim) 136 break; 137 ++p; 138 ++c; 139 } 140 141 if (terminator && terminator < 3) { 142 if (1 == terminator && *p != '\'') 143 return(0); 144 if (2 == terminator && *p != ']') 145 return(0); 146 ++p; 147 ++c; 148 } 149 150 return(c); 151 case ('f'): 152 /* FALLTHROUGH */ 153 case ('F'): 154 /* FALLTHROUGH */ 155 case ('*'): 156 if (0 == *++p || ! isgraph((u_char)*p)) 157 return(0); 158 switch (*p) { 159 case ('('): 160 if (0 == *++p || ! isgraph((u_char)*p)) 161 return(0); 162 return(4); 163 case ('['): 164 for (c = 3, p++; *p && ']' != *p; p++, c++) 165 if ( ! isgraph((u_char)*p)) 166 break; 167 return(*p == ']' ? c : 0); 168 default: 169 break; 170 } 171 return(3); 172 case ('('): 173 if (0 == *++p || ! isgraph((u_char)*p)) 174 return(0); 175 if (0 == *++p || ! isgraph((u_char)*p)) 176 return(0); 177 return(4); 178 case ('['): 179 break; 180 default: 181 return(0); 182 } 183 184 for (c = 3, p++; *p && ']' != *p; p++, c++) 185 if ( ! isgraph((u_char)*p)) 186 break; 187 188 return(*p == ']' ? c : 0); 189 } 190 191 192 void * 193 mandoc_calloc(size_t num, size_t size) 194 { 195 void *ptr; 196 197 ptr = calloc(num, size); 198 if (NULL == ptr) { 199 perror(NULL); 200 exit(EXIT_FAILURE); 201 } 202 203 return(ptr); 204 } 205 206 207 void * 208 mandoc_malloc(size_t size) 209 { 210 void *ptr; 211 212 ptr = malloc(size); 213 if (NULL == ptr) { 214 perror(NULL); 215 exit(EXIT_FAILURE); 216 } 217 218 return(ptr); 219 } 220 221 222 void * 223 mandoc_realloc(void *ptr, size_t size) 224 { 225 226 ptr = realloc(ptr, size); 227 if (NULL == ptr) { 228 perror(NULL); 229 exit(EXIT_FAILURE); 230 } 231 232 return(ptr); 233 } 234 235 236 char * 237 mandoc_strdup(const char *ptr) 238 { 239 char *p; 240 241 p = strdup(ptr); 242 if (NULL == p) { 243 perror(NULL); 244 exit(EXIT_FAILURE); 245 } 246 247 return(p); 248 } 249 250 251 static int 252 a2time(time_t *t, const char *fmt, const char *p) 253 { 254 struct tm tm; 255 char *pp; 256 257 memset(&tm, 0, sizeof(struct tm)); 258 259 pp = strptime(p, fmt, &tm); 260 if (NULL != pp && '\0' == *pp) { 261 *t = mktime(&tm); 262 return(1); 263 } 264 265 return(0); 266 } 267 268 269 /* 270 * Convert from a manual date string (see mdoc(7) and man(7)) into a 271 * date according to the stipulated date type. 272 */ 273 time_t 274 mandoc_a2time(int flags, const char *p) 275 { 276 time_t t; 277 278 if (MTIME_MDOCDATE & flags) { 279 if (0 == strcmp(p, "$" "Mdocdate$")) 280 return(time(NULL)); 281 if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p)) 282 return(t); 283 } 284 285 if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags) 286 if (a2time(&t, "%b %d, %Y", p)) 287 return(t); 288 289 if (MTIME_ISO_8601 & flags) 290 if (a2time(&t, "%Y-%m-%d", p)) 291 return(t); 292 293 if (MTIME_REDUCED & flags) { 294 if (a2time(&t, "%d, %Y", p)) 295 return(t); 296 if (a2time(&t, "%Y", p)) 297 return(t); 298 } 299 300 return(0); 301 } 302 303