1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-04-21 03:12:48 +02:00

merge with 1.9.2i

This commit is contained in:
Jim Meyering
1994-02-12 17:23:44 +00:00
parent 4caa3d07cf
commit 9935449e9d
6 changed files with 302 additions and 181 deletions

View File

@@ -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 <stddef.h>
#endif /* not IN_GCC */
extern size_t strlen (const char *);
#endif /* ! (defined (emacs) && !defined (__STDC__)) */
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */

View File

@@ -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 <sys/types.h>
#include <errno.h>
#ifndef STDC_HEADERS
extern int errno;
#endif
#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
/* 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 <config.h> 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 <config.h>
#else
#include <time.h>
#include "config.h"
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#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 <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
#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 <stdio.h>
#include <ctype.h>
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 }
};
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
#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. */
static time_t
dist_tm (t1, t2)
struct tm *t1;
struct tm *t2;
{
time_t distance = 0;
unsigned long int v1, v2;
int diff_flag = 0;
v1 = v2 = 0;
#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 (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
never hang if there's a problem with
this algorithm. */
{
distance = diff_flag;
}
/* 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(tp)
register struct tm *tp;
_mktime_internal (timeptr, producer)
struct tm *timeptr;
struct tm *(*producer) __P ((const time_t *));
{
static struct tm min, max;
static char init = 0;
struct tm private_mktime_struct_tm; /* Yes, users can get a ptr to this. */
struct tm *me;
time_t result;
register time_t result;
register time_t t;
register int i;
register unsigned short *l;
register struct tm *new;
time_t end;
me = &private_mktime_struct_tm;
*me = *timeptr;
if (tp == NULL)
{
errno = EINVAL;
invalid();
#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)); \
}
if (!init)
{
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;
}
/* 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; \
}
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);
/* 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))
#ifdef DEBUG
if (debugging_enabled)
{
if (low(tm_mon))
invalid();
else if (lowbound(tm_mon))
{
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();
}
}
}
}
printf ("After normalizing: ");
printtm (me);
puts ("\n");
}
else if (highbound(tm_year))
{
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();
}
}
}
}
}
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;
result = search (me, producer);
*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)
{
long q;
printf ("starting long test...\n");
for (q = 10000000; q < 1000000000; q++)
{
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);
}
if (argc != 2)
{
printf ("wrong # of args\n");
exit (0);
}
debugging_enabled = 1; /* We want to see the info */
++argv;
time = atoi (*argv);
printf ("Time: %d %s\n", time, ctime ((time_t *) &time));
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 */