Blame libarchive/archive_getdate.c

Packit Service 1d0348
/*
Packit Service 1d0348
 * This code is in the public domain and has no copyright.
Packit Service 1d0348
 *
Packit Service 1d0348
 * This is a plain C recursive-descent translation of an old
Packit Service 1d0348
 * public-domain YACC grammar that has been used for parsing dates in
Packit Service 1d0348
 * very many open-source projects.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Since the original authors were generous enough to donate their
Packit Service 1d0348
 * work to the public domain, I feel compelled to match their
Packit Service 1d0348
 * generosity.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Tim Kientzle, February 2009.
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Header comment from original getdate.y:
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
**  Originally written by Steven M. Bellovin <smb@research.att.com> while
Packit Service 1d0348
**  at the University of North Carolina at Chapel Hill.  Later tweaked by
Packit Service 1d0348
**  a couple of people on Usenet.  Completely overhauled by Rich $alz
Packit Service 1d0348
**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
Packit Service 1d0348
**
Packit Service 1d0348
**  This grammar has 10 shift/reduce conflicts.
Packit Service 1d0348
**
Packit Service 1d0348
**  This code is in the public domain and has no copyright.
Packit Service 1d0348
*/
Packit Service 1d0348
Packit Service 1d0348
#ifdef __FreeBSD__
Packit Service 1d0348
#include <sys/cdefs.h>
Packit Service 1d0348
__FBSDID("$FreeBSD$");
Packit Service 1d0348
#endif
Packit Service 1d0348
Packit Service 1d0348
#include <ctype.h>
Packit Service 1d0348
#include <stdio.h>
Packit Service 1d0348
#include <stdlib.h>
Packit Service 1d0348
#include <string.h>
Packit Service 1d0348
#include <time.h>
Packit Service 1d0348
Packit Service 1d0348
#define __LIBARCHIVE_BUILD 1
Packit Service 1d0348
#include "archive_getdate.h"
Packit Service 1d0348
Packit Service 1d0348
/* Basic time units. */
Packit Service 1d0348
#define	EPOCH		1970
Packit Service 1d0348
#define	MINUTE		(60L)
Packit Service 1d0348
#define	HOUR		(60L * MINUTE)
Packit Service 1d0348
#define	DAY		(24L * HOUR)
Packit Service 1d0348
Packit Service 1d0348
/* Daylight-savings mode:  on, off, or not yet known. */
Packit Service 1d0348
enum DSTMODE { DSTon, DSToff, DSTmaybe };
Packit Service 1d0348
/* Meridian:  am or pm. */
Packit Service 1d0348
enum { tAM, tPM };
Packit Service 1d0348
/* Token types returned by nexttoken() */
Packit Service 1d0348
enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,
Packit Service 1d0348
       tUNUMBER, tZONE, tDST };
Packit Service 1d0348
struct token { int token; time_t value; };
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Parser state.
Packit Service 1d0348
 */
Packit Service 1d0348
struct gdstate {
Packit Service 1d0348
	struct token *tokenp; /* Pointer to next token. */
Packit Service 1d0348
	/* HaveXxxx counts how many of this kind of phrase we've seen;
Packit Service 1d0348
	 * it's a fatal error to have more than one time, zone, day,
Packit Service 1d0348
	 * or date phrase. */
Packit Service 1d0348
	int	HaveYear;
Packit Service 1d0348
	int	HaveMonth;
Packit Service 1d0348
	int	HaveDay;
Packit Service 1d0348
	int	HaveWeekDay; /* Day of week */
Packit Service 1d0348
	int	HaveTime; /* Hour/minute/second */
Packit Service 1d0348
	int	HaveZone; /* timezone and/or DST info */
Packit Service 1d0348
	int	HaveRel; /* time offset; we can have more than one */
Packit Service 1d0348
	/* Absolute time values. */
Packit Service 1d0348
	time_t	Timezone;  /* Seconds offset from GMT */
Packit Service 1d0348
	time_t	Day;
Packit Service 1d0348
	time_t	Hour;
Packit Service 1d0348
	time_t	Minutes;
Packit Service 1d0348
	time_t	Month;
Packit Service 1d0348
	time_t	Seconds;
Packit Service 1d0348
	time_t	Year;
Packit Service 1d0348
	/* DST selection */
Packit Service 1d0348
	enum DSTMODE	DSTmode;
Packit Service 1d0348
	/* Day of week accounting, e.g., "3rd Tuesday" */
Packit Service 1d0348
	time_t	DayOrdinal; /* "3" in "3rd Tuesday" */
Packit Service 1d0348
	time_t	DayNumber; /* "Tuesday" in "3rd Tuesday" */
Packit Service 1d0348
	/* Relative time values: hour/day/week offsets are measured in
Packit Service 1d0348
	 * seconds, month/year are counted in months. */
Packit Service 1d0348
	time_t	RelMonth;
Packit Service 1d0348
	time_t	RelSeconds;
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * A series of functions that recognize certain common time phrases.
Packit Service 1d0348
 * Each function returns 1 if it managed to make sense of some of the
Packit Service 1d0348
 * tokens, zero otherwise.
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 *  hour:minute or hour:minute:second with optional AM, PM, or numeric
Packit Service 1d0348
 *  timezone offset
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
timephrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == ':'
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[3].token == ':'
Packit Service 1d0348
	    && gds->tokenp[4].token == tUNUMBER) {
Packit Service 1d0348
		/* "12:14:18" or "22:08:07" */
Packit Service 1d0348
		++gds->HaveTime;
Packit Service 1d0348
		gds->Hour = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Minutes = gds->tokenp[2].value;
Packit Service 1d0348
		gds->Seconds = gds->tokenp[4].value;
Packit Service 1d0348
		gds->tokenp += 5;
Packit Service 1d0348
	}
Packit Service 1d0348
	else if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == ':'
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER) {
Packit Service 1d0348
		/* "12:14" or "22:08" */
Packit Service 1d0348
		++gds->HaveTime;
Packit Service 1d0348
		gds->Hour = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Minutes = gds->tokenp[2].value;
Packit Service 1d0348
		gds->Seconds = 0;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
	}
Packit Service 1d0348
	else if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == tAMPM) {
Packit Service 1d0348
		/* "7" is a time if it's followed by "am" or "pm" */
Packit Service 1d0348
		++gds->HaveTime;
Packit Service 1d0348
		gds->Hour = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Minutes = gds->Seconds = 0;
Packit Service 1d0348
		/* We'll handle the AM/PM below. */
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
	} else {
Packit Service 1d0348
		/* We can't handle this. */
Packit Service 1d0348
		return 0;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tAMPM) {
Packit Service 1d0348
		/* "7:12pm", "12:20:13am" */
Packit Service 1d0348
		if (gds->Hour == 12)
Packit Service 1d0348
			gds->Hour = 0;
Packit Service 1d0348
		if (gds->tokenp[0].value == tPM)
Packit Service 1d0348
			gds->Hour += 12;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == '+'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER) {
Packit Service 1d0348
		/* "7:14+0700" */
Packit Service 1d0348
		gds->HaveZone++;
Packit Service 1d0348
		gds->DSTmode = DSToff;
Packit Service 1d0348
		gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR
Packit Service 1d0348
		    + (gds->tokenp[1].value % 100) * MINUTE);
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == '-'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER) {
Packit Service 1d0348
		/* "19:14:12-0530" */
Packit Service 1d0348
		gds->HaveZone++;
Packit Service 1d0348
		gds->DSTmode = DSToff;
Packit Service 1d0348
		gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR
Packit Service 1d0348
		    + (gds->tokenp[1].value % 100) * MINUTE);
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
	}
Packit Service 1d0348
	return 1;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Timezone name, possibly including DST.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
zonephrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (gds->tokenp[0].token == tZONE
Packit Service 1d0348
	    && gds->tokenp[1].token == tDST) {
Packit Service 1d0348
		gds->HaveZone++;
Packit Service 1d0348
		gds->Timezone = gds->tokenp[0].value;
Packit Service 1d0348
		gds->DSTmode = DSTon;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tZONE) {
Packit Service 1d0348
		gds->HaveZone++;
Packit Service 1d0348
		gds->Timezone = gds->tokenp[0].value;
Packit Service 1d0348
		gds->DSTmode = DSToff;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tDAYZONE) {
Packit Service 1d0348
		gds->HaveZone++;
Packit Service 1d0348
		gds->Timezone = gds->tokenp[0].value;
Packit Service 1d0348
		gds->DSTmode = DSTon;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	return 0;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Year/month/day in various combinations.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
datephrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == '/'
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[3].token == '/'
Packit Service 1d0348
	    && gds->tokenp[4].token == tUNUMBER) {
Packit Service 1d0348
		gds->HaveYear++;
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		if (gds->tokenp[0].value >= 13) {
Packit Service 1d0348
			/* First number is big:  2004/01/29, 99/02/17 */
Packit Service 1d0348
			gds->Year = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Month = gds->tokenp[2].value;
Packit Service 1d0348
			gds->Day = gds->tokenp[4].value;
Packit Service 1d0348
		} else if ((gds->tokenp[4].value >= 13)
Packit Service 1d0348
		    || (gds->tokenp[2].value >= 13)) {
Packit Service 1d0348
			/* Last number is big:  01/07/98 */
Packit Service 1d0348
			/* Middle number is big:  01/29/04 */
Packit Service 1d0348
			gds->Month = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Day = gds->tokenp[2].value;
Packit Service 1d0348
			gds->Year = gds->tokenp[4].value;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			/* No significant clues: 02/03/04 */
Packit Service 1d0348
			gds->Month = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Day = gds->tokenp[2].value;
Packit Service 1d0348
			gds->Year = gds->tokenp[4].value;
Packit Service 1d0348
		}
Packit Service 1d0348
		gds->tokenp += 5;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == '/'
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER) {
Packit Service 1d0348
		/* "1/15" */
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Month = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Day = gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == '-'
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[3].token == '-'
Packit Service 1d0348
	    && gds->tokenp[4].token == tUNUMBER) {
Packit Service 1d0348
		/* ISO 8601 format.  yyyy-mm-dd.  */
Packit Service 1d0348
		gds->HaveYear++;
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Year = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Month = gds->tokenp[2].value;
Packit Service 1d0348
		gds->Day = gds->tokenp[4].value;
Packit Service 1d0348
		gds->tokenp += 5;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == '-'
Packit Service 1d0348
	    && gds->tokenp[2].token == tMONTH
Packit Service 1d0348
	    && gds->tokenp[3].token == '-'
Packit Service 1d0348
	    && gds->tokenp[4].token == tUNUMBER) {
Packit Service 1d0348
		gds->HaveYear++;
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		if (gds->tokenp[0].value > 31) {
Packit Service 1d0348
			/* e.g. 1992-Jun-17 */
Packit Service 1d0348
			gds->Year = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Month = gds->tokenp[2].value;
Packit Service 1d0348
			gds->Day = gds->tokenp[4].value;
Packit Service 1d0348
		} else {
Packit Service 1d0348
			/* e.g. 17-JUN-1992.  */
Packit Service 1d0348
			gds->Day = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Month = gds->tokenp[2].value;
Packit Service 1d0348
			gds->Year = gds->tokenp[4].value;
Packit Service 1d0348
		}
Packit Service 1d0348
		gds->tokenp += 5;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tMONTH
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[2].token == ','
Packit Service 1d0348
	    && gds->tokenp[3].token == tUNUMBER) {
Packit Service 1d0348
		/* "June 17, 2001" */
Packit Service 1d0348
		gds->HaveYear++;
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Month = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Day = gds->tokenp[1].value;
Packit Service 1d0348
		gds->Year = gds->tokenp[3].value;
Packit Service 1d0348
		gds->tokenp += 4;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tMONTH
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER) {
Packit Service 1d0348
		/* "May 3" */
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Month = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Day = gds->tokenp[1].value;
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == tMONTH
Packit Service 1d0348
	    && gds->tokenp[2].token == tUNUMBER) {
Packit Service 1d0348
		/* "12 Sept 1997" */
Packit Service 1d0348
		gds->HaveYear++;
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Day = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Month = gds->tokenp[1].value;
Packit Service 1d0348
		gds->Year = gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == tMONTH) {
Packit Service 1d0348
		/* "12 Sept" */
Packit Service 1d0348
		gds->HaveMonth++;
Packit Service 1d0348
		gds->HaveDay++;
Packit Service 1d0348
		gds->Day = gds->tokenp[0].value;
Packit Service 1d0348
		gds->Month = gds->tokenp[1].value;
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return 0;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
relunitphrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (gds->tokenp[0].token == '-'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[2].token == tSEC_UNIT) {
Packit Service 1d0348
		/* "-3 hours" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == '+'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[2].token == tSEC_UNIT) {
Packit Service 1d0348
		/* "+1 minute" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == tSEC_UNIT) {
Packit Service 1d0348
		/* "1 day" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value;
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == '-'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[2].token == tMONTH_UNIT) {
Packit Service 1d0348
		/* "-3 months" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == '+'
Packit Service 1d0348
	    && gds->tokenp[1].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[2].token == tMONTH_UNIT) {
Packit Service 1d0348
		/* "+5 years" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value;
Packit Service 1d0348
		gds->tokenp += 3;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
	    && gds->tokenp[1].token == tMONTH_UNIT) {
Packit Service 1d0348
		/* "2 years" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value;
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == tSEC_UNIT) {
Packit Service 1d0348
		/* "now", "tomorrow" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelSeconds += gds->tokenp[0].value;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == tMONTH_UNIT) {
Packit Service 1d0348
		/* "month" */
Packit Service 1d0348
		gds->HaveRel++;
Packit Service 1d0348
		gds->RelMonth += gds->tokenp[0].value;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	return 0;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Day of the week specification.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
dayphrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (gds->tokenp[0].token == tDAY) {
Packit Service 1d0348
		/* "tues", "wednesday," */
Packit Service 1d0348
		gds->HaveWeekDay++;
Packit Service 1d0348
		gds->DayOrdinal = 1;
Packit Service 1d0348
		gds->DayNumber = gds->tokenp[0].value;
Packit Service 1d0348
		gds->tokenp += 1;
Packit Service 1d0348
		if (gds->tokenp[0].token == ',')
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER
Packit Service 1d0348
		&& gds->tokenp[1].token == tDAY) {
Packit Service 1d0348
		/* "second tues" "3 wed" */
Packit Service 1d0348
		gds->HaveWeekDay++;
Packit Service 1d0348
		gds->DayOrdinal = gds->tokenp[0].value;
Packit Service 1d0348
		gds->DayNumber = gds->tokenp[1].value;
Packit Service 1d0348
		gds->tokenp += 2;
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
	return 0;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Try to match a phrase using one of the above functions.
Packit Service 1d0348
 * This layer also deals with a couple of generic issues.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
phrase(struct gdstate *gds)
Packit Service 1d0348
{
Packit Service 1d0348
	if (timephrase(gds))
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	if (zonephrase(gds))
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	if (datephrase(gds))
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	if (dayphrase(gds))
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	if (relunitphrase(gds)) {
Packit Service 1d0348
		if (gds->tokenp[0].token == tAGO) {
Packit Service 1d0348
			gds->RelSeconds = -gds->RelSeconds;
Packit Service 1d0348
			gds->RelMonth = -gds->RelMonth;
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
		}
Packit Service 1d0348
		return 1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Bare numbers sometimes have meaning. */
Packit Service 1d0348
	if (gds->tokenp[0].token == tUNUMBER) {
Packit Service 1d0348
		if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) {
Packit Service 1d0348
			gds->HaveYear++;
Packit Service 1d0348
			gds->Year = gds->tokenp[0].value;
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
			return 1;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if(gds->tokenp[0].value > 10000) {
Packit Service 1d0348
			/* "20040301" */
Packit Service 1d0348
			gds->HaveYear++;
Packit Service 1d0348
			gds->HaveMonth++;
Packit Service 1d0348
			gds->HaveDay++;
Packit Service 1d0348
			gds->Day= (gds->tokenp[0].value)%100;
Packit Service 1d0348
			gds->Month= (gds->tokenp[0].value/100)%100;
Packit Service 1d0348
			gds->Year = gds->tokenp[0].value/10000;
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
			return 1;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if (gds->tokenp[0].value < 24) {
Packit Service 1d0348
			gds->HaveTime++;
Packit Service 1d0348
			gds->Hour = gds->tokenp[0].value;
Packit Service 1d0348
			gds->Minutes = 0;
Packit Service 1d0348
			gds->Seconds = 0;
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
			return 1;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		if ((gds->tokenp[0].value / 100 < 24)
Packit Service 1d0348
		    && (gds->tokenp[0].value % 100 < 60)) {
Packit Service 1d0348
			/* "513" is same as "5:13" */
Packit Service 1d0348
			gds->Hour = gds->tokenp[0].value / 100;
Packit Service 1d0348
			gds->Minutes = gds->tokenp[0].value % 100;
Packit Service 1d0348
			gds->Seconds = 0;
Packit Service 1d0348
			gds->tokenp += 1;
Packit Service 1d0348
			return 1;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	return 0;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * A dictionary of time words.
Packit Service 1d0348
 */
Packit Service 1d0348
static struct LEXICON {
Packit Service 1d0348
	size_t		abbrev;
Packit Service 1d0348
	const char	*name;
Packit Service 1d0348
	int		type;
Packit Service 1d0348
	time_t		value;
Packit Service 1d0348
} const TimeWords[] = {
Packit Service 1d0348
	/* am/pm */
Packit Service 1d0348
	{ 0, "am",		tAMPM,	tAM },
Packit Service 1d0348
	{ 0, "pm",		tAMPM,	tPM },
Packit Service 1d0348
Packit Service 1d0348
	/* Month names. */
Packit Service 1d0348
	{ 3, "january",		tMONTH,  1 },
Packit Service 1d0348
	{ 3, "february",	tMONTH,  2 },
Packit Service 1d0348
	{ 3, "march",		tMONTH,  3 },
Packit Service 1d0348
	{ 3, "april",		tMONTH,  4 },
Packit Service 1d0348
	{ 3, "may",		tMONTH,  5 },
Packit Service 1d0348
	{ 3, "june",		tMONTH,  6 },
Packit Service 1d0348
	{ 3, "july",		tMONTH,  7 },
Packit Service 1d0348
	{ 3, "august",		tMONTH,  8 },
Packit Service 1d0348
	{ 3, "september",	tMONTH,  9 },
Packit Service 1d0348
	{ 3, "october",		tMONTH, 10 },
Packit Service 1d0348
	{ 3, "november",	tMONTH, 11 },
Packit Service 1d0348
	{ 3, "december",	tMONTH, 12 },
Packit Service 1d0348
Packit Service 1d0348
	/* Days of the week. */
Packit Service 1d0348
	{ 2, "sunday",		tDAY, 0 },
Packit Service 1d0348
	{ 3, "monday",		tDAY, 1 },
Packit Service 1d0348
	{ 2, "tuesday",		tDAY, 2 },
Packit Service 1d0348
	{ 3, "wednesday",	tDAY, 3 },
Packit Service 1d0348
	{ 2, "thursday",	tDAY, 4 },
Packit Service 1d0348
	{ 2, "friday",		tDAY, 5 },
Packit Service 1d0348
	{ 2, "saturday",	tDAY, 6 },
Packit Service 1d0348
Packit Service 1d0348
	/* Timezones: Offsets are in seconds. */
Packit Service 1d0348
	{ 0, "gmt",  tZONE,     0*HOUR }, /* Greenwich Mean */
Packit Service 1d0348
	{ 0, "ut",   tZONE,     0*HOUR }, /* Universal (Coordinated) */
Packit Service 1d0348
	{ 0, "utc",  tZONE,     0*HOUR },
Packit Service 1d0348
	{ 0, "wet",  tZONE,     0*HOUR }, /* Western European */
Packit Service 1d0348
	{ 0, "bst",  tDAYZONE,  0*HOUR }, /* British Summer */
Packit Service 1d0348
	{ 0, "wat",  tZONE,     1*HOUR }, /* West Africa */
Packit Service 1d0348
	{ 0, "at",   tZONE,     2*HOUR }, /* Azores */
Packit Service 1d0348
	/* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */
Packit Service 1d0348
	/* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/
Packit Service 1d0348
	{ 0, "nft",  tZONE,     3*HOUR+30*MINUTE }, /* Newfoundland */
Packit Service 1d0348
	{ 0, "nst",  tZONE,     3*HOUR+30*MINUTE }, /* Newfoundland Standard */
Packit Service 1d0348
	{ 0, "ndt",  tDAYZONE,  3*HOUR+30*MINUTE }, /* Newfoundland Daylight */
Packit Service 1d0348
	{ 0, "ast",  tZONE,     4*HOUR }, /* Atlantic Standard */
Packit Service 1d0348
	{ 0, "adt",  tDAYZONE,  4*HOUR }, /* Atlantic Daylight */
Packit Service 1d0348
	{ 0, "est",  tZONE,     5*HOUR }, /* Eastern Standard */
Packit Service 1d0348
	{ 0, "edt",  tDAYZONE,  5*HOUR }, /* Eastern Daylight */
Packit Service 1d0348
	{ 0, "cst",  tZONE,     6*HOUR }, /* Central Standard */
Packit Service 1d0348
	{ 0, "cdt",  tDAYZONE,  6*HOUR }, /* Central Daylight */
Packit Service 1d0348
	{ 0, "mst",  tZONE,     7*HOUR }, /* Mountain Standard */
Packit Service 1d0348
	{ 0, "mdt",  tDAYZONE,  7*HOUR }, /* Mountain Daylight */
Packit Service 1d0348
	{ 0, "pst",  tZONE,     8*HOUR }, /* Pacific Standard */
Packit Service 1d0348
	{ 0, "pdt",  tDAYZONE,  8*HOUR }, /* Pacific Daylight */
Packit Service 1d0348
	{ 0, "yst",  tZONE,     9*HOUR }, /* Yukon Standard */
Packit Service 1d0348
	{ 0, "ydt",  tDAYZONE,  9*HOUR }, /* Yukon Daylight */
Packit Service 1d0348
	{ 0, "hst",  tZONE,     10*HOUR }, /* Hawaii Standard */
Packit Service 1d0348
	{ 0, "hdt",  tDAYZONE,  10*HOUR }, /* Hawaii Daylight */
Packit Service 1d0348
	{ 0, "cat",  tZONE,     10*HOUR }, /* Central Alaska */
Packit Service 1d0348
	{ 0, "ahst", tZONE,     10*HOUR }, /* Alaska-Hawaii Standard */
Packit Service 1d0348
	{ 0, "nt",   tZONE,     11*HOUR }, /* Nome */
Packit Service 1d0348
	{ 0, "idlw", tZONE,     12*HOUR }, /* Intl Date Line West */
Packit Service 1d0348
	{ 0, "cet",  tZONE,     -1*HOUR }, /* Central European */
Packit Service 1d0348
	{ 0, "met",  tZONE,     -1*HOUR }, /* Middle European */
Packit Service 1d0348
	{ 0, "mewt", tZONE,     -1*HOUR }, /* Middle European Winter */
Packit Service 1d0348
	{ 0, "mest", tDAYZONE,  -1*HOUR }, /* Middle European Summer */
Packit Service 1d0348
	{ 0, "swt",  tZONE,     -1*HOUR }, /* Swedish Winter */
Packit Service 1d0348
	{ 0, "sst",  tDAYZONE,  -1*HOUR }, /* Swedish Summer */
Packit Service 1d0348
	{ 0, "fwt",  tZONE,     -1*HOUR }, /* French Winter */
Packit Service 1d0348
	{ 0, "fst",  tDAYZONE,  -1*HOUR }, /* French Summer */
Packit Service 1d0348
	{ 0, "eet",  tZONE,     -2*HOUR }, /* Eastern Eur, USSR Zone 1 */
Packit Service 1d0348
	{ 0, "bt",   tZONE,     -3*HOUR }, /* Baghdad, USSR Zone 2 */
Packit Service 1d0348
	{ 0, "it",   tZONE,     -3*HOUR-30*MINUTE },/* Iran */
Packit Service 1d0348
	{ 0, "zp4",  tZONE,     -4*HOUR }, /* USSR Zone 3 */
Packit Service 1d0348
	{ 0, "zp5",  tZONE,     -5*HOUR }, /* USSR Zone 4 */
Packit Service 1d0348
	{ 0, "ist",  tZONE,     -5*HOUR-30*MINUTE },/* Indian Standard */
Packit Service 1d0348
	{ 0, "zp6",  tZONE,     -6*HOUR }, /* USSR Zone 5 */
Packit Service 1d0348
	/* { 0, "nst",  tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */
Packit Service 1d0348
	/* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */
Packit Service 1d0348
	{ 0, "wast", tZONE,     -7*HOUR }, /* West Australian Standard */
Packit Service 1d0348
	{ 0, "wadt", tDAYZONE,  -7*HOUR }, /* West Australian Daylight */
Packit Service 1d0348
	{ 0, "jt",   tZONE,     -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/
Packit Service 1d0348
	{ 0, "cct",  tZONE,     -8*HOUR }, /* China Coast, USSR Zone 7 */
Packit Service 1d0348
	{ 0, "jst",  tZONE,     -9*HOUR }, /* Japan Std, USSR Zone 8 */
Packit Service 1d0348
	{ 0, "cast", tZONE,     -9*HOUR-30*MINUTE },/* Ctrl Australian Std */
Packit Service 1d0348
	{ 0, "cadt", tDAYZONE,  -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */
Packit Service 1d0348
	{ 0, "east", tZONE,     -10*HOUR }, /* Eastern Australian Std */
Packit Service 1d0348
	{ 0, "eadt", tDAYZONE,  -10*HOUR }, /* Eastern Australian Daylt */
Packit Service 1d0348
	{ 0, "gst",  tZONE,     -10*HOUR }, /* Guam Std, USSR Zone 9 */
Packit Service 1d0348
	{ 0, "nzt",  tZONE,     -12*HOUR }, /* New Zealand */
Packit Service 1d0348
	{ 0, "nzst", tZONE,     -12*HOUR }, /* New Zealand Standard */
Packit Service 1d0348
	{ 0, "nzdt", tDAYZONE,  -12*HOUR }, /* New Zealand Daylight */
Packit Service 1d0348
	{ 0, "idle", tZONE,     -12*HOUR }, /* Intl Date Line East */
Packit Service 1d0348
Packit Service 1d0348
	{ 0, "dst",  tDST,		0 },
Packit Service 1d0348
Packit Service 1d0348
	/* Time units. */
Packit Service 1d0348
	{ 4, "years",		tMONTH_UNIT,	12 },
Packit Service 1d0348
	{ 5, "months",		tMONTH_UNIT,	1 },
Packit Service 1d0348
	{ 9, "fortnights",	tSEC_UNIT,	14 * DAY },
Packit Service 1d0348
	{ 4, "weeks",		tSEC_UNIT,	7 * DAY },
Packit Service 1d0348
	{ 3, "days",		tSEC_UNIT,	DAY },
Packit Service 1d0348
	{ 4, "hours",		tSEC_UNIT,	HOUR },
Packit Service 1d0348
	{ 3, "minutes",		tSEC_UNIT,	MINUTE },
Packit Service 1d0348
	{ 3, "seconds",		tSEC_UNIT,	1 },
Packit Service 1d0348
Packit Service 1d0348
	/* Relative-time words. */
Packit Service 1d0348
	{ 0, "tomorrow",	tSEC_UNIT,	DAY },
Packit Service 1d0348
	{ 0, "yesterday",	tSEC_UNIT,	-DAY },
Packit Service 1d0348
	{ 0, "today",		tSEC_UNIT,	0 },
Packit Service 1d0348
	{ 0, "now",		tSEC_UNIT,	0 },
Packit Service 1d0348
	{ 0, "last",		tUNUMBER,	-1 },
Packit Service 1d0348
	{ 0, "this",		tSEC_UNIT,	0 },
Packit Service 1d0348
	{ 0, "next",		tUNUMBER,	2 },
Packit Service 1d0348
	{ 0, "first",		tUNUMBER,	1 },
Packit Service 1d0348
	{ 0, "1st",		tUNUMBER,	1 },
Packit Service 1d0348
/*	{ 0, "second",		tUNUMBER,	2 }, */
Packit Service 1d0348
	{ 0, "2nd",		tUNUMBER,	2 },
Packit Service 1d0348
	{ 0, "third",		tUNUMBER,	3 },
Packit Service 1d0348
	{ 0, "3rd",		tUNUMBER,	3 },
Packit Service 1d0348
	{ 0, "fourth",		tUNUMBER,	4 },
Packit Service 1d0348
	{ 0, "4th",		tUNUMBER,	4 },
Packit Service 1d0348
	{ 0, "fifth",		tUNUMBER,	5 },
Packit Service 1d0348
	{ 0, "5th",		tUNUMBER,	5 },
Packit Service 1d0348
	{ 0, "sixth",		tUNUMBER,	6 },
Packit Service 1d0348
	{ 0, "seventh",		tUNUMBER,	7 },
Packit Service 1d0348
	{ 0, "eighth",		tUNUMBER,	8 },
Packit Service 1d0348
	{ 0, "ninth",		tUNUMBER,	9 },
Packit Service 1d0348
	{ 0, "tenth",		tUNUMBER,	10 },
Packit Service 1d0348
	{ 0, "eleventh",	tUNUMBER,	11 },
Packit Service 1d0348
	{ 0, "twelfth",		tUNUMBER,	12 },
Packit Service 1d0348
	{ 0, "ago",		tAGO,		1 },
Packit Service 1d0348
Packit Service 1d0348
	/* Military timezones. */
Packit Service 1d0348
	{ 0, "a",	tZONE,	1*HOUR },
Packit Service 1d0348
	{ 0, "b",	tZONE,	2*HOUR },
Packit Service 1d0348
	{ 0, "c",	tZONE,	3*HOUR },
Packit Service 1d0348
	{ 0, "d",	tZONE,	4*HOUR },
Packit Service 1d0348
	{ 0, "e",	tZONE,	5*HOUR },
Packit Service 1d0348
	{ 0, "f",	tZONE,	6*HOUR },
Packit Service 1d0348
	{ 0, "g",	tZONE,	7*HOUR },
Packit Service 1d0348
	{ 0, "h",	tZONE,	8*HOUR },
Packit Service 1d0348
	{ 0, "i",	tZONE,	9*HOUR },
Packit Service 1d0348
	{ 0, "k",	tZONE,	10*HOUR },
Packit Service 1d0348
	{ 0, "l",	tZONE,	11*HOUR },
Packit Service 1d0348
	{ 0, "m",	tZONE,	12*HOUR },
Packit Service 1d0348
	{ 0, "n",	tZONE,	-1*HOUR },
Packit Service 1d0348
	{ 0, "o",	tZONE,	-2*HOUR },
Packit Service 1d0348
	{ 0, "p",	tZONE,	-3*HOUR },
Packit Service 1d0348
	{ 0, "q",	tZONE,	-4*HOUR },
Packit Service 1d0348
	{ 0, "r",	tZONE,	-5*HOUR },
Packit Service 1d0348
	{ 0, "s",	tZONE,	-6*HOUR },
Packit Service 1d0348
	{ 0, "t",	tZONE,	-7*HOUR },
Packit Service 1d0348
	{ 0, "u",	tZONE,	-8*HOUR },
Packit Service 1d0348
	{ 0, "v",	tZONE,	-9*HOUR },
Packit Service 1d0348
	{ 0, "w",	tZONE,	-10*HOUR },
Packit Service 1d0348
	{ 0, "x",	tZONE,	-11*HOUR },
Packit Service 1d0348
	{ 0, "y",	tZONE,	-12*HOUR },
Packit Service 1d0348
	{ 0, "z",	tZONE,	0*HOUR },
Packit Service 1d0348
Packit Service 1d0348
	/* End of table. */
Packit Service 1d0348
	{ 0, NULL,	0,	0 }
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Year is either:
Packit Service 1d0348
 *  = A number from 0 to 99, which means a year from 1970 to 2069, or
Packit Service 1d0348
 *  = The actual year (>=100).
Packit Service 1d0348
 */
Packit Service 1d0348
static time_t
Packit Service 1d0348
Convert(time_t Month, time_t Day, time_t Year,
Packit Service 1d0348
	time_t Hours, time_t Minutes, time_t Seconds,
Packit Service 1d0348
	time_t Timezone, enum DSTMODE DSTmode)
Packit Service 1d0348
{
Packit Service 1d0348
	signed char DaysInMonth[12] = {
Packit Service 1d0348
		31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
Packit Service 1d0348
	};
Packit Service 1d0348
	time_t	Julian;
Packit Service 1d0348
	int	i;
Packit Service 1d0348
Packit Service 1d0348
	if (Year < 69)
Packit Service 1d0348
		Year += 2000;
Packit Service 1d0348
	else if (Year < 100)
Packit Service 1d0348
		Year += 1900;
Packit Service 1d0348
	DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
Packit Service 1d0348
	    ? 29 : 28;
Packit Service 1d0348
	/* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
Packit Service 1d0348
	   I'm too lazy to try to check for time_t overflow in another way.  */
Packit Service 1d0348
	if (Year < EPOCH || Year > 2038
Packit Service 1d0348
	    || Month < 1 || Month > 12
Packit Service 1d0348
	    /* Lint fluff:  "conversion from long may lose accuracy" */
Packit Service 1d0348
	    || Day < 1 || Day > DaysInMonth[(int)--Month]
Packit Service 1d0348
	    || Hours < 0 || Hours > 23
Packit Service 1d0348
	    || Minutes < 0 || Minutes > 59
Packit Service 1d0348
	    || Seconds < 0 || Seconds > 59)
Packit Service 1d0348
		return -1;
Packit Service 1d0348
Packit Service 1d0348
	Julian = Day - 1;
Packit Service 1d0348
	for (i = 0; i < Month; i++)
Packit Service 1d0348
		Julian += DaysInMonth[i];
Packit Service 1d0348
	for (i = EPOCH; i < Year; i++)
Packit Service 1d0348
		Julian += 365 + (i % 4 == 0);
Packit Service 1d0348
	Julian *= DAY;
Packit Service 1d0348
	Julian += Timezone;
Packit Service 1d0348
	Julian += Hours * HOUR + Minutes * MINUTE + Seconds;
Packit Service 1d0348
	if (DSTmode == DSTon
Packit Service 1d0348
	    || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
Packit Service 1d0348
		Julian -= HOUR;
Packit Service 1d0348
	return Julian;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
static time_t
Packit Service 1d0348
DSTcorrect(time_t Start, time_t Future)
Packit Service 1d0348
{
Packit Service 1d0348
	time_t	StartDay;
Packit Service 1d0348
	time_t	FutureDay;
Packit Service 1d0348
Packit Service 1d0348
	StartDay = (localtime(&Start)->tm_hour + 1) % 24;
Packit Service 1d0348
	FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
Packit Service 1d0348
	return (Future - Start) + (StartDay - FutureDay) * HOUR;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
static time_t
Packit Service 1d0348
RelativeDate(time_t Start, time_t zone, int dstmode,
Packit Service 1d0348
    time_t DayOrdinal, time_t DayNumber)
Packit Service 1d0348
{
Packit Service 1d0348
	struct tm	*tm;
Packit Service 1d0348
	time_t	t, now;
Packit Service 1d0348
Packit Service 1d0348
	t = Start - zone;
Packit Service 1d0348
	tm = gmtime(&t);
Packit Service 1d0348
	now = Start;
Packit Service 1d0348
	now += DAY * ((DayNumber - tm->tm_wday + 7) % 7);
Packit Service 1d0348
	now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
Packit Service 1d0348
	if (dstmode == DSTmaybe)
Packit Service 1d0348
		return DSTcorrect(Start, now);
Packit Service 1d0348
	return now - Start;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
static time_t
Packit Service 1d0348
RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
Packit Service 1d0348
{
Packit Service 1d0348
	struct tm	*tm;
Packit Service 1d0348
	time_t	Month;
Packit Service 1d0348
	time_t	Year;
Packit Service 1d0348
Packit Service 1d0348
	if (RelMonth == 0)
Packit Service 1d0348
		return 0;
Packit Service 1d0348
	tm = localtime(&Start;;
Packit Service 1d0348
	Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
Packit Service 1d0348
	Year = Month / 12;
Packit Service 1d0348
	Month = Month % 12 + 1;
Packit Service 1d0348
	return DSTcorrect(Start,
Packit Service 1d0348
	    Convert(Month, (time_t)tm->tm_mday, Year,
Packit Service 1d0348
		(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
Packit Service 1d0348
		Timezone, DSTmaybe));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Tokenizer.
Packit Service 1d0348
 */
Packit Service 1d0348
static int
Packit Service 1d0348
nexttoken(const char **in, time_t *value)
Packit Service 1d0348
{
Packit Service 1d0348
	char	c;
Packit Service 1d0348
	char	buff[64];
Packit Service 1d0348
Packit Service 1d0348
	for ( ; ; ) {
Packit Service 1d0348
		while (isspace((unsigned char)**in))
Packit Service 1d0348
			++*in;
Packit Service 1d0348
Packit Service 1d0348
		/* Skip parenthesized comments. */
Packit Service 1d0348
		if (**in == '(') {
Packit Service 1d0348
			int Count = 0;
Packit Service 1d0348
			do {
Packit Service 1d0348
				c = *(*in)++;
Packit Service 1d0348
				if (c == '\0')
Packit Service 1d0348
					return c;
Packit Service 1d0348
				if (c == '(')
Packit Service 1d0348
					Count++;
Packit Service 1d0348
				else if (c == ')')
Packit Service 1d0348
					Count--;
Packit Service 1d0348
			} while (Count > 0);
Packit Service 1d0348
			continue;
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		/* Try the next token in the word table first. */
Packit Service 1d0348
		/* This allows us to match "2nd", for example. */
Packit Service 1d0348
		{
Packit Service 1d0348
			const char *src = *in;
Packit Service 1d0348
			const struct LEXICON *tp;
Packit Service 1d0348
			unsigned i = 0;
Packit Service 1d0348
Packit Service 1d0348
			/* Force to lowercase and strip '.' characters. */
Packit Service 1d0348
			while (*src != '\0'
Packit Service 1d0348
			    && (isalnum((unsigned char)*src) || *src == '.')
Packit Service 1d0348
			    && i < sizeof(buff)-1) {
Packit Service 1d0348
				if (*src != '.') {
Packit Service 1d0348
					if (isupper((unsigned char)*src))
Packit Service 1d0348
						buff[i++] = tolower((unsigned char)*src);
Packit Service 1d0348
					else
Packit Service 1d0348
						buff[i++] = *src;
Packit Service 1d0348
				}
Packit Service 1d0348
				src++;
Packit Service 1d0348
			}
Packit Service 1d0348
			buff[i] = '\0';
Packit Service 1d0348
Packit Service 1d0348
			/*
Packit Service 1d0348
			 * Find the first match.  If the word can be
Packit Service 1d0348
			 * abbreviated, make sure we match at least
Packit Service 1d0348
			 * the minimum abbreviation.
Packit Service 1d0348
			 */
Packit Service 1d0348
			for (tp = TimeWords; tp->name; tp++) {
Packit Service 1d0348
				size_t abbrev = tp->abbrev;
Packit Service 1d0348
				if (abbrev == 0)
Packit Service 1d0348
					abbrev = strlen(tp->name);
Packit Service 1d0348
				if (strlen(buff) >= abbrev
Packit Service 1d0348
				    && strncmp(tp->name, buff, strlen(buff))
Packit Service 1d0348
				    	== 0) {
Packit Service 1d0348
					/* Skip over token. */
Packit Service 1d0348
					*in = src;
Packit Service 1d0348
					/* Return the match. */
Packit Service 1d0348
					*value = tp->value;
Packit Service 1d0348
					return tp->type;
Packit Service 1d0348
				}
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		/*
Packit Service 1d0348
		 * Not in the word table, maybe it's a number.  Note:
Packit Service 1d0348
		 * Because '-' and '+' have other special meanings, I
Packit Service 1d0348
		 * don't deal with signed numbers here.
Packit Service 1d0348
		 */
Packit Service 1d0348
		if (isdigit((unsigned char)(c = **in))) {
Packit Service 1d0348
			for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
Packit Service 1d0348
				*value = 10 * *value + c - '0';
Packit Service 1d0348
			(*in)--;
Packit Service 1d0348
			return (tUNUMBER);
Packit Service 1d0348
		}
Packit Service 1d0348
Packit Service 1d0348
		return *(*in)++;
Packit Service 1d0348
	}
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#define	TM_YEAR_ORIGIN 1900
Packit Service 1d0348
Packit Service 1d0348
/* Yield A - B, measured in seconds.  */
Packit Service 1d0348
static long
Packit Service 1d0348
difftm (struct tm *a, struct tm *b)
Packit Service 1d0348
{
Packit Service 1d0348
	int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
Packit Service 1d0348
	int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
Packit Service 1d0348
	int days = (
Packit Service 1d0348
		/* difference in day of year */
Packit Service 1d0348
		a->tm_yday - b->tm_yday
Packit Service 1d0348
		/* + intervening leap days */
Packit Service 1d0348
		+  ((ay >> 2) - (by >> 2))
Packit Service 1d0348
		-  (ay/100 - by/100)
Packit Service 1d0348
		+  ((ay/100 >> 2) - (by/100 >> 2))
Packit Service 1d0348
		/* + difference in years * 365 */
Packit Service 1d0348
		+  (long)(ay-by) * 365
Packit Service 1d0348
		);
Packit Service 1d0348
	return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR
Packit Service 1d0348
	    + (a->tm_min - b->tm_min) * MINUTE
Packit Service 1d0348
	    + (a->tm_sec - b->tm_sec));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 *
Packit Service 1d0348
 * The public function.
Packit Service 1d0348
 *
Packit Service 1d0348
 * TODO: tokens[] array should be dynamically sized.
Packit Service 1d0348
 */
Packit Service 1d0348
time_t
Packit Service 1d0348
__archive_get_date(time_t now, const char *p)
Packit Service 1d0348
{
Packit Service 1d0348
	struct token	tokens[256];
Packit Service 1d0348
	struct gdstate	_gds;
Packit Service 1d0348
	struct token	*lasttoken;
Packit Service 1d0348
	struct gdstate	*gds;
Packit Service 1d0348
	struct tm	local, *tm;
Packit Service 1d0348
	struct tm	gmt, *gmt_ptr;
Packit Service 1d0348
	time_t		Start;
Packit Service 1d0348
	time_t		tod;
Packit Service 1d0348
	long		tzone;
Packit Service 1d0348
Packit Service 1d0348
	/* Clear out the parsed token array. */
Packit Service 1d0348
	memset(tokens, 0, sizeof(tokens));
Packit Service 1d0348
	/* Initialize the parser state. */
Packit Service 1d0348
	memset(&_gds, 0, sizeof(_gds));
Packit Service 1d0348
	gds = &_gds;
Packit Service 1d0348
Packit Service 1d0348
	/* Look up the current time. */
Packit Service 1d0348
	memset(&local, 0, sizeof(local));
Packit Service 1d0348
	tm = localtime (&now;;
Packit Service 1d0348
	if (tm == NULL)
Packit Service 1d0348
		return -1;
Packit Service 1d0348
	local = *tm;
Packit Service 1d0348
Packit Service 1d0348
	/* Look up UTC if we can and use that to determine the current
Packit Service 1d0348
	 * timezone offset. */
Packit Service 1d0348
	memset(&gmt, 0, sizeof(gmt));
Packit Service 1d0348
	gmt_ptr = gmtime (&now;;
Packit Service 1d0348
	if (gmt_ptr != NULL) {
Packit Service 1d0348
		/* Copy, in case localtime and gmtime use the same buffer. */
Packit Service 1d0348
		gmt = *gmt_ptr;
Packit Service 1d0348
	}
Packit Service 1d0348
	if (gmt_ptr != NULL)
Packit Service 1d0348
		tzone = difftm (&gmt, &local);
Packit Service 1d0348
	else
Packit Service 1d0348
		/* This system doesn't understand timezones; fake it. */
Packit Service 1d0348
		tzone = 0;
Packit Service 1d0348
	if(local.tm_isdst)
Packit Service 1d0348
		tzone += HOUR;
Packit Service 1d0348
Packit Service 1d0348
	/* Tokenize the input string. */
Packit Service 1d0348
	lasttoken = tokens;
Packit Service 1d0348
	while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) {
Packit Service 1d0348
		++lasttoken;
Packit Service 1d0348
		if (lasttoken > tokens + 255)
Packit Service 1d0348
			return -1;
Packit Service 1d0348
	}
Packit Service 1d0348
	gds->tokenp = tokens;
Packit Service 1d0348
Packit Service 1d0348
	/* Match phrases until we run out of input tokens. */
Packit Service 1d0348
	while (gds->tokenp < lasttoken) {
Packit Service 1d0348
		if (!phrase(gds))
Packit Service 1d0348
			return -1;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Use current local timezone if none was specified. */
Packit Service 1d0348
	if (!gds->HaveZone) {
Packit Service 1d0348
		gds->Timezone = tzone;
Packit Service 1d0348
		gds->DSTmode = DSTmaybe;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* If a timezone was specified, use that for generating the default
Packit Service 1d0348
	 * time components instead of the local timezone. */
Packit Service 1d0348
	if (gds->HaveZone && gmt_ptr != NULL) {
Packit Service 1d0348
		now -= gds->Timezone;
Packit Service 1d0348
		gmt_ptr = gmtime (&now;;
Packit Service 1d0348
		if (gmt_ptr != NULL)
Packit Service 1d0348
			local = *gmt_ptr;
Packit Service 1d0348
		now += gds->Timezone;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	if (!gds->HaveYear)
Packit Service 1d0348
		gds->Year = local.tm_year + 1900;
Packit Service 1d0348
	if (!gds->HaveMonth)
Packit Service 1d0348
		gds->Month = local.tm_mon + 1;
Packit Service 1d0348
	if (!gds->HaveDay)
Packit Service 1d0348
		gds->Day = local.tm_mday;
Packit Service 1d0348
	/* Note: No default for hour/min/sec; a specifier that just
Packit Service 1d0348
	 * gives date always refers to 00:00 on that date. */
Packit Service 1d0348
Packit Service 1d0348
	/* If we saw more than one time, timezone, weekday, year, month,
Packit Service 1d0348
	 * or day, then give up. */
Packit Service 1d0348
	if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1
Packit Service 1d0348
	    || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1)
Packit Service 1d0348
		return -1;
Packit Service 1d0348
Packit Service 1d0348
	/* Compute an absolute time based on whatever absolute information
Packit Service 1d0348
	 * we collected. */
Packit Service 1d0348
	if (gds->HaveYear || gds->HaveMonth || gds->HaveDay
Packit Service 1d0348
	    || gds->HaveTime || gds->HaveWeekDay) {
Packit Service 1d0348
		Start = Convert(gds->Month, gds->Day, gds->Year,
Packit Service 1d0348
		    gds->Hour, gds->Minutes, gds->Seconds,
Packit Service 1d0348
		    gds->Timezone, gds->DSTmode);
Packit Service 1d0348
		if (Start < 0)
Packit Service 1d0348
			return -1;
Packit Service 1d0348
	} else {
Packit Service 1d0348
		Start = now;
Packit Service 1d0348
		if (!gds->HaveRel)
Packit Service 1d0348
			Start -= local.tm_hour * HOUR + local.tm_min * MINUTE
Packit Service 1d0348
			    + local.tm_sec;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* Add the relative offset. */
Packit Service 1d0348
	Start += gds->RelSeconds;
Packit Service 1d0348
	Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth);
Packit Service 1d0348
Packit Service 1d0348
	/* Adjust for day-of-week offsets. */
Packit Service 1d0348
	if (gds->HaveWeekDay
Packit Service 1d0348
	    && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) {
Packit Service 1d0348
		tod = RelativeDate(Start, gds->Timezone,
Packit Service 1d0348
		    gds->DSTmode, gds->DayOrdinal, gds->DayNumber);
Packit Service 1d0348
		Start += tod;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* -1 is an error indicator, so return 0 instead of -1 if
Packit Service 1d0348
	 * that's the actual time. */
Packit Service 1d0348
	return Start == -1 ? 0 : Start;
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
Packit Service 1d0348
#if	defined(TEST)
Packit Service 1d0348
Packit Service 1d0348
/* ARGSUSED */
Packit Service 1d0348
int
Packit Service 1d0348
main(int argc, char **argv)
Packit Service 1d0348
{
Packit Service 1d0348
    time_t	d;
Packit Service 1d0348
    time_t	now = time(NULL);
Packit Service 1d0348
Packit Service 1d0348
    while (*++argv != NULL) {
Packit Service 1d0348
	    (void)printf("Input: %s\n", *argv);
Packit Service 1d0348
	    d = get_date(now, *argv);
Packit Service 1d0348
	    if (d == -1)
Packit Service 1d0348
		    (void)printf("Bad format - couldn't convert.\n");
Packit Service 1d0348
	    else
Packit Service 1d0348
		    (void)printf("Output: %s\n", ctime(&d);;
Packit Service 1d0348
    }
Packit Service 1d0348
    exit(0);
Packit Service 1d0348
    /* NOTREACHED */
Packit Service 1d0348
}
Packit Service 1d0348
#endif	/* defined(TEST) */