00001
00017 #include "copyright.h"
00018 #include "autoconf.h"
00019 #include "config.h"
00020 #include "externs.h"
00021
00022
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
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
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
00107
00108 DCL_INLINE int iRemainder(int x, int y)
00109 {
00110 return x % y;
00111 }
00112
00113
00114
00115 DCL_INLINE int iDivision(int x, int y)
00116 {
00117 return x / y;
00118 }
00119
00120
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
00263
00264 int DCL_INLINE iMod(int x, int y)
00265 {
00266 return x % y;
00267 }
00268
00269
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
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
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
00475
00476 while (mux_isspace(*str))
00477 {
00478 str++;
00479 }
00480
00481
00482
00483 if (*str == '-')
00484 {
00485 bMinus = true;
00486 str++;
00487
00488
00489
00490 if (!*str)
00491 {
00492 return false;
00493 }
00494 }
00495
00496
00497
00498 bGotOne = false;
00499 char *pIntegerStart = str;
00500 if (mux_isdigit(*str))
00501 {
00502 bGotOne = true;
00503 str++;
00504 }
00505
00506
00507
00508 while (mux_isdigit(*str))
00509 {
00510 str++;
00511 }
00512 char *pIntegerEnd = str;
00513
00514
00515
00516 if (*str == '.')
00517 {
00518 str++;
00519 }
00520
00521
00522
00523 char *pFractionalStart = str;
00524 if (mux_isdigit(*str))
00525 {
00526 bGotOne = true;
00527 str++;
00528 }
00529
00530
00531
00532 while (mux_isdigit(*str))
00533 {
00534 str++;
00535 }
00536 char *pFractionalEnd = str;
00537
00538
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
00556
00557 if (bMinus)
00558 {
00559 *p++ = '-';
00560 nBufferAvailable--;
00561 }
00562
00563
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
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
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
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 <a)
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
00720
00721
00722
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
00783
00784
00785 m_tAbsolute += EPOCH_OFFSET;
00786 }
00787
00788 INT64 CLinearTimeAbsolute::ReturnSeconds(void)
00789 {
00790
00791
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
00801
00802 return false;
00803 }
00804 unsigned long wMod = iMod(iYear, 400);
00805 if ((wMod == 100) || (wMod == 200) || (wMod == 300))
00806 {
00807
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
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
00867
00868
00869 return iFixedDay - 584389;
00870 }
00871
00872
00873
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
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
00936
00937
00938 GregorianFromFixed(iFixedDay + 584389, iYear, iMonth, iDayOfYear, iDayOfMonth, iDayOfWeek);
00939 }
00940
00941
00942
00943
00944
00945
00946
00947
00948
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
00962
00963 const char *p = *pp;
00964 while (*p == ' ')
00965 {
00966 p++;
00967 }
00968
00969
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
00984
00985 if (q - p != 3)
00986 {
00987 return false;
00988 }
00989 p = q;
00990
00991
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
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
01041
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;
01054
01055
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
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
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
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
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
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
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
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
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
01409
01410 #ifdef WIN32
01411
01412
01413
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
01504
01505 li = a + (b-a)/2;
01506 return true;
01507 }
01508
01509
01510
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
01549
01550
01551
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
01565
01566
01567
01568 INT64 tError = Ticks2Seconds.Convert(li) + xIntercept - t;
01569
01570
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
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
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
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
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
01853
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
01882
01883
01884
01885
01886
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
01924
01925
01926 static void test_time_t(void)
01927 {
01928
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
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
01966
01967 for (;;)
01968 {
01969 struct tm *ptm = localtime(&tLower);
01970
01971 if (ptm->tm_isdst <= 0)
01972 {
01973
01974
01975
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
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
02036
02037
02038
02039
02040
02041
02042
02043
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
02060
02061
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
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 <a,
02113 CLinearTimeDelta ltdOffset,
02114 bool isDST,
02115 int i
02116 )
02117 {
02118 Again:
02119
02120 nTouched0++;
02121
02122
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
02134
02135
02136
02137
02138
02139 if ( 0 <= i
02140 && OffsetTable[i].ltdOffset == ltdOffset
02141 && OffsetTable[i].isDST == isDST
02142 && lta <= OffsetTable[i].ltaEnd + ltdIntervalMinimum)
02143 {
02144
02145
02146
02147 OffsetTable[i].ltaEnd = lta;
02148 OffsetTable[i].nTouched = nTouched0;
02149
02150
02151
02152
02153 bTryMerge = true;
02154 }
02155
02156
02157
02158
02159
02160
02161
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
02171
02172
02173 OffsetTable[iNext].ltaStart = lta;
02174 OffsetTable[iNext].nTouched = nTouched0;
02175
02176
02177
02178
02179 bTryMerge = true;
02180 }
02181
02182 if (bTryMerge)
02183 {
02184
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
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
02221
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
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274 if (lta > ltaUpperBound)
02275 {
02276
02277
02278
02279 FIELDEDTIME ft;
02280 lta.ReturnFields(&ft);
02281 ft.iYear = NearestYearOfType[YearType(ft.iYear)];
02282 lta.SetFields(&ft);
02283 }
02284
02285
02286
02287
02288
02289 time_t lt = (time_t)lta.ReturnSeconds();
02290 struct tm *ptm = localtime(<);
02291 if (!ptm)
02292 {
02293
02294
02295
02296 return ltdTimeZoneStandard;
02297 }
02298
02299
02300
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
02317
02318
02319 UpdateOffsetTable(lta, ltdOffset, *pisDST, iEntry);
02320 return ltdOffset;
02321 }
02322
02323 static CLinearTimeDelta QueryLocalOffsetAtUTC
02324 (
02325 const CLinearTimeAbsolute <a,
02326 bool *pisDST
02327 )
02328 {
02329 *pisDST = false;
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352 if (lta < ltaLowerBound)
02353 {
02354 return ltdTimeZoneStandard;
02355 }
02356
02357
02358
02359
02360
02361
02362
02363 CLinearTimeDelta ltdOffset;
02364 int iEntry;
02365 if (QueryOffsetTable(lta, <dOffset, pisDST, &iEntry))
02366 {
02367 return ltdOffset;
02368 }
02369 ltdOffset = QueryLocalOffsetAt_Internal(lta, pisDST, iEntry);
02370
02371
02372
02373
02374
02375 CLinearTimeAbsolute ltaProbe;
02376 CLinearTimeDelta ltdDontCare;
02377 bool bDontCare;
02378
02379 ltaProbe = lta - ltdIntervalMinimum;
02380 if (!QueryOffsetTable(ltaProbe, <dDontCare, &bDontCare, &iEntry))
02381 {
02382 QueryLocalOffsetAt_Internal(ltaProbe, &bDontCare, iEntry);
02383 }
02384
02385 ltaProbe = lta + ltdIntervalMinimum;
02386 if (!QueryOffsetTable(ltaProbe, <dDontCare, &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
02411
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
02423
02424
02425
02426
02427
02428 typedef struct tag_pd_node
02429 {
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453 unsigned uCouldBe;
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
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
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
02543
02544 static bool isValidYear(size_t nStr, char *pStr, int iValue)
02545 {
02546 UNUSED_PARAMETER(pStr);
02547 UNUSED_PARAMETER(iValue);
02548
02549
02550
02551
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
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
02579
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
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
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
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
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
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
02664
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
02680
02681
02682 if (nStr <= 7)
02683 {
02684 return true;
02685 }
02686 return false;
02687 }
02688
02689
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
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
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
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
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
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
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
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
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
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,
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,
02899 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_DAY_OF_YEAR|PDCB_SUBSECOND,
02900 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND,
02901 PDCB_YEAR|PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YD|PDCB_SUBSECOND,
02902 PDCB_HMS_TIME|PDCB_HMS_TIMEZONE|PDCB_YMD|PDCB_MDY|PDCB_DMY|PDCB_YD|PDCB_SUBSECOND,
02903 PDCB_YMD|PDCB_YD|PDCB_SUBSECOND,
02904 PDCB_YMD|PDCB_YD,
02905 PDCB_YMD
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
02937
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
03075
03076 5, 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,
03078 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
03079 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
03080 0, 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,
03082 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
03083 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,
03084
03085 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03086 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03087 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03088 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03089 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03091 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
03092 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
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
03141
03142
03143
03144
03145
03146
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
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
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
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
03392
03393 if (pNode->uCouldBe != PDCB_SUBSECOND)
03394 {
03395 pNode->uCouldBe &= ~PDCB_SUBSECOND;
03396 }
03397
03398
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
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
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
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
03467
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
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
03573
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
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
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
03607
03608
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
03618
03619 if ( (pNode->uCouldBe & PDCB_TIMEZONE)
03620 && !bMightHaveSeenTimeHour)
03621 {
03622 pNode->uCouldBe &= ~PDCB_TIMEZONE;
03623 }
03624
03625
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
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
03768
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 ;
03917 }
03918 else
03919 {
03920 return false;
03921 }
03922 pNode = PD_NextNode(pNode);
03923 }
03924 return true;
03925 }
03926
03927 static bool ConvertAllFieldsToLinearTime(CLinearTimeAbsolute <a, 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
03953
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
03970
03971
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
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
03992 {
03993 if (-3 <= j)
03994 {
03995 return false;
03996 }
03997 }
03998 }
03999 }
04000 else
04001 {
04002
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 <,
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 }