psdate.c revision 30259
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 */ 2620253Sjoerg 2730259Scharnier#ifndef lint 2830259Scharnierstatic const char rcsid[] = 2930259Scharnier "$Id$"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 3220253Sjoerg#include <stdio.h> 3320253Sjoerg#include <stdlib.h> 3420253Sjoerg#include <string.h> 3520253Sjoerg#include <ctype.h> 3620253Sjoerg 3720253Sjoerg#include "psdate.h" 3820253Sjoerg 3920253Sjoerg 4020253Sjoergstatic int 4120253Sjoerga2i(char const ** str) 4220253Sjoerg{ 4320253Sjoerg int i = 0; 4420253Sjoerg char const *s = *str; 4520253Sjoerg 4620253Sjoerg if (isdigit(*s)) { 4720253Sjoerg i = atoi(s); 4820253Sjoerg while (isdigit(*s)) 4920253Sjoerg ++s; 5020253Sjoerg *str = s; 5120253Sjoerg } 5220253Sjoerg return i; 5320253Sjoerg} 5420253Sjoerg 5520253Sjoergstatic int 5620253Sjoergnumerics(char const * str) 5720253Sjoerg{ 5820253Sjoerg int rc = isdigit(*str); 5920253Sjoerg 6020253Sjoerg if (rc) 6120253Sjoerg while (isdigit(*str) || *str == 'x') 6220253Sjoerg ++str; 6320253Sjoerg return rc && !*str; 6420253Sjoerg} 6520253Sjoerg 6620253Sjoergstatic int 6720253Sjoergaindex(char const * arr[], char const ** str, int len) 6820253Sjoerg{ 6920253Sjoerg int l, i; 7020253Sjoerg char mystr[32]; 7120253Sjoerg 7220253Sjoerg mystr[len] = '\0'; 7320253Sjoerg l = strlen(strncpy(mystr, *str, len)); 7420253Sjoerg for (i = 0; i < l; i++) 7520253Sjoerg mystr[i] = (char) tolower(mystr[i]); 7620253Sjoerg for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); 7720253Sjoerg if (arr[i] == NULL) 7820253Sjoerg i = -1; 7920253Sjoerg else { /* Skip past it */ 8020253Sjoerg while (**str && isalpha(**str)) 8120253Sjoerg ++(*str); 8220253Sjoerg /* And any following whitespace */ 8320253Sjoerg while (**str && (**str == ',' || isspace(**str))) 8420253Sjoerg ++(*str); 8520253Sjoerg } /* Return index */ 8620253Sjoerg return i; 8720253Sjoerg} 8820253Sjoerg 8920253Sjoergstatic int 9020253Sjoergweekday(char const ** str) 9120253Sjoerg{ 9220253Sjoerg static char const *days[] = 9320253Sjoerg {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; 9420253Sjoerg 9520253Sjoerg return aindex(days, str, 3); 9620253Sjoerg} 9720253Sjoerg 9820253Sjoergstatic int 9920253Sjoergmonth(char const ** str) 10020253Sjoerg{ 10120253Sjoerg static char const *months[] = 10220253Sjoerg {"jan", "feb", "mar", "apr", "may", "jun", "jul", 10320253Sjoerg "aug", "sep", "oct", "nov", "dec", NULL}; 10420253Sjoerg 10520253Sjoerg return aindex(months, str, 3); 10620253Sjoerg} 10720253Sjoerg 10820253Sjoergstatic void 10920253Sjoergparse_time(char const * str, int *hour, int *min, int *sec) 11020253Sjoerg{ 11120253Sjoerg *hour = a2i(&str); 11220253Sjoerg if ((str = strchr(str, ':')) == NULL) 11320253Sjoerg *min = *sec = 0; 11420253Sjoerg else { 11520253Sjoerg ++str; 11620253Sjoerg *min = a2i(&str); 11720253Sjoerg *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str); 11820253Sjoerg } 11920253Sjoerg} 12020253Sjoerg 12120253Sjoerg 12220253Sjoergstatic void 12320253Sjoergparse_datesub(char const * str, int *day, int *mon, int *year) 12420253Sjoerg{ 12520253Sjoerg int i; 12620253Sjoerg 12720253Sjoerg static char const nchrs[] = "0123456789 \t,/-."; 12820253Sjoerg 12920253Sjoerg if ((i = month(&str)) != -1) { 13020253Sjoerg *mon = i; 13120253Sjoerg if ((i = a2i(&str)) != 0) 13220253Sjoerg *day = i; 13320253Sjoerg } else if ((i = a2i(&str)) != 0) { 13420253Sjoerg *day = i; 13520253Sjoerg while (*str && strchr(nchrs + 10, *str) != NULL) 13620253Sjoerg ++str; 13720253Sjoerg if ((i = month(&str)) != -1) 13820253Sjoerg *mon = i; 13920253Sjoerg else if ((i = a2i(&str)) != 0) 14020253Sjoerg *mon = i - 1; 14120253Sjoerg } else 14220253Sjoerg return; 14320253Sjoerg 14420253Sjoerg while (*str && strchr(nchrs + 10, *str) != NULL) 14520253Sjoerg ++str; 14620253Sjoerg if (isdigit(*str)) { 14720253Sjoerg *year = atoi(str); 14820253Sjoerg if (*year > 1900) 14920253Sjoerg *year -= 1900; 15020253Sjoerg else if (*year < 32) 15120253Sjoerg *year += 100; 15220253Sjoerg } 15320253Sjoerg} 15420253Sjoerg 15520253Sjoerg 15620253Sjoerg/*- 15720253Sjoerg * Parse time must be flexible, it handles the following formats: 15820253Sjoerg * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now 15920253Sjoerg * 0xnnnnnnnn UNIX timestamp in hexadecimal 16020253Sjoerg * 0nnnnnnnnn UNIX timestamp in octal 16120253Sjoerg * 0 Given time 16220253Sjoerg * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years 16320253Sjoerg * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years 16420253Sjoerg * dd[ ./-]mmm[ ./-]yy Date } 16520253Sjoerg * hh:mm:ss Time } May be combined 16620253Sjoerg */ 16720253Sjoerg 16820253Sjoergtime_t 16920253Sjoergparse_date(time_t dt, char const * str) 17020253Sjoerg{ 17120253Sjoerg char *p; 17220253Sjoerg int i; 17320253Sjoerg long val; 17420253Sjoerg struct tm *T; 17520253Sjoerg 17620253Sjoerg if (dt == 0) 17720253Sjoerg dt = time(NULL); 17820253Sjoerg 17920253Sjoerg while (*str && isspace(*str)) 18020253Sjoerg ++str; 18120253Sjoerg 18220253Sjoerg if (numerics(str)) { 18320253Sjoerg val = strtol(str, &p, 0); 18420253Sjoerg dt = val ? val : dt; 18520253Sjoerg } else if (*str == '+' || *str == '-') { 18620253Sjoerg val = strtol(str, &p, 0); 18720253Sjoerg switch (*p) { 18820253Sjoerg case 'h': 18920253Sjoerg case 'H': /* hours */ 19020253Sjoerg dt += (val * 3600L); 19120253Sjoerg break; 19220253Sjoerg case '\0': 19320253Sjoerg case 'm': 19420253Sjoerg case 'M': /* minutes */ 19520253Sjoerg dt += (val * 60L); 19620253Sjoerg break; 19720253Sjoerg case 's': 19820253Sjoerg case 'S': /* seconds */ 19920253Sjoerg dt += val; 20020253Sjoerg break; 20120253Sjoerg case 'd': 20220253Sjoerg case 'D': /* days */ 20320253Sjoerg dt += (val * 86400L); 20420253Sjoerg break; 20520253Sjoerg case 'w': 20620253Sjoerg case 'W': /* weeks */ 20720253Sjoerg dt += (val * 604800L); 20820253Sjoerg break; 20920253Sjoerg case 'o': 21020253Sjoerg case 'O': /* months */ 21120253Sjoerg T = localtime(&dt); 21220253Sjoerg T->tm_mon += (int) val; 21320253Sjoerg i = T->tm_mday; 21420253Sjoerg goto fixday; 21520253Sjoerg case 'y': 21620253Sjoerg case 'Y': /* years */ 21720253Sjoerg T = localtime(&dt); 21820253Sjoerg T->tm_year += (int) val; 21920253Sjoerg i = T->tm_mday; 22020253Sjoerg fixday: 22120253Sjoerg dt = mktime(T); 22220253Sjoerg T = localtime(&dt); 22320253Sjoerg if (T->tm_mday != i) { 22420253Sjoerg T->tm_mday = 1; 22520253Sjoerg dt = mktime(T); 22620253Sjoerg dt -= (time_t) 86400L; 22720253Sjoerg } 22820253Sjoerg default: /* unknown */ 22920253Sjoerg break; /* leave untouched */ 23020253Sjoerg } 23120253Sjoerg } else { 23220253Sjoerg char *q, tmp[64]; 23320253Sjoerg 23420253Sjoerg /* 23520253Sjoerg * Skip past any weekday prefix 23620253Sjoerg */ 23720253Sjoerg weekday(&str); 23820253Sjoerg str = strncpy(tmp, str, sizeof tmp - 1); 23920253Sjoerg tmp[sizeof tmp - 1] = '\0'; 24020253Sjoerg T = localtime(&dt); 24120253Sjoerg 24220253Sjoerg /* 24320253Sjoerg * See if we can break off any timezone 24420253Sjoerg */ 24520253Sjoerg while ((q = strrchr(tmp, ' ')) != NULL) { 24620253Sjoerg if (strchr("(+-", q[1]) != NULL) 24720253Sjoerg *q = '\0'; 24820253Sjoerg else { 24920253Sjoerg int j = 1; 25020253Sjoerg 25120253Sjoerg while (q[j] && isupper(q[j])) 25220253Sjoerg ++j; 25320253Sjoerg if (q[j] == '\0') 25420253Sjoerg *q = '\0'; 25520253Sjoerg else 25620253Sjoerg break; 25720253Sjoerg } 25820253Sjoerg } 25920253Sjoerg 26020253Sjoerg /* 26120253Sjoerg * See if there is a time hh:mm[:ss] 26220253Sjoerg */ 26320253Sjoerg if ((p = strchr(tmp, ':')) == NULL) { 26420253Sjoerg 26520253Sjoerg /* 26620253Sjoerg * No time string involved 26720253Sjoerg */ 26820253Sjoerg T->tm_hour = T->tm_min = T->tm_sec = 0; 26920253Sjoerg parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year); 27020253Sjoerg } else { 27120253Sjoerg char datestr[64], timestr[64]; 27220253Sjoerg 27320253Sjoerg /* 27420253Sjoerg * Let's chip off the time string 27520253Sjoerg */ 27620253Sjoerg if ((q = strpbrk(p, " \t")) != NULL) { /* Time first? */ 27720253Sjoerg int l = q - str; 27820253Sjoerg 27920253Sjoerg strncpy(timestr, str, l); 28020253Sjoerg timestr[l] = '\0'; 28120253Sjoerg strncpy(datestr, q + 1, sizeof datestr); 28220253Sjoerg datestr[sizeof datestr - 1] = '\0'; 28320253Sjoerg parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 28420253Sjoerg parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 28520253Sjoerg } else if ((q = strrchr(tmp, ' ')) != NULL) { /* Time last */ 28620253Sjoerg int l = q - tmp; 28720253Sjoerg 28820253Sjoerg strncpy(timestr, q + 1, sizeof timestr); 28920253Sjoerg timestr[sizeof timestr - 1] = '\0'; 29020253Sjoerg strncpy(datestr, tmp, l); 29120253Sjoerg datestr[l] = '\0'; 29220253Sjoerg } else /* Bail out */ 29320253Sjoerg return dt; 29420253Sjoerg parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec); 29520253Sjoerg parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year); 29620253Sjoerg } 29720253Sjoerg dt = mktime(T); 29820253Sjoerg } 29920253Sjoerg return dt; 30020253Sjoerg} 301