File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lrzsz / lib / mktime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Thu Oct 24 15:49:50 2019 UTC (4 years, 11 months ago) by misho
Branches: lrzsz, MAIN
CVS tags: v0_12_20p5, HEAD
lrzsz ver 0.12.20

    1: /* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
    2:    Contributed by Noel Cragg (noel@cs.oberlin.edu), with fixes by
    3:    Michael E. Calwas (calwas@ttd.teradyne.com) and
    4:    Wade Hampton (tasi029@tmn.com).
    5: 
    6: 
    7: NOTE: The canonical source of this file is maintained with the GNU C Library.
    8: Bugs can be reported to bug-glibc@prep.ai.mit.edu.
    9: 
   10: This program is free software; you can redistribute it and/or modify it
   11: under the terms of the GNU General Public License as published by the
   12: Free Software Foundation; either version 2, or (at your option) any
   13: later version.
   14: 
   15: This program is distributed in the hope that it will be useful,
   16: but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: GNU General Public License for more details.
   19: 
   20: You should have received a copy of the GNU General Public License
   21: along with this program; if not, write to the Free Software
   22: Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
   23: 
   24: /* Define this to have a standalone program to test this implementation of
   25:    mktime.  */
   26: /* #define DEBUG */
   27: 
   28: #ifdef HAVE_CONFIG_H
   29: #include <config.h>
   30: #endif
   31: 
   32: #include <sys/types.h>		/* Some systems define `time_t' here.  */
   33: #include <time.h>
   34: 
   35: 
   36: #ifndef __isleap
   37: /* Nonzero if YEAR is a leap year (every 4 years,
   38:    except every 100th isn't, and every 400th is).  */
   39: #define	__isleap(year)	\
   40:   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
   41: #endif
   42: 
   43: #ifndef __P
   44: #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
   45: #define __P(args) args
   46: #else
   47: #define __P(args) ()
   48: #endif  /* GCC.  */
   49: #endif  /* Not __P.  */
   50: 
   51: /* How many days are in each month.  */
   52: const unsigned short int __mon_lengths[2][12] =
   53:   {
   54:     /* Normal years.  */
   55:     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
   56:     /* Leap years.  */
   57:     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
   58:   };
   59: 
   60: 
   61: static int times_through_search; /* This library routine should never
   62: 				    hang -- make sure we always return
   63: 				    when we're searching for a value */
   64: 
   65: 
   66: #ifdef DEBUG
   67: 
   68: #include <stdio.h>
   69: #include <ctype.h>
   70: 
   71: int debugging_enabled = 0;
   72: 
   73: /* Print the values in a `struct tm'. */
   74: static void
   75: printtm (it)
   76:      struct tm *it;
   77: {
   78:   printf ("%02d/%02d/%04d %02d:%02d:%02d (%s) yday:%03d dst:%d gmtoffset:%ld",
   79: 	  it->tm_mon + 1,
   80: 	  it->tm_mday,
   81: 	  it->tm_year + 1900,
   82: 	  it->tm_hour,
   83: 	  it->tm_min,
   84: 	  it->tm_sec,
   85: 	  it->tm_zone,
   86: 	  it->tm_yday,
   87: 	  it->tm_isdst,
   88: 	  it->tm_gmtoff);
   89: }
   90: #endif
   91: 
   92: 
   93: static time_t
   94: dist_tm (t1, t2)
   95:      struct tm *t1;
   96:      struct tm *t2;
   97: {
   98:   time_t distance = 0;
   99:   unsigned long int v1, v2;
  100:   int diff_flag = 0;
  101: 
  102:   v1 = v2 = 0;
  103: 
  104: #define doit(x, secs)                                                         \
  105:   v1 += t1->x * secs;                                                         \
  106:   v2 += t2->x * secs;                                                         \
  107:   if (!diff_flag)                                                             \
  108:     {                                                                         \
  109:       if (t1->x < t2->x)                                                      \
  110: 	diff_flag = -1;                                                       \
  111:       else if (t1->x > t2->x)                                                 \
  112: 	diff_flag = 1;                                                        \
  113:     }
  114:   
  115:   doit (tm_year, 31536000);	/* Okay, not all years have 365 days. */
  116:   doit (tm_mon, 2592000);	/* Okay, not all months have 30 days. */
  117:   doit (tm_mday, 86400);
  118:   doit (tm_hour, 3600);
  119:   doit (tm_min, 60);
  120:   doit (tm_sec, 1);
  121:   
  122: #undef doit
  123:   
  124:   /* We should also make sure that the sign of DISTANCE is correct -- if
  125:      DIFF_FLAG is positive, the distance should be positive and vice versa. */
  126:   
  127:   distance = (v1 > v2) ? (v1 - v2) : (v2 - v1);
  128:   if (diff_flag < 0)
  129:     distance = -distance;
  130: 
  131:   if (times_through_search > 20) /* Arbitrary # of calls, but makes sure we
  132: 				    never hang if there's a problem with
  133: 				    this algorithm.  */
  134:     {
  135:       distance = diff_flag;
  136:     }
  137: 
  138:   /* We need this DIFF_FLAG business because it is forseeable that the
  139:      distance may be zero when, in actuality, the two structures are
  140:      different.  This is usually the case when the dates are 366 days apart
  141:      and one of the years is a leap year.  */
  142: 
  143:   if (distance == 0 && diff_flag)
  144:     distance = 86400 * diff_flag;
  145: 
  146:   return distance;
  147: }
  148:       
  149: 
  150: /* MKTIME converts the values in a struct tm to a time_t.  The values
  151:    in tm_wday and tm_yday are ignored; other values can be put outside
  152:    of legal ranges since they will be normalized.  This routine takes
  153:    care of that normalization. */
  154: 
  155: void
  156: do_normalization (tmptr)
  157:      struct tm *tmptr;
  158: {
  159: 
  160: #define normalize(foo,x,y,bar); \
  161:   while (tmptr->foo < x) \
  162:     { \
  163:       tmptr->bar--; \
  164:       tmptr->foo = (y - (x - tmptr->foo) + 1); \
  165:     } \
  166:   while (tmptr->foo > y) \
  167:     { \
  168:       tmptr->foo = (x + (tmptr->foo - y) - 1); \
  169:       tmptr->bar++; \
  170:     }
  171:   
  172:   normalize (tm_sec, 0, 59, tm_min);
  173:   normalize (tm_min, 0, 59, tm_hour);
  174:   normalize (tm_hour, 0, 23, tm_mday);
  175:   
  176:   /* Do the month first, so day range can be found. */
  177:   normalize (tm_mon, 0, 11, tm_year);
  178: 
  179:   /* Since the day range modifies the month, we should be careful how
  180:      we reference the array of month lengths -- it is possible that
  181:      the month will go negative, hence the modulo...
  182: 
  183:      Also, tm_year is the year - 1900, so we have to 1900 to have it
  184:      work correctly. */
  185: 
  186:   normalize (tm_mday, 1,
  187: 	     __mon_lengths[__isleap (tmptr->tm_year + 1900)]
  188:                           [((tmptr->tm_mon < 0)
  189: 			    ? (12 + (tmptr->tm_mon % 12))
  190: 			    : (tmptr->tm_mon % 12)) ],
  191: 	     tm_mon);
  192: 
  193:   /* Do the month again, because the day may have pushed it out of range. */
  194:   normalize (tm_mon, 0, 11, tm_year);
  195: 
  196:   /* Do the day again, because the month may have changed the range. */
  197:   normalize (tm_mday, 1,
  198: 	     __mon_lengths[__isleap (tmptr->tm_year + 1900)]
  199: 	                  [((tmptr->tm_mon < 0)
  200: 			    ? (12 + (tmptr->tm_mon % 12))
  201: 			    : (tmptr->tm_mon % 12)) ],
  202: 	     tm_mon);
  203:   
  204: #ifdef DEBUG
  205:   if (debugging_enabled)
  206:     {
  207:       printf ("   After normalizing:\n     ");
  208:       printtm (tmptr);
  209:       putchar ('\n');
  210:     }
  211: #endif
  212: 
  213: }
  214: 
  215: 
  216: /* Here's where the work gets done. */
  217: 
  218: #define BAD_STRUCT_TM ((time_t) -1)
  219: 
  220: time_t
  221: __mktime_internal (timeptr, producer)
  222:      struct tm *timeptr;
  223:      struct tm *(*producer) __P ((const time_t *, struct tm *));
  224: {
  225:   struct tm our_tm;		/* our working space */
  226:   struct tm *me = &our_tm;	/* a pointer to the above */
  227:   time_t result;		/* the value we return */
  228: 
  229:   *me = *timeptr;		/* copy the struct tm that was passed
  230: 				   in by the caller */
  231: 
  232: 
  233:   /***************************/
  234:   /* Normalize the structure */
  235:   /***************************/
  236: 
  237:   /* This routine assumes that the value of TM_ISDST is -1, 0, or 1.
  238:      If the user didn't pass it in that way, fix it. */
  239: 
  240:   if (me->tm_isdst > 0)
  241:     me->tm_isdst = 1;
  242:   else if (me->tm_isdst < 0)
  243:     me->tm_isdst = -1;
  244: 
  245:   do_normalization (me);
  246: 
  247:   /* Get out of here if it's not possible to represent this struct.
  248:      If any of the values in the normalized struct tm are negative,
  249:      our algorithms won't work.  Luckily, we only need to check the
  250:      year at this point; normalization guarantees that all values will
  251:      be in correct ranges EXCEPT the year. */
  252: 
  253:   if (me->tm_year < 0)
  254:     return BAD_STRUCT_TM;
  255: 
  256:   /*************************************************/
  257:   /* Find the appropriate time_t for the structure */
  258:   /*************************************************/
  259: 
  260:   /* Modified b-search -- make intelligent guesses as to where the
  261:      time might lie along the timeline, assuming that our target time
  262:      lies a linear distance (w/o considering time jumps of a
  263:      particular region).
  264: 
  265:      Assume that time does not fluctuate at all along the timeline --
  266:      e.g., assume that a day will always take 86400 seconds, etc. --
  267:      and come up with a hypothetical value for the time_t
  268:      representation of the struct tm TARGET, in relation to the guess
  269:      variable -- it should be pretty close!
  270: 
  271:      After testing this, the maximum number of iterations that I had
  272:      on any number that I tried was 3!  Not bad.
  273: 
  274:      The reason this is not a subroutine is that we will modify some
  275:      fields in the struct tm (yday and mday).  I've never felt good
  276:      about side-effects when writing structured code... */
  277: 
  278:   {
  279:     struct tm *guess_tm;
  280:     struct tm guess_struct;
  281:     time_t guess = 0;
  282:     time_t distance = 0;
  283:     time_t last_distance = 0;
  284: 
  285:     times_through_search = 0;
  286: 
  287:     do
  288:       {
  289: 	guess += distance;
  290: 
  291: 	times_through_search++;     
  292:       
  293: 	guess_tm = (*producer) (&guess, &guess_struct);
  294:       
  295: #ifdef DEBUG
  296: 	if (debugging_enabled)
  297: 	  {
  298: 	    printf ("   Guessing time_t == %d\n     ", (int) guess);
  299: 	    printtm (guess_tm);
  300: 	    putchar ('\n');
  301: 	  }
  302: #endif
  303:       
  304: 	/* How far is our guess from the desired struct tm? */
  305: 	distance = dist_tm (me, guess_tm);
  306:       
  307: 	/* Handle periods of time where a period of time is skipped.
  308: 	   For example, 2:15 3 April 1994 does not exist, because DST
  309: 	   is in effect.  The distance function will alternately
  310: 	   return values of 3600 and -3600, because it doesn't know
  311: 	   that the requested time doesn't exist.  In these situations
  312: 	   (even if the skip is not exactly an hour) the distances
  313: 	   returned will be the same, but alternating in sign.  We
  314: 	   want the later time, so check to see that the distance is
  315: 	   oscillating and we've chosen the correct of the two
  316: 	   possibilities.
  317: 
  318: 	   Useful: 3 Apr 94 765356300, 30 Oct 94 783496000 */
  319: 
  320: 	if ((distance == -last_distance) && (distance < last_distance))
  321: 	  {
  322: 	    /* If the caller specified that the DST flag was off, it's
  323:                not possible to represent this time. */
  324: 	    if (me->tm_isdst == 0)
  325: 	      {
  326: #ifdef DEBUG
  327: 	    printf ("   Distance is oscillating -- dst flag nixes struct!\n");
  328: #endif
  329: 		return BAD_STRUCT_TM;
  330: 	      }
  331: 
  332: #ifdef DEBUG
  333: 	    printf ("   Distance is oscillating -- chose the later time.\n");
  334: #endif
  335: 	    distance = 0;
  336: 	  }
  337: 
  338: 	if ((distance == 0) && (me->tm_isdst != -1)
  339: 	    && (me->tm_isdst != guess_tm->tm_isdst))
  340: 	  {
  341: 	    /* If we're in this code, we've got the right time but the
  342:                wrong daylight savings flag.  We need to move away from
  343:                the time that we have and approach the other time from
  344:                the other direction.  That is, if I've requested the
  345:                non-DST version of a time and I get the DST version
  346:                instead, I want to put us forward in time and search
  347:                backwards to get the other time.  I checked all of the
  348:                configuration files for the tz package -- no entry
  349:                saves more than two hours, so I think we'll be safe by
  350:                moving 24 hours in one direction.  IF THE AMOUNT OF
  351:                TIME SAVED IN THE CONFIGURATION FILES CHANGES, THIS
  352:                VALUE MAY NEED TO BE ADJUSTED.  Luckily, we can never
  353:                have more than one level of overlaps, or this would
  354:                never work. */
  355: 
  356: #define SKIP_VALUE 86400
  357: 
  358: 	    if (guess_tm->tm_isdst == 0)
  359: 	      /* we got the later one, but want the earlier one */
  360: 	      distance = -SKIP_VALUE;
  361: 	    else
  362: 	      distance = SKIP_VALUE;
  363: 	    
  364: #ifdef DEBUG
  365: 	    printf ("   Got the right time, wrong DST value -- adjusting\n");
  366: #endif
  367: 	  }
  368: 
  369: 	last_distance = distance;
  370: 
  371:       } while (distance != 0);
  372: 
  373:     /* Check to see that the dst flag matches */
  374: 
  375:     if (me->tm_isdst != -1)
  376:       {
  377: 	if (me->tm_isdst != guess_tm->tm_isdst)
  378: 	  {
  379: #ifdef DEBUG
  380: 	    printf ("   DST flag doesn't match!  FIXME?\n");
  381: #endif
  382: 	    return BAD_STRUCT_TM;
  383: 	  }
  384:       }
  385: 
  386:     result = guess;		/* Success! */
  387: 
  388:     /* On successful completion, the values of tm_wday and tm_yday
  389:        have to be set appropriately. */
  390:     
  391:     /* me->tm_yday = guess_tm->tm_yday; 
  392:        me->tm_mday = guess_tm->tm_mday; */
  393: 
  394:     *me = *guess_tm;
  395:   }
  396: 
  397:   /* Update the caller's version of the structure */
  398: 
  399:   *timeptr = *me;
  400: 
  401:   return result;
  402: }
  403: 
  404: #if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
  405: #ifdef _LIBC
  406: #define localtime_r __localtime_r
  407: #else
  408: /* Approximate localtime_r as best we can in its absence.  */
  409: #define localtime_r my_localtime_r /* Avoid clash with system localtime_r.  */
  410: static struct tm *
  411: localtime_r (t, tp)
  412:      const time_t *t;
  413:      struct tm *tp;
  414: { 
  415:   struct tm *l = localtime (t);
  416:   if (! l)
  417:     return 0;
  418:   *tp = *l;
  419:   return tp;
  420: }
  421: #endif /* ! _LIBC */
  422: #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
  423: 
  424: time_t
  425: #ifdef DEBUG			/* make it work even if the system's
  426: 				   libc has it's own mktime routine */
  427: my_mktime (timeptr)
  428: #else
  429: mktime (timeptr)
  430: #endif
  431:      struct tm *timeptr;
  432: {
  433:   return __mktime_internal (timeptr, localtime_r);
  434: }
  435: 
  436: #ifdef weak_alias
  437: weak_alias (mktime, timelocal)
  438: #endif
  439: 
  440: #ifdef DEBUG
  441: void
  442: main (argc, argv)
  443:      int argc;
  444:      char *argv[];
  445: {
  446:   int time;
  447:   int result_time;
  448:   struct tm *tmptr;
  449:   
  450:   if (argc == 1)
  451:     {
  452:       long q;
  453:       
  454:       printf ("starting long test...\n");
  455: 
  456:       for (q = 10000000; q < 1000000000; q += 599)
  457: 	{
  458: 	  struct tm *tm = localtime ((time_t *) &q);
  459: 	  if ((q % 10000) == 0) { printf ("%ld\n", q); fflush (stdout); }
  460: 	  if (q != my_mktime (tm))
  461: 	    { printf ("failed for %ld\n", q); fflush (stdout); }
  462: 	}
  463:       
  464:       printf ("test finished\n");
  465: 
  466:       exit (0);
  467:     }
  468:   
  469:   if (argc != 2)
  470:     {
  471:       printf ("wrong # of args\n");
  472:       exit (0);
  473:     }
  474:   
  475:   debugging_enabled = 1;	/* We want to see the info */
  476: 
  477:   ++argv;
  478:   time = atoi (*argv);
  479:   
  480:   tmptr = localtime ((time_t *) &time);
  481:   printf ("Localtime tells us that a time_t of %d represents\n     ", time);
  482:   printtm (tmptr);
  483:   putchar ('\n');
  484: 
  485:   printf ("   Given localtime's return val, mktime returns %d which is\n     ",
  486: 	  (int) my_mktime (tmptr));
  487:   printtm (tmptr);
  488:   putchar ('\n');
  489: 
  490: #if 0
  491:   tmptr->tm_sec -= 20;
  492:   tmptr->tm_min -= 20;
  493:   tmptr->tm_hour -= 20;
  494:   tmptr->tm_mday -= 20;
  495:   tmptr->tm_mon -= 20;
  496:   tmptr->tm_year -= 20;
  497:   tmptr->tm_gmtoff -= 20000;	/* This has no effect! */
  498:   tmptr->tm_zone = NULL;	/* Nor does this! */
  499:   tmptr->tm_isdst = -1;
  500: #endif
  501:   
  502:   tmptr->tm_hour += 1;
  503:   tmptr->tm_isdst = -1;
  504: 
  505:   printf ("\n\nchanged ranges: ");
  506:   printtm (tmptr);
  507:   putchar ('\n');
  508: 
  509:   result_time = my_mktime (tmptr);
  510:   printf ("\nmktime: %d\n", result_time);
  511: 
  512:   tmptr->tm_isdst = 0;
  513: 
  514:   printf ("\n\nchanged ranges: ");
  515:   printtm (tmptr);
  516:   putchar ('\n');
  517: 
  518:   result_time = my_mktime (tmptr);
  519:   printf ("\nmktime: %d\n", result_time);
  520: }
  521: #endif /* DEBUG */
  522: 
  523: 
  524: /*
  525: Local Variables:
  526: compile-command: "gcc -g mktime.c -o mktime -DDEBUG"
  527: End:
  528: */
  529: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>