misc.c

Go to the documentation of this file.
00001 /*
00002  * misc - data and miscellaneous routines
00003  */
00004 /* $Header: /opt/proj/minix/cvsroot/src/lib/ansi/misc.c,v 1.2 2005/06/17 13:00:04 jnherder Exp $ */
00005 
00006 #include        <ctype.h>
00007 #include        <time.h>
00008 #include        <stdlib.h>
00009 #include        <string.h>
00010 
00011 #if     defined(__BSD4_2)
00012 
00013 struct timeval {
00014         long    tv_sec;         /* seconds */
00015         long    tv_usec;        /* and microseconds */
00016 };
00017 
00018 struct timezone {
00019         int     tz_minuteswest; /* minutes west of Greenwich */
00020         int     tz_dsttime;     /* type of dst correction */
00021 };
00022 
00023 int _gettimeofday(struct timeval *tp, struct timezone *tzp);
00024 
00025 #elif   !defined(_POSIX_SOURCE) && !defined(__USG)
00026 #if     !defined(_MINIX)                /* MINIX has no ftime() */
00027 struct timeb {
00028         long    time;
00029         unsigned short millitm;
00030         short   timezone;
00031         short   dstflag;
00032 };
00033 void _ftime(struct timeb *bp);
00034 #endif
00035 #endif
00036 
00037 #include        "loc_time.h"
00038 
00039 #define RULE_LEN        120
00040 #define TZ_LEN          10
00041 
00042 /* Make sure that the strings do not end up in ROM.
00043  * These strings probably contain the wrong value, and we cannot obtain the
00044  * right value from the system. TZ is the only help.
00045  */
00046 static char ntstr[TZ_LEN + 1] = "GMT";  /* string for normal time */
00047 static char dststr[TZ_LEN + 1] = "GDT"; /* string for daylight saving */
00048 
00049 long    _timezone = 0;
00050 long    _dst_off = 60 * 60;
00051 int     _daylight = 0;
00052 char    *_tzname[2] = {ntstr, dststr};
00053 
00054 #if     defined(__USG) || defined(_POSIX_SOURCE)
00055 char    *tzname[2] = {ntstr, dststr};
00056 
00057 #if     defined(__USG)
00058 long    timezone = 0;
00059 int     daylight = 0;
00060 #endif
00061 #endif
00062 
00063 static struct dsttype {
00064         char ds_type;           /* Unknown, Julian, Zero-based or M */
00065         int ds_date[3];         /* months, weeks, days */
00066         long ds_sec;            /* usually 02:00:00 */
00067 }       dststart = { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
00068         , dstend = { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
00069 
00070 const char *_days[] = {
00071                         "Sunday", "Monday", "Tuesday", "Wednesday",
00072                         "Thursday", "Friday", "Saturday"
00073                 };
00074 
00075 const char *_months[] = {
00076                         "January", "February", "March",
00077                         "April", "May", "June",
00078                         "July", "August", "September",
00079                         "October", "November", "December"
00080                 };
00081 
00082 const int _ytab[2][12] = {
00083                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00084                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00085         };
00086 
00087 static const char *
00088 parseZoneName(register char *buf, register const char *p)
00089 {
00090         register int n = 0;
00091 
00092         if (*p == ':') return NULL;
00093         while (*p && !isdigit(*p) && *p != ',' && *p != '-' && *p != '+') {
00094                 if (n < TZ_LEN)
00095                         *buf++ = *p;
00096                 p++;
00097                 n++;
00098         }
00099         if (n < 3) return NULL;                         /* error */
00100         *buf = '\0';
00101         return p;
00102 }
00103 
00104 static const char *
00105 parseTime(register long *tm, const char *p, register struct dsttype *dst)
00106 {
00107         register int n = 0;
00108         register const char *q = p;
00109         char ds_type = (dst ? dst->ds_type : '\0');
00110 
00111         if (dst) dst->ds_type = 'U';
00112 
00113         *tm = 0;
00114         while(*p >= '0' && *p <= '9') {
00115                 n = 10 * n + (*p++ - '0');
00116         }
00117         if (q == p) return NULL;        /* "The hour shall be required" */
00118         if (n < 0 || n >= 24)   return NULL;
00119         *tm = n * 60 * 60;
00120         if (*p == ':') {
00121                 p++;
00122                 n = 0;
00123                 while(*p >= '0' && *p <= '9') {
00124                         n = 10 * n + (*p++ - '0');
00125                 }
00126                 if (q == p) return NULL;        /* format error */
00127                 if (n < 0 || n >= 60)   return NULL;
00128                 *tm += n * 60;
00129                 if (*p == ':') {
00130                         p++;
00131                         n = 0;
00132                         while(*p >= '0' && *p <= '9') {
00133                                 n = 10 * n + (*p++ - '0');
00134                         }
00135                         if (q == p) return NULL;        /* format error */
00136                         if (n < 0 || n >= 60)   return NULL;
00137                         *tm += n;
00138                 }
00139         }
00140         if (dst) {
00141                 dst->ds_type = ds_type;
00142                 dst->ds_sec = *tm;
00143         }
00144         return p;
00145 }
00146 
00147 static const char *
00148 parseDate(register char *buf, register const char *p, struct dsttype *dstinfo)
00149 {
00150         register const char *q;
00151         register int n = 0;
00152         int cnt = 0;
00153         const int bnds[3][2] =  {       { 1, 12 },
00154                                         { 1, 5 },
00155                                         { 0, 6}
00156                                  };
00157         char ds_type;
00158 
00159         if (*p != 'M') {
00160                 if (*p == 'J') {
00161                         *buf++ = *p++;
00162                         ds_type = 'J';
00163                 }
00164                 else    ds_type = 'Z';
00165                 q = p;
00166                 while(*p >= '0' && *p <= '9') {
00167                         n = 10 * n + (*p - '0');
00168                         *buf++ = *p++;
00169                 }
00170                 if (q == p) return NULL;        /* format error */
00171                 if (n < (ds_type == 'J') || n > 365) return NULL;
00172                 dstinfo->ds_type = ds_type;
00173                 dstinfo->ds_date[0] = n;
00174                 return p;
00175         }
00176         ds_type = 'M';
00177         do {
00178                 *buf++ = *p++;
00179                 q = p;
00180                 n = 0;
00181                 while(*p >= '0' && *p <= '9') {
00182                         n = 10 * n + (*p - '0');
00183                         *buf++ = *p++;
00184                 }
00185                 if (q == p) return NULL;        /* format error */
00186                 if (n < bnds[cnt][0] || n > bnds[cnt][1]) return NULL;
00187                 dstinfo->ds_date[cnt] = n;
00188                 cnt++;
00189         } while (cnt < 3 && *p == '.');
00190         if (cnt != 3) return NULL;
00191         *buf = '\0';
00192         dstinfo->ds_type = ds_type;
00193         return p;
00194 }
00195 
00196 static const char *
00197 parseRule(register char *buf, register const char *p)
00198 {
00199         long time;
00200         register const char *q;
00201 
00202         if (!(p = parseDate(buf, p, &dststart))) return NULL;
00203         buf += strlen(buf);
00204         if (*p == '/') {
00205                 q = ++p;
00206                 if (!(p = parseTime(&time, p, &dststart))) return NULL;
00207                 while( p != q) *buf++ = *q++;
00208         }
00209         if (*p != ',') return NULL;
00210         p++;
00211         if (!(p = parseDate(buf, p, &dstend))) return NULL;
00212         buf += strlen(buf);
00213         if (*p == '/') {
00214                 q = ++p;
00215                 if (!(p = parseTime(&time, p, &dstend))) return NULL;
00216                 while(*buf++ = *q++);
00217         }
00218         if (*p) return NULL;
00219         return p;
00220 }
00221 
00222 /* The following routine parses timezone information in POSIX-format. For
00223  * the requirements, see IEEE Std 1003.1-1988 section 8.1.1.
00224  * The function returns as soon as it spots an error.
00225  */
00226 static void
00227 parseTZ(const char *p)
00228 {
00229         long tz, dst = 60 * 60, sign = 1;
00230         static char lastTZ[2 * RULE_LEN];
00231         static char buffer[RULE_LEN];
00232 
00233         if (!p) return;
00234 
00235         if (*p == ':') {
00236                 /*
00237                  * According to POSIX, this is implementation defined.
00238                  * Since it depends on the particular operating system, we
00239                  * can do nothing.
00240                  */
00241                 return;
00242         }
00243 
00244         if (!strcmp(lastTZ, p)) return;         /* nothing changed */
00245 
00246         *_tzname[0] = '\0';
00247         *_tzname[1] = '\0';
00248         dststart.ds_type = 'U';
00249         dststart.ds_sec = 2 * 60 * 60;
00250         dstend.ds_type = 'U';
00251         dstend.ds_sec = 2 * 60 * 60;
00252 
00253         if (strlen(p) > 2 * RULE_LEN) return;
00254         strcpy(lastTZ, p);
00255 
00256         if (!(p = parseZoneName(buffer, p))) return;
00257 
00258         if (*p == '-') {
00259                 sign = -1;
00260                 p++;
00261         } else if (*p == '+') p++;
00262 
00263         if (!(p = parseTime(&tz, p, NULL))) return;
00264         tz *= sign;
00265         _timezone = tz;
00266         strncpy(_tzname[0], buffer, TZ_LEN);
00267 
00268         if (!(_daylight = (*p != '\0'))) return;
00269 
00270         buffer[0] = '\0';
00271         if (!(p = parseZoneName(buffer, p))) return;
00272         strncpy(_tzname[1], buffer, TZ_LEN);
00273 
00274         buffer[0] = '\0';
00275         if (*p && (*p != ','))
00276                 if (!(p = parseTime(&dst, p, NULL))) return;
00277         _dst_off = dst;                 /* dst was initialized to 1 hour */
00278         if (*p) {
00279                 if (*p != ',') return;
00280                 p++;
00281                 if (strlen(p) > RULE_LEN) return;
00282                 if (!(p = parseRule(buffer, p))) return;
00283         }
00284 }
00285 
00286 void
00287 _tzset(void)
00288 {
00289 #if     defined(__BSD4_2)
00290 
00291         struct timeval tv;
00292         struct timezone tz;
00293 
00294         _gettimeofday(&tv, &tz);
00295         _daylight = tz.tz_dsttime;
00296         _timezone = tz.tz_minuteswest * 60L;
00297 
00298 #elif   !defined(_POSIX_SOURCE) && !defined(__USG)
00299 
00300 #if     !defined(_MINIX)                /* MINIX has no ftime() */
00301         struct timeb time;
00302 
00303         _ftime(&time);
00304         _timezone = time.timezone * 60L;
00305         _daylight = time.dstflag;
00306 #endif
00307 
00308 #endif  /* !_POSIX_SOURCE && !__USG */
00309 
00310         parseTZ(getenv("TZ"));          /* should go inside #if */
00311 
00312 #if     defined(__USG) || defined(_POSIX_SOURCE)
00313         tzname[0] = _tzname[0];
00314         tzname[1] = _tzname[1];
00315 #if     defined(__USG)
00316         timezone = _timezone;
00317         daylight = _daylight;
00318 #endif
00319 #endif  /* __USG || _POSIX_SOURCE */
00320 }
00321 
00322 static int
00323 last_sunday(register int day, register struct tm *timep)
00324 {
00325         int first = FIRSTSUNDAY(timep);
00326 
00327         if (day >= 58 && LEAPYEAR(YEAR0 + timep->tm_year)) day++;
00328         if (day < first) return first;
00329         return day - (day - first) % 7;
00330 }
00331 
00332 static int
00333 date_of(register struct dsttype *dst, struct tm *timep)
00334 {
00335         int leap = LEAPYEAR(YEAR0 + timep->tm_year);
00336         int firstday, tmpday;
00337         register int day, month;
00338 
00339         if (dst->ds_type != 'M') {
00340                 return dst->ds_date[0] -
00341                             (dst->ds_type == 'J'
00342                                 && leap
00343                                 && dst->ds_date[0] < 58);
00344         }
00345         day = 0;
00346         month = 1;
00347         while (month < dst->ds_date[0]) {
00348                 day += _ytab[leap][month - 1];
00349                 month++;
00350         }
00351         firstday = (day + FIRSTDAYOF(timep)) % 7;
00352         tmpday = day;
00353         day += (dst->ds_date[2] - firstday + 7) % 7
00354                 + 7 * (dst->ds_date[1] - 1);
00355         if (day >= tmpday + _ytab[leap][month-1]) day -= 7;
00356         return day;
00357 }
00358 
00359 /*
00360  * The default dst transitions are those for Western Europe (except Great
00361  * Britain). 
00362  */
00363 unsigned
00364 _dstget(register struct tm *timep)
00365 {
00366         int begindst, enddst;
00367         register struct dsttype *dsts = &dststart, *dste = &dstend;
00368         int do_dst = 0;
00369 
00370         if (_daylight == -1)
00371                 _tzset();
00372 
00373         timep->tm_isdst = _daylight;
00374         if (!_daylight) return 0;
00375 
00376         if (dsts->ds_type != 'U')
00377                 begindst = date_of(dsts, timep);
00378         else begindst = last_sunday(89, timep); /* last Sun before Apr */
00379         if (dste->ds_type != 'U')
00380                 enddst = date_of(dste, timep);
00381         else enddst = last_sunday(272, timep);  /* last Sun in Sep */
00382 
00383         /* assume begindst != enddst (otherwise it would be no use) */
00384         if (begindst < enddst) {                /* northern hemisphere */
00385                 if (timep->tm_yday > begindst && timep->tm_yday < enddst)
00386                         do_dst = 1;
00387         } else {                                /* southern hemisphere */
00388                 if (timep->tm_yday > begindst || timep->tm_yday < enddst)
00389                         do_dst = 1;
00390         }
00391 
00392         if (!do_dst
00393             && (timep->tm_yday == begindst || timep->tm_yday == enddst)) {
00394                 long dsttranssec;       /* transition when day is this old */
00395                 long cursec;
00396 
00397                 if (timep->tm_yday == begindst)
00398                         dsttranssec = dsts->ds_sec;
00399                 else    dsttranssec = dste->ds_sec;
00400                 cursec = ((timep->tm_hour * 60) + timep->tm_min) * 60L
00401                             + timep->tm_sec;
00402 
00403                 if ((timep->tm_yday == begindst && cursec >= dsttranssec)
00404                     || (timep->tm_yday == enddst && cursec < dsttranssec))
00405                         do_dst = 1;
00406         }
00407         if (do_dst) return _dst_off;
00408         timep->tm_isdst = 0;
00409         return 0;
00410 }

Generated on Fri Apr 14 22:56:47 2006 for minix by  doxygen 1.4.6