head 1.4; access; symbols; locks; strict; comment @# @; 1.4 date 2002.09.07.01.50.38; author curt; state Exp; branches; next 1.3; 1.3 date 2002.08.31.19.01.55; author curt; state Exp; branches; next 1.2; 1.2 date 2002.08.31.18.54.01; author curt; state Exp; branches; next 1.1; 1.1 date 2002.02.15.17.21.57; author curt; state Exp; branches; next ; desc @@ 1.4 log @Updated doxygen docs. @ text @
Main Page Class Hierarchy Compound List File List Compound Members File Members

# lowleveltime.cxx

    00001 /* -*- Mode: C++ -*- *****************************************************
    00002  * Written by various people (I"ll look up the exact credits later)
    00003  * Modified by Durk Talsma, July 1999 for use in FlightGear
    00004  *
    00005  * This library is free software; you can redistribute it and/or
    00006  * modify it under the terms of the GNU Library General Public
    00007  * License as published by the Free Software Foundation; either
    00008  * version 2 of the License, or (at your option) any later version.
    00009  *
    00010  * This library is distributed in the hope that it will be useful,
    00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  * Library General Public License for more details.
    00014  *
    00015  * You should have received a copy of the GNU Library General Public
    00016  * License along with this library; if not, write to the
    00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018  * Boston, MA  02111-1307, USA.
    00019  *
    00020  **************************************************************************/
    00021
    00022 /********************************************************************
    00023  * This file redefines some low-level Unix-like time functions for  *
    00024  * use with FlightGear. Most notably, localtime() is adapted to use *
    00025  * a custom timezone, in order to get the 'local' time for a given  *
    00026  * aircraft's position, and not only for the current location of the*
    00027  * computer running the sim.                                        *
    00028  *                                                                  *
    00029  * Software adapted from glibc functions, by Durk Talsma. Started   *
    00030  * July, 17, 1999.                                                  *
    00031  ********************************************************************/
    00032
    00033
    00034 #include <time.h>
    00035 #include <stdio.h>
    00036 #include <ctype.h>
    00037 #include <errno.h>
    00038 //#include <libc-lock.h>
    00039 #include <stddef.h>
    00040 #include <stdio.h>
    00041 #include <stdlib.h>
    00042 #include <string.h>
    00043 #include <limits.h>
    00044 #include "lowleveltime.h"
    00045
    00046
    00047 /* BIG FAT WARNING: NOTICE THAT I HARDCODED ENDIANNES. PLEASE CHANGE THIS */
    00048 #ifndef BIG_ENDIAN
    00049 #define BIG_ENDIAN 4321
    00050 #endif
    00051
    00052 #ifndef LITTLE_ENDIAN
    00053 #define LITTLE_ENDIAN 1234
    00054 #endif
    00055
    00056 #ifndef BYTE_ORDER
    00057 #define BYTE_ORDER LITTLE_ENDIAN
    00058 #endif
    00059
    00060
    00061 #ifndef BYTE_ORDER
    00062 #define BYTE_ORDER
    00063 #endif
    00064
    00065 /* END OF BIG FAT WARNING */
    00066
    00067 //#include "tzfile.h"
    00068
    00069 #define min(a, b)       ((a) < (b) ? (a) : (b))
    00070 #define max(a, b)       ((a) > (b) ? (a) : (b))
    00071 #define sign(x)         ((x) < 0 ? -1 : 1)
    00072
    00073 struct leap
    00074   {
    00075     time_t transition;          /* Time the transition takes effect.  */
    00076     long int change;            /* Seconds of correction to apply.  */
    00077   };
    00078
    00079 /* Header for a list of buffers containing time zone strings.  */
    00080 struct tzstring_head
    00081 {
    00082   struct tzstring_head *next;
    00083   /* The buffer itself immediately follows the header.
    00084      The buffer contains zero or more (possibly overlapping) strings.
    00085      The last string is followed by 2 '\0's instead of the usual 1.  */
    00086 };
    00087
    00088
    00089 /* First in a list of buffers containing time zone strings.
    00090    All the buffers but the last are read-only.  */
    00091 static struct
    00092 {
    00093   struct tzstring_head head;
    00094   char data[48];
    00095 } tzstring_list;
    00096
    00097 /* Size of the last buffer in the list, not counting its header.  */
    00098 static size_t tzstring_last_buffer_size = sizeof tzstring_list.data;
    00099
    00100
    00101 static char *old_fgtz = NULL;
    00102 static int use_fgtzfile = 1;
    00103 static int fgdaylight;
    00104 static char* fgtzname[2];
    00105 static long int fgtimezone;
    00106
    00107
    00108 static size_t num_transitions;
    00109 static time_t *transitions = NULL;
    00110 static unsigned char *type_idxs = NULL;
    00111 static size_t num_types;
    00112 static struct ttinfo *types = NULL;
    00113 static char *zone_names = NULL;
    00114 static size_t num_leaps;
    00115 static struct leap *leaps = NULL;
    00116
    00117
    00118 static void fgtzset_internal (int always, const char *tz);
    00119 static int fgtz_compute(time_t timer, const struct tm *tm);
    00120 static int fgcompute_change(fgtz_rule *rule, int year);
    00121 static struct ttinfo *fgfind_transition (time_t timer);
    00122 static void fgcompute_tzname_max (size_t chars);
    00123 static inline int decode (const void *ptr);
    00124 void fgtzfile_read (const char *file);
    00125 static void offtime (const time_t *t, long int offset, struct tm *tp);
    00126 static char *tzstring (const char* string);
    00127
    00128 /* tz_rules[0] is standard, tz_rules[1] is daylight.  */
    00129 static fgtz_rule fgtz_rules[2];
    00130
    00131 int fgtzfile_compute (time_t timer, int use_localtime,
    00132                   long int *leap_correct, int *leap_hit);
    00133 struct ttinfo
    00134   {
    00135     long int offset;            /* Seconds east of GMT.  */
    00136     unsigned char isdst;        /* Used to set tm_isdst.  */
    00137     unsigned char idx;          /* Index into `zone_names'.  */
    00138     unsigned char isstd;        /* Transition times are in standard time.  */
    00139     unsigned char isgmt;        /* Transition times are in GMT.  */
    00140   };
    00141
    00142
    00143
    00144 /* How many days come before each month (0-12).  */
    00145 const unsigned short int mon_yday[2][13] =
    00146   {
    00147     /* Normal years.  */
    00148     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
    00149     /* Leap years.  */
    00150     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
    00151   };
    00152
    00153
    00154 /* The C Standard says that localtime and gmtime return the same pointer.  */
    00155 struct tm _fgtmbuf;
    00156
    00157
    00158 #ifndef isleap
    00159 /* Nonzero if YEAR is a leap year (every 4 years,
    00160    except every 100th isn't, and every 400th is).  */
    00161 # define isleap(year) \
    00162   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
    00163 #endif
    00164
    00165
    00166
    00167
    00168 /* Return the `struct tm' representation of *T in local time.  */
    00169 struct tm * fgLocaltime (const time_t *t, const char *tzName)
    00170 {
    00171   return fgtz_convert (t, 1, &_fgtmbuf, tzName);
    00172 }
    00173
    00174
    00175 /* Return the `struct tm' representation of *TIMER in the local timezone.
    00176    Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
    00177 struct tm * fgtz_convert (const time_t *timer, int use_localtime, struct tm *tp, const char *tzName)
    00178 {
    00179   long int leap_correction;
    00180   long int offsetCorr;                 // ADDED TO RESOLVE NON-ANSI FIELDS IN struct tm
    00181   int leap_extra_secs;
    00182
    00183   if (timer == NULL)
    00184     {
    00185       //set_errno (EINVAL);
    00186       return NULL;
    00187     }
    00188
    00189   //libc_lock_lock (tzset_lock);
    00190
    00191   /* Update internal database according to current TZ setting.
    00192      POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
    00193      This is a good idea since this allows at least a bit more parallelism.
    00194      By analogy we apply the same rule to gmtime_r.  */
    00195   fgtzset_internal (tp == &_fgtmbuf, tzName);
    00196
    00197   if (use_fgtzfile)
    00198     {
    00199       if (! fgtzfile_compute (*timer, use_localtime,
    00200                               &leap_correction, &leap_extra_secs))
    00201         tp = NULL;
    00202     }
    00203   else
    00204     {
    00205       offtime (timer, 0, tp);
    00206       if (! fgtz_compute (*timer, tp))
    00207         tp = NULL;
    00208       leap_correction = 0L;
    00209       leap_extra_secs = 0;
    00210     }
    00211
    00212   if (tp)
    00213     {
    00214       if (use_localtime)
    00215         {
    00216           tp->tm_isdst = fgdaylight;
    00217           //tp->tm_zone = fgtzname[fgdaylight];       // NON_ANSI
    00218           //tp->tm_gmtoff = -fgtimezone;              // NON_ANSI
    00219           offsetCorr = -fgtimezone;
    00220         }
    00221       else
    00222         {
    00223           tp->tm_isdst = 0;
    00224           //tp->tm_zone = "GMT";                     // NON_ANSI
    00225           //tp->tm_gmtoff = 0L;                      // NON_ANSI
    00226           offsetCorr = -fgtimezone;
    00227         }
    00228
    00229       //offtime (timer, tp->tm_gmtoff - leap_correction, tp);
    00230       offtime (timer, offsetCorr - leap_correction, tp);
    00231       tp->tm_sec += leap_extra_secs;
    00232     }
    00233
    00234   //libc_lock_unlock (tzset_lock);
    00235
    00236   return tp;
    00237 }
    00238
    00239
    00240
    00241 /* the following stuff is adapted from the tzCode package */
    00242
    00243 static size_t   longest;
    00244 static char *   abbr (struct tm * tmp);
    00245
    00246 void show(const char *zone, time_t t, int v)
    00247 {
    00248         struct tm *     tmp;
    00249
    00250         (void) printf("%-*s  ", (int) longest, zone);
    00251         if (v)
    00252                 (void) printf("%.24s UTC = ", asctime(gmtime(&t)));
    00253         tmp = fgLocaltime(&t, zone);
    00254         (void) printf("%.24s", asctime(tmp));
    00255         if (*abbr(tmp) != '\0')
    00256                 (void) printf(" %s", abbr(tmp));
    00257         if (v) {
    00258                 (void) printf(" isdst=%d", tmp->tm_isdst);
    00259 #ifdef TM_GMTOFF
    00260                 (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
    00261 #endif /* defined TM_GMTOFF */
    00262         }
    00263         (void) printf("\n");
    00264 }
    00265
    00266 static char *abbr(struct tm *tmp)
    00267 {
    00268         register char * result;
    00269         static char     nada;
    00270
    00271         if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
    00272                 return &nada;
    00273         result = fgtzname[tmp->tm_isdst];
    00274         return (result == NULL) ? &nada : result;
    00275 }
    00276
    00277
    00278
    00279 /***********************************************************************/
    00280
    00281
    00282 /* Interpret the TZ envariable.  */
    00283 static void fgtzset_internal (int always, const char *tz)
    00284 {
    00285   time_t now;
    00286   time(&now);
    00287   static int is_initialized = 0;
    00288   //register const char *tz;
    00289   // register size_t l;
    00290   // char *tzbuf;
    00291   // unsigned short int hh, mm, ss;
    00292   // unsigned short int whichrule;
    00293
    00294   if (is_initialized && !always)
    00295     return;
    00296   is_initialized = 1;
    00297
    00298   /* Examine the TZ environment variable.  */
    00299   //tz = getenv ("TZ");
    00300   if (tz == NULL)
    00301     /* No user specification; use the site-wide default.  */
    00302     tz = TZDEFAULT;
    00303   else if (*tz == '\0')
    00304     /* User specified the empty string; use UTC explicitly.  */
    00305     tz = "Universal";
    00306
    00307 #ifdef macintosh
    00308   /* as you well know, mac paths contain leading colon, this code
    00309      messes things up.... */
    00310 #else
    00311   /* A leading colon means "implementation defined syntax".
    00312      We ignore the colon and always use the same algorithm:
    00313      try a data file, and if none exists parse the 1003.1 syntax.  */
    00314   if (tz && *tz == ':')
    00315     ++tz;
    00316 #endif
    00317
    00318   /* Check whether the value changes since the last run.  */
    00319   if (old_fgtz != NULL && tz != NULL && strcmp (tz, old_fgtz) == 0)
    00320     /* No change, simply return.  */
    00321     return;
    00322
    00323   fgtz_rules[0].name = NULL;
    00324   fgtz_rules[1].name = NULL;
    00325
    00326   /* Save the value of `tz'.  */
    00327   if (old_fgtz != NULL)
    00328     free (old_fgtz);
    00329   old_fgtz = tz ? strdup (tz) : NULL;
    00330
    00331   /* Try to read a data file.  */
    00332   fgtzfile_read (tz);
    00333   if (use_fgtzfile)
    00334     return;
    00335   // The default behaviour of the originale tzset_internal (int always, char* tz)
    00336   // function is to set up a default timezone, in any casetz file_read() fails
    00337   // Currently this leads to problems, because it modidifies the system timezone
    00338   // and not the local aircraft timezone, contained in FlightGear. I could adapt
    00339   // this in future versions of this code, but doubt whether this is what we really
    00340   // want. So right now, exit when timezone information reading failed.
    00341   // Guess I'll change that to something like 12 * (FG_LON / 180.0)
    00342   //
    00343   // For now, I'll leave it like this.
    00344   else
    00345   {
    00346     printf ("Timezone reading failed\n");
    00347     exit(1);
    00348   }
    00349   // this emacs "comment out" function is cool!
    00350
    00351 //   // /* No data file found.  Default to UTC if nothing specified.  */
    00352 // //   printf ("1. Current local time          = %24s", asctime(localtime(&now)));
    00353 //   if (tz == NULL || *tz == '\0')
    00354 //     {
    00355 //       fgtz_rules[0].name = fgtz_rules[1].name = "UTC";
    00356 //       fgtz_rules[0].type = fgtz_rules[1].type = fgtz_rule::J0;
    00357 //       fgtz_rules[0].m = fgtz_rules[0].n = fgtz_rules[0].d = 0;
    00358 //       fgtz_rules[1].m = fgtz_rules[1].n = fgtz_rules[1].d = 0;
    00359 //       fgtz_rules[0].secs = fgtz_rules[1].secs = 0;
    00360 //       fgtz_rules[0].offset = fgtz_rules[1].offset = 0L;
    00361 //       fgtz_rules[0].change = fgtz_rules[1].change = (time_t) -1;
    00362 //       fgtz_rules[0].computed_for = fgtz_rules[1].computed_for = 0;
    00363 //       return;
    00364 //     }
    00365
    00366 //   /* Clear out old state and reset to unnamed UTC.  */
    00367 //   //printf ("2. Current local time          = %24s", asctime(localtime(&now)));
    00368 //   memset (fgtz_rules, 0, sizeof fgtz_rules);
    00369 //   fgtz_rules[0].name = fgtz_rules[1].name = "";
    00370
    00371 //   /* Get the standard timezone name.  */
    00372 //   tzbuf = malloc (strlen (tz) + 1);
    00373 //   if (! tzbuf)
    00374 //     {
    00375 //       /* Clear the old tz name so we will try again.  */
    00376 //       free (old_fgtz);
    00377 //       old_fgtz = NULL;
    00378 //       return;
    00379 //     }
    00380 //   //printf ("3. Current local time          = %24s", asctime(localtime(&now)));
    00381 //   if (sscanf (tz, "%[^0-9,+-]", tzbuf) != 1 ||
    00382 //       (l = strlen (tzbuf)) < 3)
    00383 //     {
    00384 //       free (tzbuf);
    00385 //       return;
    00386 //     }
    00387
    00388 //   fgtz_rules[0].name = tzstring (tzbuf);
    00389
    00390 //   tz += l;
    00391 //   //printf ("4. Current local time          = %24s", asctime(localtime(&now)));
    00392 //   /* Figure out the standard offset from UTC.  */
    00393 //   if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
    00394 //     {
    00395 //       free (tzbuf);
    00396 //       return;
    00397 //     }
    00398 //   //printf ("5. Current local time          = %24s", asctime(localtime(&now)));
    00399 //   if (*tz == '-' || *tz == '+')
    00400 //     fgtz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
    00401 //   else
    00402 //     fgtz_rules[0].offset = -1L;
    00403 //   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
    00404 //     {
    00405 //     default:
    00406 //       free (tzbuf);
    00407 //       return;
    00408 //     case 1:
    00409 //       mm = 0;
    00410 //     case 2:
    00411 //       ss = 0;
    00412 //     case 3:
    00413 //       break;
    00414 //     }
    00415 //     //printf ("6. Current local time          = %24s", asctime(localtime(&now)));
    00416 //   fgtz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
    00417 //                       (min (hh, 23) * 60 * 60));
    00418
    00419 //   for (l = 0; l < 3; ++l)
    00420 //     {
    00421 //       while (isdigit(*tz))
    00422 //      ++tz;
    00423 //       if (l < 2 && *tz == ':')
    00424 //      ++tz;
    00425 //     }
    00426 //   //printf ("7. Current local time          = %24s", asctime(localtime(&now)));
    00427 //   /* Get the DST timezone name (if any).  */
    00428 //   if (*tz != '\0')
    00429 //     {
    00430 //       char *n = tzbuf + strlen (tzbuf) + 1;
    00431 //       if (sscanf (tz, "%[^0-9,+-]", n) != 1 ||
    00432 //        (l = strlen (n)) < 3)
    00433 //      goto done_names;        /* Punt on name, set up the offsets.  */
    00434 //   //printf ("7.1 Current local time          = %24s", asctime(localtime(&now)));
    00435 //       fgtz_rules[1].name = tzstring (n);
    00436
    00437 //       tz += l;
    00438
    00439 //       /* Figure out the DST offset from GMT.  */
    00440 //       if (*tz == '-' || *tz == '+')
    00441 //      fgtz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
    00442 //       else
    00443 //      fgtz_rules[1].offset = -1L;
    00444 //   //printf ("7.2 Current local time          = %24s", asctime(localtime(&now)));
    00445 //       switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
    00446 //      {
    00447 //      default:
    00448 //        /* Default to one hour later than standard time.  */
    00449 //        fgtz_rules[1].offset = fgtz_rules[0].offset + (60 * 60);
    00450 //        break;
    00451
    00452 //      case 1:
    00453 //        mm = 0;
    00454 //      case 2:
    00455 //        ss = 0;
    00456 //      case 3:
    00457 //        fgtz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
    00458 //                               (min (hh, 23) * (60 * 60)));
    00459 //        break;
    00460 //      }
    00461 //   //printf ("7.3 Current local time          = %24s", asctime(localtime(&now)));
    00462 //       for (l = 0; l < 3; ++l)
    00463 //      {
    00464 //        while (isdigit (*tz))
    00465 //          ++tz;
    00466 //        if (l < 2 && *tz == ':')
    00467 //          ++tz;
    00468 //      }
    00469 //   //printf ("7.4 Current local time          = %24s", asctime(localtime(&now)));
    00470 //       if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
    00471 //      {
    00472 //        /* There is no rule.  See if there is a default rule file.  */
    00473 //   //printf ("7.4.1 Current local time          = %24s", asctime(localtime(&now)));
    00474 //        tzfile_default (fgtz_rules[0].name, fgtz_rules[1].name,
    00475 //                          fgtz_rules[0].offset, fgtz_rules[1].offset);
    00476 //   //printf ("7.4.2 Current local time          = %24s", asctime(localtime(&now)));
    00477 //        if (use_fgtzfile)
    00478 //          {
    00479 //            free (old_fgtz);
    00480 //            old_fgtz = NULL;
    00481 //            free (tzbuf);
    00482 //            return;
    00483 //          }
    00484 //      }
    00485 //     }
    00486 //   else
    00487 //     {
    00488 //       /* There is no DST.  */
    00489 //       fgtz_rules[1].name = fgtz_rules[0].name;
    00490 //       free (tzbuf);
    00491 //       return;
    00492 //     }
    00493 //   //printf ("7.5 Current local time          = %24s", asctime(localtime(&now)));
    00494 //  done_names:
    00495 //   //printf ("8. Current local time          = %24s", asctime(localtime(&now)));
    00496 //   free (tzbuf);
    00497
    00498 //   /* Figure out the standard <-> DST rules.  */
    00499 //   for (whichrule = 0; whichrule < 2; ++whichrule)
    00500 //     {
    00501 //       register fgtz_rule *tzr = &fgtz_rules[whichrule];
    00502
    00503 //       /* Ignore comma to support string following the incorrect
    00504 //       specification in early POSIX.1 printings.  */
    00505 //       tz += *tz == ',';
    00506
    00507 //       /* Get the date of the change.  */
    00508 //       if (*tz == 'J' || isdigit (*tz))
    00509 //      {
    00510 //        char *end;
    00511 //        tzr->type = *tz == 'J' ? fgtz_rule::J1 : fgtz_rule::J0;
    00512 //        if (tzr->type == fgtz_rule::J1 && !isdigit (*++tz))
    00513 //          return;
    00514 //        tzr->d = (unsigned short int) strtoul (tz, &end, 10);
    00515 //        if (end == tz || tzr->d > 365)
    00516 //          return;
    00517 //        else if (tzr->type == fgtz_rule::J1 && tzr->d == 0)
    00518 //          return;
    00519 //        tz = end;
    00520 //      }
    00521 //       else if (*tz == 'M')
    00522 //      {
    00523 //        int n;
    00524 //        tzr->type = fgtz_rule::M;
    00525 //        if (sscanf (tz, "M%hu.%hu.%hu%n",
    00526 //                    &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
    00527 //            tzr->m < 1 || tzr->m > 12 ||
    00528 //            tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
    00529 //          return;
    00530 //        tz += n;
    00531 //      }
    00532 //       else if (*tz == '\0')
    00533 //      {
    00534 //        /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0".  */
    00535 //        tzr->type = fgtz_rule::M;
    00536 //        if (tzr == &fgtz_rules[0])
    00537 //          {
    00538 //            tzr->m = 4;
    00539 //            tzr->n = 1;
    00540 //            tzr->d = 0;
    00541 //          }
    00542 //        else
    00543 //          {
    00544 //            tzr->m = 10;
    00545 //            tzr->n = 5;
    00546 //            tzr->d = 0;
    00547 //          }
    00548 //      }
    00549 //       else
    00550 //      return;
    00551 //       //printf ("9. Current local time          = %24s", asctime(localtime(&now)));
    00552 //       if (*tz != '\0' && *tz != '/' && *tz != ',')
    00553 //      return;
    00554 //       else if (*tz == '/')
    00555 //      {
    00556 //        /* Get the time of day of the change.  */
    00557 //        ++tz;
    00558 //        if (*tz == '\0')
    00559 //          return;
    00560 //        switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
    00561 //          {
    00562 //          default:
    00563 //            hh = 2;           /* Default to 2:00 AM.  */
    00564 //          case 1:
    00565 //            mm = 0;
    00566 //          case 2:
    00567 //            ss = 0;
    00568 //          case 3:
    00569 //            break;
    00570 //          }
    00571 //        for (l = 0; l < 3; ++l)
    00572 //          {
    00573 //            while (isdigit (*tz))
    00574 //              ++tz;
    00575 //            if (l < 2 && *tz == ':')
    00576 //              ++tz;
    00577 //          }
    00578 //        tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
    00579 //      }
    00580 //       else
    00581 //      /* Default to 2:00 AM.  */
    00582 //      tzr->secs = 2 * 60 * 60;
    00583
    00584 //       tzr->computed_for = -1;
    00585 //     }
    00586 // //   printf ("10. Current local time          = %24s", asctime(localtime(&now)));
    00587 //
    00588 }
    00589
    00590 /************************************************************************/
    00591
    00592
    00593 /* Figure out the correct timezone for *TIMER and TM (which must be the same)
    00594    and set `tzname', `timezone', and `daylight' accordingly.
    00595    Return nonzero on success, zero on failure.  */
    00596 size_t fgtzname_cur_max;
    00597
    00598 static int fgtz_compute (time_t timer, const struct tm* tm)
    00599   //     time_t timer;
    00600   // const struct tm *tm;
    00601 {
    00602   if (! fgcompute_change (&fgtz_rules[0], 1900 + tm->tm_year) ||
    00603       ! fgcompute_change (&fgtz_rules[1], 1900 + tm->tm_year))
    00604     return 0;
    00605
    00606   fgdaylight = timer >= fgtz_rules[0].change && timer < fgtz_rules[1].change;
    00607   fgtimezone = -fgtz_rules[fgdaylight].offset;
    00608   fgtzname[0] = (char *) fgtz_rules[0].name;
    00609   fgtzname[1] = (char *) fgtz_rules[1].name;
    00610
    00611   {
    00612     /* Keep tzname_cur_max up to date.  */
    00613     size_t len0 = strlen (fgtzname[0]);
    00614     size_t len1 = strlen (fgtzname[1]);
    00615     if (len0 > fgtzname_cur_max)
    00616       fgtzname_cur_max = len0;
    00617     if (len1 > fgtzname_cur_max)
    00618       fgtzname_cur_max = len1;
    00619   }
    00620
    00621   return 1;
    00622 }
    00623
    00624 /**********************************************************************/
    00625
    00626 /* Figure out the exact time (as a time_t) in YEAR
    00627    when the change described by RULE will occur and
    00628    put it in RULE->change, saving YEAR in RULE->computed_for.
    00629    Return nonzero if successful, zero on failure.  */
    00630 static int fgcompute_change (fgtz_rule *rule, int year)
    00631   //     tz_rule *rule;
    00632   // int year;
    00633 {
    00634   register time_t t;
    00635   int y;
    00636
    00637   if (year != -1 && rule->computed_for == year)
    00638     /* Operations on times in 1969 will be slower.  Oh well.  */
    00639     return 1;
    00640
    00641   /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
    00642   t = 0;
    00643   for (y = 1970; y < year; ++y)
    00644     t += SECSPERDAY * (isleap (y) ? 366 : 365);
    00645
    00646   switch (rule->type)
    00647     {
    00648     case fgtz_rule::J1:
    00649       /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
    00650          In non-leap years, or if the day number is 59 or less, just
    00651          add SECSPERDAY times the day number-1 to the time of
    00652          January 1, midnight, to get the day.  */
    00653       t += (rule->d - 1) * SECSPERDAY;
    00654       if (rule->d >= 60 && isleap (year))
    00655         t += SECSPERDAY;
    00656       break;
    00657
    00658     case fgtz_rule::J0:
    00659       /* n - Day of year.
    00660          Just add SECSPERDAY times the day number to the time of Jan 1st.  */
    00661       t += rule->d * SECSPERDAY;
    00662       break;
    00663
    00664     case fgtz_rule::M:
    00665       /* Mm.n.d - Nth "Dth day" of month M.  */
    00666       {
    00667         register int i, d, m1, yy0, yy1, yy2, dow;
    00668         register const unsigned short int *myday =
    00669           &mon_yday[isleap (year)][rule->m];
    00670
    00671         /* First add SECSPERDAY for each day in months before M.  */
    00672         t += myday[-1] * SECSPERDAY;
    00673
    00674         /* Use Zeller's Congruence to get day-of-week of first day of month. */
    00675         m1 = (rule->m + 9) % 12 + 1;
    00676         yy0 = (rule->m <= 2) ? (year - 1) : year;
    00677         yy1 = yy0 / 100;
    00678         yy2 = yy0 % 100;
    00679         dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
    00680         if (dow < 0)
    00681           dow += 7;
    00682
    00683         /* DOW is the day-of-week of the first day of the month.  Get the
    00684            day-of-month (zero-origin) of the first DOW day of the month.  */
    00685         d = rule->d - dow;
    00686         if (d < 0)
    00687           d += 7;
    00688         for (i = 1; i < rule->n; ++i)
    00689           {
    00690             if (d + 7 >= myday[0] - myday[-1])
    00691               break;
    00692             d += 7;
    00693           }
    00694
    00695         /* D is the day-of-month (zero-origin) of the day we want.  */
    00696         t += d * SECSPERDAY;
    00697       }
    00698       break;
    00699     }
    00700
    00701   /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
    00702      Just add the time of day and local offset from GMT, and we're done.  */
    00703
    00704   rule->change = t - rule->offset + rule->secs;
    00705   rule->computed_for = year;
    00706   return 1;
    00707 }
    00708
    00709 /*************************************************************************/
    00710
    00711 int fgtzfile_compute (time_t timer, int use_localtime,
    00712                   long int *leap_correct, int *leap_hit)
    00713 {
    00714   register size_t i;
    00715
    00716   if (use_localtime)
    00717     {
    00718       struct ttinfo *info = fgfind_transition (timer);
    00719       fgdaylight = info->isdst;
    00720       fgtimezone = -info->offset;
    00721       for (i = 0;
    00722            i < num_types && i < sizeof (fgtzname) / sizeof (fgtzname[0]);
    00723            ++i)
    00724         fgtzname[types[i].isdst] = &zone_names[types[i].idx];
    00725       if (info->isdst < sizeof (fgtzname) / sizeof (fgtzname[0]))
    00726         fgtzname[info->isdst] = &zone_names[info->idx];
    00727     }
    00728
    00729   *leap_correct = 0L;
    00730   *leap_hit = 0;
    00731
    00732   /* Find the last leap second correction transition time before TIMER.  */
    00733   i = num_leaps;
    00734   do
    00735     if (i-- == 0)
    00736       return 1;
    00737   while (timer < leaps[i].transition);
    00738
    00739   /* Apply its correction.  */
    00740   *leap_correct = leaps[i].change;
    00741
    00742   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
    00743       ((i == 0 && leaps[i].change > 0) ||
    00744        leaps[i].change > leaps[i - 1].change))
    00745     {
    00746       *leap_hit = 1;
    00747       while (i > 0 &&
    00748              leaps[i].transition == leaps[i - 1].transition + 1 &&
    00749              leaps[i].change == leaps[i - 1].change + 1)
    00750         {
    00751           ++*leap_hit;
    00752           --i;
    00753         }
    00754     }
    00755
    00756   return 1;
    00757 }
    00758
    00759 /**************************************************************************/
    00760
    00761 static struct ttinfo * fgfind_transition (time_t timer)
    00762 {
    00763   size_t i;
    00764
    00765   if (num_transitions == 0 || timer < transitions[0])
    00766     {
    00767       /* TIMER is before any transition (or there are no transitions).
    00768          Choose the first non-DST type
    00769          (or the first if they're all DST types).  */
    00770       i = 0;
    00771       while (i < num_types && types[i].isdst)
    00772         ++i;
    00773       if (i == num_types)
    00774         i = 0;
    00775     }
    00776   else
    00777     {
    00778       /* Find the first transition after TIMER, and
    00779          then pick the type of the transition before it.  */
    00780       for (i = 1; i < num_transitions; ++i)
    00781         if (timer < transitions[i])
    00782           break;
    00783       i = type_idxs[i - 1];
    00784     }
    00785
    00786   return &types[i];
    00787 }
    00788
    00789
    00790 /**************************************************************************/
    00791 void fgtzfile_read (const char *file)
    00792 {
    00793   // static const char default_tzdir[] = TZDIR;
    00794   size_t num_isstd, num_isgmt;
    00795   register FILE *f;
    00796   struct tzhead tzhead;
    00797   size_t chars;
    00798   register size_t i;
    00799   struct ttinfo *info;
    00800
    00801   use_fgtzfile = 0;
    00802
    00803   if (transitions != NULL)
    00804     free ((void *) transitions);
    00805   transitions = NULL;
    00806   if (type_idxs != NULL)
    00807     free ((void *) type_idxs);
    00808   type_idxs = NULL;
    00809   if (types != NULL)
    00810     free ((void *) types);
    00811   types = NULL;
    00812   if (zone_names != NULL)
    00813     free ((void *) zone_names);
    00814   zone_names = NULL;
    00815   if (leaps != NULL)
    00816     free ((void *) leaps);
    00817   leaps = NULL;
    00818
    00819   if (file == NULL)
    00820     /* No user specification; use the site-wide default.  */
    00821     file = TZDEFAULT;
    00822   else if (*file == '\0')
    00823     /* User specified the empty string; use UTC with no leap seconds.  */
    00824     return;
    00825   else
    00826     {
    00827       /* We must not allow to read an arbitrary file in a setuid
    00828          program.  So we fail for any file which is not in the
    00829          directory hierachy starting at TZDIR
    00830          and which is not the system wide default TZDEFAULT.  */
    00831       //if (libc_enable_secure
    00832       //  && ((*file == '/'
    00833       //       && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
    00834       //       && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
    00835       //      || strstr (file, "../") != NULL))
    00836         /* This test is certainly a bit too restrictive but it should
    00837            catch all critical cases.  */
    00838       //return;
    00839     }
    00840
    00841 //   if (*file != '/') // if a relative path is used, append what file points to
    00842 //                     // to the path indicated by TZDIR.
    00843 //     {
    00844 //       const char *tzdir;
    00845 //       unsigned int len, tzdir_len;
    00846 //       char *_new;
    00847
    00848 //       tzdir = getenv ("TZDIR");
    00849 //       if (tzdir == NULL || *tzdir == '\0')
    00850 //      {
    00851 //        tzdir = default_tzdir;
    00852 //        tzdir_len = sizeof (default_tzdir) - 1;
    00853 //      }
    00854 //       else
    00855 //      tzdir_len = strlen (tzdir);
    00856 //       len = strlen (file) + 1;
    00857 //       _new = (char *) alloca (tzdir_len + 1 + len);
    00858 //       memcpy (_new, tzdir, tzdir_len);
    00859 //       _new[tzdir_len] = '/';
    00860 //       memcpy (&_new[tzdir_len + 1], file, len);
    00861 //       file = _new;
    00862 //     }
    00863
    00864   f = fopen (file, "rb");
    00865
    00866   if (f == NULL) {
    00867       perror( "fgtzfile_read(): " );
    00868       errno = 0;
    00869       return;
    00870   }
    00871
    00872   if (fread ((void *) &tzhead, sizeof (tzhead), 1, f) != 1)
    00873     goto lose;
    00874
    00875   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
    00876   num_types = (size_t) decode (tzhead.tzh_typecnt);
    00877   chars = (size_t) decode (tzhead.tzh_charcnt);
    00878   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
    00879   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
    00880   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
    00881
    00882   if (num_transitions > 0)
    00883     {
    00884       transitions = (time_t *) malloc (num_transitions * sizeof(time_t));
    00885       if (transitions == NULL)
    00886         goto lose;
    00887       type_idxs = (unsigned char *) malloc (num_transitions);
    00888       if (type_idxs == NULL)
    00889         goto lose;
    00890     }
    00891   if (num_types > 0)
    00892     {
    00893       types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
    00894       if (types == NULL)
    00895         goto lose;
    00896     }
    00897   if (chars > 0)
    00898     {
    00899       zone_names = (char *) malloc (chars);
    00900       if (zone_names == NULL)
    00901         goto lose;
    00902     }
    00903   if (num_leaps > 0)
    00904     {
    00905       leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
    00906       if (leaps == NULL)
    00907         goto lose;
    00908     }
    00909
    00910   if (sizeof (time_t) < 4)
    00911       abort ();
    00912
    00913   if (fread(transitions, 4, num_transitions, f) != num_transitions ||
    00914       fread(type_idxs, 1, num_transitions, f) != num_transitions)
    00915     goto lose;
    00916
    00917   /* Check for bogus indices in the data file, so we can hereafter
    00918      safely use type_idxs[T] as indices into `types' and never crash.  */
    00919   for (i = 0; i < num_transitions; ++i)
    00920     if (type_idxs[i] >= num_types)
    00921       goto lose;
    00922
    00923   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
    00924     {
    00925       /* Decode the transition times, stored as 4-byte integers in
    00926          network (big-endian) byte order.  We work from the end of
    00927          the array so as not to clobber the next element to be
    00928          processed when sizeof (time_t) > 4.  */
    00929       i = num_transitions;
    00930       while (i-- > 0)
    00931         transitions[i] = decode ((char *) transitions + i*4);
    00932     }
    00933
    00934   for (i = 0; i < num_types; ++i)
    00935     {
    00936       unsigned char x[4];
    00937       if (fread (x, 1, 4, f) != 4 ||
    00938           fread (&types[i].isdst, 1, 1, f) != 1 ||
    00939           fread (&types[i].idx, 1, 1, f) != 1)
    00940         goto lose;
    00941       if (types[i].idx >= chars) /* Bogus index in data file.  */
    00942         goto lose;
    00943       types[i].offset = (long int) decode (x);
    00944     }
    00945
    00946   if (fread (zone_names, 1, chars, f) != chars)
    00947     goto lose;
    00948
    00949   for (i = 0; i < num_leaps; ++i)
    00950     {
    00951       unsigned char x[4];
    00952       if (fread (x, 1, sizeof (x), f) != sizeof (x))
    00953         goto lose;
    00954       leaps[i].transition = (time_t) decode (x);
    00955       if (fread (x, 1, sizeof (x), f) != sizeof (x))
    00956         goto lose;
    00957       leaps[i].change = (long int) decode (x);
    00958     }
    00959
    00960   for (i = 0; i < num_isstd; ++i)
    00961     {
    00962       int c = getc (f);
    00963       if (c == EOF)
    00964         goto lose;
    00965       types[i].isstd = c != 0;
    00966     }
    00967   while (i < num_types)
    00968     types[i++].isstd = 0;
    00969
    00970   for (i = 0; i < num_isgmt; ++i)
    00971     {
    00972       int c = getc (f);
    00973       if (c == EOF)
    00974         goto lose;
    00975       types[i].isgmt = c != 0;
    00976     }
    00977   while (i < num_types)
    00978     types[i++].isgmt = 0;
    00979
    00980   fclose (f);
    00981
    00982   info = fgfind_transition (0);
    00983   for (i = 0; i < num_types && i < sizeof (fgtzname) / sizeof (fgtzname[0]);
    00984        ++i)
    00985     fgtzname[types[i].isdst] = tzstring (&zone_names[types[i].idx]);
    00986   if (info->isdst < sizeof (fgtzname) / sizeof (fgtzname[0]))
    00987     fgtzname[info->isdst] = tzstring (&zone_names[info->idx]);
    00988
    00989   fgcompute_tzname_max (chars);
    00990
    00991   use_fgtzfile = 1;
    00992   return;
    00993
    00994  lose:;
    00995   fclose(f);
    00996 }
    00997
    00998 /****************************************************************************/
    00999 static void fgcompute_tzname_max (size_t chars)
    01000 {
    01001   // extern size_t tzname_cur_max; /* Defined in tzset.c. */
    01002
    01003   const char *p;
    01004
    01005   p = zone_names;
    01006   do
    01007     {
    01008       const char *start = p;
    01009       while (*p != '\0')
    01010         ++p;
    01011       if ((size_t) (p - start) > fgtzname_cur_max)
    01012         fgtzname_cur_max = p - start;
    01013     } while (++p < &zone_names[chars]);
    01014 }
    01015
    01016 /**************************************************************************/
    01017
    01018 //#include <endian.h>
    01019
    01020 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
    01021 static inline int decode (const void *ptr)
    01022 {
    01023   if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
    01024     return *(const int *) ptr;
    01025   else
    01026     {
    01027       const unsigned char *p = (unsigned char *)ptr;
    01028       int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
    01029
    01030       result = (result << 8) | *p++;
    01031       result = (result << 8) | *p++;
    01032       result = (result << 8) | *p++;
    01033       result = (result << 8) | *p++;
    01034
    01035       return result;
    01036     }
    01037 }
    01038
    01039
    01040
    01041 #define SECS_PER_HOUR   (60 * 60)
    01042 #define SECS_PER_DAY    (SECS_PER_HOUR * 24)
    01043
    01044 /* Compute the `struct tm' representation of *T,
    01045    offset OFFSET seconds east of UTC,
    01046    and store year, yday, mon, mday, wday, hour, min, sec into *TP.  */
    01047
    01048 void offtime (const time_t *t, long int offset, struct tm *tp)
    01049   //    const time_t *t;
    01050   // long int offset;
    01051   // struct tm *tp;
    01052 {
    01053   register long int days, rem, y;
    01054   register const unsigned short int *ip;
    01055
    01056   days = *t / SECS_PER_DAY;
    01057   rem = *t % SECS_PER_DAY;
    01058   rem += offset;
    01059   while (rem < 0)
    01060     {
    01061       rem += SECS_PER_DAY;
    01062       --days;
    01063     }
    01064   while (rem >= SECS_PER_DAY)
    01065     {
    01066       rem -= SECS_PER_DAY;
    01067       ++days;
    01068     }
    01069   tp->tm_hour = rem / SECS_PER_HOUR;
    01070   rem %= SECS_PER_HOUR;
    01071   tp->tm_min = rem / 60;
    01072   tp->tm_sec = rem % 60;
    01073   /* January 1, 1970 was a Thursday.  */
    01074   tp->tm_wday = (4 + days) % 7;
    01075   if (tp->tm_wday < 0)
    01076     tp->tm_wday += 7;
    01077   y = 1970;
    01078
    01079 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
    01080
    01081   while (days < 0 || days >= (isleap (y) ? 366 : 365))
    01082     {
    01083       /* Guess a corrected year, assuming 365 days per year.  */
    01084       long int yg = y + days / 365 - (days % 365 < 0);
    01085
    01086       /* Adjust DAYS and Y to match the guessed year.  */
    01087       days -= ((yg - y) * 365
    01088                + LEAPS_THRU_END_OF (yg - 1)
    01089                - LEAPS_THRU_END_OF (y - 1));
    01090       y = yg;
    01091     }
    01092   tp->tm_year = y - 1900;
    01093   tp->tm_yday = days;
    01094   ip = mon_yday[isleap(y)];
    01095   for (y = 11; days < ip[y]; --y)
    01096     continue;
    01097   days -= ip[y];
    01098   tp->tm_mon = y;
    01099   tp->tm_mday = days + 1;
    01100 }
    01101
    01102 /* Allocate a time zone string with given contents.
    01103    The string will never be moved or deallocated.
    01104    However, its contents may be shared with other such strings.  */
    01105 char *tzstring (const char* string)
    01106   //const char *string;
    01107 {
    01108   struct tzstring_head *h = &tzstring_list.head;
    01109   size_t needed;
    01110   char *p;
    01111
    01112   /* Look through time zone string list for a duplicate of this one.  */
    01113   for (h = &tzstring_list.head;  ;  h = h->next)
    01114     {
    01115       for (p = (char *) (h + 1);  p[0] | p[1];  ++p)
    01116         if (strcmp (p, string) == 0)
    01117           return p;
    01118       if (! h->next)
    01119         break;
    01120     }
    01121
    01122   /* No duplicate was found.  Copy to the end of this buffer if there's room;
    01123      otherwise, append a large-enough new buffer to the list and use it.  */
    01124   ++p;
    01125   needed = strlen (string) + 2; /* Need 2 trailing '\0's after last string.  */
    01126
    01127   if ((size_t) ((char *) (h + 1) + tzstring_last_buffer_size - p) < needed)
    01128     {
    01129       size_t buffer_size = tzstring_last_buffer_size;
    01130       while ((buffer_size *= 2) < needed)
    01131         continue;
    01132       if (! (h = h->next = (struct tzstring_head *)malloc (sizeof *h + buffer_size)))
    01133         return NULL;
    01134       h->next = NULL;
    01135       tzstring_last_buffer_size = buffer_size;
    01136       p = (char *) (h + 1);
    01137     }
    01138
    01139   return strncpy (p, string, needed);
    01140 }

@ 1.3 log @Oops, try again. @ text @d1149 1 a1149 1