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 * 26ad7cf975SJoerg Wunsch * $Id: psdate.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $ 27d6f907dcSJoerg Wunsch */ 28d6f907dcSJoerg Wunsch 29d6f907dcSJoerg Wunsch #include <stdio.h> 30d6f907dcSJoerg Wunsch #include <stdlib.h> 31d6f907dcSJoerg Wunsch #include <string.h> 32d6f907dcSJoerg Wunsch #include <ctype.h> 33d6f907dcSJoerg Wunsch 34d6f907dcSJoerg Wunsch #include "psdate.h" 35d6f907dcSJoerg Wunsch 36d6f907dcSJoerg Wunsch 37d6f907dcSJoerg Wunsch static int 38d6f907dcSJoerg Wunsch a2i(char const ** str) 39d6f907dcSJoerg Wunsch { 40d6f907dcSJoerg Wunsch int i = 0; 41d6f907dcSJoerg Wunsch char const *s = *str; 42d6f907dcSJoerg Wunsch 43d6f907dcSJoerg Wunsch if (isdigit(*s)) { 44d6f907dcSJoerg Wunsch i = atoi(s); 45d6f907dcSJoerg Wunsch while (isdigit(*s)) 46d6f907dcSJoerg Wunsch ++s; 47d6f907dcSJoerg Wunsch *str = s; 48d6f907dcSJoerg Wunsch } 49d6f907dcSJoerg Wunsch return i; 50d6f907dcSJoerg Wunsch } 51d6f907dcSJoerg Wunsch 52d6f907dcSJoerg Wunsch static int 53d6f907dcSJoerg Wunsch numerics(char const * str) 54d6f907dcSJoerg Wunsch { 55d6f907dcSJoerg Wunsch int rc = isdigit(*str); 56d6f907dcSJoerg Wunsch 57d6f907dcSJoerg Wunsch if (rc) 58d6f907dcSJoerg Wunsch while (isdigit(*str) || *str == 'x') 59d6f907dcSJoerg Wunsch ++str; 60d6f907dcSJoerg Wunsch return rc && !*str; 61d6f907dcSJoerg Wunsch } 62d6f907dcSJoerg Wunsch 63d6f907dcSJoerg Wunsch static int 64d6f907dcSJoerg Wunsch aindex(char const * arr[], char const ** str, int len) 65d6f907dcSJoerg Wunsch { 66d6f907dcSJoerg Wunsch int l, i; 67d6f907dcSJoerg Wunsch char mystr[32]; 68d6f907dcSJoerg Wunsch 69d6f907dcSJoerg Wunsch mystr[len] = '\0'; 70d6f907dcSJoerg Wunsch l = strlen(strncpy(mystr, *str, len)); 71d6f907dcSJoerg Wunsch for (i = 0; i < l; i++) 72d6f907dcSJoerg Wunsch mystr[i] = (char) tolower(mystr[i]); 73d6f907dcSJoerg Wunsch for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); 74d6f907dcSJoerg Wunsch if (arr[i] == NULL) 75d6f907dcSJoerg Wunsch i = -1; 76d6f907dcSJoerg Wunsch else { /* Skip past it */ 77d6f907dcSJoerg Wunsch while (**str && isalpha(**str)) 78d6f907dcSJoerg Wunsch ++(*str); 79d6f907dcSJoerg Wunsch /* And any following whitespace */ 80d6f907dcSJoerg Wunsch while (**str && (**str == ',' || isspace(**str))) 81d6f907dcSJoerg Wunsch ++(*str); 82d6f907dcSJoerg Wunsch } /* Return index */ 83d6f907dcSJoerg Wunsch return i; 84d6f907dcSJoerg Wunsch } 85d6f907dcSJoerg Wunsch 86d6f907dcSJoerg Wunsch static int 87d6f907dcSJoerg Wunsch weekday(char const ** str) 88d6f907dcSJoerg Wunsch { 89d6f907dcSJoerg Wunsch static char const *days[] = 90d6f907dcSJoerg Wunsch {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; 91d6f907dcSJoerg Wunsch 92d6f907dcSJoerg Wunsch return aindex(days, str, 3); 93d6f907dcSJoerg Wunsch } 94d6f907dcSJoerg Wunsch 95d6f907dcSJoerg Wunsch static int 96d6f907dcSJoerg Wunsch month(char const ** str) 97d6f907dcSJoerg Wunsch { 98d6f907dcSJoerg Wunsch static char const *months[] = 99d6f907dcSJoerg Wunsch {"jan", "feb", "mar", "apr", "may", "jun", "jul", 100d6f907dcSJoerg Wunsch "aug", "sep", "oct", "nov", "dec", NULL}; 101d6f907dcSJoerg Wunsch 102d6f907dcSJoerg Wunsch return aindex(months, str, 3); 103d6f907dcSJoerg Wunsch } 104d6f907dcSJoerg Wunsch 105d6f907dcSJoerg Wunsch static void 106d6f907dcSJoerg Wunsch parse_time(char const * str, int *hour, int *min, int *sec) 107d6f907dcSJoerg Wunsch { 108d6f907dcSJoerg Wunsch *hour = a2i(&str); 109d6f907dcSJoerg Wunsch if ((str = strchr(str, ':')) == NULL) 110d6f907dcSJoerg Wunsch *min = *sec = 0; 111d6f907dcSJoerg Wunsch else { 112d6f907dcSJoerg Wunsch ++str; 113d6f907dcSJoerg Wunsch *min = a2i(&str); 114d6f907dcSJoerg Wunsch *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str); 115d6f907dcSJoerg Wunsch } 116d6f907dcSJoerg Wunsch } 117d6f907dcSJoerg Wunsch 118d6f907dcSJoerg Wunsch 119d6f907dcSJoerg Wunsch static void 120d6f907dcSJoerg Wunsch parse_datesub(char const * str, int *day, int *mon, int *year) 121d6f907dcSJoerg Wunsch { 122d6f907dcSJoerg Wunsch int i; 123d6f907dcSJoerg Wunsch 124d6f907dcSJoerg Wunsch static char const nchrs[] = "0123456789 \t,/-."; 125d6f907dcSJoerg Wunsch 126d6f907dcSJoerg Wunsch if ((i = month(&str)) != -1) { 127d6f907dcSJoerg Wunsch *mon = i; 128d6f907dcSJoerg Wunsch if ((i = a2i(&str)) != 0) 129d6f907dcSJoerg Wunsch *day = i; 130d6f907dcSJoerg Wunsch } else if ((i = a2i(&str)) != 0) { 131d6f907dcSJoerg Wunsch *day = i; 132d6f907dcSJoerg Wunsch while (*str && strchr(nchrs + 10, *str) != NULL) 133d6f907dcSJoerg Wunsch ++str; 134d6f907dcSJoerg Wunsch if ((i = month(&str)) != -1) 135d6f907dcSJoerg Wunsch *mon = i; 136d6f907dcSJoerg Wunsch else if ((i = a2i(&str)) != 0) 137d6f907dcSJoerg Wunsch *mon = i - 1; 138d6f907dcSJoerg Wunsch } else 139d6f907dcSJoerg Wunsch return; 140d6f907dcSJoerg Wunsch 141d6f907dcSJoerg Wunsch while (*str && strchr(nchrs + 10, *str) != NULL) 142d6f907dcSJoerg Wunsch ++str; 143d6f907dcSJoerg Wunsch if (isdigit(*str)) { 144d6f907dcSJoerg Wunsch *year = atoi(str); 145d6f907dcSJoerg Wunsch if (*year > 1900) 146d6f907dcSJoerg Wunsch *year -= 1900; 147d6f907dcSJoerg Wunsch else if (*year < 32) 148d6f907dcSJoerg Wunsch *year += 100; 149d6f907dcSJoerg Wunsch } 150d6f907dcSJoerg Wunsch } 151d6f907dcSJoerg Wunsch 152d6f907dcSJoerg Wunsch 153d6f907dcSJoerg Wunsch /*- 154d6f907dcSJoerg Wunsch * Parse time must be flexible, it handles the following formats: 155d6f907dcSJoerg Wunsch * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now 156d6f907dcSJoerg Wunsch * 0xnnnnnnnn UNIX timestamp in hexadecimal 157d6f907dcSJoerg Wunsch * 0nnnnnnnnn UNIX timestamp in octal 158d6f907dcSJoerg Wunsch * 0 Given time 159d6f907dcSJoerg Wunsch * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years 160d6f907dcSJoerg Wunsch * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years 161d6f907dcSJoerg Wunsch * dd[ ./-]mmm[ ./-]yy Date } 162d6f907dcSJoerg Wunsch * hh:mm:ss Time } May be combined 163d6f907dcSJoerg Wunsch */ 164d6f907dcSJoerg Wunsch 165d6f907dcSJoerg Wunsch time_t 166d6f907dcSJoerg Wunsch parse_date(time_t dt, char const * str) 167d6f907dcSJoerg Wunsch { 168d6f907dcSJoerg Wunsch char *p; 169d6f907dcSJoerg Wunsch int i; 170d6f907dcSJoerg Wunsch long val; 171d6f907dcSJoerg Wunsch struct tm *T; 172d6f907dcSJoerg Wunsch 173d6f907dcSJoerg Wunsch if (dt == 0) 174d6f907dcSJoerg Wunsch dt = time(NULL); 175d6f907dcSJoerg Wunsch 176d6f907dcSJoerg Wunsch while (*str && isspace(*str)) 177d6f907dcSJoerg Wunsch ++str; 178d6f907dcSJoerg Wunsch 179d6f907dcSJoerg Wunsch if (numerics(str)) { 180d6f907dcSJoerg Wunsch val = strtol(str, &p, 0); 181d6f907dcSJoerg Wunsch dt = val ? val : dt; 182d6f907dcSJoerg Wunsch } else if (*str == '+' || *str == '-') { 183d6f907dcSJoerg Wunsch val = strtol(str, &p, 0); 184d6f907dcSJoerg Wunsch switch (*p) { 185d6f907dcSJoerg Wunsch case 'h': 186d6f907dcSJoerg Wunsch case 'H': /* hours */ 187d6f907dcSJoerg Wunsch dt += (val * 3600L); 188d6f907dcSJoerg Wunsch break; 189d6f907dcSJoerg Wunsch case '\0': 190d6f907dcSJoerg Wunsch case 'm': 191d6f907dcSJoerg Wunsch case 'M': /* minutes */ 192d6f907dcSJoerg Wunsch dt += (val * 60L); 193d6f907dcSJoerg Wunsch break; 194d6f907dcSJoerg Wunsch case 's': 195d6f907dcSJoerg Wunsch case 'S': /* seconds */ 196d6f907dcSJoerg Wunsch dt += val; 197d6f907dcSJoerg Wunsch break; 198d6f907dcSJoerg Wunsch case 'd': 199d6f907dcSJoerg Wunsch case 'D': /* days */ 200d6f907dcSJoerg Wunsch dt += (val * 86400L); 201d6f907dcSJoerg Wunsch break; 202d6f907dcSJoerg Wunsch case 'w': 203d6f907dcSJoerg Wunsch case 'W': /* weeks */ 204d6f907dcSJoerg Wunsch dt += (val * 604800L); 205d6f907dcSJoerg Wunsch break; 206d6f907dcSJoerg Wunsch case 'o': 207d6f907dcSJoerg Wunsch case 'O': /* months */ 208d6f907dcSJoerg Wunsch T = localtime(&dt); 209d6f907dcSJoerg Wunsch T->tm_mon += (int) val; 210d6f907dcSJoerg Wunsch i = T->tm_mday; 211d6f907dcSJoerg Wunsch goto fixday; 212d6f907dcSJoerg Wunsch case 'y': 213d6f907dcSJoerg Wunsch case 'Y': /* years */ 214d6f907dcSJoerg Wunsch T = localtime(&dt); 215d6f907dcSJoerg Wunsch T->tm_year += (int) val; 216d6f907dcSJoerg Wunsch i = T->tm_mday; 217d6f907dcSJoerg Wunsch fixday: 218d6f907dcSJoerg Wunsch dt = mktime(T); 219d6f907dcSJoerg Wunsch T = localtime(&dt); 220d6f907dcSJoerg Wunsch if (T->tm_mday != i) { 221d6f907dcSJoerg Wunsch T->tm_mday = 1; 222d6f907dcSJoerg Wunsch dt = mktime(T); 223d6f907dcSJoerg Wunsch dt -= (time_t) 86400L; 224d6f907dcSJoerg Wunsch } 225d6f907dcSJoerg Wunsch default: /* unknown */ 226d6f907dcSJoerg Wunsch break; /* leave untouched */ 227d6f907dcSJoerg Wunsch } 228d6f907dcSJoerg Wunsch } else { 229d6f907dcSJoerg Wunsch char *q, tmp[64]; 230d6f907dcSJoerg Wunsch 231d6f907dcSJoerg Wunsch /* 232d6f907dcSJoerg Wunsch * Skip past any weekday prefix 233d6f907dcSJoerg Wunsch */ 234d6f907dcSJoerg Wunsch weekday(&str); 235d6f907dcSJoerg Wunsch str = strncpy(tmp, str, sizeof tmp - 1); 236d6f907dcSJoerg Wunsch tmp[sizeof tmp - 1] = '\0'; 237d6f907dcSJoerg Wunsch T = localtime(&dt); 238d6f907dcSJoerg Wunsch 239d6f907dcSJoerg Wunsch /* 240d6f907dcSJoerg Wunsch * See if we can break off any timezone 241d6f907dcSJoerg Wunsch */ 242d6f907dcSJoerg Wunsch while ((q = strrchr(tmp, ' ')) != NULL) { 243d6f907dcSJoerg Wunsch if (strchr("(+-", q[1]) != NULL) 244d6f907dcSJoerg Wunsch *q = '\0'; 245d6f907dcSJoerg Wunsch else { 246d6f907dcSJoerg Wunsch int j = 1; 247d6f907dcSJoerg Wunsch 248d6f907dcSJoerg Wunsch while (q[j] && isupper(q[j])) 249d6f907dcSJoerg Wunsch ++j; 250d6f907dcSJoerg Wunsch if (q[j] == '\0') 251d6f907dcSJoerg Wunsch *q = '\0'; 252d6f907dcSJoerg Wunsch else 253d6f907dcSJoerg Wunsch break; 254d6f907dcSJoerg Wunsch } 255d6f907dcSJoerg Wunsch } 256d6f907dcSJoerg Wunsch 257d6f907dcSJoerg Wunsch /* 258d6f907dcSJoerg Wunsch * See if there is a time hh:mm[:ss] 259d6f907dcSJoerg Wunsch */ 260d6f907dcSJoerg Wunsch if ((p = strchr(tmp, ':')) == NULL) { 261d6f907dcSJoerg Wunsch 262d6f907dcSJoerg Wunsch /* 263d6f907dcSJoerg Wunsch * No time string involved 264d6f907dcSJoerg Wunsch */ 265d6f907dcSJoerg Wunsch T->tm_hour = T->tm_min = T->tm_sec = 0; 266d6f907dcSJoerg Wunsch parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year); 267d6f907dcSJoerg Wunsch } else { 268d6f907dcSJoerg Wunsch char datestr[64], timestr[64]; 269d6f907dcSJoerg Wunsch 270d6f907dcSJoerg Wunsch /* 271d6f907dcSJoerg Wunsch * Let's chip off the time string 272d6f907dcSJoerg Wunsch */ 273d6f907dcSJoerg Wunsch if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */ 274d6f907dcSJoerg Wunsch int l = q - str; 275d6f907dcSJoerg Wunsch 276d6f907dcSJoerg Wunsch strncpy(timestr, str, l); 277d6f907dcSJoerg Wunsch timestr[l] = '\0'; 278d6f907dcSJoerg Wunsch strncpy(datestr, q + 1, sizeof datestr); 279d6f907dcSJoerg Wunsch datestr[sizeof datestr - 1] = '\0'; 280d6f907dcSJoerg Wunsch parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 281d6f907dcSJoerg Wunsch parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 282d6f907dcSJoerg Wunsch } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */ 283d6f907dcSJoerg Wunsch int l = q - tmp; 284d6f907dcSJoerg Wunsch 285d6f907dcSJoerg Wunsch strncpy(timestr, q + 1, sizeof timestr); 286d6f907dcSJoerg Wunsch timestr[sizeof timestr - 1] = '\0'; 287d6f907dcSJoerg Wunsch strncpy(datestr, tmp, l); 288d6f907dcSJoerg Wunsch datestr[l] = '\0'; 289d6f907dcSJoerg Wunsch } else /* Bail out */ 290d6f907dcSJoerg Wunsch return dt; 291d6f907dcSJoerg Wunsch parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 292d6f907dcSJoerg Wunsch parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 293d6f907dcSJoerg Wunsch } 294d6f907dcSJoerg Wunsch dt = mktime(T); 295d6f907dcSJoerg Wunsch } 296d6f907dcSJoerg Wunsch return dt; 297d6f907dcSJoerg Wunsch } 298