From 6a75c0b2de353ea0aaa7741d8624aec4fdefcdfd Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 12 Feb 1994 17:23:51 +0000 Subject: [PATCH] merge with 1.9.2i --- lib/getopt.c | 8 +- lib/mktime.c | 455 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 290 insertions(+), 173 deletions(-) diff --git a/lib/getopt.c b/lib/getopt.c index 6cdedb019b..65af7ecd50 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -195,11 +195,9 @@ my_index (str, chr) } /* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. - (Supposedly there are some machines where it might get a warning, - but changing this conditional to __STDC__ is too risky.) */ + If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ -#if ! (defined (emacs) && !defined (__STDC__)) +#ifndef __STDC__ #ifdef IN_GCC #include "gstddef.h" #else /* not IN_GCC */ @@ -208,7 +206,7 @@ my_index (str, chr) #include #endif /* not IN_GCC */ extern size_t strlen (const char *); -#endif /* ! (defined (emacs) && !defined (__STDC__)) */ +#endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ diff --git a/lib/mktime.c b/lib/mktime.c index 1c5bf6466f..07fe494f47 100644 --- a/lib/mktime.c +++ b/lib/mktime.c @@ -1,4 +1,6 @@ -/* Copyright (C) 1991 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1994 Free Software Foundation, Inc. + Contributed by Noel Cragg (noel@cs.oberlin.edu). + This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -16,209 +18,326 @@ License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#ifndef STDC_HEADERS -extern int errno; -#endif -#ifdef TM_IN_SYS_TIME -#include +/* Define this to have a standalone program to test this implementation of + mktime. */ +/* #define DEBUG */ + +#ifdef HAVE_CONFIG_H +#if defined (CONFIG_BROKETS) +/* We use instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include #else -#include +#include "config.h" #endif -#ifdef HAVE_LIMITS_H -#include -#else -#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1))) -#define LONG_MIN (-LONG_MAX - 1) -#define INT_MAX (~(1 << (sizeof (int) * 8 - 1))) -#define INT_MIN (-INT_MAX - 1) #endif -#ifndef NULL -#define NULL 0 -#endif +#include /* Some systems define `time_t' here. */ +#include + #ifndef __isleap /* Nonzero if YEAR is a leap year (every 4 years, - except every 100th isn't, and every 1000th is). */ + except every 100th isn't, and every 400th is). */ #define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0)) + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) #endif +#ifndef __P +#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +#define __P(args) args +#else +#define __P(args) () +#endif /* GCC. */ +#endif /* Not __P. */ + /* How many days are in each month. */ -static unsigned short int __mon_lengths[2][12] = +const unsigned short int __mon_lengths[2][12] = + { + /* Normal years. */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + /* Leap years. */ + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + +static int times_through_search; /* This library routine should never + hang -- make sure we always return + when we're searching for a value */ + +/* After testing this, the maximum number of iterations that I had on + any number that I tried was 3! Not bad. + + mktime converts a `struct tm' (broken-down local time) into a `time_t'; + it is the opposite of localtime. It is possible to put the following + values out of range and have mktime compensate: tm_sec, tm_min, tm_hour, + tm_mday, tm_year. The other values in the structure are ignored. */ + +#ifdef DEBUG + +#include +#include + +int debugging_enabled = 0; + +/* Print the values in a `struct tm'. */ +static void +printtm (it) + struct tm *it; { - /* Normal years. */ - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - /* Leap years. */ - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -#define invalid() return (time_t) -1 - -/* Return the `time_t' representation of TP and normalizes TP. - Return (time_t) -1 if TP is not representable as a `time_t'. - Note that 31 Dec 1969 23:59:59 is not representable - because it is represented as (time_t) -1. */ -time_t -mktime(tp) -register struct tm *tp; + printf ("%d/%d/%d %d:%d:%d (%s) yday:%d f:%d o:%ld", + it->tm_mon, + it->tm_mday, + it->tm_year, + it->tm_hour, + it->tm_min, + it->tm_sec, + it->tm_zone, + it->tm_yday, + it->tm_isdst, + it->tm_gmtoff); +} +#endif + + +static time_t +dist_tm (t1, t2) + struct tm *t1; + struct tm *t2; { - static struct tm min, max; - static char init = 0; + time_t distance = 0; + unsigned long int v1, v2; + int diff_flag = 0; - register time_t result; - register time_t t; - register int i; - register unsigned short *l; - register struct tm *new; - time_t end; + v1 = v2 = 0; - if (tp == NULL) - { - errno = EINVAL; - invalid(); +#define doit(x, secs) \ + v1 += t1->x * secs; \ + v2 += t2->x * secs; \ + if (!diff_flag) \ + { \ + if (t1->x < t2->x) \ + diff_flag = -1; \ + else if (t1->x > t2->x) \ + diff_flag = 1; \ } + + doit (tm_year, 31536000); /* Okay, not all years have 365 days. */ + doit (tm_mon, 2592000); /* Okay, not all months have 30 days. */ + doit (tm_mday, 86400); + doit (tm_hour, 3600); + doit (tm_min, 60); + doit (tm_sec, 1); + +#undef doit + + /* We should also make sure that the sign of DISTANCE is correct -- if + DIFF_FLAG is positive, the distance should be positive and vice versa. */ + + distance = (v1 > v2) ? (v1 - v2) : (v2 - v1); + if (diff_flag < 0) + distance = -distance; - if (!init) + if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we + never hang if there's a problem with + this algorithm. */ { - init = 1; - end = (time_t) LONG_MIN; - new = gmtime(&end); - if (new != NULL) - min = *new; - else - min.tm_sec = min.tm_min = min.tm_hour = - min.tm_mday = min.tm_mon = min.tm_year = INT_MIN; - - end = (time_t) LONG_MAX; - new = gmtime(&end); - if (new != NULL) - max = *new; - else - max.tm_sec = max.tm_min = max.tm_hour = - max.tm_mday = max.tm_mon = max.tm_year = INT_MAX; + distance = diff_flag; } - /* Make all the elements of TP that we pay attention to - be within the ranges of reasonable values for those things. */ -#define normalize(elt, min, max, nextelt) \ - while (tp->elt < min) \ - { \ - --tp->nextelt; \ - tp->elt += max + 1; \ - } \ - while (tp->elt > max) \ - { \ - ++tp->nextelt; \ - tp->elt -= max + 1; \ - } + /* We need this DIFF_FLAG business because it is forseeable that the + distance may be zero when, in actuality, the two structures are + different. This is usually the case when the dates are 366 days apart + and one of the years is a leap year. */ + + if (distance == 0 && diff_flag) + distance = 86400 * diff_flag; + + return distance; +} + + +/* Modified b-search -- make intelligent guesses as to where the time might + lie along the timeline, assuming that our target time lies a linear + distance (w/o considering time jumps of a particular region). + + Assume that time does not fluctuate at all along the timeline -- e.g., + assume that a day will always take 86400 seconds, etc. -- and come up + with a hypothetical value for the time_t representation of the struct tm + TARGET, in relation to the guess variable -- it should be pretty close! */ + +static time_t +search (target, producer) + struct tm *target; + struct tm *(*producer) __P ((const time_t *)); +{ + struct tm *guess_tm; + time_t guess = 0; + time_t distance = 0; + + times_through_search = 0; + + do + { + guess += distance; + times_through_search++; + + guess_tm = (*producer) (&guess); + +#ifdef DEBUG + if (debugging_enabled) + { + printf ("guess %d == ", (int) guess); + printtm (guess_tm); + puts (""); + } +#endif + + /* Are we on the money? */ + distance = dist_tm (target, guess_tm); + + } while (distance != 0); + + return guess; +} + +/* Since this function will call localtime many times (and the user might + be passing their `struct tm *' right from localtime, let's make a copy + for ourselves and run the search on the copy. + + Also, we have to normalize *TIMEPTR because it's possible to call mktime + with values that are out of range for a specific item (like Feb 30th). */ +time_t +_mktime_internal (timeptr, producer) + struct tm *timeptr; + struct tm *(*producer) __P ((const time_t *)); +{ + struct tm private_mktime_struct_tm; /* Yes, users can get a ptr to this. */ + struct tm *me; + time_t result; + + me = &private_mktime_struct_tm; + + *me = *timeptr; + +#define normalize(foo,x,y,bar); \ + while (me->foo < x) \ + { \ + me->bar--; \ + me->foo = (y - (x - me->foo)); \ + } \ + while (me->foo > y) \ + { \ + me->bar++; \ + me->foo = (x + (me->foo - y)); \ + } + normalize (tm_sec, 0, 59, tm_min); normalize (tm_min, 0, 59, tm_hour); - normalize (tm_hour, 0, 24, tm_mday); - - /* Normalize the month first so we can use - it to figure the range for the day. */ + normalize (tm_hour, 0, 23, tm_mday); + + /* Do the month first, so day range can be found. */ normalize (tm_mon, 0, 11, tm_year); - normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon], + normalize (tm_mday, 1, + __mon_lengths[__isleap (me->tm_year)][me->tm_mon], tm_mon); - /* Normalize the month again, since normalizing - the day may have pushed it out of range. */ + /* Do the month again, because the day may have pushed it out of range. */ normalize (tm_mon, 0, 11, tm_year); - /* Normalize the day again, because normalizing - the month may have changed the range. */ - normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon], + /* Do the day again, because the month may have changed the range. */ + normalize (tm_mday, 1, + __mon_lengths[__isleap (me->tm_year)][me->tm_mon], tm_mon); + +#ifdef DEBUG + if (debugging_enabled) + { + printf ("After normalizing: "); + printtm (me); + puts ("\n"); + } +#endif + + result = search (me, producer); - /* Check for out-of-range values. */ -#define lowhigh(field, minmax, cmp) (tp->field cmp minmax.field) -#define low(field) lowhigh(field, min, <) -#define high(field) lowhigh(field, max, >) -#define oor(field) (low(field) || high(field)) -#define lowbound(field) (tp->field == min.field) -#define highbound(field) (tp->field == max.field) - if (oor(tm_year)) - invalid(); - else if (lowbound(tm_year)) + *timeptr = *me; + + return result; +} + +time_t +mktime (timeptr) + struct tm *timeptr; +{ + return _mktime_internal (timeptr, localtime); +} + +#ifdef DEBUG +void +main (argc, argv) + int argc; + char *argv[]; +{ + int time; + int result_time; + struct tm *tmptr; + + if (argc == 1) { - if (low(tm_mon)) - invalid(); - else if (lowbound(tm_mon)) + long q; + + printf ("starting long test...\n"); + + for (q = 10000000; q < 1000000000; q++) { - if (low(tm_mday)) - invalid(); - else if (lowbound(tm_mday)) - { - if (low(tm_hour)) - invalid(); - else if (lowbound(tm_hour)) - { - if (low(tm_min)) - invalid(); - else if (lowbound(tm_min)) - { - if (low(tm_sec)) - invalid(); - } - } - } + struct tm *tm = localtime (&q); + if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); } + if (q != mktime (tm)) + { printf ("failed for %ld\n", q); fflush (stdout); } } + + printf ("test finished\n"); + + exit (0); } - else if (highbound(tm_year)) + + if (argc != 2) { - if (high(tm_mon)) - invalid(); - else if (highbound(tm_mon)) - { - if (high(tm_mday)) - invalid(); - else if (highbound(tm_mday)) - { - if (high(tm_hour)) - invalid(); - else if (highbound(tm_hour)) - { - if (high(tm_min)) - invalid(); - else if (highbound(tm_min)) - { - if (high(tm_sec)) - invalid(); - } - } - } - } + printf ("wrong # of args\n"); + exit (0); } + + debugging_enabled = 1; /* We want to see the info */ - t = 0; - for (i = 1970; i > 1900 + tp->tm_year; --i) - t -= __isleap(i) ? 366 : 365; - for (i = 1970; i < 1900 + tp->tm_year; ++i) - t += __isleap(i) ? 366 : 365; - l = __mon_lengths[__isleap(1900 + tp->tm_year)]; - for (i = 0; i < tp->tm_mon; ++i) - t += l[i]; - t += tp->tm_mday - 1; - result = ((t * 60 * 60 * 24) + - (tp->tm_hour * 60 * 60) + - (tp->tm_min * 60) + - tp->tm_sec); - - end = result; -#if 0 /* This code breaks it, on SunOS anyway. */ - if (tp->tm_isdst < 0) - new = localtime(&end); - else -#endif - new = gmtime(&end); - if (new == NULL) - invalid(); - new->tm_isdst = tp->tm_isdst; - *tp = *new; + ++argv; + time = atoi (*argv); + + printf ("Time: %d %s\n", time, ctime ((time_t *) &time)); - return result; + tmptr = localtime ((time_t *) &time); + printf ("localtime returns: "); + printtm (tmptr); + printf ("\n"); + printf ("mktime: %d\n\n", (int) mktime (tmptr)); + + tmptr->tm_sec -= 20; + tmptr->tm_min -= 20; + tmptr->tm_hour -= 20; + tmptr->tm_mday -= 20; + tmptr->tm_mon -= 20; + tmptr->tm_year -= 20; + tmptr->tm_gmtoff -= 20000; /* This has no effect! */ + tmptr->tm_zone = NULL; /* Nor does this! */ + tmptr->tm_isdst = -1; + + printf ("changed ranges: "); + printtm (tmptr); + printf ("\n\n"); + + result_time = mktime (tmptr); + printf ("\nmktime: %d\n", result_time); } +#endif /* DEBUG */ -- 2.30.2