/* compat.c -- functions that we need to provide because they are missing */

#include "autoconf.h"
#include "copyright.h"
#ifndef	lint
static char RCSid[] = "$Id: compat.c,v 1.7 1995/03/20 23:59:52 ambar Exp $";
USE(RCSid);
#endif

#ifdef NEED_TIMELOCAL

#define	altzone		((time_t)(timezone + 3600))

/* CAUTION: side effects */
#define	is_leap(x)	(((!((x)%4)&&(x)%100)||!(((x)+1900)%400))?1:0)

static int yday_size[2][12] =
{
    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};

static int mon_size[2][12] =
{
    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

/*e.g: normalize(&tm_secs, &tm_hour, 60); */
static void 
normalize(x, y, f)
    int *x, *y, f;
{
    if (*x >= f) {
	*y += *x / f;
	*x %= f;
    }
    /* can't rely on modulus for negative numbers */

    while (*x < 0) {
	*x += f;
	(*y)--;
    }
}

time_t 
timelocal(tp)
    struct tm *tp;
{
    long unsigned k;
    struct tm tm;
    time_t t, t1, timezone = tp->tm_gmtoff;

    tzset();			/* set up time zone */

    /* normalize the time */
    normalize(&tp->tm_sec, &tp->tm_min, 60);
    normalize(&tp->tm_min, &tp->tm_hour, 60);
    normalize(&tp->tm_hour, &tp->tm_mday, 24);

    /* normalize the month first */
    normalize(&tp->tm_mon, &tp->tm_year, 12);

    /* days to months a little tricky */
    while (tp->tm_mday < 1) {
	if (--tp->tm_mon < 0) {
	    tp->tm_year--;
	    tp->tm_mon += 12;
	}
	tp->tm_mday += mon_size[is_leap(tp->tm_year)][tp->tm_mon];
    }

    while (tp->tm_mday > (k = mon_size[is_leap(tp->tm_year)][tp->tm_mon])) {
	tp->tm_mday -= k;

	if (++tp->tm_mon > 12) {
	    tp->tm_year++;
	    tp->tm_mon -= 12;
	}
    }

    k = tp->tm_year / 4;	/* number of 4 year groups */
    t = (k * 1461) - 1;		/* number of days */
    k = tp->tm_year % 4;	/* number of years beyond group */
    t += (k * 365);		/* add number of days */
    if (k)			/* if not group break year */
	t++;			/* add one day */

    /* Since the epoch starts at Jan 1/70, we have to subtract the
     * of days from Jan 1/00.  This is actually 25567 days.  See
     * below for the explanation of the discrepancy
     */

    t -= 25568;			/* t = # days to 00:00:00 Jan 1/70 */
    t += yday_size[is_leap(tp->tm_year)][tp->tm_mon];

    /* Add the number of days in month.  Note that we should really
     * subtract 1 from the day first but we effectively did this
     * above when we subtracted an extra day (25568 instead of 25567)
     */

    t += tp->tm_mday;		/* # days to given day at 00:00:00 */

    /* now add in the number of seconds in the day */

    t = (t * 24) + tp->tm_hour;
    t = (t * 60) + tp->tm_min;
    t = (t * 60) + tp->tm_sec;	/* total number of seconds */

    /* if caller thinks he/she knows what time zone then believe them */

    if (tp->tm_isdst == 0)
	t += timezone;
    else if (tp->tm_isdst > 0)
	t += altzone;
    else {
	/* we have to figure it out, guess dst first */

	t1 = t + altzone;
	tm = *localtime(&t1);

	/* see if the guess matches the reality */

	if (tm.tm_hour == tp->tm_hour && tm.tm_min == tp->tm_min)
	    t = t1;
	else {

#ifdef CHECK_INVALID

	    /* if CHECK_INVALID is defined then we attempt to
	     * check for the invalid time case e.g. a time of
	     * 0230h on the first sunday in April will return -1
	     * - personally I don't think this is polite behaviour
	     */

	    t1 = t + timezone;
	    tm = *localtime(&t1);

	    if ((tm.tm_hour == tp->tm_hour) &&
		(tm.tm_min == tp->tm_min))
		t = t1;
	    else
		return (-1);
#else
	    t += timezone;
#endif
	}
    }

    *tp = *localtime(&t);	/* set other fields in structure */
    return (t);
}

#endif /* NEED_TIMELOCAL */
