psdate.c revision 20302
120253Sjoerg/*- 220302Sjoerg * Copyright (C) 1996 320302Sjoerg * David L. Nugent. All rights reserved. 420253Sjoerg * 520253Sjoerg * Redistribution and use in source and binary forms, with or without 620253Sjoerg * modification, are permitted provided that the following conditions 720253Sjoerg * are met: 820253Sjoerg * 1. Redistributions of source code must retain the above copyright 920302Sjoerg * notice, this list of conditions and the following disclaimer. 1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1120253Sjoerg * notice, this list of conditions and the following disclaimer in the 1220253Sjoerg * documentation and/or other materials provided with the distribution. 1320253Sjoerg * 1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1720302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2420253Sjoerg * SUCH DAMAGE. 2520253Sjoerg * 2620302Sjoerg * $Id: psdate.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $ 2720253Sjoerg */ 2820253Sjoerg 2920253Sjoerg#include <stdio.h> 3020253Sjoerg#include <stdlib.h> 3120253Sjoerg#include <string.h> 3220253Sjoerg#include <ctype.h> 3320253Sjoerg 3420253Sjoerg#include "psdate.h" 3520253Sjoerg 3620253Sjoerg 3720253Sjoergstatic int 3820253Sjoerga2i(char const ** str) 3920253Sjoerg{ 4020253Sjoerg int i = 0; 4120253Sjoerg char const *s = *str; 4220253Sjoerg 4320253Sjoerg if (isdigit(*s)) { 4420253Sjoerg i = atoi(s); 4520253Sjoerg while (isdigit(*s)) 4620253Sjoerg ++s; 4720253Sjoerg *str = s; 4820253Sjoerg } 4920253Sjoerg return i; 5020253Sjoerg} 5120253Sjoerg 5220253Sjoergstatic int 5320253Sjoergnumerics(char const * str) 5420253Sjoerg{ 5520253Sjoerg int rc = isdigit(*str); 5620253Sjoerg 5720253Sjoerg if (rc) 5820253Sjoerg while (isdigit(*str) || *str == 'x') 5920253Sjoerg ++str; 6020253Sjoerg return rc && !*str; 6120253Sjoerg} 6220253Sjoerg 6320253Sjoergstatic int 6420253Sjoergaindex(char const * arr[], char const ** str, int len) 6520253Sjoerg{ 6620253Sjoerg int l, i; 6720253Sjoerg char mystr[32]; 6820253Sjoerg 6920253Sjoerg mystr[len] = '\0'; 7020253Sjoerg l = strlen(strncpy(mystr, *str, len)); 7120253Sjoerg for (i = 0; i < l; i++) 7220253Sjoerg mystr[i] = (char) tolower(mystr[i]); 7320253Sjoerg for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); 7420253Sjoerg if (arr[i] == NULL) 7520253Sjoerg i = -1; 7620253Sjoerg else { /* Skip past it */ 7720253Sjoerg while (**str && isalpha(**str)) 7820253Sjoerg ++(*str); 7920253Sjoerg /* And any following whitespace */ 8020253Sjoerg while (**str && (**str == ',' || isspace(**str))) 8120253Sjoerg ++(*str); 8220253Sjoerg } /* Return index */ 8320253Sjoerg return i; 8420253Sjoerg} 8520253Sjoerg 8620253Sjoergstatic int 8720253Sjoergweekday(char const ** str) 8820253Sjoerg{ 8920253Sjoerg static char const *days[] = 9020253Sjoerg {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; 9120253Sjoerg 9220253Sjoerg return aindex(days, str, 3); 9320253Sjoerg} 9420253Sjoerg 9520253Sjoergstatic int 9620253Sjoergmonth(char const ** str) 9720253Sjoerg{ 9820253Sjoerg static char const *months[] = 9920253Sjoerg {"jan", "feb", "mar", "apr", "may", "jun", "jul", 10020253Sjoerg "aug", "sep", "oct", "nov", "dec", NULL}; 10120253Sjoerg 10220253Sjoerg return aindex(months, str, 3); 10320253Sjoerg} 10420253Sjoerg 10520253Sjoergstatic void 10620253Sjoergparse_time(char const * str, int *hour, int *min, int *sec) 10720253Sjoerg{ 10820253Sjoerg *hour = a2i(&str); 10920253Sjoerg if ((str = strchr(str, ':')) == NULL) 11020253Sjoerg *min = *sec = 0; 11120253Sjoerg else { 11220253Sjoerg ++str; 11320253Sjoerg *min = a2i(&str); 11420253Sjoerg *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str); 11520253Sjoerg } 11620253Sjoerg} 11720253Sjoerg 11820253Sjoerg 11920253Sjoergstatic void 12020253Sjoergparse_datesub(char const * str, int *day, int *mon, int *year) 12120253Sjoerg{ 12220253Sjoerg int i; 12320253Sjoerg 12420253Sjoerg static char const nchrs[] = "0123456789 \t,/-."; 12520253Sjoerg 12620253Sjoerg if ((i = month(&str)) != -1) { 12720253Sjoerg *mon = i; 12820253Sjoerg if ((i = a2i(&str)) != 0) 12920253Sjoerg *day = i; 13020253Sjoerg } else if ((i = a2i(&str)) != 0) { 13120253Sjoerg *day = i; 13220253Sjoerg while (*str && strchr(nchrs + 10, *str) != NULL) 13320253Sjoerg ++str; 13420253Sjoerg if ((i = month(&str)) != -1) 13520253Sjoerg *mon = i; 13620253Sjoerg else if ((i = a2i(&str)) != 0) 13720253Sjoerg *mon = i - 1; 13820253Sjoerg } else 13920253Sjoerg return; 14020253Sjoerg 14120253Sjoerg while (*str && strchr(nchrs + 10, *str) != NULL) 14220253Sjoerg ++str; 14320253Sjoerg if (isdigit(*str)) { 14420253Sjoerg *year = atoi(str); 14520253Sjoerg if (*year > 1900) 14620253Sjoerg *year -= 1900; 14720253Sjoerg else if (*year < 32) 14820253Sjoerg *year += 100; 14920253Sjoerg } 15020253Sjoerg} 15120253Sjoerg 15220253Sjoerg 15320253Sjoerg/*- 15420253Sjoerg * Parse time must be flexible, it handles the following formats: 15520253Sjoerg * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now 15620253Sjoerg * 0xnnnnnnnn UNIX timestamp in hexadecimal 15720253Sjoerg * 0nnnnnnnnn UNIX timestamp in octal 15820253Sjoerg * 0 Given time 15920253Sjoerg * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years 16020253Sjoerg * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years 16120253Sjoerg * dd[ ./-]mmm[ ./-]yy Date } 16220253Sjoerg * hh:mm:ss Time } May be combined 16320253Sjoerg */ 16420253Sjoerg 16520253Sjoergtime_t 16620253Sjoergparse_date(time_t dt, char const * str) 16720253Sjoerg{ 16820253Sjoerg char *p; 16920253Sjoerg int i; 17020253Sjoerg long val; 17120253Sjoerg struct tm *T; 17220253Sjoerg 17320253Sjoerg if (dt == 0) 17420253Sjoerg dt = time(NULL); 17520253Sjoerg 17620253Sjoerg while (*str && isspace(*str)) 17720253Sjoerg ++str; 17820253Sjoerg 17920253Sjoerg if (numerics(str)) { 18020253Sjoerg val = strtol(str, &p, 0); 18120253Sjoerg dt = val ? val : dt; 18220253Sjoerg } else if (*str == '+' || *str == '-') { 18320253Sjoerg val = strtol(str, &p, 0); 18420253Sjoerg switch (*p) { 18520253Sjoerg case 'h': 18620253Sjoerg case 'H': /* hours */ 18720253Sjoerg dt += (val * 3600L); 18820253Sjoerg break; 18920253Sjoerg case '\0': 19020253Sjoerg case 'm': 19120253Sjoerg case 'M': /* minutes */ 19220253Sjoerg dt += (val * 60L); 19320253Sjoerg break; 19420253Sjoerg case 's': 19520253Sjoerg case 'S': /* seconds */ 19620253Sjoerg dt += val; 19720253Sjoerg break; 19820253Sjoerg case 'd': 19920253Sjoerg case 'D': /* days */ 20020253Sjoerg dt += (val * 86400L); 20120253Sjoerg break; 20220253Sjoerg case 'w': 20320253Sjoerg case 'W': /* weeks */ 20420253Sjoerg dt += (val * 604800L); 20520253Sjoerg break; 20620253Sjoerg case 'o': 20720253Sjoerg case 'O': /* months */ 20820253Sjoerg T = localtime(&dt); 20920253Sjoerg T->tm_mon += (int) val; 21020253Sjoerg i = T->tm_mday; 21120253Sjoerg goto fixday; 21220253Sjoerg case 'y': 21320253Sjoerg case 'Y': /* years */ 21420253Sjoerg T = localtime(&dt); 21520253Sjoerg T->tm_year += (int) val; 21620253Sjoerg i = T->tm_mday; 21720253Sjoerg fixday: 21820253Sjoerg dt = mktime(T); 21920253Sjoerg T = localtime(&dt); 22020253Sjoerg if (T->tm_mday != i) { 22120253Sjoerg T->tm_mday = 1; 22220253Sjoerg dt = mktime(T); 22320253Sjoerg dt -= (time_t) 86400L; 22420253Sjoerg } 22520253Sjoerg default: /* unknown */ 22620253Sjoerg break; /* leave untouched */ 22720253Sjoerg } 22820253Sjoerg } else { 22920253Sjoerg char *q, tmp[64]; 23020253Sjoerg 23120253Sjoerg /* 23220253Sjoerg * Skip past any weekday prefix 23320253Sjoerg */ 23420253Sjoerg weekday(&str); 23520253Sjoerg str = strncpy(tmp, str, sizeof tmp - 1); 23620253Sjoerg tmp[sizeof tmp - 1] = '\0'; 23720253Sjoerg T = localtime(&dt); 23820253Sjoerg 23920253Sjoerg /* 24020253Sjoerg * See if we can break off any timezone 24120253Sjoerg */ 24220253Sjoerg while ((q = strrchr(tmp, ' ')) != NULL) { 24320253Sjoerg if (strchr("(+-", q[1]) != NULL) 24420253Sjoerg *q = '\0'; 24520253Sjoerg else { 24620253Sjoerg int j = 1; 24720253Sjoerg 24820253Sjoerg while (q[j] && isupper(q[j])) 24920253Sjoerg ++j; 25020253Sjoerg if (q[j] == '\0') 25120253Sjoerg *q = '\0'; 25220253Sjoerg else 25320253Sjoerg break; 25420253Sjoerg } 25520253Sjoerg } 25620253Sjoerg 25720253Sjoerg /* 25820253Sjoerg * See if there is a time hh:mm[:ss] 25920253Sjoerg */ 26020253Sjoerg if ((p = strchr(tmp, ':')) == NULL) { 26120253Sjoerg 26220253Sjoerg /* 26320253Sjoerg * No time string involved 26420253Sjoerg */ 26520253Sjoerg T->tm_hour = T->tm_min = T->tm_sec = 0; 26620253Sjoerg parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year); 26720253Sjoerg } else { 26820253Sjoerg char datestr[64], timestr[64]; 26920253Sjoerg 27020253Sjoerg /* 27120253Sjoerg * Let's chip off the time string 27220253Sjoerg */ 27320253Sjoerg if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */ 27420253Sjoerg int l = q - str; 27520253Sjoerg 27620253Sjoerg strncpy(timestr, str, l); 27720253Sjoerg timestr[l] = '\0'; 27820253Sjoerg strncpy(datestr, q + 1, sizeof datestr); 27920253Sjoerg datestr[sizeof datestr - 1] = '\0'; 28020253Sjoerg parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 28120253Sjoerg parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 28220253Sjoerg } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */ 28320253Sjoerg int l = q - tmp; 28420253Sjoerg 28520253Sjoerg strncpy(timestr, q + 1, sizeof timestr); 28620253Sjoerg timestr[sizeof timestr - 1] = '\0'; 28720253Sjoerg strncpy(datestr, tmp, l); 28820253Sjoerg datestr[l] = '\0'; 28920253Sjoerg } else /* Bail out */ 29020253Sjoerg return dt; 29120253Sjoerg parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 29220253Sjoerg parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 29320253Sjoerg } 29420253Sjoerg dt = mktime(T); 29520253Sjoerg } 29620253Sjoerg return dt; 29720253Sjoerg} 298