1 /* $Vendor-Id: mandoc.c,v 1.27 2010/07/25 19:05:59 joerg Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> 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 "mandoc.h" 31 #include "libmandoc.h" 32 33 static int a2time(time_t *, const char *, const char *); 34 35 36 int 37 mandoc_special(char *p) 38 { 39 int len, i; 40 char term; 41 char *sv; 42 43 len = 0; 44 term = '\0'; 45 sv = p; 46 47 assert('\\' == *p); 48 p++; 49 50 switch (*p++) { 51 #if 0 52 case ('Z'): 53 /* FALLTHROUGH */ 54 case ('X'): 55 /* FALLTHROUGH */ 56 case ('x'): 57 /* FALLTHROUGH */ 58 case ('w'): 59 /* FALLTHROUGH */ 60 case ('v'): 61 /* FALLTHROUGH */ 62 case ('S'): 63 /* FALLTHROUGH */ 64 case ('R'): 65 /* FALLTHROUGH */ 66 case ('o'): 67 /* FALLTHROUGH */ 68 case ('N'): 69 /* FALLTHROUGH */ 70 case ('l'): 71 /* FALLTHROUGH */ 72 case ('L'): 73 /* FALLTHROUGH */ 74 case ('H'): 75 /* FALLTHROUGH */ 76 case ('h'): 77 /* FALLTHROUGH */ 78 case ('D'): 79 /* FALLTHROUGH */ 80 case ('C'): 81 /* FALLTHROUGH */ 82 case ('b'): 83 /* FALLTHROUGH */ 84 case ('B'): 85 /* FALLTHROUGH */ 86 case ('a'): 87 /* FALLTHROUGH */ 88 case ('A'): 89 if (*p++ != '\'') 90 return(0); 91 term = '\''; 92 break; 93 #endif 94 case ('s'): 95 if (ASCII_HYPH == *p) 96 *p = '-'; 97 if ('+' == *p || '-' == *p) 98 p++; 99 100 i = ('s' != *(p - 1)); 101 102 switch (*p++) { 103 case ('('): 104 len = 2; 105 break; 106 case ('['): 107 term = ']'; 108 break; 109 case ('\''): 110 term = '\''; 111 break; 112 case ('0'): 113 i++; 114 /* FALLTHROUGH */ 115 default: 116 len = 1; 117 p--; 118 break; 119 } 120 121 if (ASCII_HYPH == *p) 122 *p = '-'; 123 if ('+' == *p || '-' == *p) { 124 if (i++) 125 return(0); 126 p++; 127 } 128 129 if (0 == i) 130 return(0); 131 break; 132 #if 0 133 case ('Y'): 134 /* FALLTHROUGH */ 135 case ('V'): 136 /* FALLTHROUGH */ 137 case ('$'): 138 /* FALLTHROUGH */ 139 case ('n'): 140 /* FALLTHROUGH */ 141 case ('k'): 142 /* FALLTHROUGH */ 143 #endif 144 case ('M'): 145 /* FALLTHROUGH */ 146 case ('m'): 147 /* FALLTHROUGH */ 148 case ('f'): 149 /* FALLTHROUGH */ 150 case ('F'): 151 /* FALLTHROUGH */ 152 case ('*'): 153 switch (*p++) { 154 case ('('): 155 len = 2; 156 break; 157 case ('['): 158 term = ']'; 159 break; 160 default: 161 len = 1; 162 p--; 163 break; 164 } 165 break; 166 case ('('): 167 len = 2; 168 break; 169 case ('['): 170 term = ']'; 171 break; 172 default: 173 len = 1; 174 p--; 175 break; 176 } 177 178 if (term) { 179 for ( ; *p && term != *p; p++) 180 if (ASCII_HYPH == *p) 181 *p = '-'; 182 return(*p ? (int)(p - sv) : 0); 183 } 184 185 for (i = 0; *p && i < len; i++, p++) 186 if (ASCII_HYPH == *p) 187 *p = '-'; 188 return(i == len ? (int)(p - sv) : 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 304 int 305 mandoc_eos(const char *p, size_t sz, int enclosed) 306 { 307 const char *q; 308 int found; 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 found = 0; 320 for (q = p + (int)sz - 1; q >= p; q--) { 321 switch (*q) { 322 case ('\"'): 323 /* FALLTHROUGH */ 324 case ('\''): 325 /* FALLTHROUGH */ 326 case (']'): 327 /* FALLTHROUGH */ 328 case (')'): 329 if (0 == found) 330 enclosed = 1; 331 break; 332 case ('.'): 333 /* FALLTHROUGH */ 334 case ('!'): 335 /* FALLTHROUGH */ 336 case ('?'): 337 found = 1; 338 break; 339 default: 340 return(found && (!enclosed || isalnum((unsigned char)*q))); 341 } 342 } 343 344 return(found && !enclosed); 345 } 346 347 348 int 349 mandoc_hyph(const char *start, const char *c) 350 { 351 352 /* 353 * Choose whether to break at a hyphenated character. We only 354 * do this if it's free-standing within a word. 355 */ 356 357 /* Skip first/last character of buffer. */ 358 if (c == start || '\0' == *(c + 1)) 359 return(0); 360 /* Skip first/last character of word. */ 361 if ('\t' == *(c + 1) || '\t' == *(c - 1)) 362 return(0); 363 if (' ' == *(c + 1) || ' ' == *(c - 1)) 364 return(0); 365 /* Skip double invocations. */ 366 if ('-' == *(c + 1) || '-' == *(c - 1)) 367 return(0); 368 /* Skip escapes. */ 369 if ('\\' == *(c - 1)) 370 return(0); 371 372 return(1); 373 } 374