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