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[] = 2950479Speter "$FreeBSD: stable/10/usr.sbin/pw/psdate.c 326849 2017-12-14 13:10:22Z eugen $"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 32287084Sbapt#include <ctype.h> 33287084Sbapt#include <err.h> 3420253Sjoerg#include <stdlib.h> 3520253Sjoerg#include <string.h> 36287084Sbapt#include <xlocale.h> 3720253Sjoerg 3820253Sjoerg#include "psdate.h" 3920253Sjoerg 4020253Sjoerg 41326849Seugenint 4220253Sjoergnumerics(char const * str) 4320253Sjoerg{ 4420253Sjoerg 45314277Sbapt return (str[strspn(str, "0123456789x")] == '\0'); 4620253Sjoerg} 4720253Sjoerg 4820253Sjoergstatic int 4920253Sjoergaindex(char const * arr[], char const ** str, int len) 5020253Sjoerg{ 5120253Sjoerg int l, i; 5220253Sjoerg char mystr[32]; 5320253Sjoerg 5420253Sjoerg mystr[len] = '\0'; 5520253Sjoerg l = strlen(strncpy(mystr, *str, len)); 5620253Sjoerg for (i = 0; i < l; i++) 5761957Sache mystr[i] = (char) tolower((unsigned char)mystr[i]); 5820253Sjoerg for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); 5920253Sjoerg if (arr[i] == NULL) 6020253Sjoerg i = -1; 6120253Sjoerg else { /* Skip past it */ 6261957Sache while (**str && isalpha((unsigned char)**str)) 6320253Sjoerg ++(*str); 6420253Sjoerg /* And any following whitespace */ 6561957Sache while (**str && (**str == ',' || isspace((unsigned char)**str))) 6620253Sjoerg ++(*str); 6720253Sjoerg } /* Return index */ 6820253Sjoerg return i; 6920253Sjoerg} 7020253Sjoerg 7120253Sjoergstatic int 7220253Sjoergweekday(char const ** str) 7320253Sjoerg{ 7420253Sjoerg static char const *days[] = 7520253Sjoerg {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; 7620253Sjoerg 7720253Sjoerg return aindex(days, str, 3); 7820253Sjoerg} 7920253Sjoerg 80287084Sbaptstatic void 81287084Sbaptparse_datesub(char const * str, struct tm *t) 8220253Sjoerg{ 83287084Sbapt struct tm tm; 84287084Sbapt locale_t l; 85287084Sbapt int i; 86287084Sbapt char *ret; 87287084Sbapt const char *valid_formats[] = { 88287084Sbapt "%d-%b-%y", 89287084Sbapt "%d-%b-%Y", 90287084Sbapt "%d-%m-%y", 91287084Sbapt "%d-%m-%Y", 92287084Sbapt "%H:%M %d-%b-%y", 93287084Sbapt "%H:%M %d-%b-%Y", 94287084Sbapt "%H:%M %d-%m-%y", 95287084Sbapt "%H:%M %d-%m-%Y", 96287084Sbapt "%H:%M:%S %d-%b-%y", 97287084Sbapt "%H:%M:%S %d-%b-%Y", 98287084Sbapt "%H:%M:%S %d-%m-%y", 99287084Sbapt "%H:%M:%S %d-%m-%Y", 100287084Sbapt "%d-%b-%y %H:%M", 101287084Sbapt "%d-%b-%Y %H:%M", 102287084Sbapt "%d-%m-%y %H:%M", 103287084Sbapt "%d-%m-%Y %H:%M", 104287084Sbapt "%d-%b-%y %H:%M:%S", 105287084Sbapt "%d-%b-%Y %H:%M:%S", 106287084Sbapt "%d-%m-%y %H:%M:%S", 107287084Sbapt "%d-%m-%Y %H:%M:%S", 108287084Sbapt "%H:%M\t%d-%b-%y", 109287084Sbapt "%H:%M\t%d-%b-%Y", 110287084Sbapt "%H:%M\t%d-%m-%y", 111287084Sbapt "%H:%M\t%d-%m-%Y", 112287084Sbapt "%H:%M\t%S %d-%b-%y", 113287084Sbapt "%H:%M\t%S %d-%b-%Y", 114287084Sbapt "%H:%M\t%S %d-%m-%y", 115287084Sbapt "%H:%M\t%S %d-%m-%Y", 116287084Sbapt "%d-%b-%y\t%H:%M", 117287084Sbapt "%d-%b-%Y\t%H:%M", 118287084Sbapt "%d-%m-%y\t%H:%M", 119287084Sbapt "%d-%m-%Y\t%H:%M", 120287084Sbapt "%d-%b-%y\t%H:%M:%S", 121287084Sbapt "%d-%b-%Y\t%H:%M:%S", 122287084Sbapt "%d-%m-%y\t%H:%M:%S", 123287084Sbapt "%d-%m-%Y\t%H:%M:%S", 124287084Sbapt NULL, 125287084Sbapt }; 12620253Sjoerg 127287084Sbapt l = newlocale(LC_ALL_MASK, "C", NULL); 12820253Sjoerg 129287084Sbapt memset(&tm, 0, sizeof(tm)); 130287084Sbapt for (i=0; valid_formats[i] != NULL; i++) { 131287084Sbapt ret = strptime_l(str, valid_formats[i], &tm, l); 132287084Sbapt if (ret && *ret == '\0') { 133287084Sbapt t->tm_mday = tm.tm_mday; 134287084Sbapt t->tm_mon = tm.tm_mon; 135287084Sbapt t->tm_year = tm.tm_year; 136287084Sbapt t->tm_hour = tm.tm_hour; 137287084Sbapt t->tm_min = tm.tm_min; 138287084Sbapt t->tm_sec = tm.tm_sec; 139287084Sbapt freelocale(l); 140287084Sbapt return; 141287084Sbapt } 14220253Sjoerg } 14320253Sjoerg 144287084Sbapt freelocale(l); 14520253Sjoerg 146287084Sbapt errx(EXIT_FAILURE, "Invalid date"); 14720253Sjoerg} 14820253Sjoerg 14920253Sjoerg 15020253Sjoerg/*- 15120253Sjoerg * Parse time must be flexible, it handles the following formats: 15220253Sjoerg * nnnnnnnnnnn UNIX timestamp (all numeric), 0 = now 15320253Sjoerg * 0xnnnnnnnn UNIX timestamp in hexadecimal 15420253Sjoerg * 0nnnnnnnnn UNIX timestamp in octal 15520253Sjoerg * 0 Given time 15620253Sjoerg * +nnnn[smhdwoy] Given time + nnnn hours, mins, days, weeks, months or years 15720253Sjoerg * -nnnn[smhdwoy] Given time - nnnn hours, mins, days, weeks, months or years 15820253Sjoerg * dd[ ./-]mmm[ ./-]yy Date } 15920253Sjoerg * hh:mm:ss Time } May be combined 16020253Sjoerg */ 16120253Sjoerg 16220253Sjoergtime_t 16320253Sjoergparse_date(time_t dt, char const * str) 16420253Sjoerg{ 16520253Sjoerg char *p; 16620253Sjoerg int i; 16720253Sjoerg long val; 16820253Sjoerg struct tm *T; 16920253Sjoerg 17020253Sjoerg if (dt == 0) 17120253Sjoerg dt = time(NULL); 17220253Sjoerg 17361957Sache while (*str && isspace((unsigned char)*str)) 17420253Sjoerg ++str; 17520253Sjoerg 17620253Sjoerg if (numerics(str)) { 17744775Sdavidn dt = strtol(str, &p, 0); 17820253Sjoerg } else if (*str == '+' || *str == '-') { 17920253Sjoerg val = strtol(str, &p, 0); 18020253Sjoerg switch (*p) { 18120253Sjoerg case 'h': 18220253Sjoerg case 'H': /* hours */ 18320253Sjoerg dt += (val * 3600L); 18420253Sjoerg break; 18520253Sjoerg case '\0': 18620253Sjoerg case 'm': 18720253Sjoerg case 'M': /* minutes */ 18820253Sjoerg dt += (val * 60L); 18920253Sjoerg break; 19020253Sjoerg case 's': 19120253Sjoerg case 'S': /* seconds */ 19220253Sjoerg dt += val; 19320253Sjoerg break; 19420253Sjoerg case 'd': 19520253Sjoerg case 'D': /* days */ 19620253Sjoerg dt += (val * 86400L); 19720253Sjoerg break; 19820253Sjoerg case 'w': 19920253Sjoerg case 'W': /* weeks */ 20020253Sjoerg dt += (val * 604800L); 20120253Sjoerg break; 20220253Sjoerg case 'o': 20320253Sjoerg case 'O': /* months */ 20420253Sjoerg T = localtime(&dt); 20520253Sjoerg T->tm_mon += (int) val; 20620253Sjoerg i = T->tm_mday; 20720253Sjoerg goto fixday; 20820253Sjoerg case 'y': 20920253Sjoerg case 'Y': /* years */ 21020253Sjoerg T = localtime(&dt); 21120253Sjoerg T->tm_year += (int) val; 21220253Sjoerg i = T->tm_mday; 21320253Sjoerg fixday: 21420253Sjoerg dt = mktime(T); 21520253Sjoerg T = localtime(&dt); 21620253Sjoerg if (T->tm_mday != i) { 21720253Sjoerg T->tm_mday = 1; 21820253Sjoerg dt = mktime(T); 21920253Sjoerg dt -= (time_t) 86400L; 22020253Sjoerg } 22120253Sjoerg default: /* unknown */ 22220253Sjoerg break; /* leave untouched */ 22320253Sjoerg } 22420253Sjoerg } else { 22520253Sjoerg char *q, tmp[64]; 22620253Sjoerg 22720253Sjoerg /* 22820253Sjoerg * Skip past any weekday prefix 22920253Sjoerg */ 23020253Sjoerg weekday(&str); 231130633Srobert strlcpy(tmp, str, sizeof(tmp)); 232130633Srobert str = tmp; 23320253Sjoerg T = localtime(&dt); 23420253Sjoerg 23520253Sjoerg /* 23620253Sjoerg * See if we can break off any timezone 23720253Sjoerg */ 23820253Sjoerg while ((q = strrchr(tmp, ' ')) != NULL) { 23920253Sjoerg if (strchr("(+-", q[1]) != NULL) 24020253Sjoerg *q = '\0'; 24120253Sjoerg else { 24220253Sjoerg int j = 1; 24320253Sjoerg 24461957Sache while (q[j] && isupper((unsigned char)q[j])) 24520253Sjoerg ++j; 24620253Sjoerg if (q[j] == '\0') 24720253Sjoerg *q = '\0'; 24820253Sjoerg else 24920253Sjoerg break; 25020253Sjoerg } 25120253Sjoerg } 25220253Sjoerg 253287084Sbapt parse_datesub(tmp, T); 25420253Sjoerg dt = mktime(T); 25520253Sjoerg } 25620253Sjoerg return dt; 25720253Sjoerg} 258