1d6f907dcSJoerg Wunsch /*- 2ad7cf975SJoerg Wunsch * Copyright (C) 1996 3ad7cf975SJoerg Wunsch * David L. Nugent. All rights reserved. 4d6f907dcSJoerg Wunsch * 5d6f907dcSJoerg Wunsch * Redistribution and use in source and binary forms, with or without 6d6f907dcSJoerg Wunsch * modification, are permitted provided that the following conditions 7d6f907dcSJoerg Wunsch * are met: 8d6f907dcSJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 9ad7cf975SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 10d6f907dcSJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 11d6f907dcSJoerg Wunsch * notice, this list of conditions and the following disclaimer in the 12d6f907dcSJoerg Wunsch * documentation and/or other materials provided with the distribution. 13d6f907dcSJoerg Wunsch * 14ad7cf975SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 15d6f907dcSJoerg Wunsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d6f907dcSJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ad7cf975SJoerg Wunsch * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 18d6f907dcSJoerg Wunsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d6f907dcSJoerg Wunsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d6f907dcSJoerg Wunsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d6f907dcSJoerg Wunsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d6f907dcSJoerg Wunsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d6f907dcSJoerg Wunsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d6f907dcSJoerg Wunsch * SUCH DAMAGE. 25d6f907dcSJoerg Wunsch */ 26d6f907dcSJoerg Wunsch 271dcc6ec7SPhilippe Charnier #ifndef lint 281dcc6ec7SPhilippe Charnier static const char rcsid[] = 2997d92980SPeter Wemm "$FreeBSD$"; 301dcc6ec7SPhilippe Charnier #endif /* not lint */ 311dcc6ec7SPhilippe Charnier 32d6f907dcSJoerg Wunsch #include <stdio.h> 33d6f907dcSJoerg Wunsch #include <stdlib.h> 34d6f907dcSJoerg Wunsch #include <string.h> 35d6f907dcSJoerg Wunsch #include <ctype.h> 36d6f907dcSJoerg Wunsch 37d6f907dcSJoerg Wunsch #include "psdate.h" 38d6f907dcSJoerg Wunsch 39d6f907dcSJoerg Wunsch 40d6f907dcSJoerg Wunsch static int 41d6f907dcSJoerg Wunsch a2i(char const ** str) 42d6f907dcSJoerg Wunsch { 43d6f907dcSJoerg Wunsch int i = 0; 44d6f907dcSJoerg Wunsch char const *s = *str; 45d6f907dcSJoerg Wunsch 46e7161f36SAndrey A. Chernov if (isdigit((unsigned char)*s)) { 47d6f907dcSJoerg Wunsch i = atoi(s); 48e7161f36SAndrey A. Chernov while (isdigit((unsigned char)*s)) 49d6f907dcSJoerg Wunsch ++s; 50d6f907dcSJoerg Wunsch *str = s; 51d6f907dcSJoerg Wunsch } 52d6f907dcSJoerg Wunsch return i; 53d6f907dcSJoerg Wunsch } 54d6f907dcSJoerg Wunsch 55d6f907dcSJoerg Wunsch static int 56d6f907dcSJoerg Wunsch numerics(char const * str) 57d6f907dcSJoerg Wunsch { 58e7161f36SAndrey A. Chernov int rc = isdigit((unsigned char)*str); 59d6f907dcSJoerg Wunsch 60d6f907dcSJoerg Wunsch if (rc) 61e7161f36SAndrey A. Chernov while (isdigit((unsigned char)*str) || *str == 'x') 62d6f907dcSJoerg Wunsch ++str; 63d6f907dcSJoerg Wunsch return rc && !*str; 64d6f907dcSJoerg Wunsch } 65d6f907dcSJoerg Wunsch 66d6f907dcSJoerg Wunsch static int 67d6f907dcSJoerg Wunsch aindex(char const * arr[], char const ** str, int len) 68d6f907dcSJoerg Wunsch { 69d6f907dcSJoerg Wunsch int l, i; 70d6f907dcSJoerg Wunsch char mystr[32]; 71d6f907dcSJoerg Wunsch 72d6f907dcSJoerg Wunsch mystr[len] = '\0'; 73d6f907dcSJoerg Wunsch l = strlen(strncpy(mystr, *str, len)); 74d6f907dcSJoerg Wunsch for (i = 0; i < l; i++) 75e7161f36SAndrey A. Chernov mystr[i] = (char) tolower((unsigned char)mystr[i]); 76d6f907dcSJoerg Wunsch for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); 77d6f907dcSJoerg Wunsch if (arr[i] == NULL) 78d6f907dcSJoerg Wunsch i = -1; 79d6f907dcSJoerg Wunsch else { /* Skip past it */ 80e7161f36SAndrey A. Chernov while (**str && isalpha((unsigned char)**str)) 81d6f907dcSJoerg Wunsch ++(*str); 82d6f907dcSJoerg Wunsch /* And any following whitespace */ 83e7161f36SAndrey A. Chernov while (**str && (**str == ',' || isspace((unsigned char)**str))) 84d6f907dcSJoerg Wunsch ++(*str); 85d6f907dcSJoerg Wunsch } /* Return index */ 86d6f907dcSJoerg Wunsch return i; 87d6f907dcSJoerg Wunsch } 88d6f907dcSJoerg Wunsch 89d6f907dcSJoerg Wunsch static int 90d6f907dcSJoerg Wunsch weekday(char const ** str) 91d6f907dcSJoerg Wunsch { 92d6f907dcSJoerg Wunsch static char const *days[] = 93d6f907dcSJoerg Wunsch {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; 94d6f907dcSJoerg Wunsch 95d6f907dcSJoerg Wunsch return aindex(days, str, 3); 96d6f907dcSJoerg Wunsch } 97d6f907dcSJoerg Wunsch 98d6f907dcSJoerg Wunsch static int 99d6f907dcSJoerg Wunsch month(char const ** str) 100d6f907dcSJoerg Wunsch { 101d6f907dcSJoerg Wunsch static char const *months[] = 102d6f907dcSJoerg Wunsch {"jan", "feb", "mar", "apr", "may", "jun", "jul", 103d6f907dcSJoerg Wunsch "aug", "sep", "oct", "nov", "dec", NULL}; 104d6f907dcSJoerg Wunsch 105d6f907dcSJoerg Wunsch return aindex(months, str, 3); 106d6f907dcSJoerg Wunsch } 107d6f907dcSJoerg Wunsch 108d6f907dcSJoerg Wunsch static void 109d6f907dcSJoerg Wunsch parse_time(char const * str, int *hour, int *min, int *sec) 110d6f907dcSJoerg Wunsch { 111d6f907dcSJoerg Wunsch *hour = a2i(&str); 112d6f907dcSJoerg Wunsch if ((str = strchr(str, ':')) == NULL) 113d6f907dcSJoerg Wunsch *min = *sec = 0; 114d6f907dcSJoerg Wunsch else { 115d6f907dcSJoerg Wunsch ++str; 116d6f907dcSJoerg Wunsch *min = a2i(&str); 117d6f907dcSJoerg Wunsch *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str); 118d6f907dcSJoerg Wunsch } 119d6f907dcSJoerg Wunsch } 120d6f907dcSJoerg Wunsch 121d6f907dcSJoerg Wunsch 122d6f907dcSJoerg Wunsch static void 123d6f907dcSJoerg Wunsch parse_datesub(char const * str, int *day, int *mon, int *year) 124d6f907dcSJoerg Wunsch { 125d6f907dcSJoerg Wunsch int i; 126d6f907dcSJoerg Wunsch 127d6f907dcSJoerg Wunsch static char const nchrs[] = "0123456789 \t,/-."; 128d6f907dcSJoerg Wunsch 129d6f907dcSJoerg Wunsch if ((i = month(&str)) != -1) { 130d6f907dcSJoerg Wunsch *mon = i; 131d6f907dcSJoerg Wunsch if ((i = a2i(&str)) != 0) 132d6f907dcSJoerg Wunsch *day = i; 133d6f907dcSJoerg Wunsch } else if ((i = a2i(&str)) != 0) { 134d6f907dcSJoerg Wunsch *day = i; 135d6f907dcSJoerg Wunsch while (*str && strchr(nchrs + 10, *str) != NULL) 136d6f907dcSJoerg Wunsch ++str; 137d6f907dcSJoerg Wunsch if ((i = month(&str)) != -1) 138d6f907dcSJoerg Wunsch *mon = i; 139d6f907dcSJoerg Wunsch else if ((i = a2i(&str)) != 0) 140d6f907dcSJoerg Wunsch *mon = i - 1; 141d6f907dcSJoerg Wunsch } else 142d6f907dcSJoerg Wunsch return; 143d6f907dcSJoerg Wunsch 144d6f907dcSJoerg Wunsch while (*str && strchr(nchrs + 10, *str) != NULL) 145d6f907dcSJoerg Wunsch ++str; 146e7161f36SAndrey A. Chernov if (isdigit((unsigned char)*str)) { 147d6f907dcSJoerg Wunsch *year = atoi(str); 148d6f907dcSJoerg Wunsch if (*year > 1900) 149d6f907dcSJoerg Wunsch *year -= 1900; 150d6f907dcSJoerg Wunsch else if (*year < 32) 151d6f907dcSJoerg Wunsch *year += 100; 152d6f907dcSJoerg Wunsch } 153d6f907dcSJoerg Wunsch } 154d6f907dcSJoerg Wunsch 155d6f907dcSJoerg Wunsch 156d6f907dcSJoerg Wunsch /*- 157d6f907dcSJoerg Wunsch * Parse time must be flexible, it handles the following formats: 158d6f907dcSJoerg Wunsch * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now 159d6f907dcSJoerg Wunsch * 0xnnnnnnnn UNIX timestamp in hexadecimal 160d6f907dcSJoerg Wunsch * 0nnnnnnnnn UNIX timestamp in octal 161d6f907dcSJoerg Wunsch * 0 Given time 162d6f907dcSJoerg Wunsch * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years 163d6f907dcSJoerg Wunsch * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years 164d6f907dcSJoerg Wunsch * dd[ ./-]mmm[ ./-]yy Date } 165d6f907dcSJoerg Wunsch * hh:mm:ss Time } May be combined 166d6f907dcSJoerg Wunsch */ 167d6f907dcSJoerg Wunsch 168d6f907dcSJoerg Wunsch time_t 169d6f907dcSJoerg Wunsch parse_date(time_t dt, char const * str) 170d6f907dcSJoerg Wunsch { 171d6f907dcSJoerg Wunsch char *p; 172d6f907dcSJoerg Wunsch int i; 173d6f907dcSJoerg Wunsch long val; 174d6f907dcSJoerg Wunsch struct tm *T; 175d6f907dcSJoerg Wunsch 176d6f907dcSJoerg Wunsch if (dt == 0) 177d6f907dcSJoerg Wunsch dt = time(NULL); 178d6f907dcSJoerg Wunsch 179e7161f36SAndrey A. Chernov while (*str && isspace((unsigned char)*str)) 180d6f907dcSJoerg Wunsch ++str; 181d6f907dcSJoerg Wunsch 182d6f907dcSJoerg Wunsch if (numerics(str)) { 1832bffe0d5SDavid Nugent dt = strtol(str, &p, 0); 184d6f907dcSJoerg Wunsch } else if (*str == '+' || *str == '-') { 185d6f907dcSJoerg Wunsch val = strtol(str, &p, 0); 186d6f907dcSJoerg Wunsch switch (*p) { 187d6f907dcSJoerg Wunsch case 'h': 188d6f907dcSJoerg Wunsch case 'H': /* hours */ 189d6f907dcSJoerg Wunsch dt += (val * 3600L); 190d6f907dcSJoerg Wunsch break; 191d6f907dcSJoerg Wunsch case '\0': 192d6f907dcSJoerg Wunsch case 'm': 193d6f907dcSJoerg Wunsch case 'M': /* minutes */ 194d6f907dcSJoerg Wunsch dt += (val * 60L); 195d6f907dcSJoerg Wunsch break; 196d6f907dcSJoerg Wunsch case 's': 197d6f907dcSJoerg Wunsch case 'S': /* seconds */ 198d6f907dcSJoerg Wunsch dt += val; 199d6f907dcSJoerg Wunsch break; 200d6f907dcSJoerg Wunsch case 'd': 201d6f907dcSJoerg Wunsch case 'D': /* days */ 202d6f907dcSJoerg Wunsch dt += (val * 86400L); 203d6f907dcSJoerg Wunsch break; 204d6f907dcSJoerg Wunsch case 'w': 205d6f907dcSJoerg Wunsch case 'W': /* weeks */ 206d6f907dcSJoerg Wunsch dt += (val * 604800L); 207d6f907dcSJoerg Wunsch break; 208d6f907dcSJoerg Wunsch case 'o': 209d6f907dcSJoerg Wunsch case 'O': /* months */ 210d6f907dcSJoerg Wunsch T = localtime(&dt); 211d6f907dcSJoerg Wunsch T->tm_mon += (int) val; 212d6f907dcSJoerg Wunsch i = T->tm_mday; 213d6f907dcSJoerg Wunsch goto fixday; 214d6f907dcSJoerg Wunsch case 'y': 215d6f907dcSJoerg Wunsch case 'Y': /* years */ 216d6f907dcSJoerg Wunsch T = localtime(&dt); 217d6f907dcSJoerg Wunsch T->tm_year += (int) val; 218d6f907dcSJoerg Wunsch i = T->tm_mday; 219d6f907dcSJoerg Wunsch fixday: 220d6f907dcSJoerg Wunsch dt = mktime(T); 221d6f907dcSJoerg Wunsch T = localtime(&dt); 222d6f907dcSJoerg Wunsch if (T->tm_mday != i) { 223d6f907dcSJoerg Wunsch T->tm_mday = 1; 224d6f907dcSJoerg Wunsch dt = mktime(T); 225d6f907dcSJoerg Wunsch dt -= (time_t) 86400L; 226d6f907dcSJoerg Wunsch } 227d6f907dcSJoerg Wunsch default: /* unknown */ 228d6f907dcSJoerg Wunsch break; /* leave untouched */ 229d6f907dcSJoerg Wunsch } 230d6f907dcSJoerg Wunsch } else { 231d6f907dcSJoerg Wunsch char *q, tmp[64]; 232d6f907dcSJoerg Wunsch 233d6f907dcSJoerg Wunsch /* 234d6f907dcSJoerg Wunsch * Skip past any weekday prefix 235d6f907dcSJoerg Wunsch */ 236d6f907dcSJoerg Wunsch weekday(&str); 237d6f907dcSJoerg Wunsch str = strncpy(tmp, str, sizeof tmp - 1); 238d6f907dcSJoerg Wunsch tmp[sizeof tmp - 1] = '\0'; 239d6f907dcSJoerg Wunsch T = localtime(&dt); 240d6f907dcSJoerg Wunsch 241d6f907dcSJoerg Wunsch /* 242d6f907dcSJoerg Wunsch * See if we can break off any timezone 243d6f907dcSJoerg Wunsch */ 244d6f907dcSJoerg Wunsch while ((q = strrchr(tmp, ' ')) != NULL) { 245d6f907dcSJoerg Wunsch if (strchr("(+-", q[1]) != NULL) 246d6f907dcSJoerg Wunsch *q = '\0'; 247d6f907dcSJoerg Wunsch else { 248d6f907dcSJoerg Wunsch int j = 1; 249d6f907dcSJoerg Wunsch 250e7161f36SAndrey A. Chernov while (q[j] && isupper((unsigned char)q[j])) 251d6f907dcSJoerg Wunsch ++j; 252d6f907dcSJoerg Wunsch if (q[j] == '\0') 253d6f907dcSJoerg Wunsch *q = '\0'; 254d6f907dcSJoerg Wunsch else 255d6f907dcSJoerg Wunsch break; 256d6f907dcSJoerg Wunsch } 257d6f907dcSJoerg Wunsch } 258d6f907dcSJoerg Wunsch 259d6f907dcSJoerg Wunsch /* 260d6f907dcSJoerg Wunsch * See if there is a time hh:mm[:ss] 261d6f907dcSJoerg Wunsch */ 262d6f907dcSJoerg Wunsch if ((p = strchr(tmp, ':')) == NULL) { 263d6f907dcSJoerg Wunsch 264d6f907dcSJoerg Wunsch /* 265d6f907dcSJoerg Wunsch * No time string involved 266d6f907dcSJoerg Wunsch */ 267d6f907dcSJoerg Wunsch T->tm_hour = T->tm_min = T->tm_sec = 0; 268d6f907dcSJoerg Wunsch parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year); 269d6f907dcSJoerg Wunsch } else { 270d6f907dcSJoerg Wunsch char datestr[64], timestr[64]; 271d6f907dcSJoerg Wunsch 272d6f907dcSJoerg Wunsch /* 273d6f907dcSJoerg Wunsch * Let's chip off the time string 274d6f907dcSJoerg Wunsch */ 275d6f907dcSJoerg Wunsch if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */ 276d6f907dcSJoerg Wunsch int l = q - str; 277d6f907dcSJoerg Wunsch 278d6f907dcSJoerg Wunsch strncpy(timestr, str, l); 279d6f907dcSJoerg Wunsch timestr[l] = '\0'; 280d6f907dcSJoerg Wunsch strncpy(datestr, q + 1, sizeof datestr); 281d6f907dcSJoerg Wunsch datestr[sizeof datestr - 1] = '\0'; 282d6f907dcSJoerg Wunsch parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 283d6f907dcSJoerg Wunsch parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 284d6f907dcSJoerg Wunsch } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */ 285d6f907dcSJoerg Wunsch int l = q - tmp; 286d6f907dcSJoerg Wunsch 287d6f907dcSJoerg Wunsch strncpy(timestr, q + 1, sizeof timestr); 288d6f907dcSJoerg Wunsch timestr[sizeof timestr - 1] = '\0'; 289d6f907dcSJoerg Wunsch strncpy(datestr, tmp, l); 290d6f907dcSJoerg Wunsch datestr[l] = '\0'; 291d6f907dcSJoerg Wunsch } else /* Bail out */ 292d6f907dcSJoerg Wunsch return dt; 293d6f907dcSJoerg Wunsch parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 294d6f907dcSJoerg Wunsch parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 295d6f907dcSJoerg Wunsch } 296d6f907dcSJoerg Wunsch dt = mktime(T); 297d6f907dcSJoerg Wunsch } 298d6f907dcSJoerg Wunsch return dt; 299d6f907dcSJoerg Wunsch } 300