mux/src/timeutil.cpp

Go to the documentation of this file.
00001 
00017 #include "copyright.h"
00018 #include "autoconf.h"
00019 #include "config.h"
00020 #include "externs.h"
00021 
00022 // for tzset() and localtime()
00023 //
00024 #include <time.h>
00025 
00026 #include "timeutil.h"
00027 #include "stringutil.h"
00028 
00029 CMuxAlarm MuxAlarm;
00030 
00031 #ifdef SMALLEST_INT_GTE_NEG_QUOTIENT
00032 
00033 // The following functions provide a consistent division/modulus function
00034 // regardless of how the platform chooses to provide this function.
00035 //
00036 // Confused yet? Here's an example:
00037 //
00038 // SMALLEST_INT_GTE_NEG_QUOTIENT indicates that this platform computes
00039 // division and modulus like so:
00040 //
00041 //   -9/5 ==> -1 and -9%5 ==> -4
00042 //   and (-9/5)*5 + (-9%5) ==> -1*5 + -4 ==> -5 + -4 ==> -9
00043 //
00044 // The iMod() function uses this to provide LARGEST_INT_LTE_NEG_QUOTIENT
00045 // behavior (required by much math). This behavior computes division and
00046 // modulus like so:
00047 //
00048 //   -9/5 ==> -2 and -9%5 ==> 1
00049 //   and (-9/5)*5 + (-9%5) ==> -2*5 + 1 ==> -10 + 1 ==> -9
00050 //
00051 
00052 // Provide LLEQ modulus on a SGEQ platform.
00053 //
00054 int iMod(int x, int y)
00055 {
00056     if (y < 0)
00057     {
00058         if (x <= 0)
00059         {
00060             return x % y;
00061         }
00062         else
00063         {
00064             return ((x-1) % y) + y + 1;
00065         }
00066     }
00067     else
00068     {
00069         if (x < 0)
00070         {
00071             return ((x+1) % y) + y - 1;
00072         }
00073         else
00074         {
00075             return x % y;
00076         }
00077     }
00078 }
00079 
00080 INT64 i64Mod(INT64 x, INT64 y)
00081 {
00082     if (y < 0)
00083     {
00084         if (x <= 0)
00085         {
00086             return x % y;
00087         }
00088         else
00089         {
00090             return ((x-1) % y) + y + 1;
00091         }
00092     }
00093     else
00094     {
00095         if (x < 0)
00096         {
00097             return ((x+1) % y) + y - 1;
00098         }
00099         else
00100         {
00101             return x % y;
00102         }
00103     }
00104 }
00105 
00106 // Provide SGEQ modulus on a SGEQ platform.
00107 //
00108 DCL_INLINE int iRemainder(int x, int y)
00109 {
00110     return x % y;
00111 }
00112 
00113 // Provide SGEQ division on a SGEQ platform.
00114 //
00115 DCL_INLINE int iDivision(int x, int y)
00116 {
00117     return x / y;
00118 }
00119 
00120 // Provide LLEQ division on a SGEQ platform.
00121 //
00122 static int iFloorDivision(int x, int y)
00123 {
00124     if (y < 0)
00125     {
00126         if (x <= 0)
00127         {
00128             return x / y;
00129         }
00130         else
00131         {
00132             return (x - y - 1) / y;
00133         }
00134     }
00135     else
00136     {
00137         if (x < 0)
00138         {
00139             return (x - y + 1) / y;
00140         }
00141         else
00142         {
00143             return x / y;
00144         }
00145     }
00146 }
00147 
00148 INT64 i64FloorDivision(INT64 x, INT64 y)
00149 {
00150     if (y < 0)
00151     {
00152         if (x <= 0)
00153         {
00154             return x / y;
00155         }
00156         else
00157         {
00158             return (x - y - 1) / y;
00159         }
00160     }
00161     else
00162     {
00163         if (x < 0)
00164         {
00165             return (x - y + 1) / y;
00166         }
00167         else
00168         {
00169             return x / y;
00170         }
00171     }
00172 }
00173 
00174 int iFloorDivisionMod(int x, int y, int *piMod)
00175 {
00176     if (y < 0)
00177     {
00178         if (x <= 0)
00179         {
00180             *piMod = x % y;
00181             return x / y;
00182         }
00183         else
00184         {
00185             *piMod = ((x-1) % y) + y + 1;
00186             return (x - y - 1) / y;
00187         }
00188     }
00189     else
00190     {
00191         if (x < 0)
00192         {
00193             *piMod = ((x+1) % y) + y - 1;
00194             return (x - y + 1) / y;
00195         }
00196         else
00197         {
00198             *piMod = x % y;
00199             return x / y;
00200         }
00201     }
00202 }
00203 
00204 static INT64 i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod)
00205 {
00206     if (y < 0)
00207     {
00208         if (x <= 0)
00209         {
00210             *piMod = x % y;
00211             return x / y;
00212         }
00213         else
00214         {
00215             *piMod = ((x-1) % y) + y + 1;
00216             return (x - y - 1) / y;
00217         }
00218     }
00219     else
00220     {
00221         if (x < 0)
00222         {
00223             *piMod = ((x+1) % y) + y - 1;
00224             return (x - y + 1) / y;
00225         }
00226         else
00227         {
00228             *piMod = x % y;
00229             return x / y;
00230         }
00231     }
00232 }
00233 
00234 #if 0
00235 int iCeilingDivision(int x, int y)
00236 {
00237     if (x < 0)
00238     {
00239         return x / y;
00240     }
00241     else
00242     {
00243         return (x + y - 1) / y;
00244     }
00245 }
00246 
00247 INT64 i64CeilingDivision(INT64 x, INT64 y)
00248 {
00249     if (x < 0)
00250     {
00251         return x / y;
00252     }
00253     else
00254     {
00255         return (x + y - 1) / y;
00256     }
00257 }
00258 #endif // 0
00259 
00260 #else // LARGEST_INT_LTE_NEG_QUOTIENT
00261 
00262 // Provide LLEQ modulus on a LLEQ platform.
00263 //
00264 int DCL_INLINE iMod(int x, int y)
00265 {
00266     return x % y;
00267 }
00268 
00269 // Provide a SGEQ modulus on a LLEQ platform.
00270 //
00271 int iRemainder(int x, int y)
00272 {
00273     if (y < 0)
00274     {
00275         if (x <= 0)
00276         {
00277             return x % y;
00278         }
00279         else
00280         {
00281             return ((x+1) % y) - y - 1;
00282         }
00283     }
00284     else
00285     {
00286         if (x < 0)
00287         {
00288             return ((x-1) % y) - y + 1;
00289         }
00290         else
00291         {
00292             return x % y;
00293         }
00294     }
00295 }
00296 
00297 INT64 i64Remainder(INT64 x, INT64 y)
00298 {
00299     if (y < 0)
00300     {
00301         if (x <= 0)
00302         {
00303             return x % y;
00304         }
00305         else
00306         {
00307             return ((x+1) % y) - y - 1;
00308         }
00309     }
00310     else
00311     {
00312         if (x < 0)
00313         {
00314             return ((x-1) % y) - y + 1;
00315         }
00316         else
00317         {
00318             return x % y;
00319         }
00320     }
00321 }
00322 
00323 // Provide SGEQ division on a LLEQ platform.
00324 //
00325 int iDivision(int x, int y)
00326 {
00327     if (y < 0)
00328     {
00329         if (x <= 0)
00330         {
00331             return x / y;
00332         }
00333         else
00334         {
00335             return (x + y + 1) / y;
00336         }
00337     }
00338     else
00339     {
00340         if (x < 0)
00341         {
00342             return (x + y - 1) / y;
00343         }
00344         else
00345         {
00346             return x / y;
00347         }
00348     }
00349 }
00350 
00351 INT64 i64Division(INT64 x, INT64 y)
00352 {
00353     if (y < 0)
00354     {
00355         if (x <= 0)
00356         {
00357             return x / y;
00358         }
00359         else
00360         {
00361             return (x + y + 1) / y;
00362         }
00363     }
00364     else
00365     {
00366         if (x < 0)
00367         {
00368             return (x + y - 1) / y;
00369         }
00370         else
00371         {
00372             return x / y;
00373         }
00374     }
00375 }
00376 
00377 // Provide a LLEQ division on a LLEQ platform.
00378 //
00379 int DCL_INLINE iFloorDivision(int x, int y)
00380 {
00381     return x / y;
00382 }
00383 
00384 INT64 DCL_INLINE i64FloorDivisionMod(INT64 x, INT64 y, INT64 *piMod)
00385 {
00386     *piMod = x % y;
00387     return x / y;
00388 }
00389 #endif // LARGEST_INT_LTE_NEG_QUOTIENT
00390 
00391 #if 0
00392 static int iModAdjusted(int x, int y)
00393 {
00394     return iMod(x - 1, y) + 1;
00395 }
00396 
00397 static INT64 i64ModAdjusted(INT64 x, INT64 y)
00398 {
00399     return i64Mod(x - 1, y) + 1;
00400 }
00401 #endif // 0
00402 
00403 #ifdef WIN32
00404 const INT64 FACTOR_100NS_PER_SECOND = 10000000i64;
00405 #else // WIN32
00406 const INT64 FACTOR_100NS_PER_SECOND = 10000000ull;
00407 #endif // WIN32
00408 const INT64 FACTOR_100NS_PER_MINUTE = FACTOR_100NS_PER_SECOND*60;
00409 const INT64 FACTOR_100NS_PER_HOUR   = FACTOR_100NS_PER_MINUTE*60;
00410 const INT64 FACTOR_100NS_PER_DAY = FACTOR_100NS_PER_HOUR*24;
00411 const INT64 FACTOR_100NS_PER_WEEK = FACTOR_100NS_PER_DAY*7;
00412 
00413 int CLinearTimeAbsolute::m_nCount = 0;
00414 char CLinearTimeAbsolute::m_Buffer[204];
00415 char CLinearTimeDelta::m_Buffer[204];
00416 
00417 static void GetUTCLinearTime(INT64 *plt);
00418 
00419 bool operator<(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00420 {
00421     return lta.m_tAbsolute < ltb.m_tAbsolute;
00422 }
00423 
00424 bool operator>(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00425 {
00426     return lta.m_tAbsolute > ltb.m_tAbsolute;
00427 }
00428 
00429 bool operator==(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00430 {
00431     return lta.m_tAbsolute == ltb.m_tAbsolute;
00432 }
00433 
00434 bool operator==(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00435 {
00436     return lta.m_tDelta == ltb.m_tDelta;
00437 }
00438 
00439 bool operator!=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00440 {
00441     return lta.m_tDelta != ltb.m_tDelta;
00442 }
00443 
00444 bool operator<=(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
00445 {
00446     return lta.m_tDelta <= ltb.m_tDelta;
00447 }
00448 
00449 bool operator<=(const CLinearTimeAbsolute& lta, const CLinearTimeAbsolute& ltb)
00450 {
00451     return lta.m_tAbsolute <= ltb.m_tAbsolute;
00452 }
00453 
00454 CLinearTimeAbsolute operator-(const CLinearTimeAbsolute& lta, const CLinearTimeDelta& ltd)
00455 {
00456     CLinearTimeAbsolute t;
00457     t.m_tAbsolute = lta.m_tAbsolute - ltd.m_tDelta;
00458     return t;
00459 }
00460 
00461 CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute& ltaOrigin, const CLinearTimeDelta& ltdOffset)
00462 {
00463     m_tAbsolute = ltaOrigin.m_tAbsolute + ltdOffset.m_tDelta;
00464 }
00465 
00466 static bool ParseFractionalSecondsString(INT64 &i64, char *str)
00467 {
00468     bool bMinus = false;
00469 
00470     i64 = 0;
00471 
00472     bool bGotOne;
00473 
00474     // Leading spaces.
00475     //
00476     while (mux_isspace(*str))
00477     {
00478         str++;
00479     }
00480 
00481     // Leading minus
00482     //
00483     if (*str == '-')
00484     {
00485         bMinus = true;
00486         str++;
00487 
00488         // But not if just a minus
00489         //
00490         if (!*str)
00491         {
00492             return false;
00493         }
00494     }
00495 
00496     // Need at least one digit.
00497     //
00498     bGotOne = false;
00499     char *pIntegerStart = str;
00500     if (mux_isdigit(*str))
00501     {
00502         bGotOne = true;
00503         str++;
00504     }
00505 
00506     // The number (int)
00507     //
00508     while (mux_isdigit(*str))
00509     {
00510         str++;
00511     }
00512     char *pIntegerEnd = str;
00513 
00514     // Decimal point.
00515     //
00516     if (*str == '.')
00517     {
00518         str++;
00519     }
00520 
00521     // Need at least one digit
00522     //
00523     char *pFractionalStart = str;
00524     if (mux_isdigit(*str))
00525     {
00526         bGotOne = true;
00527         str++;
00528     }
00529 
00530     // The number (fract)
00531     //
00532     while (mux_isdigit(*str))
00533     {
00534         str++;
00535     }
00536     char *pFractionalEnd = str;
00537 
00538     // Trailing spaces.
00539     //
00540     while (mux_isspace(*str))
00541     {
00542         str++;
00543     }
00544 
00545     if (*str || !bGotOne)
00546     {
00547         return false;
00548     }
00549 
00550 #define PFSS_PRECISION 7
00551     char   aBuffer[64];
00552     size_t nBufferAvailable = sizeof(aBuffer) - PFSS_PRECISION - 1;
00553     char  *p = aBuffer;
00554 
00555     // Sign.
00556     //
00557     if (bMinus)
00558     {
00559         *p++ = '-';
00560         nBufferAvailable--;
00561     }
00562 
00563     // Integer part.
00564     //
00565     bool bOverUnderflow = false;
00566     size_t n = pIntegerEnd - pIntegerStart;
00567     if (n > 0)
00568     {
00569         if (n > nBufferAvailable)
00570         {
00571             bOverUnderflow = true;
00572             n = nBufferAvailable;
00573         }
00574         memcpy(p, pIntegerStart, n);
00575         p += n;
00576         nBufferAvailable -= n;
00577     }
00578 
00579     // Fractional part.
00580     //
00581     n = pFractionalEnd - pFractionalStart;
00582     if (n > 0)
00583     {
00584         if (n > PFSS_PRECISION)
00585         {
00586             n = PFSS_PRECISION;
00587         }
00588         memcpy(p, pFractionalStart, n);
00589         p += n;
00590         nBufferAvailable -= n;
00591     }
00592 
00593     // Handle trailing zeroes.
00594     //
00595     n = PFSS_PRECISION - n;
00596     if (n > 0)
00597     {
00598         memset(p, '0', n);
00599         p += n;
00600     }
00601     *p++ = '\0';
00602 
00603     if (bOverUnderflow)
00604     {
00605         if (bMinus)
00606         {
00607             i64 = INT64_MIN_VALUE;
00608         }
00609         else
00610         {
00611             i64 = INT64_MAX_VALUE;
00612         }
00613     }
00614     else
00615     {
00616         i64 = mux_atoi64(aBuffer);
00617     }
00618     return true;
00619 }
00620 
00621 static void ConvertToSecondsString(char *buffer, INT64 n64, int nFracDigits)
00622 {
00623     INT64 Leftover;
00624     INT64 lt = i64FloorDivisionMod(n64, FACTOR_100NS_PER_SECOND, &Leftover);
00625 
00626     size_t n = mux_i64toa(lt, buffer);
00627     if (Leftover == 0)
00628     {
00629         return;
00630     }
00631 
00632     // Sanitize Precision Request.
00633     //
00634     const int maxFracDigits = 7;
00635     const int minFracDigits = 0;
00636     if (nFracDigits < minFracDigits)
00637     {
00638         nFracDigits = minFracDigits;
00639     }
00640     else if (maxFracDigits < nFracDigits)
00641     {
00642         nFracDigits = maxFracDigits;
00643     }
00644     if (0 < nFracDigits)
00645     {
00646         char *p = buffer + n;
00647         *p++ = '.';
00648         char *q = p;
00649 
00650         char buf[maxFracDigits+1];
00651         size_t m = mux_i64toa(Leftover, buf);
00652         memset(p, '0', maxFracDigits - m);
00653         p += maxFracDigits - m;
00654         memcpy(p, buf, m);
00655         p = q + nFracDigits - 1;
00656         while (*p == '0')
00657         {
00658             p--;
00659         }
00660         p++;
00661         *p = '\0';
00662     }
00663 }
00664 
00665 char *CLinearTimeDelta::ReturnSecondsString(int nFracDigits)
00666 {
00667     ConvertToSecondsString(m_Buffer, m_tDelta, nFracDigits);
00668     return m_Buffer;
00669 }
00670 
00671 char *CLinearTimeAbsolute::ReturnSecondsString(int nFracDigits)
00672 {
00673     ConvertToSecondsString(m_Buffer, m_tAbsolute - EPOCH_OFFSET, nFracDigits);
00674     return m_Buffer;
00675 }
00676 
00677 CLinearTimeAbsolute::CLinearTimeAbsolute(const CLinearTimeAbsolute &lta)
00678 {
00679     m_tAbsolute = lta.m_tAbsolute;
00680 }
00681 
00682 CLinearTimeAbsolute::CLinearTimeAbsolute(void)
00683 {
00684     m_tAbsolute = 0;
00685 }
00686 
00687 CLinearTimeDelta::CLinearTimeDelta(void)
00688 {
00689     m_tDelta = 0;
00690 }
00691 
00692 CLinearTimeDelta::CLinearTimeDelta(INT64 arg_t100ns)
00693 {
00694     m_tDelta = arg_t100ns;
00695 }
00696 
00697 void CLinearTimeDelta::ReturnTimeValueStruct(struct timeval *tv)
00698 {
00699     INT64 Leftover;
00700     tv->tv_sec = (long)i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover);
00701     tv->tv_usec = (long)i64FloorDivision(Leftover, FACTOR_100NS_PER_MICROSECOND);
00702 }
00703 
00704 #ifdef HAVE_NANOSLEEP
00705 void CLinearTimeDelta::ReturnTimeSpecStruct(struct timespec *ts)
00706 {
00707     INT64 Leftover;
00708     ts->tv_sec = (long)i64FloorDivisionMod(m_tDelta, FACTOR_100NS_PER_SECOND, &Leftover);
00709     ts->tv_nsec = (long)Leftover*FACTOR_NANOSECONDS_PER_100NS;
00710 }
00711 #endif // HAVE_NANOSLEEP
00712 
00713 void CLinearTimeDelta::SetTimeValueStruct(struct timeval *tv)
00714 {
00715     m_tDelta = FACTOR_100NS_PER_SECOND * tv->tv_sec
00716              + FACTOR_100NS_PER_MICROSECOND * tv->tv_usec;
00717 }
00718 
00719 // Time string format is usually 24 characters long, in format
00720 // Ddd Mmm DD HH:MM:SS YYYY
00721 //
00722 // However, the year may be larger than 4 characters.
00723 //
00724 
00725 char *DayOfWeekString[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00726 static const char daystab[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00727 const char *monthtab[] =
00728 {
00729     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00730 };
00731 
00732 void CLinearTimeDelta::SetMilliseconds(unsigned long arg_dwMilliseconds)
00733 {
00734     m_tDelta = arg_dwMilliseconds * FACTOR_100NS_PER_MILLISECOND;
00735 }
00736 
00737 long CLinearTimeDelta::ReturnMilliseconds(void)
00738 {
00739     return (long)(m_tDelta/FACTOR_100NS_PER_MILLISECOND);
00740 }
00741 
00742 INT64 CLinearTimeDelta::ReturnMicroseconds(void)
00743 {
00744     return m_tDelta/FACTOR_100NS_PER_MICROSECOND;
00745 }
00746 
00747 void CLinearTimeDelta::SetSecondsString(char *arg_szSeconds)
00748 {
00749     ParseFractionalSecondsString(m_tDelta, arg_szSeconds);
00750 }
00751 
00752 void CLinearTimeDelta::SetSeconds(INT64 arg_tSeconds)
00753 {
00754     m_tDelta = arg_tSeconds * FACTOR_100NS_PER_SECOND;
00755 }
00756 
00757 void CLinearTimeDelta::Set100ns(INT64 arg_t100ns)
00758 {
00759     m_tDelta = arg_t100ns;
00760 }
00761 
00762 INT64 CLinearTimeDelta::Return100ns(void)
00763 {
00764     return m_tDelta;
00765 }
00766 
00767 void CLinearTimeAbsolute::Set100ns(INT64 arg_t100ns)
00768 {
00769     m_tAbsolute = arg_t100ns;
00770 }
00771 
00772 INT64 CLinearTimeAbsolute::Return100ns(void)
00773 {
00774     return m_tAbsolute;
00775 }
00776 
00777 void CLinearTimeAbsolute::SetSeconds(INT64 arg_tSeconds)
00778 {
00779     m_tAbsolute = arg_tSeconds;
00780     m_tAbsolute *= FACTOR_100NS_PER_SECOND;
00781 
00782     // Epoch difference between (00:00:00 UTC, January 1, 1970) and
00783     // (00:00:00 UTC, January 1, 1601).
00784     //
00785     m_tAbsolute += EPOCH_OFFSET;
00786 }
00787 
00788 INT64 CLinearTimeAbsolute::ReturnSeconds(void)
00789 {
00790     // INT64 is in hundreds of nanoseconds.
00791     // And the Epoch is 0:00 1/1/1601 instead of 0:00 1/1/1970
00792     //
00793     return i64FloorDivision(m_tAbsolute - EPOCH_OFFSET, FACTOR_100NS_PER_SECOND);
00794 }
00795 
00796 bool isLeapYear(long iYear)
00797 {
00798     if (iMod(iYear, 4) != 0)
00799     {
00800         // Not a leap year.
00801         //
00802         return false;
00803     }
00804     unsigned long wMod = iMod(iYear, 400);
00805     if ((wMod == 100) || (wMod == 200) || (wMod == 300))
00806     {
00807         // Not a leap year.
00808         //
00809         return false;
00810     }
00811     return true;
00812 }
00813 
00814 static bool isValidDate(int iYear, int iMonth, int iDay)
00815 {
00816     if (iYear < -27256 || 30826 < iYear)
00817     {
00818         return false;
00819     }
00820     if (iMonth < 1 || 12 < iMonth)
00821     {
00822         return false;
00823     }
00824     if (iDay < 1 || daystab[iMonth-1] < iDay)
00825     {
00826         return false;
00827     }
00828     if (iMonth == 2 && iDay == 29 && !isLeapYear(iYear))
00829     {
00830         return false;
00831     }
00832     return true;
00833 }
00834 
00835 static int FixedFromGregorian(int iYear, int iMonth, int iDay)
00836 {
00837     iYear = iYear - 1;
00838     int iFixedDay = 365 * iYear;
00839     iFixedDay += iFloorDivision(iYear, 4);
00840     iFixedDay -= iFloorDivision(iYear, 100);
00841     iFixedDay += iFloorDivision(iYear, 400);
00842     iFixedDay += iFloorDivision(367 * iMonth - 362, 12);
00843     iFixedDay += iDay;
00844 
00845     if (iMonth > 2)
00846     {
00847         if (isLeapYear(iYear+1))
00848         {
00849             iFixedDay -= 1;
00850         }
00851         else
00852         {
00853             iFixedDay -= 2;
00854         }
00855     }
00856 
00857     // At this point, iFixedDay has an epoch of 1 R.D.
00858     //
00859     return iFixedDay;
00860 }
00861 
00862 static int FixedFromGregorian_Adjusted(int iYear, int iMonth, int iDay)
00863 {
00864     int iFixedDay = FixedFromGregorian(iYear, iMonth, iDay);
00865 
00866     // At this point, iFixedDay has an epoch of 1 R.D.
00867     // We need an Epoch of (00:00:00 UTC, January 1, 1601)
00868     //
00869     return iFixedDay - 584389;
00870 }
00871 
00872 
00873 // Epoch of iFixedDay should be 1 R.D.
00874 //
00875 static void GregorianFromFixed(int iFixedDay, int &iYear, int &iMonth,  int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek)
00876 {
00877     int d0 = iFixedDay - 1;
00878     int d1, n400 = iFloorDivisionMod(d0, 146097, &d1);
00879     int d2, n100 = iFloorDivisionMod(d1,  36524, &d2);
00880     int d3, n4   = iFloorDivisionMod(d2,   1461, &d3);
00881     int d4, n1   = iFloorDivisionMod(d3,    365, &d4);
00882     d4 = d4 + 1;
00883 
00884     iYear = 400*n400 + 100*n100 + 4*n4 + n1;
00885 
00886     if (n100 != 4 && n1 != 4)
00887     {
00888         iYear = iYear + 1;
00889     }
00890 
00891     static int cache_iYear = 99999;
00892     static int cache_iJan1st = 0;
00893     static int cache_iMar1st = 0;
00894     int iFixedDayOfJanuary1st;
00895     int iFixedDayOfMarch1st;
00896     if (iYear == cache_iYear)
00897     {
00898         iFixedDayOfJanuary1st = cache_iJan1st;
00899         iFixedDayOfMarch1st = cache_iMar1st;
00900     }
00901     else
00902     {
00903         cache_iYear = iYear;
00904         cache_iJan1st = iFixedDayOfJanuary1st = FixedFromGregorian(iYear, 1, 1);
00905         cache_iMar1st = iFixedDayOfMarch1st = FixedFromGregorian(iYear, 3, 1);
00906     }
00907 
00908 
00909     int iPriorDays = iFixedDay - iFixedDayOfJanuary1st;
00910     int iCorrection;
00911     if (iFixedDay < iFixedDayOfMarch1st)
00912     {
00913         iCorrection = 0;
00914     }
00915     else if (isLeapYear(iYear))
00916     {
00917         iCorrection = 1;
00918     }
00919     else
00920     {
00921         iCorrection = 2;
00922     }
00923 
00924     iMonth = (12*(iPriorDays+iCorrection)+373)/367;
00925     iDayOfMonth = iFixedDay - FixedFromGregorian(iYear, iMonth, 1) + 1;
00926     iDayOfYear = iPriorDays + 1;
00927 
00928     // Calculate the Day of week using the linear progression of days.
00929     //
00930     iDayOfWeek = iMod(iFixedDay, 7);
00931 }
00932 
00933 static void GregorianFromFixed_Adjusted(int iFixedDay, int &iYear, int &iMonth, int &iDayOfYear, int &iDayOfMonth, int &iDayOfWeek)
00934 {
00935     // We need to convert the Epoch to 1 R.D. from
00936     // (00:00:00 UTC, January 1, 1601)
00937     //
00938     GregorianFromFixed(iFixedDay + 584389, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek);
00939 }
00940 
00941 // do_convtime()
00942 //
00943 // converts time string to time structure (fielded time). Returns 1 on
00944 // success, 0 on fail. Time string format is:
00945 //
00946 //     [Ddd] Mmm DD HH:MM:SS YYYY
00947 //
00948 // The initial Day-of-week token is optional.
00949 //
00950 static int MonthTabHash[12] =
00951 {
00952     0x004a414e, 0x00464542, 0x004d4152, 0x00415052,
00953     0x004d4159, 0x004a554e, 0x004a554c, 0x00415547,
00954     0x00534550, 0x004f4354, 0x004e4f56, 0x00444543
00955 };
00956 
00957 static bool ParseThreeLetters(const char **pp, int *piHash)
00958 {
00959     *piHash = 0;
00960 
00961     // Skip Initial spaces
00962     //
00963     const char *p = *pp;
00964     while (*p == ' ')
00965     {
00966         p++;
00967     }
00968 
00969     // Parse space-separate token.
00970     //
00971     const char *q = p;
00972     int iHash = 0;
00973     while (*q && *q != ' ')
00974     {
00975         if (!mux_isalpha(*q))
00976         {
00977             return false;
00978         }
00979         iHash = (iHash << 8) | mux_toupper(*q);
00980         q++;
00981     }
00982 
00983     // Must be exactly 3 letters long.
00984     //
00985     if (q - p != 3)
00986     {
00987         return false;
00988     }
00989     p = q;
00990 
00991     // Skip final spaces
00992     //
00993     while (*p == ' ')
00994     {
00995         p++;
00996     }
00997 
00998     *pp = p;
00999     *piHash = iHash;
01000     return true;
01001 }
01002 
01003 static void ParseDecimalSeconds(size_t n, const char *p, unsigned short *iMilli,
01004                          unsigned short *iMicro, unsigned short *iNano)
01005 {
01006    char aBuffer[10];
01007    if (n > sizeof(aBuffer) - 1)
01008    {
01009        n = sizeof(aBuffer) - 1;
01010    }
01011    memcpy(aBuffer, p, n);
01012    memset(aBuffer + n, '0', sizeof(aBuffer) - n - 1);
01013    aBuffer[sizeof(aBuffer) - 1] = '\0';
01014    int ns = mux_atol(aBuffer);
01015    *iNano = ns % 1000;
01016    ns /= 1000;
01017    *iMicro = ns % 1000;
01018    *iMilli = ns / 1000;
01019 }
01020 
01021 static bool do_convtime(const char *str, FIELDEDTIME *ft)
01022 {
01023     memset(ft, 0, sizeof(FIELDEDTIME));
01024     if (!str || !ft)
01025     {
01026         return false;
01027     }
01028 
01029     // Day-of-week OR month.
01030     //
01031     const char *p = str;
01032     int i, iHash;
01033     if (!ParseThreeLetters(&p, &iHash))
01034     {
01035         return false;
01036     }
01037     for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) ;
01038     if (i == 12)
01039     {
01040         // The above three letters were probably the Day-Of-Week, the
01041         // next three letters are required to be the month name.
01042         //
01043         if (!ParseThreeLetters(&p, &iHash))
01044         {
01045             return false;
01046         }
01047         for (i = 0; (i < 12) && iHash != MonthTabHash[i]; i++) ;
01048         if (i == 12)
01049         {
01050             return false;
01051         }
01052     }
01053     ft->iMonth = i + 1; // January = 1, February = 2, etc.
01054 
01055     // Day of month.
01056     //
01057     ft->iDayOfMonth = (unsigned short)mux_atol(p);
01058     if (ft->iDayOfMonth < 1 || daystab[i] < ft->iDayOfMonth)
01059     {
01060         return false;
01061     }
01062     while (*p && *p != ' ') p++;
01063     while (*p == ' ') p++;
01064 
01065     // Hours
01066     //
01067     ft->iHour = (unsigned short)mux_atol(p);
01068     if (ft->iHour > 23 || (ft->iHour == 0 && *p != '0'))
01069     {
01070         return false;
01071     }
01072     while (*p && *p != ':') p++;
01073     if (*p == ':') p++;
01074     while (*p == ' ') p++;
01075 
01076     // Minutes
01077     //
01078     ft->iMinute = (unsigned short)mux_atol(p);
01079     if (ft->iMinute > 59 || (ft->iMinute == 0 && *p != '0'))
01080     {
01081         return false;
01082     }
01083     while (*p && *p != ':') p++;
01084     if (*p == ':') p++;
01085     while (*p == ' ') p++;
01086 
01087     // Seconds
01088     //
01089     ft->iSecond = (unsigned short)mux_atol(p);
01090     if (ft->iSecond > 59 || (ft->iSecond == 0 && *p != '0'))
01091     {
01092         return false;
01093     }
01094     while (mux_isdigit(*p))
01095     {
01096         p++;
01097     }
01098 
01099     // Milliseconds, Microseconds, and Nanoseconds
01100     //
01101     if (*p == '.')
01102     {
01103         p++;
01104         size_t n;
01105         const char *q = strchr(p, ' ');
01106         if (q)
01107         {
01108             n = q - p;
01109         }
01110         else
01111         {
01112             n = strlen(p);
01113         }
01114 
01115         ParseDecimalSeconds(n, p, &ft->iMillisecond, &ft->iMicrosecond,
01116             &ft->iNanosecond);
01117     }
01118     while (*p && *p != ' ') p++;
01119     while (*p == ' ') p++;
01120 
01121     // Year
01122     //
01123     ft->iYear = (short)mux_atol(p);
01124     while (mux_isdigit(*p))
01125     {
01126         p++;
01127     }
01128     while (*p == ' ') p++;
01129     if (*p != '\0')
01130     {
01131         return false;
01132     }
01133 
01134     // DayOfYear and DayOfWeek
01135     //
01136     ft->iDayOfYear = 0;
01137     ft->iDayOfWeek = 0;
01138 
01139     return isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth);
01140 }
01141 
01142 CLinearTimeDelta::CLinearTimeDelta(CLinearTimeAbsolute t0, CLinearTimeAbsolute t1)
01143 {
01144     m_tDelta = t1.m_tAbsolute - t0.m_tAbsolute;
01145 }
01146 
01147 long CLinearTimeDelta::ReturnDays(void)
01148 {
01149     return (long)(m_tDelta/FACTOR_100NS_PER_DAY);
01150 }
01151 
01152 long CLinearTimeDelta::ReturnSeconds(void)
01153 {
01154     return (long)(m_tDelta/FACTOR_100NS_PER_SECOND);
01155 }
01156 
01157 bool CLinearTimeAbsolute::ReturnFields(FIELDEDTIME *arg_tStruct)
01158 {
01159     return LinearTimeToFieldedTime(m_tAbsolute, arg_tStruct);
01160 }
01161 
01162 bool CLinearTimeAbsolute::SetString(const char *arg_tBuffer)
01163 {
01164     FIELDEDTIME ft;
01165     if (do_convtime(arg_tBuffer, &ft))
01166     {
01167         if (FieldedTimeToLinearTime(&ft, &m_tAbsolute))
01168         {
01169             return true;
01170         }
01171     }
01172     m_tAbsolute = 0;
01173     return false;
01174 }
01175 
01176 void CLinearTimeDelta::operator+=(const CLinearTimeDelta& ltd)
01177 {
01178     m_tDelta += ltd.m_tDelta;
01179 }
01180 
01181 CLinearTimeDelta operator-(const CLinearTimeAbsolute& ltaA, const CLinearTimeAbsolute& ltaB)
01182 {
01183     CLinearTimeDelta ltd;
01184     ltd.m_tDelta = ltaA.m_tAbsolute - ltaB.m_tAbsolute;
01185     return ltd;
01186 }
01187 
01188 CLinearTimeDelta operator-(const CLinearTimeDelta& lta, const CLinearTimeDelta& ltb)
01189 {
01190     CLinearTimeDelta ltd;
01191     ltd.m_tDelta = lta.m_tDelta - ltb.m_tDelta;
01192     return ltd;
01193 }
01194 
01195 CLinearTimeAbsolute operator+(const CLinearTimeAbsolute& ltaA, const CLinearTimeDelta& ltdB)
01196 {
01197     CLinearTimeAbsolute lta;
01198     lta.m_tAbsolute = ltaA.m_tAbsolute + ltdB.m_tDelta;
01199     return lta;
01200 }
01201 
01202 void CLinearTimeAbsolute::operator=(const CLinearTimeAbsolute& lta)
01203 {
01204     m_tAbsolute = lta.m_tAbsolute;
01205 }
01206 
01207 CLinearTimeDelta operator*(const CLinearTimeDelta& ltd, int Scale)
01208 {
01209     CLinearTimeDelta ltdResult;
01210     ltdResult.m_tDelta = ltd.m_tDelta * Scale;
01211     return ltdResult;
01212 }
01213 
01214 int operator/(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01215 {
01216     int iResult = (int)(ltdA.m_tDelta / ltdB.m_tDelta);
01217     return iResult;
01218 }
01219 
01220 bool operator<(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01221 {
01222     return ltdA.m_tDelta < ltdB.m_tDelta;
01223 }
01224 
01225 bool operator>(const CLinearTimeDelta& ltdA, const CLinearTimeDelta& ltdB)
01226 {
01227     return ltdA.m_tDelta > ltdB.m_tDelta;
01228 }
01229 
01230 void CLinearTimeAbsolute::operator-=(const CLinearTimeDelta& ltd)
01231 {
01232     m_tAbsolute -= ltd.m_tDelta;
01233 }
01234 
01235 void CLinearTimeAbsolute::operator+=(const CLinearTimeDelta& ltd)
01236 {
01237     m_tAbsolute += ltd.m_tDelta;
01238 }
01239 
01240 bool CLinearTimeAbsolute::SetFields(FIELDEDTIME *arg_tStruct)
01241 {
01242     m_tAbsolute = 0;
01243     return FieldedTimeToLinearTime(arg_tStruct, &m_tAbsolute);
01244 }
01245 
01246 static void SetStructTm(FIELDEDTIME *ft, struct tm *ptm)
01247 {
01248     ft->iYear = ptm->tm_year + 1900;
01249     ft->iMonth = ptm->tm_mon + 1;
01250     ft->iDayOfMonth = ptm->tm_mday;
01251     ft->iDayOfWeek = ptm->tm_wday;
01252     ft->iDayOfYear = 0;
01253     ft->iHour = ptm->tm_hour;
01254     ft->iMinute = ptm->tm_min;
01255     ft->iSecond = ptm->tm_sec;
01256 }
01257 
01258 void CLinearTimeAbsolute::ReturnUniqueString(char *buffer)
01259 {
01260     FIELDEDTIME ft;
01261     if (LinearTimeToFieldedTime(m_tAbsolute, &ft))
01262     {
01263         sprintf(buffer, "%04d%02d%02d-%02d%02d%02d", ft.iYear, ft.iMonth,
01264                 ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond);
01265     }
01266     else
01267     {
01268         sprintf(buffer, "%03d", m_nCount++);
01269     }
01270 }
01271 
01272 char *CLinearTimeAbsolute::ReturnDateString(int nFracDigits)
01273 {
01274     FIELDEDTIME ft;
01275     if (LinearTimeToFieldedTime(m_tAbsolute, &ft))
01276     {
01277         // Sanitize Precision Request.
01278         //
01279         const int maxFracDigits = 7;
01280         const int minFracDigits = 0;
01281         if (nFracDigits < minFracDigits)
01282         {
01283             nFracDigits = minFracDigits;
01284         }
01285         else if (maxFracDigits < nFracDigits)
01286         {
01287             nFracDigits = maxFracDigits;
01288         }
01289 
01290         char buffer[11];
01291         buffer[0] = '\0';
01292         if (  0 < nFracDigits
01293            && (  ft.iMillisecond != 0
01294               || ft.iMicrosecond != 0
01295               || ft.iNanosecond != 0))
01296         {
01297             sprintf(buffer, ".%03d%03d%03d", ft.iMillisecond, ft.iMicrosecond,
01298                 ft.iNanosecond);
01299 
01300             // Remove trailing zeros.
01301             //
01302             char *p = (buffer + 1) + (nFracDigits - 1);
01303             while (*p == '0')
01304             {
01305                 p--;
01306             }
01307             p++;
01308             *p = '\0';
01309         }
01310         sprintf(m_Buffer, "%s %s %02d %02d:%02d:%02d%s %04d",
01311             DayOfWeekString[ft.iDayOfWeek], monthtab[ft.iMonth-1],
01312             ft.iDayOfMonth, ft.iHour, ft.iMinute, ft.iSecond, buffer,
01313             ft.iYear);
01314     }
01315     else
01316     {
01317         m_Buffer[0] = '\0';
01318     }
01319     return m_Buffer;
01320 }
01321 
01322 void CLinearTimeAbsolute::GetUTC(void)
01323 {
01324     GetUTCLinearTime(&m_tAbsolute);
01325 }
01326 
01327 void CLinearTimeAbsolute::GetLocal(void)
01328 {
01329     GetUTCLinearTime(&m_tAbsolute);
01330     UTC2Local();
01331 }
01332 
01333 bool FieldedTimeToLinearTime(FIELDEDTIME *ft, INT64 *plt)
01334 {
01335     if (!isValidDate(ft->iYear, ft->iMonth, ft->iDayOfMonth))
01336     {
01337         *plt = 0;
01338         return false;
01339     }
01340 
01341     int iFixedDay = FixedFromGregorian_Adjusted(ft->iYear, ft->iMonth, ft->iDayOfMonth);
01342     ft->iDayOfWeek = iMod(iFixedDay+1, 7);
01343 
01344     INT64 lt;
01345     lt  = iFixedDay * FACTOR_100NS_PER_DAY;
01346     lt += ft->iHour * FACTOR_100NS_PER_HOUR;
01347     lt += ft->iMinute * FACTOR_100NS_PER_MINUTE;
01348     lt += ft->iSecond * FACTOR_100NS_PER_SECOND;
01349     lt += ft->iMicrosecond * FACTOR_100NS_PER_MICROSECOND;
01350     lt += ft->iMillisecond * FACTOR_100NS_PER_MILLISECOND;
01351     lt += ft->iNanosecond / FACTOR_NANOSECONDS_PER_100NS;
01352 
01353     *plt = lt;
01354     return true;
01355 }
01356 
01357 bool LinearTimeToFieldedTime(INT64 lt, FIELDEDTIME *ft)
01358 {
01359     INT64 ns100;
01360     int iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek;
01361 
01362     memset(ft, 0, sizeof(FIELDEDTIME));
01363     int d0 = (int)i64FloorDivisionMod(lt, FACTOR_100NS_PER_DAY, &ns100);
01364     GregorianFromFixed_Adjusted(d0, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek);
01365     if (!isValidDate(iYear, iMonth, iDayOfMonth))
01366     {
01367         return false;
01368     }
01369 
01370     ft->iYear = iYear;
01371     ft->iMonth = iMonth;
01372     ft->iDayOfYear = iDayOfYear;
01373     ft->iDayOfMonth = iDayOfMonth;
01374     ft->iDayOfWeek = iDayOfWeek;
01375 
01376     ft->iHour = (int)(ns100 / FACTOR_100NS_PER_HOUR);
01377     ns100 = ns100 % FACTOR_100NS_PER_HOUR;
01378     ft->iMinute = (int)(ns100 / FACTOR_100NS_PER_MINUTE);
01379     ns100 = ns100 % FACTOR_100NS_PER_MINUTE;
01380     ft->iSecond = (int)(ns100 / FACTOR_100NS_PER_SECOND);
01381     ns100 = ns100 % FACTOR_100NS_PER_SECOND;
01382 
01383     ft->iMillisecond = (int)(ns100 / FACTOR_100NS_PER_MILLISECOND);
01384     ns100 = ns100 % FACTOR_100NS_PER_MILLISECOND;
01385     ft->iMicrosecond = (int)(ns100 / FACTOR_100NS_PER_MICROSECOND);
01386     ns100 = ns100 % FACTOR_100NS_PER_MICROSECOND;
01387     ft->iNanosecond = (int)(ns100 * FACTOR_NANOSECONDS_PER_100NS);
01388 
01389     return true;
01390 }
01391 
01392 bool CLinearTimeAbsolute::SetSecondsString(char *arg_szSeconds)
01393 {
01394     INT64 t;
01395     const INT64 tEarliest = EARLIEST_VALID_DATE;
01396     const INT64 tLatest   = LATEST_VALID_DATE;
01397     ParseFractionalSecondsString(t, arg_szSeconds);
01398     t += EPOCH_OFFSET;
01399     if (  tEarliest <= t
01400        && t <= tLatest)
01401     {
01402         m_tAbsolute = t;
01403         return true;
01404     }
01405     return false;
01406 }
01407 
01408 // OS Dependent Routines:
01409 //
01410 #ifdef WIN32
01411 
01412 // This calculates (FACTOR_100NS_PER_SECOND*x)/y accurately without
01413 // overflow.
01414 //
01415 class CxyDiv
01416 {
01417 public:
01418     void SetDenominator(const INT64 y_arg);
01419     INT64 Convert(const INT64 x_arg);
01420 
01421 private:
01422     INT64 A, B, C, D;
01423 };
01424 
01425 void CxyDiv::SetDenominator(const INT64 y_arg)
01426 {
01427     A = FACTOR_100NS_PER_SECOND / y_arg;
01428     B = FACTOR_100NS_PER_SECOND % y_arg;
01429     C = y_arg/2;
01430     D = y_arg;
01431 }
01432 
01433 INT64 CxyDiv::Convert(const INT64 x_arg)
01434 {
01435     return A*x_arg + (B*x_arg + C)/D;
01436 }
01437 
01438 static CxyDiv Ticks2Seconds;
01439 static INT64  xIntercept = 0;
01440 static INT64  liInit;
01441 static INT64  tInit;
01442 static INT64  liMinSampleError  = 5*FACTOR_100NS_PER_MILLISECOND;
01443 static INT64  liMinSampleError2 = 5*FACTOR_100NS_PER_MILLISECOND;
01444 static bool   bQueryPerformanceAvailable = false;
01445 static bool   bUseQueryPerformance = false;
01446 
01447 const INT64 TargetError = 5*FACTOR_100NS_PER_MILLISECOND;
01448 
01460 DCL_INLINE bool GetTimeSample(INT64 &a, INT64 &t, INT64 &b)
01461 {
01462     if (QueryPerformanceCounter((LARGE_INTEGER *)&a))
01463     {
01464         GetSystemTimeAsFileTime((struct _FILETIME *)&t);
01465         if (QueryPerformanceCounter((LARGE_INTEGER *)&b))
01466         {
01467             return true;
01468         }
01469     }
01470     bQueryPerformanceAvailable = false;
01471     return false;
01472 }
01473 
01486 bool GetReasonableTimeSample(INT64 &t, INT64 &li)
01487 {
01488     int i;
01489     for (i = 0; i < 5; i++)
01490     {
01491         INT64 a, b;
01492         if (  GetTimeSample(a, t, b)
01493            && a < b)
01494         {
01495             INT64 d = b - a;
01496             if (d < liMinSampleError)
01497             {
01498                 liMinSampleError = d;
01499                 liMinSampleError2 = 2*d;
01500             }
01501             if (d < liMinSampleError2)
01502             {
01503                 // Average first and last counter values.
01504                 //
01505                 li = a + (b-a)/2;
01506                 return true;
01507             }
01508 
01509             // A glitch might cause the difference between a and b to be
01510             // unreasonably small, so we slowly open the minimum up again.
01511             //
01512             liMinSampleError++;
01513             liMinSampleError2 += 2;
01514         }
01515     }
01516     return false;
01517 }
01518 
01535 bool CalibrateQueryPerformance(void)
01536 {
01537     if (!bQueryPerformanceAvailable)
01538     {
01539         return false;
01540     }
01541 
01542     INT64 li;
01543     INT64 t;
01544 
01545     bUseQueryPerformance = false;
01546     if (GetReasonableTimeSample(t, li))
01547     {
01548         // x = y/m + b
01549         // m = dy/dx = (y1 - y0)/(x1 - x0)
01550         //
01551         // y is ticks and x is seconds.
01552         //
01553         INT64 dli = li - liInit;
01554         INT64 dt  =  t -  tInit;
01555 
01556         if (  0 < dt
01557            && 0 < dli)
01558         {
01559             CxyDiv Ticks2Freq;
01560             Ticks2Freq.SetDenominator(dt);
01561             INT64 liFreq = Ticks2Freq.Convert(dli);
01562             if (0 < liFreq)
01563             {
01564                 // Estimate error of prediction using previous line.
01565                 //
01566                 // x = y/m + b;
01567                 //
01568                 INT64 tError = Ticks2Seconds.Convert(li) + xIntercept - t;
01569 
01570                 // Establish revised line, b = x - y/m
01571                 //
01572                 Ticks2Seconds.SetDenominator(liFreq);
01573                 xIntercept = t - Ticks2Seconds.Convert(li);
01574 
01575                 if (  -TargetError < tError
01576                    && tError < TargetError)
01577                 {
01578                     bUseQueryPerformance = true;
01579                 }
01580             }
01581         }
01582     }
01583     return true;
01584 }
01585 
01586 static void InitializeQueryPerformance(void)
01587 {
01588     // The frequency returned is the number of ticks per second.
01589     //
01590     INT64 liFreq;
01591     if (QueryPerformanceFrequency((LARGE_INTEGER *)&liFreq))
01592     {
01593         Ticks2Seconds.SetDenominator(liFreq);
01594         if (GetReasonableTimeSample(tInit, liInit))
01595         {
01596             xIntercept = tInit - Ticks2Seconds.Convert(liInit);
01597             bQueryPerformanceAvailable = true;
01598         }
01599     }
01600 }
01601 
01602 void GetUTCLinearTime(INT64 *plt)
01603 {
01604     if (bUseQueryPerformance)
01605     {
01606         INT64 li;
01607         if (QueryPerformanceCounter((LARGE_INTEGER *)&li))
01608         {
01609             *plt = Ticks2Seconds.Convert(li) + xIntercept;
01610             return;
01611         }
01612         bQueryPerformanceAvailable = false;
01613         bUseQueryPerformance = false;
01614     }
01615     GetSystemTimeAsFileTime((struct _FILETIME *)plt);
01616 }
01617 
01618 static DWORD WINAPI AlarmProc(LPVOID lpParameter)
01619 {
01620     CMuxAlarm *pthis = (CMuxAlarm *)lpParameter;
01621     DWORD dwWait = pthis->dwWait;
01622     for (;;)
01623     {
01624         HANDLE hSemAlarm = pthis->hSemAlarm;
01625         if (hSemAlarm == INVALID_HANDLE_VALUE)
01626         {
01627             break;
01628         }
01629         DWORD dwReason = WaitForSingleObject(hSemAlarm, dwWait);
01630         if (dwReason == WAIT_TIMEOUT)
01631         {
01632             pthis->bAlarmed = true;
01633             dwWait = INFINITE;
01634         }
01635         else
01636         {
01637             dwWait = pthis->dwWait;
01638         }
01639     }
01640     return 1;
01641 }
01642 
01643 CMuxAlarm::CMuxAlarm(void)
01644 {
01645     hSemAlarm = CreateSemaphore(NULL, 0, 1, NULL);
01646     Clear();
01647     hThread = CreateThread(NULL, 0, AlarmProc, (LPVOID)this, 0, NULL);
01648 }
01649 
01650 CMuxAlarm::~CMuxAlarm()
01651 {
01652     HANDLE hSave = hSemAlarm;
01653     hSemAlarm = INVALID_HANDLE_VALUE;
01654     ReleaseSemaphore(hSave, 1, NULL);
01655     WaitForSingleObject(hThread, 15*FACTOR_100NS_PER_SECOND);
01656     CloseHandle(hSave);
01657 }
01658 
01659 void CMuxAlarm::Sleep(CLinearTimeDelta ltd)
01660 {
01661     ::Sleep(ltd.ReturnMilliseconds());
01662 }
01663 
01664 void CMuxAlarm::SurrenderSlice(void)
01665 {
01666     ::Sleep(0);
01667 }
01668 
01669 void CMuxAlarm::Set(CLinearTimeDelta ltd)
01670 {
01671     dwWait = ltd.ReturnMilliseconds();
01672     ReleaseSemaphore(hSemAlarm, 1, NULL);
01673     bAlarmed  = false;
01674     bAlarmSet = true;
01675 }
01676 
01677 void CMuxAlarm::Clear(void)
01678 {
01679     dwWait = INFINITE;
01680     ReleaseSemaphore(hSemAlarm, 1, NULL);
01681     bAlarmed  = false;
01682     bAlarmSet = false;
01683 }
01684 
01685 #else // !WIN32
01686 
01687 void GetUTCLinearTime(INT64 *plt)
01688 {
01689 #ifdef HAVE_GETTIMEOFDAY
01690     struct timeval tv;
01691     struct timezone tz;
01692     tz.tz_minuteswest = 0;
01693     tz.tz_dsttime = 0;
01694 
01695     gettimeofday(&tv, &tz);
01696 
01697     *plt = (((INT64)tv.tv_sec) * FACTOR_100NS_PER_SECOND)
01698          + (tv.tv_usec * FACTOR_100NS_PER_MICROSECOND)
01699          + EPOCH_OFFSET;
01700 #else
01701     time_t t;
01702 
01703     time(&t);
01704 
01705     *plt = t*FACTOR_100NS_PER_SECOND;
01706 #endif
01707 }
01708 
01709 CMuxAlarm::CMuxAlarm(void)
01710 {
01711     bAlarmed = false;
01712     bAlarmSet = false;
01713 }
01714 
01715 void CMuxAlarm::Sleep(CLinearTimeDelta ltd)
01716 {
01717 #if   defined(HAVE_NANOSLEEP)
01718     struct timespec req;
01719     ltd.ReturnTimeSpecStruct(&req);
01720     while (!mudstate.shutdown_flag)
01721     {
01722         struct timespec rem;
01723         if (  nanosleep(&req, &rem) == -1
01724            && errno == EINTR)
01725         {
01726             req = rem;
01727         }
01728         else
01729         {
01730             break;
01731         }
01732     }
01733 #else
01734 #ifdef HAVE_SETITIMER
01735     struct itimerval oit;
01736     bool   bSaved = false;
01737     if (bAlarmSet)
01738     {
01739         // Save existing timer and disable.
01740         //
01741         struct itimerval it;
01742         it.it_value.tv_sec = 0;
01743         it.it_value.tv_usec = 0;
01744         it.it_interval.tv_sec = 0;
01745         it.it_interval.tv_usec = 0;
01746         setitimer(ITIMER_PROF, &it, &oit);
01747         bSaved = true;
01748         bAlarmSet = false;
01749     }
01750 #endif
01751 #if   defined(HAVE_USLEEP)
01752 #define TIME_1S 1000000
01753     unsigned long usec;
01754     INT64 usecTotal = ltd.ReturnMicroseconds();
01755 
01756     while (  usecTotal
01757           && mudstate.shutdown_flag)
01758     {
01759         usec = usecTotal;
01760         if (usecTotal < TIME_1S)
01761         {
01762             usec = usecTotal;
01763         }
01764         else
01765         {
01766             usec = TIME_1S-1;
01767         }
01768         usleep(usec);
01769         usecTotal -= usec;
01770     }
01771 #else
01772     ::sleep(ltd.ReturnSeconds());
01773 #endif
01774 #ifdef HAVE_SETITIMER
01775     if (bSaved)
01776     {
01777         // Restore and re-enabled timer.
01778         //
01779         setitimer(ITIMER_PROF, &oit, NULL);
01780         bAlarmSet = true;
01781     }
01782 #endif
01783 #endif
01784 }
01785 
01786 void CMuxAlarm::SurrenderSlice(void)
01787 {
01788     ::sleep(0);
01789 }
01790 
01791 void CMuxAlarm::Set(CLinearTimeDelta ltd)
01792 {
01793 #ifdef HAVE_SETITIMER
01794     struct itimerval it;
01795     ltd.ReturnTimeValueStruct(&it.it_value);
01796     it.it_interval.tv_sec = 0;
01797     it.it_interval.tv_usec = 0;
01798     setitimer(ITIMER_PROF, &it, NULL);
01799     bAlarmSet = true;
01800     bAlarmed  = false;
01801 #endif
01802 }
01803 
01804 void CMuxAlarm::Clear(void)
01805 {
01806 #ifdef HAVE_SETITIMER
01807     // Turn off the timer.
01808     //
01809     struct itimerval it;
01810     it.it_value.tv_sec = 0;
01811     it.it_value.tv_usec = 0;
01812     it.it_interval.tv_sec = 0;
01813     it.it_interval.tv_usec = 0;
01814     setitimer(ITIMER_PROF, &it, NULL);
01815     bAlarmSet = false;
01816     bAlarmed  = false;
01817 #endif
01818 }
01819 
01820 void CMuxAlarm::Signal(void)
01821 {
01822     bAlarmSet = false;
01823     bAlarmed  = true;
01824 }
01825 
01826 #endif // !WIN32
01827 
01828 static int YearType(int iYear)
01829 {
01830     FIELDEDTIME ft;
01831     memset(&ft, 0, sizeof(FIELDEDTIME));
01832     ft.iYear        = iYear;
01833     ft.iMonth       = 1;
01834     ft.iDayOfMonth  = 1;
01835 
01836     CLinearTimeAbsolute ltaLocal;
01837     ltaLocal.SetFields(&ft);
01838     if (isLeapYear(iYear))
01839     {
01840         return ft.iDayOfWeek + 8;
01841     }
01842     else
01843     {
01844         return ft.iDayOfWeek + 1;
01845     }
01846 }
01847 
01848 static CLinearTimeAbsolute ltaLowerBound;
01849 static CLinearTimeAbsolute ltaUpperBound;
01850 static CLinearTimeDelta    ltdTimeZoneStandard;
01851 
01852 // Because of signed-ness and -LONG_MAX overflowing, we need to be
01853 // particularly careful with finding the mid-point.
01854 //
01855 static time_t time_t_midpoint(time_t tLower, time_t tUpper)
01856 {
01857     time_t tDiff = (tUpper-2) - tLower;
01858     return tLower+tDiff/2+1;
01859 }
01860 
01861 static time_t time_t_largest(void)
01862 {
01863     time_t t;
01864     if (sizeof(INT64) <= sizeof(time_t))
01865     {
01866         t = static_cast<time_t>(INT64_MAX_VALUE);
01867     }
01868     else
01869     {
01870         t = static_cast<time_t>(INT32_MAX_VALUE);
01871     }
01872 
01873 #if defined(TIMEUTIL_TIME_T_MAX_VALUE)
01874     INT64 t64 = static_cast<INT64>(t);
01875     if (TIMEUTIL_TIME_T_MAX_VALUE < t64)
01876     {
01877         t = static_cast<time_t>(TIMEUTIL_TIME_T_MAX_VALUE);
01878     }
01879 #endif
01880 #if defined(LOCALTIME_TIME_T_MAX_VALUE)
01881     // Windows cannot handle negative time_t values, and some versions have
01882     // an upper limit as well. Values which are too large cause an assert.
01883     //
01884     // In VS 2003, the limit is 0x100000000000i64 (beyond the size of a
01885     // time_t). In VS 2005, the limit is December 31, 2999, 23:59:59 UTC
01886     // (or 32535215999).
01887     //
01888     if (LOCALTIME_TIME_T_MAX_VALUE < t)
01889     {
01890         t = static_cast<time_t>(LOCALTIME_TIME_T_MAX_VALUE);
01891     }
01892 #endif
01893     return t;
01894 }
01895 
01896 static time_t time_t_smallest(void)
01897 {
01898     time_t t;
01899     if (sizeof(INT64) <= sizeof(time_t))
01900     {
01901         t = static_cast<time_t>(INT64_MIN_VALUE);
01902     }
01903     else
01904     {
01905         t = static_cast<time_t>(INT32_MIN_VALUE);
01906     }
01907 #if defined(TIMEUTIL_TIME_T_MIN_VALUE)
01908     INT64 t64 = static_cast<INT64>(t);
01909     if (t64 < TIMEUTIL_TIME_T_MIN_VALUE)
01910     {
01911         t = static_cast<time_t>(TIMEUTIL_TIME_T_MIN_VALUE);
01912     }
01913 #endif
01914 #if defined(LOCALTIME_TIME_T_MIN_VALUE)
01915     if (t < LOCALTIME_TIME_T_MIN_VALUE)
01916     {
01917         t = static_cast<time_t>(LOCALTIME_TIME_T_MIN_VALUE);
01918     }
01919 #endif
01920     return t;
01921 }
01922 
01923 // This determines the valid range of localtime() and finds a 'standard'
01924 // time zone near the earliest supported time_t.
01925 //
01926 static void test_time_t(void)
01927 {
01928     // Search for the highest supported value of time_t.
01929     //
01930     time_t tUpper = time_t_largest();
01931     time_t tLower = 0;
01932     time_t tMid;
01933     while (tLower < tUpper)
01934     {
01935         tMid = time_t_midpoint(tLower+1, tUpper);
01936         if (localtime(&tMid))
01937         {
01938             tLower = tMid;
01939         }
01940         else
01941         {
01942             tUpper = tMid-1;
01943         }
01944     }
01945     ltaUpperBound.SetSeconds(tLower);
01946 
01947     // Search for the lowest supported value of time_t.
01948     //
01949     tUpper = 0;
01950     tLower = time_t_smallest();
01951     while (tLower < tUpper)
01952     {
01953         tMid = time_t_midpoint(tLower, tUpper-1);
01954         if (localtime(&tMid))
01955         {
01956             tUpper = tMid;
01957         }
01958         else
01959         {
01960             tLower = tMid+1;
01961         }
01962     }
01963     ltaLowerBound.SetSeconds(tUpper);
01964 
01965     // Find a time near tLower for which DST is not in affect.
01966     //
01967     for (;;)
01968     {
01969         struct tm *ptm = localtime(&tLower);
01970 
01971         if (ptm->tm_isdst <= 0)
01972         {
01973             // Daylight savings time is either not in effect or
01974             // we have no way of knowing whether it is in effect
01975             // or not.
01976             //
01977             FIELDEDTIME ft;
01978             SetStructTm(&ft, ptm);
01979             ft.iMillisecond = 0;
01980             ft.iMicrosecond = 0;
01981             ft.iNanosecond  = 0;
01982 
01983             CLinearTimeAbsolute ltaLocal;
01984             CLinearTimeAbsolute ltaUTC;
01985             ltaLocal.SetFields(&ft);
01986             ltaUTC.SetSeconds(tLower);
01987             ltdTimeZoneStandard = ltaLocal - ltaUTC;
01988             break;
01989         }
01990 
01991         // Advance the time by 1 month (expressed as seconds).
01992         //
01993         tLower += 30*24*60*60;
01994     }
01995 }
01996 
01997 static int NearestYearOfType[15];
01998 static CLinearTimeDelta ltdIntervalMinimum;
01999 static bool bTimeInitialized = false;
02000 
02001 void TIME_Initialize(void)
02002 {
02003     if (bTimeInitialized)
02004     {
02005         return;
02006     }
02007     bTimeInitialized = true;
02008 
02009     tzset();
02010 
02011     test_time_t();
02012     ltdIntervalMinimum = time_1w;
02013     int i;
02014     for (i = 0; i < 15; i++)
02015     {
02016         NearestYearOfType[i] = -1;
02017     }
02018     int cnt = 14;
02019     FIELDEDTIME ft;
02020     ltaUpperBound.ReturnFields(&ft);
02021     for (i = ft.iYear-1; cnt; i--)
02022     {
02023         int iYearType = YearType(i);
02024         if (NearestYearOfType[iYearType] < 0)
02025         {
02026             NearestYearOfType[iYearType] = i;
02027             cnt--;
02028         }
02029     }
02030 #ifdef WIN32
02031     InitializeQueryPerformance();
02032 #endif
02033 }
02034 
02035 // Explanation of the table.
02036 //
02037 // The table contains intervals of time for which (ltdOffset, isDST)
02038 // tuples are known.
02039 //
02040 // Two intervals may be combined when they share the same tuple
02041 // value and the time between them is less than ltdIntervalMinimum.
02042 //
02043 // Intervals are thrown away in a least-recently-used (LRU) fashion.
02044 //
02045 typedef struct
02046 {
02047     CLinearTimeAbsolute ltaStart;
02048     CLinearTimeAbsolute ltaEnd;
02049     CLinearTimeDelta    ltdOffset;
02050     int                 nTouched;
02051     bool                isDST;
02052 } OffsetEntry;
02053 
02054 #define MAX_OFFSETS 50
02055 static int nOffsetTable = 0;
02056 static int nTouched0 = 0;
02057 static OffsetEntry OffsetTable[MAX_OFFSETS];
02058 
02059 // This function finds the entry in the table (0...nOffsetTable-1)
02060 // whose ltaStart is less than or equal to the search key.
02061 // If no entry satisfies this search, -1 is returned.
02062 //
02063 static int FindOffsetEntry(const CLinearTimeAbsolute& lta)
02064 {
02065     int lo = 0;
02066     int hi = nOffsetTable - 1;
02067     int mid = 0;
02068     while (lo <= hi)
02069     {
02070         mid = ((hi - lo) >> 1) + lo;
02071         if (OffsetTable[mid].ltaStart <= lta)
02072         {
02073             lo = mid + 1;
02074         }
02075         else
02076         {
02077             hi = mid - 1;
02078         }
02079 
02080     }
02081     return lo-1;
02082 }
02083 
02084 static bool QueryOffsetTable
02085 (
02086     CLinearTimeAbsolute lta,
02087     CLinearTimeDelta *pltdOffset,
02088     bool *pisDST,
02089     int *piEntry
02090 )
02091 {
02092     nTouched0++;
02093 
02094     int i = FindOffsetEntry(lta);
02095     *piEntry = i;
02096 
02097     // Is the interval defined?
02098     //
02099     if (  0 <= i
02100        && lta <= OffsetTable[i].ltaEnd)
02101     {
02102         *pltdOffset = OffsetTable[i].ltdOffset;
02103         *pisDST = OffsetTable[i].isDST;
02104         OffsetTable[i].nTouched = nTouched0;
02105         return true;
02106     }
02107     return false;
02108 }
02109 
02110 static void UpdateOffsetTable
02111 (
02112     CLinearTimeAbsolute &lta,
02113     CLinearTimeDelta ltdOffset,
02114     bool isDST,
02115     int i
02116 )
02117 {
02118 Again:
02119 
02120     nTouched0++;
02121 
02122     // Is the interval defined?
02123     //
02124     if (  0 <= i
02125        && lta <= OffsetTable[i].ltaEnd)
02126     {
02127         OffsetTable[i].nTouched = nTouched0;
02128         return;
02129     }
02130 
02131     bool bTryMerge = false;
02132 
02133     // Coalesce new data point into this interval if:
02134     //
02135     //  1. Tuple for this interval matches the new tuple value.
02136     //  2. It's close enough that we can assume all intervening
02137     //     values are the same.
02138     //
02139     if (  0 <= i
02140        && OffsetTable[i].ltdOffset == ltdOffset
02141        && OffsetTable[i].isDST == isDST
02142        && lta <= OffsetTable[i].ltaEnd + ltdIntervalMinimum)
02143     {
02144         // Cool. We can just extend this interval to include our new
02145         // data point.
02146         //
02147         OffsetTable[i].ltaEnd = lta;
02148         OffsetTable[i].nTouched = nTouched0;
02149 
02150         // Since we have changed this interval, we may be able to
02151         // coalesce it with the next interval.
02152         //
02153         bTryMerge = true;
02154     }
02155 
02156     // Coalesce new data point into next interval if:
02157     //
02158     //  1. Next interval exists.
02159     //  2. Tuple in next interval matches the new tuple value.
02160     //  3. It's close enough that we can assume all intervening
02161     //     values are the same.
02162     //
02163     int iNext = i+1;
02164     if (  0 <= iNext
02165        && iNext < nOffsetTable
02166        && OffsetTable[iNext].ltdOffset == ltdOffset
02167        && OffsetTable[iNext].isDST == isDST
02168        && OffsetTable[iNext].ltaStart - ltdIntervalMinimum <= lta)
02169     {
02170         // Cool. We can just extend the next interval to include our
02171         // new data point.
02172         //
02173         OffsetTable[iNext].ltaStart = lta;
02174         OffsetTable[iNext].nTouched = nTouched0;
02175 
02176         // Since we have changed the next interval, we may be able
02177         // to coalesce it with the previous interval.
02178         //
02179         bTryMerge = true;
02180     }
02181 
02182     if (bTryMerge)
02183     {
02184         // We should combine the current and next intervals if we can.
02185         //
02186         if (  0 <= i
02187            && iNext < nOffsetTable
02188            && OffsetTable[i].ltdOffset == OffsetTable[iNext].ltdOffset
02189            && OffsetTable[i].isDST     == OffsetTable[iNext].isDST
02190            && OffsetTable[iNext].ltaStart - ltdIntervalMinimum
02191               <= OffsetTable[i].ltaEnd)
02192         {
02193             if (0 <= i && 0 <= iNext)
02194             {
02195                 OffsetTable[i].ltaEnd = OffsetTable[iNext].ltaEnd;
02196             }
02197             int nSize = sizeof(OffsetEntry)*(nOffsetTable-i-2);
02198             memmove(OffsetTable+i+1, OffsetTable+i+2, nSize);
02199             nOffsetTable--;
02200         }
02201     }
02202     else
02203     {
02204         // We'll have'ta create a new interval.
02205         //
02206         if (nOffsetTable < MAX_OFFSETS)
02207         {
02208             size_t nSize = sizeof(OffsetEntry)*(nOffsetTable-i-1);
02209             memmove(OffsetTable+i+2, OffsetTable+i+1, nSize);
02210             nOffsetTable++;
02211             i++;
02212             OffsetTable[i].isDST = isDST;
02213             OffsetTable[i].ltdOffset = ltdOffset;
02214             OffsetTable[i].ltaStart= lta;
02215             OffsetTable[i].ltaEnd= lta;
02216             OffsetTable[i].nTouched = nTouched0;
02217         }
02218         else
02219         {
02220             // We ran out of room. Throw away the least used
02221             // interval and try again.
02222             //
02223             int nMinTouched = OffsetTable[0].nTouched;
02224             int iMinTouched = 0;
02225             for (int j = 1; j < nOffsetTable; j++)
02226             {
02227                 if (OffsetTable[j].nTouched - nMinTouched < 0)
02228                 {
02229                     nMinTouched = OffsetTable[j].nTouched;
02230                     iMinTouched = j;
02231                 }
02232             }
02233             int nSize = sizeof(OffsetEntry)*(nOffsetTable-iMinTouched-1);
02234             memmove(OffsetTable+iMinTouched, OffsetTable+iMinTouched+1, nSize);
02235             nOffsetTable--;
02236             if (iMinTouched <= i)
02237             {
02238                 i--;
02239             }
02240             goto Again;
02241         }
02242     }
02243 }
02244 
02245 static CLinearTimeDelta QueryLocalOffsetAt_Internal
02246 (
02247     CLinearTimeAbsolute lta,
02248     bool *pisDST,
02249     int iEntry
02250 )
02251 {
02252     if (!bTimeInitialized)
02253     {
02254         TIME_Initialize();
02255     }
02256 
02257     // At this point, we must use localtime() to discover what the
02258     // UTC to local time offset is for the requested UTC time.
02259     //
02260     // However, localtime() does not support times beyond around
02261     // the 2038 year on machines with 32-bit integers, so to
02262     // compensant for this, and knowing that we are already dealing
02263     // with fictionalized adjustments, we associate a future year
02264     // that is outside the supported range with one that is inside
02265     // the support range of the same type (there are 14 different
02266     // year types depending on leap-year-ness and which day of the
02267     // week that January 1st falls on.
02268     //
02269     // Note: Laws beyond the current year have not been written yet
02270     // and are subject to change at any time. For example, Israel
02271     // doesn't have regular rules for DST but makes a directive each
02272     // year...sometimes to avoid conflicts with Jewish holidays.
02273     //
02274     if (lta > ltaUpperBound)
02275     {
02276         // Map the specified year to the closest year with the same
02277         // pattern of weeks.
02278         //
02279         FIELDEDTIME ft;
02280         lta.ReturnFields(&ft);
02281         ft.iYear = NearestYearOfType[YearType(ft.iYear)];
02282         lta.SetFields(&ft);
02283     }
02284 
02285     // Rely on localtime() to take a UTC count of seconds and convert
02286     // to a fielded local time complete with known timezone and DST
02287     // adjustments.
02288     //
02289     time_t lt = (time_t)lta.ReturnSeconds();
02290     struct tm *ptm = localtime(&lt);
02291     if (!ptm)
02292     {
02293         // This should never happen as we have already taken pains
02294         // to restrict the range of UTC seconds gives to localtime().
02295         //
02296         return ltdTimeZoneStandard;
02297     }
02298 
02299     // With the fielded (or broken down) time from localtime(), we
02300     // can convert to a linear time in the same time zone.
02301     //
02302     FIELDEDTIME ft;
02303     SetStructTm(&ft, ptm);
02304     ft.iMillisecond = 0;
02305     ft.iMicrosecond = 0;
02306     ft.iNanosecond  = 0;
02307 
02308     CLinearTimeAbsolute ltaLocal;
02309     CLinearTimeDelta ltdOffset;
02310     ltaLocal.SetFields(&ft);
02311     lta.SetSeconds(lt);
02312     ltdOffset = ltaLocal - lta;
02313 
02314     *pisDST = (ptm->tm_isdst > 0);
02315 
02316     // We now have a mapping from UTC lta to a (ltdOffset, *pisDST)
02317     // tuple which will will use to update the cache.
02318     //
02319     UpdateOffsetTable(lta, ltdOffset, *pisDST, iEntry);
02320     return ltdOffset;
02321 }
02322 
02323 static CLinearTimeDelta QueryLocalOffsetAtUTC
02324 (
02325     const CLinearTimeAbsolute &lta,
02326     bool *pisDST
02327 )
02328 {
02329     *pisDST = false;
02330 
02331     // DST started in Britain in May 1916 and in the US in 1918.
02332     // Germany used it a little before May 1916, but I'm not sure
02333     // of exactly when.
02334     //
02335     // So, there is locale specific information about DST adjustments
02336     // that could reasonable be made between 1916 and 1970.
02337     // Because Unix supports negative time_t values while Win32 does
02338     // not, it can also support that 1916 to 1970 interval with
02339     // timezone information.
02340     //
02341     // Win32 only supports one timezone rule at a time, or rather
02342     // it doesn't have any historical timezone information, but you
02343     // can/must provide it yourself. So, in the Win32 case, unless we
02344     // are willing to provide historical information (from a tzfile
02345     // perhaps), it will only give us the current timezone rule
02346     // (the one selected by the control panel or by a TZ environment
02347     // variable). It projects this rule forwards and backwards.
02348     //
02349     // Feel free to fill that gap in yourself with a tzfile file
02350     // reader for Win32.
02351     //
02352     if (lta < ltaLowerBound)
02353     {
02354         return ltdTimeZoneStandard;
02355     }
02356 
02357     // Next, we check our table for whether this time falls into a
02358     // previously discovered interval. You could view this as a
02359     // cache, or you could also view it as a way of reading in the
02360     // tzfile without becoming system-dependent enough to actually
02361     // read the tzfile.
02362     //
02363     CLinearTimeDelta ltdOffset;
02364     int iEntry;
02365     if (QueryOffsetTable(lta, &ltdOffset, pisDST, &iEntry))
02366     {
02367         return ltdOffset;
02368     }
02369     ltdOffset = QueryLocalOffsetAt_Internal(lta, pisDST, iEntry);
02370 
02371     // Since the cache failed, let's make sure we have a useful
02372     // interval surrounding this last request so that future queries
02373     // nearby will be serviced by the cache.
02374     //
02375     CLinearTimeAbsolute ltaProbe;
02376     CLinearTimeDelta ltdDontCare;
02377     bool bDontCare;
02378 
02379     ltaProbe = lta - ltdIntervalMinimum;
02380     if (!QueryOffsetTable(ltaProbe, &ltdDontCare, &bDontCare, &iEntry))
02381     {
02382         QueryLocalOffsetAt_Internal(ltaProbe, &bDontCare, iEntry);
02383     }
02384 
02385     ltaProbe = lta + ltdIntervalMinimum;
02386     if (!QueryOffsetTable(ltaProbe, &ltdDontCare, &bDontCare, &iEntry))
02387     {
02388         QueryLocalOffsetAt_Internal(ltaProbe, &bDontCare, iEntry);
02389     }
02390     return ltdOffset;
02391 }
02392 
02393 void CLinearTimeAbsolute::UTC2Local(void)
02394 {
02395     bool bDST;
02396     CLinearTimeDelta ltd = QueryLocalOffsetAtUTC(*this, &bDST);
02397     m_tAbsolute += ltd.m_tDelta;
02398 }
02399 
02400 void CLinearTimeAbsolute::Local2UTC(void)
02401 {
02402     bool bDST1, bDST2;
02403     CLinearTimeDelta ltdOffset1 = QueryLocalOffsetAtUTC(*this, &bDST1);
02404     CLinearTimeAbsolute ltaUTC2 = *this - ltdOffset1;
02405     CLinearTimeDelta ltdOffset2 = QueryLocalOffsetAtUTC(ltaUTC2, &bDST2);
02406 
02407     CLinearTimeAbsolute ltaLocalGuess = ltaUTC2 + ltdOffset2;
02408     if (ltaLocalGuess == *this)
02409     {
02410         // We found an offset, UTC, local time combination that
02411         // works.
02412         //
02413         m_tAbsolute = ltaUTC2.m_tAbsolute;
02414     }
02415     else
02416     {
02417         CLinearTimeAbsolute ltaUTC1 = *this - ltdOffset2;
02418         m_tAbsolute = ltaUTC1.m_tAbsolute;
02419     }
02420 }
02421 
02422 // AUTOMAGIC DATE PARSING.
02423 
02424 // We must deal with several levels at once. That is, a single
02425 // character is overlapped by layers and layers of meaning from 'digit'
02426 // to 'the second digit of the hours field of the timezone'.
02427 //
02428 typedef struct tag_pd_node
02429 {
02430     // The following is a bitfield which contains a '1' bit for every
02431     // possible meaning associated with this token. This bitfield is
02432     // initially determined by looking at the token, and then we use
02433     // the following logic to refine this set further:
02434     //
02435     // 1. Suffix and Prefix hints. e.g., '1st', '2nd', etc. ':' with
02436     //    time fields, 'am'/'pm', timezone field must follow time
02437     //    field, 'Wn' is a week-of-year indicator, 'nTn' is an ISO
02438     //    date/time seperator, '<timefield>Z' shows that 'Z' is a
02439     //    military timezone letter, '-n' indicates that the field is
02440     //    either a year or a numeric timezone, '+n' indicates that the
02441     //    field can only be a timezone.
02442     //
02443     // 2. Single Field Exclusiveness. We only allow -one- timezone
02444     //    indicator in the field. Likewise, there can't be two months,
02445     //    two day-of-month fields, two years, etc.
02446     //
02447     // 3. Semantic exclusions. day-of-year, month/day-of-month, and
02448     //    and week-of-year/day-of-year(numeric) are mutually exclusive.
02449     //
02450     // If successful, this bitfield will ultimately only contain a single
02451     // '1' bit which tells us what it is.
02452     //
02453     unsigned  uCouldBe;
02454 
02455     // These fields deal with token things and we avoid mixing
02456     // them up in higher meanings. This is the lowest level.
02457     //
02458     // Further Notes:
02459     //
02460     // PDTT_SYMBOL is always a -single- (nToken==1) character.
02461     //
02462     // uTokenType must be one of the PDTT_* values.
02463     //
02464     // PDTT_NUMERIC_* and PDTT_TEXT types may have an
02465     // iToken value associated with them.
02466     //
02467 #define PDTT_SYMBOL           1 // e.g., :/.-+
02468 #define PDTT_NUMERIC_UNSIGNED 2 // [0-9]+
02469 #define PDTT_SPACES           3 // One or more space/tab characters
02470 #define PDTT_TEXT             4 // 'January' 'Jan' 'T' 'W'
02471 #define PDTT_NUMERIC_SIGNED   5 // [+-][0-9]+
02472     unsigned  uTokenType;
02473     char     *pToken;
02474     size_t    nToken;
02475     int       iToken;
02476 
02477     // Link to previous and next node.
02478     //
02479     struct tag_pd_node *pNextNode;
02480     struct tag_pd_node *pPrevNode;
02481 
02482 } PD_Node;
02483 
02484 #define PDCB_NOTHING              0x00000000
02485 #define PDCB_TIME_FIELD_SEPARATOR 0x00000001
02486 #define PDCB_DATE_FIELD_SEPARATOR 0x00000002
02487 #define PDCB_WHITESPACE           0x00000004
02488 #define PDCB_DAY_OF_MONTH_SUFFIX  0x00000008
02489 #define PDCB_SIGN                 0x00000010
02490 #define PDCB_SECONDS_DECIMAL      0x00000020
02491 #define PDCB_REMOVEABLE           0x00000040
02492 #define PDCB_YEAR                 0x00000080
02493 #define PDCB_MONTH                0x00000100
02494 #define PDCB_DAY_OF_MONTH         0x00000200
02495 #define PDCB_DAY_OF_WEEK          0x00000400
02496 #define PDCB_WEEK_OF_YEAR         0x00000800
02497 #define PDCB_DAY_OF_YEAR          0x00001000
02498 #define PDCB_YD                   0x00002000
02499 #define PDCB_YMD                  0x00004000
02500 #define PDCB_MDY                  0x00008000
02501 #define PDCB_DMY                  0x00010000
02502 #define PDCB_DATE_TIME_SEPARATOR  0x00020000
02503 #define PDCB_TIMEZONE             0x00040000
02504 #define PDCB_WEEK_OF_YEAR_PREFIX  0x00080000
02505 #define PDCB_MERIDIAN             0x00100000
02506 #define PDCB_MINUTE               0x00200000
02507 #define PDCB_SECOND               0x00400000
02508 #define PDCB_SUBSECOND            0x00800000
02509 #define PDCB_HOUR_TIME            0x01000000
02510 #define PDCB_HMS_TIME             0x02000000
02511 #define PDCB_HOUR_TIMEZONE        0x04000000
02512 #define PDCB_HMS_TIMEZONE         0x08000000
02513 
02514 static PD_Node *PD_NewNode(void);
02515 static void PD_AppendNode(PD_Node *pNode);
02516 static void PD_InsertAfter(PD_Node *pWhere, PD_Node *pNode);
02517 typedef void BREAK_DOWN_FUNC(PD_Node *pNode);
02518 typedef struct tag_pd_breakdown
02519 {
02520     unsigned int mask;
02521     BREAK_DOWN_FUNC *fpBreakDown;
02522 } PD_BREAKDOWN;
02523 
02524 #define NOT_PRESENT -9999999
02525 typedef struct tag_AllFields
02526 {
02527     int iYear;
02528     int iDayOfYear;
02529     int iMonthOfYear;
02530     int iDayOfMonth;
02531     int iWeekOfYear;
02532     int iDayOfWeek;
02533     int iHourTime;
02534     int iMinuteTime;
02535     int iSecondTime;
02536     int iMillisecondTime;
02537     int iMicrosecondTime;
02538     int iNanosecondTime;
02539     int iMinuteTimeZone;
02540 } ALLFIELDS;
02541 
02542 // isValidYear assumes numeric string.
02543 //
02544 static bool isValidYear(size_t nStr, char *pStr, int iValue)
02545 {
02546     UNUSED_PARAMETER(pStr);
02547     UNUSED_PARAMETER(iValue);
02548 
02549     // Year may be Y, YY, YYY, YYYY, or YYYYY.
02550     // Negative and zero years are permitted in general, but we aren't
02551     // give the leading sign.
02552     //
02553     if (1 <= nStr && nStr <= 5)
02554     {
02555         return true;
02556     }
02557     return false;
02558 }
02559 
02560 static bool isValidMonth(size_t nStr, char *pStr, int iValue)
02561 {
02562     UNUSED_PARAMETER(pStr);
02563 
02564     // Month may be 1 through 9, 01 through 09, 10, 11, or 12.
02565     //
02566     if (  1 <= nStr && nStr <= 2
02567        && 1 <= iValue && iValue <= 12)
02568     {
02569         return true;
02570     }
02571     return false;
02572 }
02573 
02574 static bool isValidDayOfMonth(size_t nStr, char *pStr, int iValue)
02575 {
02576     UNUSED_PARAMETER(pStr);
02577 
02578     // Day Of Month may be 1 through 9, 01 through 09, 10 through 19,
02579     // 20 through 29, 30, and 31.
02580     //
02581     if (  1 <= nStr && nStr <= 2
02582        && 1 <= iValue && iValue <= 31)
02583     {
02584         return true;
02585     }
02586     return false;
02587 }
02588 
02589 static bool isValidDayOfWeek(size_t nStr, char *pStr, int iValue)
02590 {
02591     UNUSED_PARAMETER(pStr);
02592 
02593     // Day Of Week may be 1 through 7.
02594     //
02595     if (  1 == nStr
02596        && 1 <= iValue && iValue <= 7)
02597     {
02598         return true;
02599     }
02600     return false;
02601 }
02602 
02603 static bool isValidDayOfYear(size_t nStr, char *pStr, int iValue)
02604 {
02605     UNUSED_PARAMETER(pStr);
02606 
02607     // Day Of Year 001 through 366
02608     //
02609     if (  3 == nStr
02610        && 1 <= iValue && iValue <= 366)
02611     {
02612         return true;
02613     }
02614     return false;
02615 }
02616 
02617 static bool isValidWeekOfYear(size_t nStr, char *pStr, int iValue)
02618 {
02619     UNUSED_PARAMETER(pStr);
02620 
02621     // Week Of Year may be 01 through 53.
02622     //
02623     if (  2 == nStr
02624        && 1 <= iValue && iValue <= 53)
02625     {
02626         return true;
02627     }
02628     return false;
02629 }
02630 
02631 static bool isValidHour(size_t nStr, char *pStr, int iValue)
02632 {
02633     UNUSED_PARAMETER(pStr);
02634 
02635     // Hour may be 0 through 9, 00 through 09, 10 through 19, 20 through 24.
02636     //
02637     if (  1 <= nStr && nStr <= 2
02638        && 0 <= iValue && iValue <= 24)
02639     {
02640         return true;
02641     }
02642     return false;
02643 }
02644 
02645 static bool isValidMinute(size_t nStr, char *pStr, int iValue)
02646 {
02647     UNUSED_PARAMETER(pStr);
02648 
02649     // Minute may be 00 through 59.
02650     //
02651     if (  2 == nStr
02652        && 0 <= iValue && iValue <= 59)
02653     {
02654         return true;
02655     }
02656     return false;
02657 }
02658 
02659 static bool isValidSecond(size_t nStr, char *pStr, int iValue)
02660 {
02661     UNUSED_PARAMETER(pStr);
02662 
02663     // Second may be 00 through 59. Leap seconds represented
02664     // by '60' are not dealt with.
02665     //
02666     if (  2 == nStr
02667        && 0 <= iValue && iValue <= 59)
02668     {
02669         return true;
02670     }
02671     return false;
02672 }
02673 
02674 static bool isValidSubSecond(size_t nStr, char *pStr, int iValue)
02675 {
02676     UNUSED_PARAMETER(pStr);
02677     UNUSED_PARAMETER(iValue);
02678 
02679     // Sub seconds can really be anything, but we limit
02680     // it's precision to 100 ns.
02681     //
02682     if (nStr <= 7)
02683     {
02684         return true;
02685     }
02686     return false;
02687 }
02688 
02689 // This function handles H, HH, HMM, HHMM, HMMSS, HHMMSS
02690 //
02691 static bool isValidHMS(size_t nStr, char *pStr, int iValue)
02692 {
02693     int iHour, iMinutes, iSeconds;
02694     switch (nStr)
02695     {
02696     case 1:
02697     case 2:
02698         return isValidHour(nStr, pStr, iValue);
02699 
02700     case 3:
02701     case 4:
02702         iHour    = iValue/100; iValue -= iHour*100;
02703         iMinutes = iValue;
02704         if (  isValidHour(nStr-2, pStr, iHour)
02705            && isValidMinute(2, pStr+nStr-2, iMinutes))
02706         {
02707             return true;
02708         }
02709         break;
02710 
02711     case 5:
02712     case 6:
02713         iHour    = iValue/10000;  iValue -= iHour*10000;
02714         iMinutes = iValue/100;    iValue -= iMinutes*100;
02715         iSeconds = iValue;
02716         if (  isValidHour(nStr-4, pStr, iHour)
02717            && isValidMinute(2, pStr+nStr-4, iMinutes)
02718            && isValidSecond(2, pStr+nStr-2, iSeconds))
02719         {
02720             return true;
02721         }
02722         break;
02723     }
02724     return false;
02725 }
02726 
02727 static void SplitLastTwoDigits(PD_Node *pNode, unsigned mask)
02728 {
02729     PD_Node *p = PD_NewNode();
02730     if (p)
02731     {
02732         *p = *pNode;
02733         p->uCouldBe = mask;
02734         p->nToken = 2;
02735         p->pToken += pNode->nToken - 2;
02736         p->iToken = pNode->iToken % 100;
02737         pNode->nToken -= 2;
02738         pNode->iToken /= 100;
02739         PD_InsertAfter(pNode, p);
02740     }
02741 }
02742 
02743 static void SplitLastThreeDigits(PD_Node *pNode, unsigned mask)
02744 {
02745     PD_Node *p = PD_NewNode();
02746     if (p)
02747     {
02748         *p = *pNode;
02749         p->uCouldBe = mask;
02750         p->nToken = 3;
02751         p->pToken += pNode->nToken - 3;
02752         p->iToken = pNode->iToken % 1000;
02753         pNode->nToken -= 3;
02754         pNode->iToken /= 1000;
02755         PD_InsertAfter(pNode, p);
02756     }
02757 }
02758 
02759 // This function breaks down H, HH, HMM, HHMM, HMMSS, HHMMSS
02760 //
02761 static void BreakDownHMS(PD_Node *pNode)
02762 {
02763     if (pNode->uCouldBe & PDCB_HMS_TIME)
02764     {
02765         pNode->uCouldBe = PDCB_HOUR_TIME;
02766     }
02767     else
02768     {
02769         pNode->uCouldBe = PDCB_HOUR_TIMEZONE;
02770     }
02771     switch (pNode->nToken)
02772     {
02773     case 5:
02774     case 6:
02775         SplitLastTwoDigits(pNode, PDCB_SECOND);
02776 
02777     case 3:
02778     case 4:
02779         SplitLastTwoDigits(pNode, PDCB_MINUTE);
02780     }
02781 }
02782 
02783 
02784 // This function handles YYMMDD, YYYMMDD, YYYYMMDD, YYYYYMMDD
02785 //
02786 static bool isValidYMD(size_t nStr, char *pStr, int iValue)
02787 {
02788     int iYear = iValue / 10000;
02789     iValue -= 10000 * iYear;
02790     int iMonth = iValue / 100;
02791     iValue -= 100 * iMonth;
02792     int iDay = iValue;
02793 
02794     if (  isValidMonth(2, pStr+nStr-4, iMonth)
02795        && isValidDayOfMonth(2, pStr+nStr-2, iDay)
02796        && isValidYear(nStr-4, pStr, iYear))
02797     {
02798         return true;
02799     }
02800     return false;
02801 }
02802 
02803 // This function breaks down YYMMDD, YYYMMDD, YYYYMMDD, YYYYYMMDD
02804 //
02805 static void BreakDownYMD(PD_Node *pNode)
02806 {
02807     pNode->uCouldBe = PDCB_YEAR;
02808     SplitLastTwoDigits(pNode, PDCB_DAY_OF_MONTH);
02809     SplitLastTwoDigits(pNode, PDCB_MONTH);
02810 }
02811 
02812 // This function handles MMDDYY
02813 //
02814 static bool isValidMDY(size_t nStr, char *pStr, int iValue)
02815 {
02816     int iMonth = iValue / 10000;
02817     iValue -= 10000 * iMonth;
02818     int iDay = iValue / 100;
02819     iValue -= 100 * iDay;
02820     int iYear = iValue;
02821 
02822     if (  6 == nStr
02823        && isValidMonth(2, pStr, iMonth)
02824        && isValidDayOfMonth(2, pStr+2, iDay)
02825        && isValidYear(2, pStr+4, iYear))
02826     {
02827         return true;
02828     }
02829     return false;
02830 }
02831 
02832 // This function breaks down MMDDYY
02833 //
02834 static void BreakDownMDY(PD_Node *pNode)
02835 {
02836     pNode->uCouldBe = PDCB_MONTH;
02837     SplitLastTwoDigits(pNode, PDCB_YEAR);
02838     SplitLastTwoDigits(pNode, PDCB_DAY_OF_MONTH);
02839 }
02840 
02841 // This function handles DDMMYY
02842 //
02843 static bool isValidDMY(size_t nStr, char *pStr, int iValue)
02844 {
02845     int iDay = iValue / 10000;
02846     iValue -= 10000 * iDay;
02847     int iMonth = iValue / 100;
02848     iValue -= 100 * iMonth;
02849     int iYear = iValue;
02850 
02851     if (  6 == nStr
02852        && isValidMonth(2, pStr+2, iMonth)
02853        && isValidDayOfMonth(2, pStr, iDay)
02854        && isValidYear(2, pStr+4, iYear))
02855     {
02856         return true;
02857     }
02858     return false;
02859 }
02860 
02861 // This function breaks down DDMMYY
02862 //
02863 static void BreakDownDMY(PD_Node *pNode)
02864 {
02865     pNode->uCouldBe = PDCB_DAY_OF_MONTH;
02866     SplitLastTwoDigits(pNode, PDCB_YEAR);
02867     SplitLastTwoDigits(pNode, PDCB_MONTH);
02868 }
02869 
02870 // This function handles YDDD, YYDDD, YYYDDD, YYYYDDD, YYYYYDDD
02871 //
02872 static bool isValidYD(size_t nStr, char *pStr, int iValue)
02873 {
02874     int iYear = iValue / 1000;
02875     iValue -= 1000*iYear;
02876     int iDay = iValue;
02877 
02878     if (  4 <= nStr && nStr <= 8
02879        && isValidDayOfYear(3, pStr+nStr-3, iDay)
02880        && isValidYear(nStr-3, pStr, iYear))
02881     {
02882         return true;
02883     }
02884     return false;
02885 }
02886 
02887 // This function breaks down YDDD, YYDDD, YYYDDD, YYYYDDD, YYYYYDDD
02888 //
02889 static void BreakDownYD(PD_Node *pNode)
02890 {
02891     pNode->uCouldBe = PDCB_YEAR;
02892     SplitLastThreeDigits(pNode, PDCB_DAY_OF_YEAR);
02893 }
02894 
02895 static const int InitialCouldBe[9] =
02896 {
02897     PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_WEEK|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_SUBSECOND,  // 1
02898     PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_MINUTE|PDCB_SECOND|PDCB_SUBSECOND, // 2
02899     PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_DAY_OF_YEAR|PDCB_SUBSECOND, // 3
02900     PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND, // 4
02901     PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND, // 5
02902     PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_YD|PDCB_SUBSECOND, // 6
02903     PDCB_YMD|PDCB_YD|PDCB_SUBSECOND, // 7
02904     PDCB_YMD|PDCB_YD, // 8
02905     PDCB_YMD  // 9
02906 };
02907 
02908 typedef bool PVALIDFUNC(size_t nStr, char *pStr, int iValue);
02909 
02910 typedef struct tag_pd_numeric_valid
02911 {
02912     unsigned mask;
02913     PVALIDFUNC *fnValid;
02914 } NUMERIC_VALID_RECORD;
02915 
02916 const NUMERIC_VALID_RECORD NumericSet[] =
02917 {
02918     { PDCB_YEAR,         isValidYear       },
02919     { PDCB_MONTH,        isValidMonth      },
02920     { PDCB_DAY_OF_MONTH, isValidDayOfMonth },
02921     { PDCB_DAY_OF_YEAR,  isValidDayOfYear  },
02922     { PDCB_WEEK_OF_YEAR, isValidWeekOfYear },
02923     { PDCB_DAY_OF_WEEK,  isValidDayOfWeek  },
02924     { PDCB_HMS_TIME|PDCB_HMS_TIMEZONE, isValidHMS },
02925     { PDCB_YMD,          isValidYMD        },
02926     { PDCB_MDY,          isValidMDY        },
02927     { PDCB_DMY,          isValidDMY        },
02928     { PDCB_YD,           isValidYD         },
02929     { PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE, isValidHour },
02930     { PDCB_MINUTE,       isValidMinute     },
02931     { PDCB_SECOND,       isValidSecond     },
02932     { PDCB_SUBSECOND,    isValidSubSecond  },
02933     { 0, 0},
02934 };
02935 
02936 // This function looks at the numeric token and assigns the initial set
02937 // of possibilities.
02938 //
02939 static void ClassifyNumericToken(PD_Node *pNode)
02940 {
02941     size_t nToken = pNode->nToken;
02942     char  *pToken = pNode->pToken;
02943     int    iToken = pNode->iToken;
02944 
02945     unsigned int uCouldBe = InitialCouldBe[nToken-1];
02946 
02947     int i = 0;
02948     int mask = 0;
02949     while ((mask = NumericSet[i].mask) != 0)
02950     {
02951         if (  (mask & uCouldBe)
02952            && !(NumericSet[i].fnValid(nToken, pToken, iToken)))
02953         {
02954             uCouldBe &= ~mask;
02955         }
02956         i++;
02957     }
02958     pNode->uCouldBe = uCouldBe;
02959 }
02960 
02961 typedef struct
02962 {
02963     char        *szText;
02964     unsigned int uCouldBe;
02965     int          iValue;
02966 } PD_TEXT_ENTRY;
02967 
02968 const PD_TEXT_ENTRY PD_TextTable[] =
02969 {
02970     {"sun",       PDCB_DAY_OF_WEEK,   7 },
02971     {"mon",       PDCB_DAY_OF_WEEK,   1 },
02972     {"tue",       PDCB_DAY_OF_WEEK,   2 },
02973     {"wed",       PDCB_DAY_OF_WEEK,   3 },
02974     {"thu",       PDCB_DAY_OF_WEEK,   4 },
02975     {"fri",       PDCB_DAY_OF_WEEK,   5 },
02976     {"sat",       PDCB_DAY_OF_WEEK,   6 },
02977     {"jan",       PDCB_MONTH,         1 },
02978     {"feb",       PDCB_MONTH,         2 },
02979     {"mar",       PDCB_MONTH,         3 },
02980     {"apr",       PDCB_MONTH,         4 },
02981     {"may",       PDCB_MONTH,         5 },
02982     {"jun",       PDCB_MONTH,         6 },
02983     {"jul",       PDCB_MONTH,         7 },
02984     {"aug",       PDCB_MONTH,         8 },
02985     {"sep",       PDCB_MONTH,         9 },
02986     {"oct",       PDCB_MONTH,        10 },
02987     {"nov",       PDCB_MONTH,        11 },
02988     {"dec",       PDCB_MONTH,        12 },
02989     {"january",   PDCB_MONTH,         1 },
02990     {"february",  PDCB_MONTH,         2 },
02991     {"march",     PDCB_MONTH,         3 },
02992     {"april",     PDCB_MONTH,         4 },
02993     {"may",       PDCB_MONTH,         5 },
02994     {"june",      PDCB_MONTH,         6 },
02995     {"july",      PDCB_MONTH,         7 },
02996     {"august",    PDCB_MONTH,         8 },
02997     {"september", PDCB_MONTH,         9 },
02998     {"october",   PDCB_MONTH,        10 },
02999     {"november",  PDCB_MONTH,        11 },
03000     {"december",  PDCB_MONTH,        12 },
03001     {"sunday",    PDCB_DAY_OF_WEEK,   7 },
03002     {"monday",    PDCB_DAY_OF_WEEK,   1 },
03003     {"tuesday",   PDCB_DAY_OF_WEEK,   2 },
03004     {"wednesday", PDCB_DAY_OF_WEEK,   3 },
03005     {"thursday",  PDCB_DAY_OF_WEEK,   4 },
03006     {"friday",    PDCB_DAY_OF_WEEK,   5 },
03007     {"saturday",  PDCB_DAY_OF_WEEK,   6 },
03008     {"a",         PDCB_TIMEZONE,    100 },
03009     {"b",         PDCB_TIMEZONE,    200 },
03010     {"c",         PDCB_TIMEZONE,    300 },
03011     {"d",         PDCB_TIMEZONE,    400 },
03012     {"e",         PDCB_TIMEZONE,    500 },
03013     {"f",         PDCB_TIMEZONE,    600 },
03014     {"g",         PDCB_TIMEZONE,    700 },
03015     {"h",         PDCB_TIMEZONE,    800 },
03016     {"i",         PDCB_TIMEZONE,    900 },
03017     {"k",         PDCB_TIMEZONE,   1000 },
03018     {"l",         PDCB_TIMEZONE,   1100 },
03019     {"m",         PDCB_TIMEZONE,   1200 },
03020     {"n",         PDCB_TIMEZONE,   -100 },
03021     {"o",         PDCB_TIMEZONE,   -200 },
03022     {"p",         PDCB_TIMEZONE,   -300 },
03023     {"q",         PDCB_TIMEZONE,   -400 },
03024     {"r",         PDCB_TIMEZONE,   -500 },
03025     {"s",         PDCB_TIMEZONE,   -600 },
03026     {"t",         PDCB_DATE_TIME_SEPARATOR|PDCB_TIMEZONE, -700},
03027     {"u",         PDCB_TIMEZONE,   -800 },
03028     {"v",         PDCB_TIMEZONE,   -900 },
03029     {"w",         PDCB_WEEK_OF_YEAR_PREFIX|PDCB_TIMEZONE,  -1000 },
03030     {"x",         PDCB_TIMEZONE,  -1100 },
03031     {"y",         PDCB_TIMEZONE,  -1200 },
03032     {"z",         PDCB_TIMEZONE,      0 },
03033     {"hst",       PDCB_TIMEZONE,  -1000 },
03034     {"akst",      PDCB_TIMEZONE,   -900 },
03035     {"pst",       PDCB_TIMEZONE,   -800 },
03036     {"mst",       PDCB_TIMEZONE,   -700 },
03037     {"cst",       PDCB_TIMEZONE,   -600 },
03038     {"est",       PDCB_TIMEZONE,   -500 },
03039     {"ast",       PDCB_TIMEZONE,   -400 },
03040     {"akdt",      PDCB_TIMEZONE,   -800 },
03041     {"pdt",       PDCB_TIMEZONE,   -700 },
03042     {"mdt",       PDCB_TIMEZONE,   -600 },
03043     {"cdt",       PDCB_TIMEZONE,   -500 },
03044     {"edt",       PDCB_TIMEZONE,   -400 },
03045     {"adt",       PDCB_TIMEZONE,   -300 },
03046     {"bst",       PDCB_TIMEZONE,    100 },
03047     {"ist",       PDCB_TIMEZONE,    100 },
03048     {"cet",       PDCB_TIMEZONE,    100 },
03049     {"cest",      PDCB_TIMEZONE,    200 },
03050     {"eet",       PDCB_TIMEZONE,    200 },
03051     {"eest",      PDCB_TIMEZONE,    300 },
03052     {"aest",      PDCB_TIMEZONE,   1000 },
03053     {"gmt",       PDCB_TIMEZONE,      0 },
03054     {"ut",        PDCB_TIMEZONE,      0 },
03055     {"utc",       PDCB_TIMEZONE,      0 },
03056     {"st",        PDCB_DAY_OF_MONTH_SUFFIX, 0 },
03057     {"nd",        PDCB_DAY_OF_MONTH_SUFFIX, 0 },
03058     {"rd",        PDCB_DAY_OF_MONTH_SUFFIX, 0 },
03059     {"th",        PDCB_DAY_OF_MONTH_SUFFIX, 0 },
03060     {"am",        PDCB_MERIDIAN,      0 },
03061     {"pm",        PDCB_MERIDIAN,     12 },
03062     { 0, 0, 0}
03063 };
03064 
03065 #define PD_LEX_INVALID 0
03066 #define PD_LEX_SYMBOL  1
03067 #define PD_LEX_DIGIT   2
03068 #define PD_LEX_SPACE   3
03069 #define PD_LEX_ALPHA   4
03070 #define PD_LEX_EOS     5
03071 
03072 const char LexTable[256] =
03073 {
03074 //  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
03075 //
03076     5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0
03077     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 1
03078     3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  // 2
03079     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,  // 3
03080     0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,  // 4
03081     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,  // 5
03082     0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,  // 6
03083     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,  // 7
03084 
03085     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 8
03086     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 9
03087     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // A
03088     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // B
03089     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // C
03090     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // D
03091     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // E
03092     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   // F
03093 };
03094 
03095 static int nNodes = 0;
03096 #define MAX_NODES 200
03097 static PD_Node Nodes[MAX_NODES];
03098 
03099 static PD_Node *PD_Head = 0;
03100 static PD_Node *PD_Tail = 0;
03101 
03102 static void PD_Reset(void)
03103 {
03104     nNodes = 0;
03105     PD_Head = 0;
03106     PD_Tail = 0;
03107 }
03108 
03109 PD_Node *PD_NewNode(void)
03110 {
03111     if (nNodes < MAX_NODES)
03112     {
03113         return Nodes+(nNodes++);
03114     }
03115     return NULL;
03116 }
03117 
03118 static PD_Node *PD_FirstNode(void)
03119 {
03120     return PD_Head;
03121 }
03122 
03123 #if 0
03124 static PD_Node *PD_LastNode(void)
03125 {
03126     return PD_Tail;
03127 }
03128 #endif
03129 
03130 static PD_Node *PD_NextNode(PD_Node *pNode)
03131 {
03132     return pNode->pNextNode;
03133 }
03134 
03135 static PD_Node *PD_PrevNode(PD_Node *pNode)
03136 {
03137     return pNode->pPrevNode;
03138 }
03139 
03140 // PD_AppendNode - Appends a node onto the end of the list. It's used during
03141 // the first pass over the date string; these nodes are therefore always
03142 // elemental nodes. It might be possible to append a group node. However,
03143 // usually group nodes a created at a later from recognizing a deeper semantic
03144 // meaning of an elemental node and this promotion event could happen anywhere
03145 // in the sequence. The order of promotion isn't clear during the first pass
03146 // over the date string.
03147 //
03148 void PD_AppendNode(PD_Node *pNode)
03149 {
03150     if (!PD_Head)
03151     {
03152         PD_Head = PD_Tail = pNode;
03153         return;
03154     }
03155     pNode->pNextNode = 0;
03156     PD_Tail->pNextNode = pNode;
03157     pNode->pPrevNode = PD_Tail;
03158     PD_Tail = pNode;
03159 }
03160 
03161 void PD_InsertAfter(PD_Node *pWhere, PD_Node *pNode)
03162 {
03163     pNode->pPrevNode = pWhere;
03164     pNode->pNextNode = pWhere->pNextNode;
03165 
03166     pWhere->pNextNode = pNode;
03167     if (pNode->pNextNode)
03168     {
03169         pNode->pNextNode->pPrevNode = pNode;
03170     }
03171     else
03172     {
03173         PD_Tail = pNode;
03174     }
03175 }
03176 
03177 static void PD_RemoveNode(PD_Node *pNode)
03178 {
03179     if (pNode == PD_Head)
03180     {
03181         if (pNode == PD_Tail)
03182         {
03183             PD_Head = PD_Tail = 0;
03184         }
03185         else
03186         {
03187             PD_Head = pNode->pNextNode;
03188             PD_Head->pPrevNode = 0;
03189             pNode->pNextNode = 0;
03190         }
03191     }
03192     else if (pNode == PD_Tail)
03193     {
03194         PD_Tail = pNode->pPrevNode;
03195         PD_Tail->pNextNode = 0;
03196         pNode->pPrevNode = 0;
03197     }
03198     else
03199     {
03200         pNode->pNextNode->pPrevNode = pNode->pPrevNode;
03201         pNode->pPrevNode->pNextNode = pNode->pNextNode;
03202         pNode->pNextNode = 0;
03203         pNode->pPrevNode = 0;
03204     }
03205 }
03206 
03207 static PD_Node *PD_ScanNextToken(char **ppString)
03208 {
03209     char *p = *ppString;
03210     int ch = *p;
03211     if (ch == 0)
03212     {
03213         return NULL;
03214     }
03215     PD_Node *pNode;
03216     int iType = LexTable[ch];
03217     if (iType == PD_LEX_EOS || iType == PD_LEX_INVALID)
03218     {
03219         return NULL;
03220     }
03221     else if (iType == PD_LEX_SYMBOL)
03222     {
03223         pNode = PD_NewNode();
03224         if (!pNode)
03225         {
03226             return NULL;
03227         }
03228         pNode->pNextNode = 0;
03229         pNode->pPrevNode = 0;
03230         pNode->iToken = 0;
03231         pNode->nToken = 1;
03232         pNode->pToken = p;
03233         pNode->uTokenType = PDTT_SYMBOL;
03234         if (ch == ':')
03235         {
03236             pNode->uCouldBe = PDCB_TIME_FIELD_SEPARATOR;
03237         }
03238         else if (ch == '-')
03239         {
03240             pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR|PDCB_SIGN;
03241         }
03242         else if (ch == '+')
03243         {
03244             pNode->uCouldBe = PDCB_SIGN;
03245         }
03246         else if (ch == '/')
03247         {
03248             pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR;
03249         }
03250         else if (ch == '.')
03251         {
03252             pNode->uCouldBe = PDCB_DATE_FIELD_SEPARATOR|PDCB_SECONDS_DECIMAL;
03253         }
03254         else if (ch == ',')
03255         {
03256             pNode->uCouldBe = PDCB_REMOVEABLE|PDCB_SECONDS_DECIMAL|PDCB_DAY_OF_MONTH_SUFFIX;
03257         }
03258 
03259         p++;
03260     }
03261     else
03262     {
03263         char *pSave = p;
03264         do
03265         {
03266             p++;
03267             ch = *p;
03268         } while (iType == LexTable[ch]);
03269 
03270         pNode = PD_NewNode();
03271         if (!pNode)
03272         {
03273             return NULL;
03274         }
03275         pNode->pNextNode = 0;
03276         pNode->pPrevNode = 0;
03277         size_t nLen = p - pSave;
03278         pNode->nToken = nLen;
03279         pNode->pToken = pSave;
03280         pNode->iToken = 0;
03281         pNode->uCouldBe = PDCB_NOTHING;
03282 
03283         if (iType == PD_LEX_DIGIT)
03284         {
03285             pNode->uTokenType = PDTT_NUMERIC_UNSIGNED;
03286 
03287             if (1 <= nLen && nLen <= 9)
03288             {
03289                 char buff[10];
03290                 memcpy(buff, pSave, nLen);
03291                 buff[nLen] = '\0';
03292                 pNode->iToken = mux_atol(buff);
03293                 ClassifyNumericToken(pNode);
03294             }
03295         }
03296         else if (iType == PD_LEX_SPACE)
03297         {
03298             pNode->uTokenType = PDTT_SPACES;
03299             pNode->uCouldBe = PDCB_WHITESPACE;
03300         }
03301         else if (iType == PD_LEX_ALPHA)
03302         {
03303             pNode->uTokenType = PDTT_TEXT;
03304 
03305             // Match Text.
03306             //
03307             int j = 0;
03308             bool bFound = false;
03309             while (PD_TextTable[j].szText)
03310             {
03311                 if (  strlen(PD_TextTable[j].szText) == nLen
03312                    && mux_memicmp(PD_TextTable[j].szText, pSave, nLen) == 0)
03313                 {
03314                     pNode->uCouldBe = PD_TextTable[j].uCouldBe;
03315                     pNode->iToken = PD_TextTable[j].iValue;
03316                     bFound = true;
03317                     break;
03318                 }
03319                 j++;
03320             }
03321             if (!bFound)
03322             {
03323                 return NULL;
03324             }
03325         }
03326     }
03327     *ppString = p;
03328     return pNode;
03329 }
03330 
03331 static const PD_BREAKDOWN BreakDownTable[] =
03332 {
03333     { PDCB_HMS_TIME, BreakDownHMS },
03334     { PDCB_HMS_TIMEZONE, BreakDownHMS },
03335     { PDCB_YD,  BreakDownYD },
03336     { PDCB_YMD, BreakDownYMD },
03337     { PDCB_MDY, BreakDownMDY },
03338     { PDCB_DMY, BreakDownDMY },
03339     { 0, 0 }
03340 };
03341 
03342 static void PD_Pass2(void)
03343 {
03344     PD_Node *pNode = PD_FirstNode();
03345     while (pNode)
03346     {
03347         PD_Node *pPrev = PD_PrevNode(pNode);
03348         PD_Node *pNext = PD_NextNode(pNode);
03349 
03350         // Absorb information from PDCB_TIME_FIELD_SEPARATOR.
03351         //
03352         if (pNode->uCouldBe & PDCB_TIME_FIELD_SEPARATOR)
03353         {
03354             if (pPrev && pNext)
03355             {
03356                 if (  (pPrev->uCouldBe & (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE))
03357                    && (pNext->uCouldBe & PDCB_MINUTE))
03358                 {
03359                     pPrev->uCouldBe &= (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE);
03360                     pNext->uCouldBe = PDCB_MINUTE;
03361                 }
03362                 else if (  (pPrev->uCouldBe & PDCB_MINUTE)
03363                         && (pNext->uCouldBe & PDCB_SECOND))
03364                 {
03365                     pPrev->uCouldBe = PDCB_MINUTE;
03366                     pNext->uCouldBe = PDCB_SECOND;
03367                 }
03368             }
03369             pNode->uCouldBe = PDCB_REMOVEABLE;
03370         }
03371 
03372         // Absorb information from PDCB_SECONDS_DECIMAL.
03373         //
03374         if (pNode->uCouldBe & PDCB_SECONDS_DECIMAL)
03375         {
03376             if (  pPrev
03377                && pNext
03378                && pPrev->uCouldBe == PDCB_SECOND
03379                && (pNext->uCouldBe & PDCB_SUBSECOND))
03380             {
03381                 pNode->uCouldBe = PDCB_SECONDS_DECIMAL;
03382                 pNext->uCouldBe = PDCB_SUBSECOND;
03383             }
03384             else
03385             {
03386                 pNode->uCouldBe &= ~PDCB_SECONDS_DECIMAL;
03387             }
03388             pNode->uCouldBe = PDCB_REMOVEABLE;
03389         }
03390 
03391         // Absorb information from PDCB_SUBSECOND
03392         //
03393         if (pNode->uCouldBe != PDCB_SUBSECOND)
03394         {
03395             pNode->uCouldBe &= ~PDCB_SUBSECOND;
03396         }
03397 
03398         // Absorb information from PDCB_DATE_FIELD_SEPARATOR.
03399         //
03400         if (pNode->uCouldBe & PDCB_DATE_FIELD_SEPARATOR)
03401         {
03402             pNode->uCouldBe &= ~PDCB_DATE_FIELD_SEPARATOR;
03403 
03404 #define PDCB_SEPS (PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_YEAR|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_WEEK)
03405             if (  pPrev
03406                && pNext
03407                && (pPrev->uCouldBe & PDCB_SEPS)
03408                && (pNext->uCouldBe & PDCB_SEPS))
03409             {
03410                 pPrev->uCouldBe &= PDCB_SEPS;
03411                 pNext->uCouldBe &= PDCB_SEPS;
03412                 pNode->uCouldBe = PDCB_REMOVEABLE;
03413             }
03414         }
03415 
03416 
03417         // Process PDCB_DAY_OF_MONTH_SUFFIX
03418         //
03419         if (pNode->uCouldBe & PDCB_DAY_OF_MONTH_SUFFIX)
03420         {
03421             pNode->uCouldBe = PDCB_REMOVEABLE;
03422             if (  pPrev
03423                && (pPrev->uCouldBe & PDCB_DAY_OF_MONTH))
03424             {
03425                 pPrev->uCouldBe = PDCB_DAY_OF_MONTH;
03426             }
03427         }
03428 
03429         // Absorb semantic meaning of PDCB_SIGN.
03430         //
03431         if (pNode->uCouldBe == PDCB_SIGN)
03432         {
03433 #define PDCB_SIGNABLES_POS (PDCB_HMS_TIME|PDCB_HMS_TIMEZONE)
03434 #define PDCB_SIGNABLES_NEG (PDCB_YEAR|PDCB_YD|PDCB_SIGNABLES_POS|PDCB_YMD)
03435             unsigned Signable;
03436             if (pNode->pToken[0] == '-')
03437             {
03438                 Signable = PDCB_SIGNABLES_NEG;
03439             }
03440             else
03441             {
03442                 Signable = PDCB_SIGNABLES_POS;
03443             }
03444             if (  pNext
03445                && (pNext->uCouldBe & Signable))
03446             {
03447                 pNext->uCouldBe &= Signable;
03448             }
03449             else
03450             {
03451                 pNode->uCouldBe = PDCB_REMOVEABLE;
03452             }
03453         }
03454 
03455         // A timezone HOUR or HMS requires a leading sign.
03456         //
03457         if (pNode->uCouldBe & (PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE))
03458         {
03459             if (  !pPrev
03460                || pPrev->uCouldBe != PDCB_SIGN)
03461             {
03462                 pNode->uCouldBe &= ~(PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE);
03463             }
03464         }
03465 
03466         // Likewise, a PDCB_HOUR_TIME or PDCB_HMS_TIME cannot have a
03467         // leading sign.
03468         //
03469         if (pNode->uCouldBe & (PDCB_HMS_TIME|PDCB_HOUR_TIME))
03470         {
03471             if (  pPrev
03472                && pPrev->uCouldBe == PDCB_SIGN)
03473             {
03474                 pNode->uCouldBe &= ~(PDCB_HMS_TIME|PDCB_HOUR_TIME);
03475             }
03476         }
03477 
03478         // Remove PDCB_WHITESPACE.
03479         //
03480         if (pNode->uCouldBe & (PDCB_WHITESPACE|PDCB_REMOVEABLE))
03481         {
03482             PD_RemoveNode(pNode);
03483         }
03484         pNode = pNext;
03485     }
03486 }
03487 
03488 typedef struct tag_pd_cantbe
03489 {
03490     unsigned int mask;
03491     unsigned int cantbe;
03492 } PD_CANTBE;
03493 
03494 const PD_CANTBE CantBeTable[] =
03495 {
03496     { PDCB_YEAR,         PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY },
03497     { PDCB_MONTH,        PDCB_MONTH|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX },
03498     { PDCB_DAY_OF_MONTH, PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX },
03499     { PDCB_DAY_OF_WEEK,  PDCB_DAY_OF_WEEK },
03500     { PDCB_WEEK_OF_YEAR, PDCB_WEEK_OF_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY },
03501     { PDCB_DAY_OF_YEAR,  PDCB_DAY_OF_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX },
03502     { PDCB_YD,           PDCB_YEAR|PDCB_YD|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_WEEK_OF_YEAR_PREFIX },
03503     { PDCB_YMD,          PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03504     { PDCB_MDY,          PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03505     { PDCB_DMY,          PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03506     { PDCB_YMD|PDCB_MDY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03507     { PDCB_MDY|PDCB_DMY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03508     { PDCB_YMD|PDCB_DMY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03509     { PDCB_YMD|PDCB_DMY|PDCB_MDY, PDCB_YEAR|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_WEEK_OF_YEAR_PREFIX|PDCB_WEEK_OF_YEAR|PDCB_YD|PDCB_DAY_OF_YEAR },
03510     { PDCB_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE },
03511     { PDCB_HOUR_TIME, PDCB_HMS_TIME|PDCB_HOUR_TIME },
03512     { PDCB_HOUR_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE },
03513     { PDCB_HMS_TIME, PDCB_HMS_TIME|PDCB_HOUR_TIME },
03514     { PDCB_HMS_TIMEZONE, PDCB_TIMEZONE|PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE },
03515     { 0, 0 }
03516 };
03517 
03518 static void PD_Deduction(void)
03519 {
03520     PD_Node *pNode = PD_FirstNode();
03521     while (pNode)
03522     {
03523         int j =0;
03524         while (CantBeTable[j].mask)
03525         {
03526             if (pNode->uCouldBe == CantBeTable[j].mask)
03527             {
03528                 PD_Node *pNodeInner = PD_FirstNode();
03529                 while (pNodeInner)
03530                 {
03531                     pNodeInner->uCouldBe &= ~CantBeTable[j].cantbe;
03532                     pNodeInner = PD_NextNode(pNodeInner);
03533                 }
03534                 pNode->uCouldBe = CantBeTable[j].mask;
03535                 break;
03536             }
03537             j++;
03538         }
03539         pNode = PD_NextNode(pNode);
03540     }
03541 }
03542 
03543 static void PD_BreakItDown(void)
03544 {
03545     PD_Node *pNode = PD_FirstNode();
03546     while (pNode)
03547     {
03548         int j =0;
03549         while (BreakDownTable[j].mask)
03550         {
03551             if (pNode->uCouldBe == BreakDownTable[j].mask)
03552             {
03553                 BreakDownTable[j].fpBreakDown(pNode);
03554                 break;
03555             }
03556             j++;
03557         }
03558         pNode = PD_NextNode(pNode);
03559     }
03560 }
03561 
03562 static void PD_Pass5(void)
03563 {
03564     bool bHaveSeenTimeHour = false;
03565     bool bMightHaveSeenTimeHour = false;
03566     PD_Node *pNode = PD_FirstNode();
03567     while (pNode)
03568     {
03569         PD_Node *pPrev = PD_PrevNode(pNode);
03570         PD_Node *pNext = PD_NextNode(pNode);
03571 
03572         // If all that is left is PDCB_HMS_TIME and PDCB_HOUR_TIME, then
03573         // it's PDCB_HOUR_TIME.
03574         //
03575         if (pNode->uCouldBe == (PDCB_HMS_TIME|PDCB_HOUR_TIME))
03576         {
03577             pNode->uCouldBe = PDCB_HOUR_TIME;
03578         }
03579         if (pNode->uCouldBe == (PDCB_HMS_TIMEZONE|PDCB_HOUR_TIMEZONE))
03580         {
03581             pNode->uCouldBe = PDCB_HOUR_TIMEZONE;
03582         }
03583 
03584         // PDCB_MINUTE must follow an PDCB_HOUR_TIME or PDCB_HOUR_TIMEZONE.
03585         //
03586         if (pNode->uCouldBe & PDCB_MINUTE)
03587         {
03588             if (  !pPrev
03589                || !(pPrev->uCouldBe & (PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE)))
03590             {
03591                 pNode->uCouldBe &= ~PDCB_MINUTE;
03592             }
03593         }
03594 
03595         // PDCB_SECOND must follow an PDCB_MINUTE.
03596         //
03597         if (pNode->uCouldBe & PDCB_SECOND)
03598         {
03599             if (  !pPrev
03600                || !(pPrev->uCouldBe & PDCB_MINUTE))
03601             {
03602                 pNode->uCouldBe &= ~PDCB_SECOND;
03603             }
03604         }
03605 
03606         // YMD MDY DMY
03607         //
03608         // PDCB_DAY_OF_MONTH cannot follow PDCB_YEAR.
03609         //
03610         if (  (pNode->uCouldBe & PDCB_DAY_OF_MONTH)
03611            && pPrev
03612            && pPrev->uCouldBe == PDCB_YEAR)
03613         {
03614             pNode->uCouldBe &= ~PDCB_DAY_OF_MONTH;
03615         }
03616 
03617         // Timezone cannot occur before the time.
03618         //
03619         if (  (pNode->uCouldBe & PDCB_TIMEZONE)
03620            && !bMightHaveSeenTimeHour)
03621         {
03622             pNode->uCouldBe &= ~PDCB_TIMEZONE;
03623         }
03624 
03625         // TimeDateSeparator cannot occur after the time.
03626         //
03627         if (  (pNode->uCouldBe & PDCB_DATE_TIME_SEPARATOR)
03628            && bHaveSeenTimeHour)
03629         {
03630             pNode->uCouldBe &= ~PDCB_DATE_TIME_SEPARATOR;
03631         }
03632 
03633         if (pNode->uCouldBe == PDCB_DATE_TIME_SEPARATOR)
03634         {
03635             PD_Node *pNodeInner = PD_FirstNode();
03636             while (pNodeInner && pNodeInner != pNode)
03637             {
03638                 pNodeInner->uCouldBe &= ~(PDCB_TIMEZONE|PDCB_HOUR_TIME|PDCB_HOUR_TIMEZONE|PDCB_MINUTE|PDCB_SECOND|PDCB_SUBSECOND|PDCB_MERIDIAN|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE);
03639                 pNodeInner = PD_NextNode(pNodeInner);
03640             }
03641             pNodeInner = pNext;
03642             while (pNodeInner)
03643             {
03644                 pNodeInner->uCouldBe &= ~(PDCB_WEEK_OF_YEAR_PREFIX|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_YEAR|PDCB_MONTH|PDCB_DAY_OF_MONTH|PDCB_DAY_OF_WEEK|PDCB_WEEK_OF_YEAR|PDCB_DAY_OF_YEAR);
03645                 pNodeInner = PD_NextNode(pNodeInner);
03646             }
03647             pNode->uCouldBe = PDCB_REMOVEABLE;
03648         }
03649 
03650         if (pNode->uCouldBe & PDCB_WEEK_OF_YEAR_PREFIX)
03651         {
03652             if (  pNext
03653                && (pNext->uCouldBe & PDCB_WEEK_OF_YEAR))
03654             {
03655                 pNext->uCouldBe = PDCB_WEEK_OF_YEAR;
03656                 pNode->uCouldBe = PDCB_REMOVEABLE;
03657             }
03658             else if (pNode->uCouldBe == PDCB_WEEK_OF_YEAR_PREFIX)
03659             {
03660                 pNode->uCouldBe = PDCB_REMOVEABLE;
03661             }
03662         }
03663 
03664         if (pNode->uCouldBe & (PDCB_HOUR_TIME|PDCB_HMS_TIME))
03665         {
03666             if ((pNode->uCouldBe & ~(PDCB_HOUR_TIME|PDCB_HMS_TIME)) == 0)
03667             {
03668                 bHaveSeenTimeHour = true;
03669             }
03670             bMightHaveSeenTimeHour = true;
03671         }
03672 
03673         // Remove PDCB_REMOVEABLE.
03674         //
03675         if (pNode->uCouldBe & PDCB_REMOVEABLE)
03676         {
03677             PD_RemoveNode(pNode);
03678         }
03679         pNode = pNext;
03680     }
03681 }
03682 
03683 static void PD_Pass6(void)
03684 {
03685     int cYear = 0;
03686     int cMonth = 0;
03687     int cDayOfMonth = 0;
03688     int cWeekOfYear = 0;
03689     int cDayOfYear = 0;
03690     int cDayOfWeek = 0;
03691     int cTime = 0;
03692 
03693     PD_Node *pNode = PD_FirstNode();
03694     while (pNode)
03695     {
03696         if (pNode->uCouldBe & (PDCB_HMS_TIME|PDCB_HOUR_TIME))
03697         {
03698             cTime++;
03699         }
03700         if (pNode->uCouldBe & PDCB_WEEK_OF_YEAR)
03701         {
03702             cWeekOfYear++;
03703         }
03704         if (pNode->uCouldBe & (PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY))
03705         {
03706             cYear++;
03707         }
03708         if (pNode->uCouldBe & (PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY))
03709         {
03710             cMonth++;
03711         }
03712         if (pNode->uCouldBe & (PDCB_DAY_OF_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY))
03713         {
03714             cDayOfMonth++;
03715         }
03716         if (pNode->uCouldBe & PDCB_DAY_OF_WEEK)
03717         {
03718             cDayOfWeek++;
03719         }
03720         if (pNode->uCouldBe & (PDCB_DAY_OF_YEAR|PDCB_YD))
03721         {
03722             cDayOfYear++;
03723         }
03724         pNode = PD_NextNode(pNode);
03725     }
03726 
03727     unsigned OnlyOneMask = 0;
03728     unsigned CantBeMask = 0;
03729     if (cYear == 1)
03730     {
03731         OnlyOneMask |= PDCB_YEAR|PDCB_YD|PDCB_YMD|PDCB_MDY|PDCB_DMY;
03732     }
03733     if (cTime == 1)
03734     {
03735         OnlyOneMask |= PDCB_HMS_TIME|PDCB_HOUR_TIME;
03736     }
03737     if (cMonth == 0 || cDayOfMonth == 0)
03738     {
03739         CantBeMask |= PDCB_MONTH|PDCB_DAY_OF_MONTH;
03740     }
03741     if (cDayOfWeek == 0)
03742     {
03743         CantBeMask |= PDCB_WEEK_OF_YEAR;
03744     }
03745     if (  cMonth == 1 && cDayOfMonth == 1
03746        && (cWeekOfYear != 1 || cDayOfWeek != 1)
03747        && cDayOfYear != 1)
03748     {
03749         OnlyOneMask |= PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY;
03750         OnlyOneMask |= PDCB_DAY_OF_MONTH;
03751         CantBeMask |= PDCB_WEEK_OF_YEAR|PDCB_YD;
03752     }
03753     else if (cDayOfYear == 1 && (cWeekOfYear != 1 || cDayOfWeek != 1))
03754     {
03755         OnlyOneMask |= PDCB_DAY_OF_YEAR|PDCB_YD;
03756         CantBeMask |= PDCB_WEEK_OF_YEAR|PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY;
03757         CantBeMask |= PDCB_DAY_OF_MONTH;
03758     }
03759     else if (cWeekOfYear == 1 && cDayOfWeek == 1)
03760     {
03761         OnlyOneMask |= PDCB_WEEK_OF_YEAR;
03762         OnlyOneMask |= PDCB_DAY_OF_WEEK;
03763         CantBeMask |= PDCB_YD|PDCB_MONTH|PDCB_YMD|PDCB_MDY|PDCB_DMY;
03764         CantBeMask |= PDCB_DAY_OF_MONTH;
03765     }
03766 
03767     // Also, if we match OnlyOneMask, then force only something in
03768     // OnlyOneMask.
03769     //
03770     pNode = PD_FirstNode();
03771     while (pNode)
03772     {
03773         if (pNode->uCouldBe & OnlyOneMask)
03774         {
03775             pNode->uCouldBe &= OnlyOneMask;
03776         }
03777         if (pNode->uCouldBe & ~CantBeMask)
03778         {
03779             pNode->uCouldBe &= ~CantBeMask;
03780         }
03781         pNode = PD_NextNode(pNode);
03782     }
03783 }
03784 
03785 static bool PD_GetFields(ALLFIELDS *paf)
03786 {
03787     paf->iYear            = NOT_PRESENT;
03788     paf->iDayOfYear       = NOT_PRESENT;
03789     paf->iMonthOfYear     = NOT_PRESENT;
03790     paf->iDayOfMonth      = NOT_PRESENT;
03791     paf->iWeekOfYear      = NOT_PRESENT;
03792     paf->iDayOfWeek       = NOT_PRESENT;
03793     paf->iHourTime        = NOT_PRESENT;
03794     paf->iMinuteTime      = NOT_PRESENT;
03795     paf->iSecondTime      = NOT_PRESENT;
03796     paf->iMillisecondTime = NOT_PRESENT;
03797     paf->iMicrosecondTime = NOT_PRESENT;
03798     paf->iNanosecondTime  = NOT_PRESENT;
03799     paf->iMinuteTimeZone  = NOT_PRESENT;
03800 
03801     PD_Node *pNode = PD_FirstNode();
03802     while (pNode)
03803     {
03804         if (pNode->uCouldBe == PDCB_YEAR)
03805         {
03806             paf->iYear = pNode->iToken;
03807             PD_Node *pPrev = PD_PrevNode(pNode);
03808             if (  pPrev
03809                && pPrev->uCouldBe == PDCB_SIGN
03810                && pPrev->pToken[0] == '-')
03811             {
03812                 paf->iYear = -paf->iYear;
03813             }
03814         }
03815         else if (pNode->uCouldBe == PDCB_DAY_OF_YEAR)
03816         {
03817             paf->iDayOfYear = pNode->iToken;
03818         }
03819         else if (pNode->uCouldBe == PDCB_MONTH)
03820         {
03821             paf->iMonthOfYear = pNode->iToken;
03822         }
03823         else if (pNode->uCouldBe == PDCB_DAY_OF_MONTH)
03824         {
03825             paf->iDayOfMonth = pNode->iToken;
03826         }
03827         else if (pNode->uCouldBe == PDCB_WEEK_OF_YEAR)
03828         {
03829             paf->iWeekOfYear = pNode->iToken;
03830         }
03831         else if (pNode->uCouldBe == PDCB_DAY_OF_WEEK)
03832         {
03833             paf->iDayOfWeek = pNode->iToken;
03834         }
03835         else if (pNode->uCouldBe == PDCB_HOUR_TIME)
03836         {
03837             paf->iHourTime = pNode->iToken;
03838             pNode = PD_NextNode(pNode);
03839             if (  pNode
03840                && pNode->uCouldBe == PDCB_MINUTE)
03841             {
03842                 paf->iMinuteTime = pNode->iToken;
03843                 pNode = PD_NextNode(pNode);
03844                 if (  pNode
03845                    && pNode->uCouldBe == PDCB_SECOND)
03846                 {
03847                     paf->iSecondTime = pNode->iToken;
03848                     pNode = PD_NextNode(pNode);
03849                     if (  pNode
03850                        && pNode->uCouldBe == PDCB_SUBSECOND)
03851                     {
03852                         unsigned short ms, us, ns;
03853                         ParseDecimalSeconds(pNode->nToken, pNode->pToken, &ms,
03854                             &us, &ns);
03855 
03856                         paf->iMillisecondTime = ms;
03857                         paf->iMicrosecondTime = us;
03858                         paf->iNanosecondTime  = ns;
03859                         pNode = PD_NextNode(pNode);
03860                     }
03861                 }
03862             }
03863             if (  pNode
03864                && pNode->uCouldBe == PDCB_MERIDIAN)
03865             {
03866                 if (paf->iHourTime == 12)
03867                 {
03868                     paf->iHourTime = 0;
03869                 }
03870                 paf->iHourTime += pNode->iToken;
03871                 pNode = PD_NextNode(pNode);
03872             }
03873             continue;
03874         }
03875         else if (pNode->uCouldBe == PDCB_HOUR_TIMEZONE)
03876         {
03877             paf->iMinuteTimeZone = pNode->iToken * 60;
03878             PD_Node *pPrev = PD_PrevNode(pNode);
03879             if (  pPrev
03880                && pPrev->uCouldBe == PDCB_SIGN
03881                && pPrev->pToken[0] == '-')
03882             {
03883                 paf->iMinuteTimeZone = -paf->iMinuteTimeZone;
03884             }
03885             pNode = PD_NextNode(pNode);
03886             if (  pNode
03887                && pNode->uCouldBe == PDCB_MINUTE)
03888             {
03889                 if (paf->iMinuteTimeZone < 0)
03890                 {
03891                     paf->iMinuteTimeZone -= pNode->iToken;
03892                 }
03893                 else
03894                 {
03895                     paf->iMinuteTimeZone += pNode->iToken;
03896                 }
03897                 pNode = PD_NextNode(pNode);
03898             }
03899             continue;
03900         }
03901         else if (pNode->uCouldBe == PDCB_TIMEZONE)
03902         {
03903             if (pNode->iToken < 0)
03904             {
03905                 paf->iMinuteTimeZone = (pNode->iToken / 100) * 60
03906                                 - ((-pNode->iToken) % 100);
03907             }
03908             else
03909             {
03910                 paf->iMinuteTimeZone = (pNode->iToken / 100) * 60
03911                                 + pNode->iToken % 100;
03912             }
03913         }
03914         else if (pNode->uCouldBe & (PDCB_SIGN|PDCB_DATE_TIME_SEPARATOR))
03915         {
03916             ; // Nothing
03917         }
03918         else
03919         {
03920             return false;
03921         }
03922         pNode = PD_NextNode(pNode);
03923     }
03924     return true;
03925 }
03926 
03927 static bool ConvertAllFieldsToLinearTime(CLinearTimeAbsolute &lta, ALLFIELDS *paf)
03928 {
03929     FIELDEDTIME ft;
03930     memset(&ft, 0, sizeof(ft));
03931 
03932     int iExtraDays = 0;
03933     if (paf->iYear == NOT_PRESENT)
03934     {
03935         return false;
03936     }
03937     ft.iYear = paf->iYear;
03938 
03939     if (paf->iMonthOfYear != NOT_PRESENT && paf->iDayOfMonth != NOT_PRESENT)
03940     {
03941         ft.iMonth = paf->iMonthOfYear;
03942         ft.iDayOfMonth = paf->iDayOfMonth;
03943     }
03944     else if (paf->iDayOfYear != NOT_PRESENT)
03945     {
03946         iExtraDays = paf->iDayOfYear - 1;
03947         ft.iMonth = 1;
03948         ft.iDayOfMonth = 1;
03949     }
03950     else if (paf->iWeekOfYear != NOT_PRESENT && paf->iDayOfWeek != NOT_PRESENT)
03951     {
03952         // Remember that iYear in this case represents an ISO year, which
03953         // is not exactly the same thing as a Gregorian year.
03954         //
03955         FIELDEDTIME ftWD;
03956         memset(&ftWD, 0, sizeof(ftWD));
03957         ftWD.iYear = paf->iYear - 1;
03958         ftWD.iMonth = 12;
03959         ftWD.iDayOfMonth = 27;
03960         if (!lta.SetFields(&ftWD))
03961         {
03962             return false;
03963         }
03964         INT64 i64 = lta.Return100ns();
03965         INT64 j64;
03966         i64FloorDivisionMod(i64+FACTOR_100NS_PER_DAY, FACTOR_100NS_PER_WEEK, &j64);
03967         i64 -= j64;
03968 
03969         // i64 now corresponds to the Sunday that strickly preceeds before
03970         // December 28th, and the 28th is guaranteed to be in the previous
03971         // year so that the ISO and Gregorian Years are the same thing.
03972         //
03973         i64 += FACTOR_100NS_PER_WEEK*paf->iWeekOfYear;
03974         i64 += FACTOR_100NS_PER_DAY*paf->iDayOfWeek;
03975         lta.Set100ns(i64);
03976         lta.ReturnFields(&ft);
03977 
03978         // Validate that this week actually has a week 53.
03979         //
03980         if (paf->iWeekOfYear == 53)
03981         {
03982             int iDOW_ISO = (ft.iDayOfWeek == 0) ? 7 : ft.iDayOfWeek;
03983             int j = ft.iDayOfMonth - iDOW_ISO;
03984             if (ft.iMonth == 12)
03985             {
03986                 if (28 <= j)
03987                 {
03988                     return false;
03989                 }
03990             }
03991             else // if (ft.iMonth == 1)
03992             {
03993                 if (-3 <= j)
03994                 {
03995                     return false;
03996                 }
03997             }
03998         }
03999     }
04000     else
04001     {
04002         // Under-specified.
04003         //
04004         return false;
04005     }
04006 
04007     if (paf->iHourTime != NOT_PRESENT)
04008     {
04009         ft.iHour = paf->iHourTime;
04010         if (paf->iMinuteTime != NOT_PRESENT)
04011         {
04012             ft.iMinute = paf->iMinuteTime;
04013             if (paf->iSecondTime != NOT_PRESENT)
04014             {
04015                 ft.iSecond = paf->iSecondTime;
04016                 if (paf->iMillisecondTime != NOT_PRESENT)
04017                 {
04018                     ft.iMillisecond = paf->iMillisecondTime;
04019                     ft.iMicrosecond = paf->iMicrosecondTime;
04020                     ft.iNanosecond = paf->iNanosecondTime;
04021                 }
04022             }
04023         }
04024     }
04025 
04026     if (lta.SetFields(&ft))
04027     {
04028         CLinearTimeDelta ltd;
04029         if (paf->iMinuteTimeZone != NOT_PRESENT)
04030         {
04031             ltd.SetSeconds(60 * paf->iMinuteTimeZone);
04032             lta -= ltd;
04033         }
04034         if (iExtraDays)
04035         {
04036             ltd.Set100ns(FACTOR_100NS_PER_DAY);
04037             lta += ltd * iExtraDays;
04038         }
04039         return true;
04040     }
04041     return false;
04042 }
04043 
04044 bool ParseDate
04045 (
04046     CLinearTimeAbsolute &lt,
04047     char *pDateString,
04048     bool *pbZoneSpecified
04049 )
04050 {
04051     PD_Reset();
04052 
04053     char *p = pDateString;
04054     PD_Node *pNode;
04055     while ((pNode = PD_ScanNextToken(&p)))
04056     {
04057         PD_AppendNode(pNode);
04058     }
04059 
04060     PD_Pass2();
04061 
04062     PD_Deduction();
04063     PD_BreakItDown();
04064     PD_Pass5();
04065     PD_Pass6();
04066 
04067     PD_Deduction();
04068     PD_BreakItDown();
04069     PD_Pass5();
04070     PD_Pass6();
04071 
04072     ALLFIELDS af;
04073     if (  PD_GetFields(&af)
04074        && ConvertAllFieldsToLinearTime(lt, &af))
04075     {
04076         *pbZoneSpecified = (af.iMinuteTimeZone != NOT_PRESENT);
04077         return true;
04078     }
04079     return false;
04080 }

Generated on Mon May 28 04:40:12 2007 for MUX by  doxygen 1.4.7