diff options
Diffstat (limited to 'usr.sbin/pw/psdate.c')
| -rw-r--r-- | usr.sbin/pw/psdate.c | 254 | 
1 files changed, 254 insertions, 0 deletions
| diff --git a/usr.sbin/pw/psdate.c b/usr.sbin/pw/psdate.c new file mode 100644 index 000000000000..7d37e6b4aa1b --- /dev/null +++ b/usr.sbin/pw/psdate.c @@ -0,0 +1,254 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 1996 + *	David L. Nugent.  All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <xlocale.h> + +#include "psdate.h" + + +int +numerics(char const * str) +{ + +	return (str[strspn(str, "0123456789x")] == '\0'); +} + +static int +aindex(char const * arr[], char const ** str, int len) +{ +	int             l, i; +	char            mystr[32]; + +	mystr[len] = '\0'; +	l = strlen(strncpy(mystr, *str, len)); +	for (i = 0; i < l; i++) +		mystr[i] = (char) tolower((unsigned char)mystr[i]); +	for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++); +	if (arr[i] == NULL) +		i = -1; +	else {			/* Skip past it */ +		while (**str && isalpha((unsigned char)**str)) +			++(*str); +		/* And any following whitespace */ +		while (**str && (**str == ',' || isspace((unsigned char)**str))) +			++(*str); +	}			/* Return index */ +	return i; +} + +static int +weekday(char const ** str) +{ +	static char const *days[] = +	{"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL}; + +	return aindex(days, str, 3); +} + +static void +parse_datesub(char const * str, struct tm *t) +{ +	struct tm	 tm; +	locale_t	 l; +	int		 i; +	char		*ret; +	const char	*valid_formats[] = { +		"%d-%b-%y", +		"%d-%b-%Y", +		"%d-%m-%y", +		"%d-%m-%Y", +		"%H:%M %d-%b-%y", +		"%H:%M %d-%b-%Y", +		"%H:%M %d-%m-%y", +		"%H:%M %d-%m-%Y", +		"%H:%M:%S %d-%b-%y", +		"%H:%M:%S %d-%b-%Y", +		"%H:%M:%S %d-%m-%y", +		"%H:%M:%S %d-%m-%Y", +		"%d-%b-%y %H:%M", +		"%d-%b-%Y %H:%M", +		"%d-%m-%y %H:%M", +		"%d-%m-%Y %H:%M", +		"%d-%b-%y %H:%M:%S", +		"%d-%b-%Y %H:%M:%S", +		"%d-%m-%y %H:%M:%S", +		"%d-%m-%Y %H:%M:%S", +		"%H:%M\t%d-%b-%y", +		"%H:%M\t%d-%b-%Y", +		"%H:%M\t%d-%m-%y", +		"%H:%M\t%d-%m-%Y", +		"%H:%M\t%S %d-%b-%y", +		"%H:%M\t%S %d-%b-%Y", +		"%H:%M\t%S %d-%m-%y", +		"%H:%M\t%S %d-%m-%Y", +		"%d-%b-%y\t%H:%M", +		"%d-%b-%Y\t%H:%M", +		"%d-%m-%y\t%H:%M", +		"%d-%m-%Y\t%H:%M", +		"%d-%b-%y\t%H:%M:%S", +		"%d-%b-%Y\t%H:%M:%S", +		"%d-%m-%y\t%H:%M:%S", +		"%d-%m-%Y\t%H:%M:%S", +		NULL, +	}; + +	l = newlocale(LC_ALL_MASK, "C", NULL); + +	for (i=0; valid_formats[i] != NULL; i++) { +		memset(&tm, 0, sizeof(tm)); +		ret = strptime_l(str, valid_formats[i], &tm, l); +		if (ret && *ret == '\0') { +			t->tm_mday = tm.tm_mday; +			t->tm_mon = tm.tm_mon; +			t->tm_year = tm.tm_year; +			t->tm_hour = tm.tm_hour; +			t->tm_min = tm.tm_min; +			t->tm_sec = tm.tm_sec; +			freelocale(l); +			return; +		} +	} + +	freelocale(l); + +	errx(EXIT_FAILURE, "Invalid date"); +} + + +/*- + * Parse time must be flexible, it handles the following formats: + * nnnnnnnnnnn		UNIX timestamp (all numeric), 0 = now + * 0xnnnnnnnn		UNIX timestamp in hexadecimal + * 0nnnnnnnnn		UNIX timestamp in octal + * 0			Given time + * +nnnn[smhdwoy]	Given time + nnnn hours, mins, days, weeks, months or years + * -nnnn[smhdwoy]	Given time - nnnn hours, mins, days, weeks, months or years + * dd[ ./-]mmm[ ./-]yy	Date } + * hh:mm:ss		Time } May be combined + */ + +time_t +parse_date(time_t dt, char const * str) +{ +	char           *p; +	int             i; +	long            val; +	struct tm      *T; + +	if (dt == 0) +		dt = time(NULL); + +	while (*str && isspace((unsigned char)*str)) +		++str; + +	if (numerics(str)) { +		dt = strtol(str, &p, 0); +	} else if (*str == '+' || *str == '-') { +		val = strtol(str, &p, 0); +		switch (*p) { +		case 'h': +		case 'H':	/* hours */ +			dt += (val * 3600L); +			break; +		case '\0': +		case 'm': +		case 'M':	/* minutes */ +			dt += (val * 60L); +			break; +		case 's': +		case 'S':	/* seconds */ +			dt += val; +			break; +		case 'd': +		case 'D':	/* days */ +			dt += (val * 86400L); +			break; +		case 'w': +		case 'W':	/* weeks */ +			dt += (val * 604800L); +			break; +		case 'o': +		case 'O':	/* months */ +			T = localtime(&dt); +			T->tm_mon += (int) val; +			i = T->tm_mday; +			goto fixday; +		case 'y': +		case 'Y':	/* years */ +			T = localtime(&dt); +			T->tm_year += (int) val; +			i = T->tm_mday; +	fixday: +			dt = mktime(T); +			T = localtime(&dt); +			if (T->tm_mday != i) { +				T->tm_mday = 1; +				dt = mktime(T); +				dt -= (time_t) 86400L; +			} +		default:	/* unknown */ +			break;	/* leave untouched */ +		} +	} else { +		char           *q, tmp[64]; + +		/* +		 * Skip past any weekday prefix +		 */ +		weekday(&str); +		strlcpy(tmp, str, sizeof(tmp)); +		str = tmp; +		T = localtime(&dt); + +		/* +		 * See if we can break off any timezone +		 */ +		while ((q = strrchr(tmp, ' ')) != NULL) { +			if (strchr("(+-", q[1]) != NULL) +				*q = '\0'; +			else { +				int             j = 1; + +				while (q[j] && isupper((unsigned char)q[j])) +					++j; +				if (q[j] == '\0') +					*q = '\0'; +				else +					break; +			} +		} + +		parse_datesub(tmp, T); +		dt = mktime(T); +	} +	return dt; +} | 
