|
Packit |
6c4009 |
/* Convert a string representation of time to a time value.
|
|
Packit |
6c4009 |
Copyright (C) 1997-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library; if not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <limits.h>
|
|
Packit |
6c4009 |
#include <stdio.h>
|
|
Packit |
6c4009 |
#include <stdio_ext.h>
|
|
Packit |
6c4009 |
#include <stdlib.h>
|
|
Packit |
6c4009 |
#include <stdbool.h>
|
|
Packit |
6c4009 |
#include <string.h>
|
|
Packit |
6c4009 |
#include <time.h>
|
|
Packit |
6c4009 |
#include <unistd.h>
|
|
Packit |
6c4009 |
#include <sys/stat.h>
|
|
Packit |
6c4009 |
#include <ctype.h>
|
|
Packit |
6c4009 |
#include <alloca.h>
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define TM_YEAR_BASE 1900
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Prototypes for local functions. */
|
|
Packit |
6c4009 |
static int first_wday (int year, int mon, int wday);
|
|
Packit |
6c4009 |
static int check_mday (int year, int mon, int mday);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Set to one of the following values to indicate an error.
|
|
Packit |
6c4009 |
1 the DATEMSK environment variable is null or undefined,
|
|
Packit |
6c4009 |
2 the template file cannot be opened for reading,
|
|
Packit |
6c4009 |
3 failed to get file status information,
|
|
Packit |
6c4009 |
4 the template file is not a regular file,
|
|
Packit |
6c4009 |
5 an error is encountered while reading the template file,
|
|
Packit |
6c4009 |
6 memory allication failed (not enough memory available),
|
|
Packit |
6c4009 |
7 there is no line in the template that matches the input,
|
|
Packit |
6c4009 |
8 invalid input specification Example: February 31 or a time is
|
|
Packit |
6c4009 |
specified that can not be represented in a time_t (representing
|
|
Packit |
6c4009 |
the time in seconds since 00:00:00 UTC, January 1, 1970) */
|
|
Packit |
6c4009 |
int getdate_err;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Returns the first weekday WDAY of month MON in the year YEAR. */
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
first_wday (int year, int mon, int wday)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct tm tm;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (wday == INT_MIN)
|
|
Packit |
6c4009 |
return 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
memset (&tm, 0, sizeof (struct tm));
|
|
Packit |
6c4009 |
tm.tm_year = year;
|
|
Packit |
6c4009 |
tm.tm_mon = mon;
|
|
Packit |
6c4009 |
tm.tm_mday = 1;
|
|
Packit |
6c4009 |
mktime (&tm;;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return (1 + (wday - tm.tm_wday + 7) % 7);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Returns 1 if MDAY is a valid day of the month in month MON of year
|
|
Packit |
6c4009 |
YEAR, and 0 if it is not. */
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
check_mday (int year, int mon, int mday)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
switch (mon)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
case 0:
|
|
Packit |
6c4009 |
case 2:
|
|
Packit |
6c4009 |
case 4:
|
|
Packit |
6c4009 |
case 6:
|
|
Packit |
6c4009 |
case 7:
|
|
Packit |
6c4009 |
case 9:
|
|
Packit |
6c4009 |
case 11:
|
|
Packit |
6c4009 |
if (mday >= 1 && mday <= 31)
|
|
Packit |
6c4009 |
return 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 3:
|
|
Packit |
6c4009 |
case 5:
|
|
Packit |
6c4009 |
case 8:
|
|
Packit |
6c4009 |
case 10:
|
|
Packit |
6c4009 |
if (mday >= 1 && mday <= 30)
|
|
Packit |
6c4009 |
return 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 1:
|
|
Packit |
6c4009 |
if (mday >= 1 && mday <= (__isleap (year) ? 29 : 28))
|
|
Packit |
6c4009 |
return 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return 0;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
int
|
|
Packit |
6c4009 |
__getdate_r (const char *string, struct tm *tp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
FILE *fp;
|
|
Packit |
6c4009 |
char *line;
|
|
Packit |
6c4009 |
size_t len;
|
|
Packit |
6c4009 |
char *datemsk;
|
|
Packit |
6c4009 |
char *result = NULL;
|
|
Packit |
6c4009 |
time_t timer;
|
|
Packit |
6c4009 |
struct tm tm;
|
|
Packit |
6c4009 |
struct stat64 st;
|
|
Packit |
6c4009 |
int mday_ok = 0;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
datemsk = getenv ("DATEMSK");
|
|
Packit |
6c4009 |
if (datemsk == NULL || *datemsk == '\0')
|
|
Packit |
6c4009 |
return 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (stat64 (datemsk, &st) < 0)
|
|
Packit |
6c4009 |
return 3;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (!S_ISREG (st.st_mode))
|
|
Packit |
6c4009 |
return 4;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (__access (datemsk, R_OK) < 0)
|
|
Packit |
6c4009 |
return 2;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Open the template file. */
|
|
Packit |
6c4009 |
fp = fopen (datemsk, "rce");
|
|
Packit |
6c4009 |
if (fp == NULL)
|
|
Packit |
6c4009 |
return 2;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* No threads reading this stream. */
|
|
Packit |
6c4009 |
__fsetlocking (fp, FSETLOCKING_BYCALLER);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Skip leading whitespace. */
|
|
Packit |
6c4009 |
while (isspace (*string))
|
|
Packit |
6c4009 |
string++;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
size_t inlen, oldlen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
oldlen = inlen = strlen (string);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Skip trailing whitespace. */
|
|
Packit |
6c4009 |
while (inlen > 0 && isspace (string[inlen - 1]))
|
|
Packit |
6c4009 |
inlen--;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
char *instr = NULL;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (inlen < oldlen)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
bool using_malloc = false;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (__libc_use_alloca (inlen + 1))
|
|
Packit |
6c4009 |
instr = alloca (inlen + 1);
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
instr = malloc (inlen + 1);
|
|
Packit |
6c4009 |
if (instr == NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
fclose (fp);
|
|
Packit |
6c4009 |
return 6;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
using_malloc = true;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
memcpy (instr, string, inlen);
|
|
Packit |
6c4009 |
instr[inlen] = '\0';
|
|
Packit |
6c4009 |
string = instr;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (!using_malloc)
|
|
Packit |
6c4009 |
instr = NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
line = NULL;
|
|
Packit |
6c4009 |
len = 0;
|
|
Packit |
6c4009 |
do
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
ssize_t n;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
n = __getline (&line, &len, fp);
|
|
Packit |
6c4009 |
if (n < 0)
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
if (line[n - 1] == '\n')
|
|
Packit |
6c4009 |
line[n - 1] = '\0';
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Do the conversion. */
|
|
Packit |
6c4009 |
tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN;
|
|
Packit |
6c4009 |
tp->tm_hour = tp->tm_sec = tp->tm_min = INT_MIN;
|
|
Packit |
6c4009 |
tp->tm_isdst = -1;
|
|
Packit |
6c4009 |
tp->tm_gmtoff = 0;
|
|
Packit |
6c4009 |
tp->tm_zone = NULL;
|
|
Packit |
6c4009 |
result = strptime (string, line, tp);
|
|
Packit |
6c4009 |
if (result && *result == '\0')
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
while (!__feof_unlocked (fp));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
free (instr);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Free the buffer. */
|
|
Packit |
6c4009 |
free (line);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Check for errors. */
|
|
Packit |
6c4009 |
if (__ferror_unlocked (fp))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
fclose (fp);
|
|
Packit |
6c4009 |
return 5;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Close template file. */
|
|
Packit |
6c4009 |
fclose (fp);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (result == NULL || *result != '\0')
|
|
Packit |
6c4009 |
return 7;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Get current time. */
|
|
Packit |
6c4009 |
time (&timer;;
|
|
Packit |
6c4009 |
__localtime_r (&timer, &tm;;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If only the weekday is given, today is assumed if the given day
|
|
Packit |
6c4009 |
is equal to the current day and next week if it is less. */
|
|
Packit |
6c4009 |
if (tp->tm_wday >= 0 && tp->tm_wday <= 6 && tp->tm_year == INT_MIN
|
|
Packit |
6c4009 |
&& tp->tm_mon == INT_MIN && tp->tm_mday == INT_MIN)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
tp->tm_year = tm.tm_year;
|
|
Packit |
6c4009 |
tp->tm_mon = tm.tm_mon;
|
|
Packit |
6c4009 |
tp->tm_mday = tm.tm_mday + (tp->tm_wday - tm.tm_wday + 7) % 7;
|
|
Packit |
6c4009 |
mday_ok = 1;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If only the month is given, the current month is assumed if the
|
|
Packit |
6c4009 |
given month is equal to the current month and next year if it is
|
|
Packit |
6c4009 |
less and no year is given (the first day of month is assumed if
|
|
Packit |
6c4009 |
no day is given. */
|
|
Packit |
6c4009 |
if (tp->tm_mon >= 0 && tp->tm_mon <= 11 && tp->tm_mday == INT_MIN)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (tp->tm_year == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_year = tm.tm_year + (((tp->tm_mon - tm.tm_mon) < 0) ? 1 : 0);
|
|
Packit |
6c4009 |
tp->tm_mday = first_wday (tp->tm_year, tp->tm_mon, tp->tm_wday);
|
|
Packit |
6c4009 |
mday_ok = 1;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If no hour, minute and second are given the current hour, minute
|
|
Packit |
6c4009 |
and second are assumed. */
|
|
Packit |
6c4009 |
if (tp->tm_hour == INT_MIN && tp->tm_min == INT_MIN && tp->tm_sec == INT_MIN)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
tp->tm_hour = tm.tm_hour;
|
|
Packit |
6c4009 |
tp->tm_min = tm.tm_min;
|
|
Packit |
6c4009 |
tp->tm_sec = tm.tm_sec;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Fill in the gaps. */
|
|
Packit |
6c4009 |
if (tp->tm_hour == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_hour = 0;
|
|
Packit |
6c4009 |
if (tp->tm_min == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_min = 0;
|
|
Packit |
6c4009 |
if (tp->tm_sec == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_sec = 0;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If no date is given, today is assumed if the given hour is
|
|
Packit |
6c4009 |
greater than the current hour and tomorrow is assumed if
|
|
Packit |
6c4009 |
it is less. */
|
|
Packit |
6c4009 |
if (tp->tm_hour >= 0 && tp->tm_hour <= 23
|
|
Packit |
6c4009 |
&& tp->tm_mon == INT_MIN
|
|
Packit |
6c4009 |
&& tp->tm_mday == INT_MIN && tp->tm_wday == INT_MIN)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
tp->tm_mon = tm.tm_mon;
|
|
Packit |
6c4009 |
tp->tm_mday = tm.tm_mday + ((tp->tm_hour - tm.tm_hour) < 0 ? 1 : 0);
|
|
Packit |
6c4009 |
mday_ok = 1;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* More fillers. */
|
|
Packit |
6c4009 |
if (tp->tm_year == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_year = tm.tm_year;
|
|
Packit |
6c4009 |
if (tp->tm_mon == INT_MIN)
|
|
Packit |
6c4009 |
tp->tm_mon = tm.tm_mon;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Check if the day of month is within range, and if the time can be
|
|
Packit |
6c4009 |
represented in a time_t. We make use of the fact that the mktime
|
|
Packit |
6c4009 |
call normalizes the struct tm. */
|
|
Packit |
6c4009 |
if ((!mday_ok && !check_mday (TM_YEAR_BASE + tp->tm_year, tp->tm_mon,
|
|
Packit |
6c4009 |
tp->tm_mday))
|
|
Packit |
6c4009 |
|| mktime (tp) == (time_t) -1)
|
|
Packit |
6c4009 |
return 8;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return 0;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
#ifdef weak_alias
|
|
Packit |
6c4009 |
weak_alias (__getdate_r, getdate_r)
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct tm *
|
|
Packit |
6c4009 |
getdate (const char *string)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Buffer returned by getdate. */
|
|
Packit |
6c4009 |
static struct tm tmbuf;
|
|
Packit |
6c4009 |
int errval = __getdate_r (string, &tmbuf);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (errval != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
getdate_err = errval;
|
|
Packit |
6c4009 |
return NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return &tmbuf;
|
|
Packit |
6c4009 |
}
|