timedate.c

Go to the documentation of this file.
00001 
00002 /*  $Id: timedate.c 1211 2006-04-06 00:20:14Z karstenw $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "error.h"
00032 #include "memory.h"
00033 #include "strings.h"
00034 #include "ops.h"
00035 #include "langinternal.h"
00036 #include "shell.h"
00037 
00038 #include "timedate.h"
00039 
00040 #ifdef MACVERSION
00041     #define tydate DateTimeRec
00042 #endif
00043 
00044 #ifdef WIN95VERSION
00045     #define tydate SYSTEMTIME
00046 #endif
00047 
00048 
00049 typedef struct tyValidationOrder {
00050     short item;
00051     short type;
00052 } tyValidationOrder, * tyValidationOrderPtr;
00053 
00054 typedef unsigned long tyCharacterAttributes;
00055 
00056 
00057 static short daysInMonthsArray[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00058 
00059 #define DateTimeSet_kDayOfWeek      0x0100
00060 #define DateTimeSet_kYear           0x0040
00061 #define DateTimeSet_kMonth          0x0020
00062 #define DateTimeSet_kDay            0x0010
00063 #define DateTimeSet_kHour           0x0008
00064 #define DateTimeSet_kMinute         0x0004
00065 #define DateTimeSet_kSecond         0x0002
00066 #define DateTimeSet_kHundredth      0x0001
00067 
00068 #define DurationUnit_kDays          0x0010
00069 
00070 #define err_kTooManyNumberFields    20000
00071 #define err_kTooFewValues           20001
00072 #define err_kOutOfOrder             20002
00073 #define err_kItemUsed               20003
00074 #define err_kInvalidPunctuation     20004
00075 #define err_kHundredthValueInvalid  20005
00076 #define err_kSecondValueInvalid     20006
00077 #define err_kMinuteValueInvalid     20007
00078 #define err_kHourValueInvalid       20008
00079 #define err_kAMorPMon24HourClock    20009
00080 
00081 #define CharAttr_kShortDate         0x00000001
00082 #define CharAttr_kLongDate          0x00000002
00083 #define CharAttr_kTime              0x00000004
00084 
00085 #define SCAN_DOW    1
00086 #define SCAN_MONTH  2
00087 #define SCAN_YEAR   4
00088 
00089 #define VALTYPE_NONE        0
00090 #define VALTYPE_KEYMONTHNAME1   1
00091 #define VALTYPE_KEYMONTHNAME2   2
00092 #define VALTYPE_KEYDAYNAME1 3
00093 #define VALTYPE_KEYDAYNAME2 4
00094 #define VALTYPE_KEYYEARNAME 5
00095 #define VALTYPE_KEYTIMEAM   6
00096 #define VALTYPE_KEYTIMEPM   7
00097 #define VALTYPE_KEYTIME24   8
00098 #define VALTYPE_CURRENCY    9
00099 #define VALTYPE_BLANK          10
00100 #define VALTYPE_NUMERIC        11
00101 #define VALTYPE_PUNC           12
00102 #define VALTYPE_NONNUMERIC     13
00103 
00104 #define VALORDER_NUMERIC    1
00105 #define VALORDER_FIXEDNUMERIC   2
00106 #define VALORDER_KEYWORD    3
00107 
00108 #define VALFLAG_ISDOLLARS   (0x1000)
00109 #define VALFLAG_ISCENTS     (0x2000)
00110 
00111 typedef struct tyvalidationtoken
00112    {
00113    short ty;
00114    char * pos;
00115    short count;
00116    long val;
00117    unsigned long flag;
00118    } tyvalidationtoken, * tyvalidationtokenptr;
00119 
00120 
00121 #ifdef WIN95VERSION
00122     static tyinternationalinfo globalII;
00123     static tyinternationalinfoptr globalIIptr = NULL;
00124     
00125     static LONGLONG gPerformanceFreq = 0;  /* for getmilliseconds() */
00126 #endif
00127 
00128 typedef struct tydaterec {
00129     short year;
00130     short month;
00131     short dayOfWeek;
00132     short day;
00133     short hour;
00134     short minute;
00135     short second;
00136     short hundredths;
00137     } tydaterec, * tydaterecptr;
00138 
00139 typedef struct tyvalidationerror {
00140     long errorNumber;
00141     long stringPosition;
00142     char * auxilaryPointer;
00143     } tyvalidationerror, * tyvalidationerrorptr;
00144 
00145 
00146 #ifdef WIN95VERSION
00147 
00148 boolean ValidDate (
00149    unsigned char * strIn,
00150    short cnt,
00151    tydaterecptr returnDT,
00152    tydaterecptr actualDT,
00153    unsigned long * validUnits,
00154    tyvalidationerrorptr err);
00155 
00156 boolean ValidTime (
00157    char * strIn,
00158    short cnt,
00159    tydaterecptr returnDT,
00160    tydaterecptr actualDT,
00161    unsigned long * validUnits,
00162    tyvalidationerrorptr err);
00163 
00164 
00165 static boolean getNewLocaleString (unsigned long lc, char ** foo, char * defValue) {
00166 
00167     char buf[300];
00168     short len;
00169 
00170     len = GetLocaleInfo (LOCALE_USER_DEFAULT, lc, buf, 300);
00171 
00172     if (len != 0) {
00173         *foo = malloc (len + 2);
00174         if (*foo != NULL) {
00175             moveleft (buf, stringbaseaddress((*foo)), len);
00176             setstringlength ((*foo), len-1);
00177             nullterminate ((*foo));
00178             return (true);
00179             }
00180         }
00181     else {
00182         len = strlen (defValue);
00183         *foo = malloc (len + 2);
00184         if (*foo != NULL) {
00185             moveleft (defValue, stringbaseaddress((*foo)), len);
00186             setstringlength ((*foo), len);
00187             nullterminate ((*foo));
00188             return (true);
00189             }
00190         }
00191 
00192     return (false);
00193     } /*getNewLocaleString*/
00194 
00195 
00196 static boolean getNewLocalePatternString (unsigned long lc, char ** foo, char * defValue) {
00197     
00198     /*
00199     2004-12-09 aradke: site of a mysterious crashing bug, possibly a CodeWarrior 8.x compiler bug.
00200     with full optimizations, the cw compiler produces the following code for Win32:
00201 
00202         221:                      buf2[j++] = '%';
00203             00420257   movsx       eax,word ptr [j]
00204             0042025E   movsx       edi,word ptr [j]
00205         222:                      buf2[j++] = '%';
00206             00420265   movsx       edx,word ptr [edi+1]
00207             00420269   mov         byte ptr buf2[eax],25h
00208         
00209     the instruction at 00420265 ends up attempting to read from address 0x00000001.
00210     details are available in bug #1081295 on sourceforge.net:
00211     http://sourceforge.net/tracker/index.php?func=detail&aid=1081295&group_id=120666&atid=687798
00212     
00213     the crashes disappear when the type of the integer variables is switched from short to int,
00214     so that's what we'll do for now.
00215     
00216     also, check len for failed GetLocaleInfo call before decrementing it.
00217     */
00218     
00219     char buf[256];
00220     char buf2[256];
00221     int i, j, cnt, len; /*2004-12-09 aradke*/
00222     char c;
00223 
00224     len = GetLocaleInfo (LOCALE_USER_DEFAULT, lc, buf, 256);
00225     
00226     if (len > 0) {
00227         --len; /*2004-12-09 aradke: dont't attempt to parse trailing nil char*/
00228         i = 0;
00229         j = 0;
00230 
00231         while (len > i) {
00232             c = buf[i++];
00233 
00234             switch (c) {
00235                 case 'M':
00236                 case 'd':
00237                 case 'y':
00238                 case 'h':
00239                 case 'm':
00240                 case 's':
00241                 case 't':
00242                     cnt = 1;
00243                     while (buf[i] == c) {
00244                         ++cnt;
00245                         ++i;
00246                         }
00247 
00248                     buf2[j++] = '%';
00249                     buf2[j++] = '%';
00250 
00251                     buf2[j++] = toupper(c);
00252 
00253                     if (cnt > 2)
00254                         buf2[j++] = 'N';
00255                     else
00256                         buf2[j++] = '#';
00257                     break;
00258 
00259                 default:
00260                     buf2[j++] = c;
00261                     break;
00262                 }
00263             }
00264 
00265         len = j;
00266 
00267         *foo = malloc (len + 2);
00268         if (*foo != NULL) {
00269             moveleft (buf2, stringbaseaddress((*foo)), len);
00270             setstringlength ((*foo), len);
00271             nullterminate ((*foo));
00272             return (true);
00273             }
00274         }
00275     else {
00276         len = strlen (defValue);
00277         *foo = malloc (len + 2);
00278         if (*foo != NULL) {
00279             moveleft (defValue, stringbaseaddress((*foo)), len);
00280             setstringlength ((*foo), len);
00281             nullterminate ((*foo));
00282             return (true);
00283             }
00284         }
00285 
00286     return (false);
00287     }
00288 
00289 
00290 static boolean initInternationalInfo() {
00291 
00292     short i;
00293     boolean res = true;
00294 
00295     res = res && getNewLocaleString (LOCALE_SDAYNAME7, &globalII.longDaysOfWeek[0], "Sunday");
00296     res = res && getNewLocaleString (LOCALE_SDAYNAME1, &globalII.longDaysOfWeek[1], "Monday");
00297     res = res && getNewLocaleString (LOCALE_SDAYNAME2, &globalII.longDaysOfWeek[2], "Tuesday");
00298     res = res && getNewLocaleString (LOCALE_SDAYNAME3, &globalII.longDaysOfWeek[3], "Wednesday");
00299     res = res && getNewLocaleString (LOCALE_SDAYNAME4, &globalII.longDaysOfWeek[4], "Thursday");
00300     res = res && getNewLocaleString (LOCALE_SDAYNAME5, &globalII.longDaysOfWeek[5], "Friday");
00301     res = res && getNewLocaleString (LOCALE_SDAYNAME6, &globalII.longDaysOfWeek[6], "Saturday");
00302     res = res && getNewLocaleString (999999, &globalII.longDaysOfWeek[7], "Yesterday");
00303     res = res && getNewLocaleString (999999, &globalII.longDaysOfWeek[8], "Today");
00304     res = res && getNewLocaleString (999999, &globalII.longDaysOfWeek[9], "Tomorrow");
00305 
00306     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME7, &globalII.shortDaysOfWeek[0], "Sun");
00307     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME1, &globalII.shortDaysOfWeek[1], "Mon");
00308     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME2, &globalII.shortDaysOfWeek[2], "Tue");
00309     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME3, &globalII.shortDaysOfWeek[3], "Wed");
00310     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME4, &globalII.shortDaysOfWeek[4], "Thu");
00311     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME5, &globalII.shortDaysOfWeek[5], "Fri");
00312     res = res && getNewLocaleString (LOCALE_SABBREVDAYNAME6, &globalII.shortDaysOfWeek[6], "Sat");
00313     res = res && getNewLocaleString (999999, &globalII.shortDaysOfWeek[7], "Yest");
00314     res = res && getNewLocaleString (999999, &globalII.shortDaysOfWeek[8], "Tod");
00315     res = res && getNewLocaleString (999999, &globalII.shortDaysOfWeek[9], "Tom");
00316 
00317     res = res && getNewLocaleString (LOCALE_SMONTHNAME1, &globalII.longMonths[0], "January");
00318     res = res && getNewLocaleString (LOCALE_SMONTHNAME2, &globalII.longMonths[1], "February");
00319     res = res && getNewLocaleString (LOCALE_SMONTHNAME3, &globalII.longMonths[2], "March");
00320     res = res && getNewLocaleString (LOCALE_SMONTHNAME4, &globalII.longMonths[3], "April");
00321     res = res && getNewLocaleString (LOCALE_SMONTHNAME5, &globalII.longMonths[4], "May");
00322     res = res && getNewLocaleString (LOCALE_SMONTHNAME6, &globalII.longMonths[5], "June");
00323     res = res && getNewLocaleString (LOCALE_SMONTHNAME7, &globalII.longMonths[6], "July");
00324     res = res && getNewLocaleString (LOCALE_SMONTHNAME8, &globalII.longMonths[7], "August");
00325     res = res && getNewLocaleString (LOCALE_SMONTHNAME9, &globalII.longMonths[8], "September");
00326     res = res && getNewLocaleString (LOCALE_SMONTHNAME10, &globalII.longMonths[9], "October");
00327     res = res && getNewLocaleString (LOCALE_SMONTHNAME11, &globalII.longMonths[10], "November");
00328     res = res && getNewLocaleString (LOCALE_SMONTHNAME12, &globalII.longMonths[11], "December");
00329     res = res && getNewLocaleString (LOCALE_SMONTHNAME13, &globalII.longMonths[12], "");
00330     
00331     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME1, &globalII.shortMonths[0], "Jan");
00332     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME2, &globalII.shortMonths[1], "Feb");
00333     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME3, &globalII.shortMonths[2], "Mar");
00334     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME4, &globalII.shortMonths[3], "Apr");
00335     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME5, &globalII.shortMonths[4], "May");
00336     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME6, &globalII.shortMonths[5], "Jun");
00337     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME7, &globalII.shortMonths[6], "Jul");
00338     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME8, &globalII.shortMonths[7], "Aug");
00339     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME9, &globalII.shortMonths[8], "Sep");
00340     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME10, &globalII.shortMonths[9], "Oct");
00341     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME11, &globalII.shortMonths[10], "Nov");
00342     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME12, &globalII.shortMonths[11], "Dec");
00343     res = res && getNewLocaleString (LOCALE_SABBREVMONTHNAME13, &globalII.shortMonths[12], "");
00344     
00345     res = res && getNewLocaleString (LOCALE_S1159, &globalII.morning, "AM");
00346     res = res && getNewLocaleString (LOCALE_S2359, &globalII.evening, "PM");
00347     res = res && getNewLocaleString (999999, &globalII.military, "hours");
00348     
00349     res = res && getNewLocaleString (LOCALE_SCURRENCY, &globalII.currency, "$");
00350     res = res && getNewLocaleString (LOCALE_SINTLSYMBOL, &globalII.intlCurrency, "USD");
00351     res = res && getNewLocaleString (LOCALE_SDECIMAL, &globalII.decimal, ".");
00352     res = res && getNewLocaleString (LOCALE_STHOUSAND, &globalII.thousands, ",");
00353     res = res && getNewLocaleString (LOCALE_SLIST, &globalII.list, ",");
00354     res = res && getNewLocaleString (LOCALE_STIME, &globalII.timesep, ":");
00355     res = res && getNewLocaleString (LOCALE_SDATE, &globalII.datesep, "/");
00356 
00357     res = res && getNewLocalePatternString (LOCALE_SSHORTDATE, &globalII.shortDateFormatPattern, "M#/D#/Y#");
00358     res = res && getNewLocalePatternString (LOCALE_SLONGDATE, &globalII.longDateFormatPattern, "DN, MN D#, YN");
00359 
00360     globalII.numberOfDays = 7;      //Make this 10 to use yesterday, today, tommorrow - dave wanted them removed.
00361     globalII.numberOfMonths = 12;
00362     globalII.numberOfYears = 0;
00363 
00364     globalII.defaultTimeFormat = false;
00365 
00366 
00367     for (i = 0; i < globalII.numberOfMonths; i++) {
00368         globalII.daysInMonth[i] = daysInMonthsArray[i];
00369         }
00370 
00371     for (i = globalII.numberOfMonths; i < 13; i++) {
00372         globalII.daysInMonth[i] = 0;
00373         }
00374 
00375     if (res)
00376         globalIIptr = &globalII;
00377 
00378     return (res);
00379     } /*initInternationalInfo*/
00380 
00381 
00382 tyinternationalinfoptr getIntlInfo (void) {
00383     if (globalIIptr == NULL) {
00384         if (initInternationalInfo()) {
00385             return (globalIIptr);
00386             }
00387         }
00388     else {
00389         return (globalIIptr);
00390         }
00391 
00392     return (NULL);
00393     }
00394 
00395 static void charStringToBigstring (bigstring bs, char * source, short len) {
00396     moveleft (source, stringbaseaddress(bs), len);
00397     setstringlength (bs, len);
00398     } /*charStringToBigstring*/
00399 
00400 static long charStringToLong (char * str, short len) {
00401     bigstring bs;
00402     long ret;
00403 
00404     charStringToBigstring (bs, str, len);
00405     stringtonumber (bs, &ret);
00406     return (ret);
00407     } /*charStringToLong*/
00408 
00409 
00410 static void getDateTime (tydaterecptr dt) {
00411     SYSTEMTIME sysdt;
00412 
00413     GetLocalTime (&sysdt);
00414 
00415     dt->year = sysdt.wYear;
00416     dt->month = sysdt.wMonth;
00417     dt->dayOfWeek = sysdt.wDayOfWeek;
00418     dt->day = sysdt.wDay;
00419     dt->hour = sysdt.wHour;
00420     dt->minute = sysdt.wMinute;
00421     dt->second = sysdt.wSecond;
00422     dt->hundredths = sysdt.wMilliseconds;
00423     } /*getDateTime*/
00424 
00425 #endif
00426 
00427 boolean isLeapYear (short year) {
00428     /* this procedure assumes the existance of the Gregorian calendar only */
00429     /* This basically means it's not valid for years before the adoption of
00430        the Gregorian calendar.  This adoption varies by country, starting in
00431        Europe as early as the 1400's and as late as the 1900's in Russia. */
00432 
00433     boolean res;
00434 
00435     res = false;
00436 
00437     if ((year % 4) == 0) {
00438         res = true;
00439 
00440         if ((year % 100) == 0) {
00441             res = false;
00442 
00443             if ((year % 400) == 0) {
00444                 res = true;
00445                 }
00446             }
00447         }
00448 
00449     return (res);
00450     } /*isLeapYear*/
00451 
00452 
00453 short daysInMonth (short month, short year) {
00454     short res;
00455 
00456     /*this procedure assumes month valid from 1 to 12*/
00457 
00458     res = daysInMonthsArray [month-1];
00459 
00460     if (month == 2) {
00461         if (isLeapYear (year))
00462             ++res;
00463         }
00464 
00465     return (res);
00466     } /* daysInMonth */
00467 
00468 
00469 
00470 #ifdef WIN95VERSION
00471 long filetimetoseconds (const FILETIME *filetime) {
00472 
00473     LARGE_INTEGER basetime;
00474     LARGE_INTEGER nowtime;
00475 
00476     basetime.u.HighPart = 0x0153b281;
00477     basetime.u.LowPart = 0xe0fb4000;
00478 
00479     nowtime.u.HighPart = (*filetime).dwHighDateTime;
00480     nowtime.u.LowPart = (*filetime).dwLowDateTime;
00481 
00482     nowtime.QuadPart = nowtime.QuadPart - basetime.QuadPart;
00483 
00484     return ((long) (nowtime.QuadPart / 10000000));  //convert to seconds
00485     } /*filetimetoseconds*/
00486 
00487 
00488 void secondstofiletime (long seconds, FILETIME *filetime) {
00489 
00490     LARGE_INTEGER basetime;
00491     LARGE_INTEGER nowtime;
00492     LARGE_INTEGER mul;
00493     
00494     basetime.u.HighPart = 0x0153b281;
00495     basetime.u.LowPart = 0xe0fb4000;
00496 
00497     mul.u.LowPart = 10000000;
00498     mul.u.HighPart = 0;
00499 
00500     nowtime.u.LowPart = seconds;
00501     nowtime.u.HighPart = 0;
00502 
00503     nowtime.QuadPart = nowtime.QuadPart * mul.QuadPart;
00504     
00505     nowtime.QuadPart = nowtime.QuadPart + basetime.QuadPart;
00506 
00507     (*filetime).dwHighDateTime = nowtime.u.HighPart;
00508     (*filetime).dwLowDateTime = nowtime.u.LowPart;
00509     } /*secondstofiletime*/
00510 
00511 
00512 void GetDateTime (long * secs) {
00513     
00514     FILETIME filetimeUTC;
00515     FILETIME filetime;
00516     //This is the Macintosh base time of Jan 1, 1904 at midnight.
00517     GetSystemTimeAsFileTime (&filetimeUTC);
00518 
00519     FileTimeToLocalFileTime (&filetimeUTC, &filetime);
00520 
00521     *secs = filetimetoseconds (&filetime);
00522     } /*GetDateTime*/
00523 
00524 #endif
00525 
00526 
00527 void timestamp (long *ptime) {
00528     
00529     GetDateTime ((unsigned long *) ptime);
00530     } /*timestamp*/
00531     
00532     
00533 unsigned long timenow (void) {
00534     
00535     /*
00536     2.1b4 dmb; more convenient than timestamp for most callers
00537     */
00538     
00539     unsigned long now;
00540     
00541     GetDateTime (&now);
00542     
00543     return (now);
00544     } /*timenow*/
00545     
00546     
00547 boolean setsystemclock (unsigned long secs) {
00548 
00549     /*
00550     3/10/97 dmb: set the system clock, using Macintosh time 
00551     conventions (seconds since 12:00 PM Jan 1, 1904)
00552     */
00553 
00554     #ifdef MACVERSION
00555         return (!oserror (SetDateTime (secs)));
00556     #endif
00557 
00558     #ifdef WIN95VERSION
00559         SYSTEMTIME date;
00560         FILETIME filetime;
00561         FILETIME utcFileTime;
00562 
00563         secondstofiletime (secs, &filetime);
00564 
00565         LocalFileTimeToFileTime (&filetime, &utcFileTime);
00566         FileTimeToSystemTime (&utcFileTime, &date);
00567 
00568         if (! SetSystemTime (&date)) {
00569             oserror (GetLastError());
00570             return (false);
00571             }
00572 
00573         return (true);
00574 #endif
00575     } /*setsystemclock*/
00576 
00577 
00578 static void
00579 adjustforcurrenttimezone (unsigned long *ptime)
00580 {
00581     /*
00582     5.1b23 dmb: avoid wraparound for near-zero dates
00583     */
00584 
00585     unsigned long adjustedtime = *ptime + getcurrenttimezonebias ();
00586 
00587     if (sgn (*ptime) == sgn (adjustedtime))
00588         *ptime = adjustedtime;
00589     } /*adjustforcurrenttimezone*/
00590 
00591 
00592 boolean
00593 timegreaterthan (
00594         unsigned long time1,
00595         unsigned long time2)
00596 {
00597     return (time1 > time2);
00598     } /*timegreaterthan*/
00599 
00600 
00601 boolean
00602 timelessthan (
00603         unsigned long time1,
00604         unsigned long time2)
00605 {
00606     return (time1 < time2);
00607 } /*timelessthan*/
00608 
00609 
00610 boolean timetotimestring (unsigned long ptime, bigstring bstime, boolean flwantseconds) {
00611 
00612 #ifdef MACVERSION
00613     //Code change by Timothy Paustian Sunday, June 25, 2000 9:45:30 PM
00614     //updated call for carbon, the nil parameter says use the current script
00615     //for formatting the time.
00616     TimeString (ptime, flwantseconds, bstime, nil);
00617 
00618         return (true);
00619     #endif
00620 
00621     #ifdef WIN95VERSION
00622         SYSTEMTIME date;
00623         FILETIME filetime;
00624         int len;
00625 
00626         secondstofiletime (ptime, &filetime);
00627 
00628         FileTimeToSystemTime (&filetime, &date);
00629 
00630         len = GetTimeFormat (LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &date, NULL, stringbaseaddress(bstime), 255);
00631 
00632         setstringlength(bstime, len - 1);
00633         
00634         return (true);
00635     #endif
00636     } /*timetotimestring*/
00637 
00638 
00639 boolean timetodatestring (unsigned long ptime, bigstring bsdate, boolean flabbreviate) {
00640 
00641 #ifdef MACVERSION
00642     //Code change by Timothy Paustian Sunday, June 25, 2000 9:45:49 PM
00643     //Updated call for carbon
00644     DateString (ptime, flabbreviate? abbrevDate : shortDate, bsdate, nil);
00645 
00646     return (true);
00647     #endif
00648 
00649     #ifdef WIN95VERSION
00650         SYSTEMTIME date;
00651         FILETIME filetime;
00652         int len;
00653 
00654         secondstofiletime (ptime, &filetime);
00655 
00656         FileTimeToSystemTime (&filetime, &date);
00657 
00658         len = GetDateFormat (LOCALE_USER_DEFAULT, flabbreviate? DATE_LONGDATE : DATE_SHORTDATE, &date, NULL, stringbaseaddress(bsdate), 255);
00659         
00660         setstringlength(bsdate, len - 1);
00661         
00662         return (true);
00663     #endif
00664     } /*timetodatestring*/
00665 
00666 
00667 boolean stringtotime (bigstring bsdate, unsigned long *ptime) {
00668     
00669     /*
00670     9/13/91 dmb: use the script manager to translate a string to a 
00671     time in seconds since 12:00 AM 1904.
00672     
00673     if a date is provided, but no time, the time is 12:00 AM
00674     
00675     if a time is provided, but no date, the date is 1/1/1904.
00676     
00677     we return true if any time/date information was extracted.
00678     */
00679     
00680     #ifdef MACVERSION
00681 
00682         Ptr p = (Ptr) bsdate + 1;
00683         long n = stringlength (bsdate);
00684         long used = 0;
00685         DateCacheRecord cache;
00686         LongDateRec longdate;
00687         boolean flgotdate;
00688         boolean flgottime;
00689         DateTimeRec shortdate;
00690         boolean flUseGMT = false;
00691         long idx;
00692         
00693         idx = stringlength (bsdate);
00694 
00695         while (getstringcharacter(bsdate, idx-1) == ' ')
00696             --idx;
00697 
00698         if (idx > 3) {
00699             if ((getstringcharacter(bsdate, idx - 3) == 'G') && (getstringcharacter(bsdate, idx - 2) == 'M') && (getstringcharacter(bsdate, idx -1) == 'T')) {
00700                 flUseGMT = true;
00701                 }
00702             }
00703 
00704         *ptime = 0; /*default return value*/
00705         
00706         clearbytes (&longdate, sizeof (longdate));
00707         
00708         if (InitDateCache (&cache) != noErr) /*must do this before calling StringToDate*/
00709             return (false);
00710         
00711         flgotdate = ((StringToDate (p, n, &cache, &used, &longdate) & fatalDateTime) == 0);
00712         
00713         flgottime = ((StringToTime (p + used, n - used, &cache, &used, &longdate) & fatalDateTime) == 0);
00714         
00715         if (!flgotdate && !flgottime) /*nuthin' doin'*/
00716             return (false);
00717         
00718         if (flgotdate) {
00719         
00720             shortdate.day = longdate.ld.day;
00721             
00722             shortdate.month = longdate.ld.month;
00723             
00724             shortdate.year = longdate.ld.year;
00725             }
00726         else {
00727             
00728             SecondsToDate (0, &shortdate);
00729             
00730             /*
00731             GetTime (&shortdate);
00732             */
00733             }
00734         
00735         shortdate.hour = longdate.ld.hour; /*time fields will be zero if !flgottime*/
00736         
00737         shortdate.minute = longdate.ld.minute;
00738         
00739         shortdate.second = longdate.ld.second;
00740         
00741         DateToSeconds (&shortdate, ptime);
00742 
00743         if (flUseGMT) {
00744             adjustforcurrenttimezone (ptime);
00745             }
00746         
00747     #endif
00748 
00749     #ifdef WIN95VERSION
00750         tydaterec returnDT;
00751         tydaterec return2DT;
00752         tydaterec actualDT;
00753         unsigned long vu;
00754         tyvalidationerror errinfo;
00755         bigstring bsdate1, bstime1;
00756         short idx;
00757         tyinternationalinfo * ii;
00758         boolean flUseGMT = false;
00759         boolean flSaveTimeFormat;
00760 
00761         ii = getIntlInfo();
00762 
00763         if (ii == NULL)
00764             return (false);
00765 
00766         idx = stringlength (bsdate);
00767         
00768         if (idx > 128) //5.0b17 dmb: too long for a date, avoid crash
00769             return (false);
00770 
00771         while (getstringcharacter(bsdate, idx-1) == ' ')
00772             --idx;
00773 
00774         if (idx > 3) {
00775             if ((getstringcharacter(bsdate, idx - 3) == 'G') && (getstringcharacter(bsdate, idx - 2) == 'M') && (getstringcharacter(bsdate, idx -1) == 'T')) {
00776                 flUseGMT = true;
00777                 flSaveTimeFormat = ii->defaultTimeFormat;
00778                 ii->defaultTimeFormat = true;
00779                 }
00780             }
00781 
00782         idx = 1;
00783         if (scanstring (getstringcharacter(ii->timesep, 0), bsdate, &idx)) {
00784             --idx;
00785             /* now check to see if this is a time preceded by a date */
00786             if (idx > 5) {  /*blank digit colon - 3 min, possibly 4 - date must be at least 3 i.e. 1/5 */
00787                 if (isnumeric (getstringcharacter(bsdate, idx-1))) {
00788                     if (idx + 1 < stringlength (bsdate)) {
00789                         if (isnumeric (getstringcharacter(bsdate, idx+1))) {
00790                             if (getstringcharacter(bsdate, idx-2) == ' ') {
00791                                 setstringcharacter(bsdate, idx-2, ';');
00792                                 }
00793                             else {
00794                                 if ((getstringcharacter(bsdate, idx-3) == ' ') && (isnumeric (getstringcharacter(bsdate, idx-2)))) {
00795                                     setstringcharacter(bsdate, idx-3, ';');
00796                                     }
00797                                 }
00798                             }
00799                         }
00800                     }
00801                 }
00802             }
00803         else {
00804             idx = 1;
00805             if (scanstring (':', bsdate, &idx)) {
00806                 --idx;
00807                 /* now check to see if this is a time preceded by a date */
00808                 if (idx > 5) {  /*blank digit colon - 3 min, possibly 4 - date must be at least 3 i.e. 1/5 */
00809                     if (isnumeric (getstringcharacter(bsdate, idx-1))) {
00810                         if (idx + 1 < stringlength (bsdate)) {
00811                             if (isnumeric (getstringcharacter(bsdate, idx+1))) {
00812                                 if (getstringcharacter(bsdate, idx-2) == ' ') {
00813                                     setstringcharacter(bsdate, idx-2, ';');
00814                                     }
00815                                 else {
00816                                     if ((getstringcharacter(bsdate, idx-3) == ' ') && (isnumeric (getstringcharacter(bsdate, idx-2)))) {
00817                                         setstringcharacter(bsdate, idx-3, ';');
00818                                         }
00819                                     }
00820                                 }
00821                             }
00822                         }
00823                     }
00824                 }
00825             }
00826 
00827         /* if the string contains a semicolon ";" then split into two strings are parse date;time */
00828 
00829         idx = 1;
00830         if (scanstring (';', bsdate, &idx)) {
00831             midstring (bsdate, 1, idx-1, bsdate1);
00832             midstring (bsdate, idx + 1, stringlength(bsdate) - idx, bstime1);
00833 
00834             ++idx;
00835             if (scanstring (';', bsdate, &idx)) {
00836                 midstring (bsdate, idx + 1, stringlength(bsdate) - idx, bstime1);
00837                 }
00838 
00839 
00840             ValidDate (stringbaseaddress (bsdate1), stringlength (bsdate1), &returnDT, &actualDT, &vu, &errinfo); 
00841 
00842             if (errinfo.errorNumber == 0)
00843                 {
00844                 ValidTime (stringbaseaddress (bstime1), stringlength (bstime1), &return2DT, &actualDT, &vu, &errinfo); 
00845 
00846                 *ptime = datetimetoseconds (returnDT.day, returnDT.month, returnDT.year, return2DT.hour, return2DT.minute, return2DT.second);
00847 
00848                 if (errinfo.errorNumber == 0) {
00849                     if (flUseGMT) {
00850                         adjustforcurrenttimezone (ptime);
00851                         ii->defaultTimeFormat = flSaveTimeFormat;
00852                         }
00853                     return (true);
00854                     }
00855 
00856                 /* try normal */
00857                 }
00858             }
00859 
00860 
00861         ValidDate (stringbaseaddress (bsdate), stringlength (bsdate), &returnDT, &actualDT, &vu, &errinfo); 
00862 
00863         *ptime = datetimetoseconds (returnDT.day, returnDT.month, returnDT.year, 0,0,0);
00864 
00865         if (errinfo.errorNumber != 0)
00866             {
00867             if (errinfo.errorNumber == err_kInvalidPunctuation) {
00868                 ValidTime (stringbaseaddress (bsdate), stringlength (bsdate), &returnDT, &actualDT, &vu, &errinfo); 
00869 
00870                 *ptime = datetimetoseconds (returnDT.day, returnDT.month, returnDT.year, returnDT.hour, returnDT.minute, returnDT.second);
00871 
00872                 if (errinfo.errorNumber == 0) {
00873                     if (flUseGMT) {
00874                         adjustforcurrenttimezone (ptime);
00875                         ii->defaultTimeFormat = flSaveTimeFormat;
00876                         }
00877                     return (true);
00878                     }
00879                 }
00880 
00881             if (flUseGMT) {
00882                 ii->defaultTimeFormat = flSaveTimeFormat;
00883                 }
00884 
00885             return (false);
00886             }
00887     #endif
00888 
00889     return (true);
00890     } /*stringtotime*/
00891 
00892 
00893 long datetimetoseconds (short day, short month, short year, short hour, short minute, short second) {
00894     
00895     /*
00896     5.0a12 dmb: Win version, must handle hour, minute, second wraparound
00897     */
00898 
00899     #ifdef MACVERSION
00900 
00901         DateTimeRec date;
00902         unsigned long secs;
00903         
00904         if (year < 100) { /*use script manager's StringToDate heuristic -- pg 188 in  docs*/
00905             
00906             long thisyear, lcentury;
00907             
00908             GetTime (&date);
00909             
00910             thisyear = date.year % 100;
00911             
00912             lcentury = date.year - thisyear;
00913             
00914             if ((thisyear <= 10) && (year >= 90)) /*assume last century*/
00915                 lcentury -= 100;
00916             else
00917                 if ((thisyear >= 90) && (year <= 10)) /*assume next century*/
00918                     lcentury += 100;
00919             
00920             year += lcentury;
00921             }
00922         
00923         clearbytes (&date, sizeof (date));
00924         
00925         date.day = day;
00926         
00927         date.month = month;
00928         
00929         date.year = year;
00930         
00931         date.hour = hour;
00932         
00933         date.minute = minute;
00934         
00935         date.second = second;
00936         
00937         DateToSeconds (&date, &secs);
00938     #endif
00939 
00940     #ifdef WIN95VERSION
00941 
00942         SYSTEMTIME date;
00943         FILETIME filetime;
00944         unsigned long secs;
00945         
00946         if (year < 100) { /*use script manager's StringToDate heuristic -- pg 188 in  docs*/
00947             
00948             long thisyear, lcentury;
00949             
00950             GetSystemTime (&date);
00951             
00952             thisyear = date.wYear % 100;
00953             
00954             lcentury = date.wYear - thisyear;
00955             
00956             if ((thisyear <= 10) && (year >= 90)) /*assume last century*/
00957                 lcentury -= 100;
00958             else
00959                 if ((thisyear >= 90) && (year <= 10)) /*assume next century*/
00960                     lcentury += 100;
00961             
00962             year += lcentury;
00963             }
00964         
00965         // Win call doesn't wrap around h:m:s
00966 
00967         minute = minute + (second / 60);
00968         second = second % 60;
00969         hour = hour + (minute / 60);
00970         minute = minute % 60;
00971         day = day + (hour / 24);
00972         hour = hour % 24;
00973 
00974         /* we pre-adjust the month to ensure that it is in a valid range */
00975         year = year + ((month - 1) / 12);
00976         month = ((month - 1) % 12) + 1;
00977 
00978         while (day > daysInMonth(month, year)) {
00979             day = day - daysInMonth(month, year);
00980 
00981             if (month < 12) {
00982                 ++month;
00983                 }
00984             else {
00985                 month = 1;
00986                 ++year;
00987                 }
00988             }
00989         
00990         clearbytes (&date, sizeof (date));
00991         
00992         date.wDay = day;
00993         
00994         date.wMonth = month;
00995         
00996         date.wYear = year;
00997         
00998         date.wHour = hour;
00999         
01000         date.wMinute = minute;
01001         
01002         date.wSecond = second;
01003         
01004         SystemTimeToFileTime (&date, &filetime);
01005 
01006         secs = filetimetoseconds (&filetime);
01007     #endif
01008     
01009     return (secs);
01010     } /*datetimetoseconds*/
01011 
01012 
01013 void secondstodatetime (long secs, short *day, short *month, short *year, short *hour, short *minute, short *second) {
01014     
01015     #ifdef MACVERSION
01016 
01017         DateTimeRec date;
01018         
01019         SecondsToDate (secs, &date);
01020         
01021         *day = date.day;
01022         
01023         *month = date.month;
01024         
01025         *year = date.year;
01026         
01027         *hour = date.hour;
01028         
01029         *minute = date.minute;
01030         
01031         *second = date.second;
01032     #endif
01033 
01034     #ifdef WIN95VERSION
01035 
01036         SYSTEMTIME date;
01037         FILETIME filetime;
01038 
01039         secondstofiletime (secs, &filetime);
01040 
01041         FileTimeToSystemTime (&filetime, &date);
01042 
01043         *day = date.wDay;
01044         
01045         *month = date.wMonth;
01046         
01047         *year = date.wYear;
01048         
01049         *hour = date.wHour;
01050         
01051         *minute = date.wMinute;
01052         
01053         *second = date.wSecond;
01054     #endif
01055     } /*secondstodatetime*/
01056 
01057 
01058 void secondstodayofweek (long secs, short *dayofweek) {
01059     
01060     #ifdef MACVERSION
01061 
01062         DateTimeRec date;
01063         
01064         SecondsToDate (secs, &date);
01065         
01066         *dayofweek = date.dayOfWeek;
01067     #endif
01068 
01069     #ifdef WIN95VERSION
01070         
01071         SYSTEMTIME date;
01072         FILETIME filetime;
01073 
01074         secondstofiletime (secs, &filetime);
01075         
01076         FileTimeToSystemTime (&filetime, &date);
01077         
01078         *dayofweek = date.wDayOfWeek + 1;
01079         
01080     #endif
01081     } /*secondstodayofweek*/
01082 
01083 
01084 static void fixdate (tydate * date) {
01085     #ifdef MACVERSION   
01086         date->minute = date->minute + (date->second / 60);
01087         date->second = date->second % 60;
01088         date->hour = date->hour + (date->minute / 60);
01089         date->minute = date->minute % 60;
01090         date->day = date->day + (date->hour / 24);
01091         date->hour = date->hour % 24;
01092 
01093         /* we pre-adjust the month to ensure that it is in a valid range */
01094         date->year = date->year + ((date->month - 1) / 12);
01095         date->month = ((date->month - 1) % 12) + 1;
01096 
01097         while (date->day > daysInMonth(date->month, date->year)) {
01098             date->day = date->day - daysInMonth(date->month, date->year);
01099 
01100             if (date->month < 12) {
01101                 ++(date->month);
01102                 }
01103             else {
01104                 date->month = 1;
01105                 ++(date->year);
01106                 }
01107             }
01108     #endif
01109 
01110     #ifdef WIN95VERSION
01111 
01112         date->wMinute = date->wMinute + (date->wSecond / 60);
01113         date->wSecond = date->wSecond % 60;
01114         date->wHour = date->wHour + (date->wMinute / 60);
01115         date->wMinute = date->wMinute % 60;
01116         date->wDay = date->wDay + (date->wHour / 24);
01117         date->wHour = date->wHour % 24;
01118 
01119         /* we pre-adjust the month to ensure that it is in a valid range */
01120         date->wYear = date->wYear + ((date->wMonth - 1) / 12);
01121         date->wMonth = ((date->wMonth - 1) % 12) + 1;
01122 
01123         while (date->wDay > daysInMonth(date->wMonth, date->wYear)) {
01124             date->wDay = date->wDay - daysInMonth(date->wMonth, date->wYear);
01125 
01126             if (date->wMonth < 12) {
01127                 ++(date->wMonth);
01128                 }
01129             else {
01130                 date->wMonth = 1;
01131                 ++(date->wYear);
01132                 }
01133             }
01134     #endif
01135     } /*fixdate*/
01136 
01137 
01138 unsigned long nextmonth(unsigned long date) {
01139 
01140     /*
01141     6.0a10 dmb: limit day to max days for new month
01142     */
01143     
01144     #ifdef MACVERSION
01145 
01146         DateTimeRec daterec;
01147         short maxday;
01148         
01149         SecondsToDate (date, &daterec);
01150         
01151         if (daterec.month < 12) {
01152             ++daterec.month;
01153             }
01154         else {
01155             daterec.month = 1;
01156             ++daterec.year;
01157             }
01158         
01159         maxday = daysInMonth(daterec.month, daterec.year);
01160         
01161         if (daterec.day > maxday)
01162             daterec.day = maxday;
01163         
01164         fixdate (&daterec);
01165 
01166         DateToSeconds (&daterec, &date);
01167 
01168         return (date);
01169     #endif
01170 
01171     #ifdef WIN95VERSION
01172         
01173         SYSTEMTIME daterec;
01174         FILETIME filetime;
01175         short maxday;
01176 
01177         secondstofiletime (date, &filetime);
01178         
01179         FileTimeToSystemTime (&filetime, &daterec);
01180         
01181         if (daterec.wMonth < 12) {
01182             ++daterec.wMonth;
01183             }
01184         else {
01185             daterec.wMonth = 1;
01186             ++daterec.wYear;
01187             }
01188         
01189         maxday = daysInMonth (daterec.wMonth, daterec.wYear);
01190         
01191         if (daterec.wDay > maxday)
01192             daterec.wDay = maxday;
01193 
01194         fixdate (&daterec);
01195 
01196         SystemTimeToFileTime (&daterec, &filetime);
01197 
01198         return (filetimetoseconds (&filetime));
01199     #endif
01200     } /*nextmonth*/
01201 
01202 unsigned long nextyear(unsigned long date) {
01203     #ifdef MACVERSION
01204 
01205         DateTimeRec daterec;
01206         
01207         SecondsToDate (date, &daterec);
01208         
01209         ++daterec.year;
01210 
01211         fixdate (&daterec);
01212 
01213         DateToSeconds (&daterec, &date);
01214 
01215         return (date);
01216     #endif
01217 
01218     #ifdef WIN95VERSION
01219         
01220         SYSTEMTIME daterec;
01221         FILETIME filetime;
01222 
01223         secondstofiletime (date, &filetime);
01224         
01225         FileTimeToSystemTime (&filetime, &daterec);
01226         
01227         ++daterec.wYear;
01228 
01229         fixdate (&daterec);
01230 
01231         SystemTimeToFileTime (&daterec, &filetime);
01232 
01233         return (filetimetoseconds (&filetime));
01234     #endif
01235     } /*nextyear*/
01236 
01237 unsigned long prevmonth(unsigned long date) {
01238 
01239     /*
01240     6.0a10 dmb: limit day to max days for new month
01241     */
01242     
01243     #ifdef MACVERSION
01244 
01245         DateTimeRec daterec;
01246         short maxday;
01247         
01248         SecondsToDate (date, &daterec);
01249         
01250         if (daterec.month > 1) {
01251             --daterec.month;
01252             }
01253         else {
01254             daterec.month = 12;
01255             --daterec.year;
01256             }
01257 
01258         maxday = daysInMonth(daterec.month, daterec.year);
01259         
01260         if (daterec.day > maxday)
01261             daterec.day = maxday;
01262         
01263         fixdate (&daterec);
01264 
01265         DateToSeconds (&daterec, &date);
01266 
01267         return (date);
01268     #endif
01269 
01270     #ifdef WIN95VERSION
01271         
01272         SYSTEMTIME daterec;
01273         FILETIME filetime;
01274         short maxday;
01275 
01276         secondstofiletime (date, &filetime);
01277         
01278         FileTimeToSystemTime (&filetime, &daterec);
01279         
01280         if (daterec.wMonth > 1) {
01281             --daterec.wMonth;
01282             }
01283         else {
01284             daterec.wMonth = 12;
01285             --daterec.wYear;
01286             }
01287 
01288         maxday = daysInMonth(daterec.wMonth, daterec.wYear);
01289         
01290         if (daterec.wDay > maxday)
01291             daterec.wDay = maxday;
01292         
01293         fixdate (&daterec);
01294 
01295         SystemTimeToFileTime (&daterec, &filetime);
01296 
01297         return (filetimetoseconds (&filetime));
01298     #endif
01299     } /*prevmonth*/
01300 
01301 unsigned long prevyear(unsigned long date) {
01302     #ifdef MACVERSION
01303 
01304         DateTimeRec daterec;
01305         
01306         SecondsToDate (date, &daterec);
01307         
01308         --daterec.year;
01309 
01310         fixdate (&daterec);
01311 
01312         DateToSeconds (&daterec, &date);
01313 
01314         return (date);
01315     #endif
01316 
01317     #ifdef WIN95VERSION
01318         
01319         SYSTEMTIME daterec;
01320         FILETIME filetime;
01321 
01322         secondstofiletime (date, &filetime);
01323         
01324         FileTimeToSystemTime (&filetime, &daterec);
01325         
01326         --daterec.wYear;
01327 
01328         fixdate (&daterec);
01329 
01330         SystemTimeToFileTime (&daterec, &filetime);
01331 
01332         return (filetimetoseconds (&filetime));
01333     #endif
01334     } /*prevyear*/
01335 
01336 unsigned long firstofmonth(unsigned long date) {
01337     #ifdef MACVERSION
01338 
01339         DateTimeRec daterec;
01340         
01341         SecondsToDate (date, &daterec);
01342         
01343         daterec.day  = 1;
01344 
01345         daterec.hour = 0;
01346         daterec.minute = 0;
01347         daterec.second = 0;
01348 
01349         DateToSeconds (&daterec, &date);
01350 
01351         return (date);
01352     #endif
01353 
01354     #ifdef WIN95VERSION
01355         
01356         SYSTEMTIME daterec;
01357         FILETIME filetime;
01358 
01359         secondstofiletime (date, &filetime);
01360         
01361         FileTimeToSystemTime (&filetime, &daterec);
01362         
01363         daterec.wDay  = 1;
01364 
01365         daterec.wHour = 0;
01366         daterec.wMinute = 0;
01367         daterec.wSecond = 0;
01368         daterec.wMilliseconds = 0;
01369 
01370         SystemTimeToFileTime (&daterec, &filetime);
01371 
01372         return (filetimetoseconds (&filetime));
01373     #endif
01374     } /*firstofmonth*/
01375 
01376 unsigned long lastofmonth(unsigned long date) {
01377     #ifdef MACVERSION
01378 
01379         DateTimeRec daterec;
01380         
01381         SecondsToDate (date, &daterec);
01382         
01383         daterec.day  = daysInMonth(daterec.month, daterec.year);
01384 
01385         daterec.hour = 0;
01386         daterec.minute = 0;
01387         daterec.second = 0;
01388 
01389         DateToSeconds (&daterec, &date);
01390 
01391         return (date);
01392     #endif
01393 
01394     #ifdef WIN95VERSION
01395         
01396         SYSTEMTIME daterec;
01397         FILETIME filetime;
01398 
01399         secondstofiletime (date, &filetime);
01400         
01401         FileTimeToSystemTime (&filetime, &daterec);
01402         
01403         daterec.wDay  = daysInMonth(daterec.wMonth, daterec.wYear);
01404 
01405         daterec.wHour = 0;
01406         daterec.wMinute = 0;
01407         daterec.wSecond = 0;
01408         daterec.wMilliseconds = 0;
01409 
01410         SystemTimeToFileTime (&daterec, &filetime);
01411 
01412         return (filetimetoseconds (&filetime));
01413     #endif
01414     } /*lastofmonth*/
01415 
01416 
01417 void shortdatestring (unsigned long date, bigstring bs) {
01418     #ifdef MACVERSION
01419         //Code change by Timothy Paustian Sunday, June 25, 2000 9:48:03 PM
01420         //Updated for carbon
01421         DateString (date, shortDate, bs, nil);
01422     #endif
01423 
01424     #ifdef WIN95VERSION
01425         timetodatestring (date, bs, false);
01426     #endif
01427     } /*shortdatestring*/
01428 
01429 void longdatestring (unsigned long date, bigstring bs) {
01430     #ifdef MACVERSION
01431         //Code change by Timothy Paustian Sunday, June 25, 2000 9:48:20 PM
01432         //Updated for Carbon
01433         DateString (date, longDate, bs, nil);
01434     #endif
01435 
01436     #ifdef WIN95VERSION
01437         timetodatestring (date, bs, true);
01438     #endif
01439     } /*longdatestring*/
01440 
01441 void abbrevdatestring (unsigned long date, bigstring bs) {
01442     #ifdef MACVERSION
01443         //Code change by Timothy Paustian Sunday, June 25, 2000 9:48:36 PM
01444         //updated for carbon
01445         DateString (date, abbrevDate, bs, nil);
01446     #endif
01447 
01448     #ifdef WIN95VERSION
01449         timetodatestring (date, bs, true);
01450     #endif
01451     } /*abbrevdatestring*/
01452 
01453 void getdaystring (short dayofweek, bigstring bs, boolean flFullname) {
01454     #ifdef MACVERSION   
01455         switch (dayofweek) {
01456             case 1:
01457                 copyctopstring ("Sunday", bs);
01458                 break;
01459 
01460             case 2:
01461                 copyctopstring ("Monday", bs);
01462                 break;
01463 
01464             case 3:
01465                 copyctopstring ("Tuesday", bs);
01466                 break;
01467 
01468             case 4:
01469                 copyctopstring ("Wednesday", bs);
01470                 break;
01471 
01472             case 5:
01473                 copyctopstring ("Thursday", bs);
01474                 break;
01475 
01476             case 6:
01477                 copyctopstring ("Friday", bs);
01478                 break;
01479 
01480             case 7:
01481                 copyctopstring ("Saturday", bs);
01482                 break;
01483 
01484             default:
01485                 copyctopstring ("Day of week number is invalid (not between 1 and 7)", bs);
01486                 break;
01487             }
01488 
01489         if (! flFullname)
01490             setstringlength (bs, 3);
01491     #endif
01492 
01493     #ifdef WIN95VERSION
01494 //      //reset day of week to a Monday thru Sunday
01495 //      dayofweek = dayofweek - 1;
01496 //
01497 //      if (dayofweek == 0)
01498 //          dayofweek = 7;
01499 //
01500 //      getWindowsLocaleString (flFullname?LOCALE_SDAYNAME1 + dayofweek - 1:LOCALE_SABBREVDAYNAME1 + dayofweek - 1, bs);
01501     tyinternationalinfo * ii;
01502 //  char temp[100];                             /*hold token string*/
01503 //  short i;
01504 
01505     ii = getIntlInfo();
01506 
01507     if (ii == NULL)
01508         return;
01509 
01510     if (flFullname)
01511         copystring (ii->longDaysOfWeek[dayofweek-1], bs);
01512     else
01513         copystring (ii->shortDaysOfWeek[dayofweek-1], bs);
01514     #endif
01515     } /*getdaystring*/
01516 
01517 long getcurrenttimezonebias(void) {
01518     #ifdef MACVERSION
01519         MachineLocation ml;
01520         long res;
01521 
01522         ReadLocation (&ml);
01523         
01524         res = ml.u.gmtDelta & 0x00FFFFFF;
01525 
01526         if ((res & 0x00800000) == 0x00800000)  //if this is a negative number extend the sign bits
01527             res = res | 0xFF000000;
01528 
01529         return (res);
01530     #endif
01531 
01532     #ifdef WIN95VERSION
01533         TIME_ZONE_INFORMATION tzi;
01534         DWORD tziResult;
01535 
01536         tziResult = GetTimeZoneInformation (&tzi);
01537 
01538         if (tziResult == TIME_ZONE_ID_STANDARD)
01539             tzi.Bias += tzi.StandardBias;
01540         else if (tziResult == TIME_ZONE_ID_DAYLIGHT)
01541             tzi.Bias += tzi.DaylightBias;
01542 
01543         return (tzi.Bias * -60L);
01544     #endif
01545     } /*getcurrenttimezonebias*/
01546 
01547 
01548 #ifdef WIN95VERSION
01549 
01550 //static unsigned long long getlongermilliseconds (void) {
01551 //  LARGE_INTEGER counter, freq;
01552 //  unsigned long long freqLong;
01553 //  
01554 //  QueryPerformanceCounter (&counter);  /* counter hits since boot-up */
01555 //  
01556 //  QueryPerformanceFrequency (&freq);   /* frequency of coutner hits (per second) */
01557 //  
01558 //  freqLong = ( freq.LowPart | ( freq.HighPart << 32 ) ) / 1000;
01559 //  
01560 //  return ( counter.LowPart | ( counter.HighPart << 32 ) ) / freqLong;
01561 //} /* getlongermilliseconds */
01562 
01563 
01564 extern long getmilliseconds(void) {
01565     LARGE_INTEGER counter;
01566     
01567     QueryPerformanceCounter (&counter);  /* counter hits since boot-up */
01568     
01569     if (gPerformanceFreq == 0) {
01570         LARGE_INTEGER freq;
01571         QueryPerformanceFrequency (&freq);   /* frequency of coutner hits (per second) */
01572         gPerformanceFreq = freq.QuadPart / 1000;
01573     }
01574     
01575     return ((long) (counter.QuadPart / gPerformanceFreq));
01576 } /* getmilliseconds */
01577 
01578 #endif
01579 
01580 
01581 #ifdef WIN95VERSION
01582 
01583 static void addDurationToDateTime(tydaterecptr dt, short delta, long units) {
01584     long actualDelta;
01585     long secs;
01586 
01587     actualDelta = 0;
01588     
01589     switch (units) {
01590         case DurationUnit_kDays:
01591             actualDelta = (long) delta * (24L * 60L * 60L);
01592             break;
01593 
01594         default:
01595             break;
01596         }
01597 
01598     secs = datetimetoseconds (dt->day, dt->month, dt->year, dt->hour, dt->minute, dt->second);
01599 
01600     secs += actualDelta;
01601 
01602     secondstodatetime (secs, &dt->day, &dt->month, &dt->year, &dt->hour, &dt->minute, &dt->second);
01603     } /*addDurationToDateTime*/
01604 
01605 
01606 static char ValNextChar (char ** pos) {
01607     char g;
01608 
01609     g = **pos;
01610     *pos = *pos + 1;
01611 
01612     return (g);
01613     } /*ValNextChar*/
01614 
01615 
01616 static boolean ValGetFullPunc (char c, tyCharacterAttributes * f) {
01617     switch (c) {
01618         case ':':
01619             *f = CharAttr_kTime;
01620             return (true);
01621             break;
01622 
01623         case '/':
01624             *f = CharAttr_kShortDate;
01625             return (true);
01626             break;
01627 
01628         case '.':
01629             *f = CharAttr_kShortDate | CharAttr_kLongDate | CharAttr_kTime; /*6.1b5 AR: added shortdate*/
01630             return (true);
01631             break;
01632 
01633         case '-':
01634             *f = CharAttr_kShortDate | CharAttr_kTime | CharAttr_kLongDate;
01635             return (true);
01636             break;
01637 
01638         case ',':
01639             *f = CharAttr_kLongDate;
01640             return (true);
01641             break;
01642 
01643         case ';':
01644             *f = CharAttr_kLongDate;
01645             return (true);
01646             break;
01647 
01648 
01649         default:
01650             break;
01651         }
01652 
01653     *f = 0;
01654     return (false);
01655     }
01656 
01657 
01658 static void ValCheckForKeyWord (tyvalidationtokenptr o) {
01659     tyinternationalinfo * ii;
01660     char temp[100];                             /*hold token string*/
01661     short i;
01662 
01663     ii = getIntlInfo();
01664 
01665     if (ii == NULL)
01666         return;
01667 
01668     charStringToBigstring(temp, (o->pos), o->count);
01669 
01670     for (i = 0; i < ii->numberOfMonths; i++) {
01671         if (equalidentifiers(ii->longMonths[i], temp)) {
01672             /*We have found a match*/
01673             o->ty = VALTYPE_KEYMONTHNAME1;
01674             o->val = i;
01675             o->flag = DateTimeSet_kMonth;
01676             return;
01677             }
01678 
01679         if (equalidentifiers(ii->shortMonths[i], temp)) {
01680             /*We have found a match*/
01681             o->ty = VALTYPE_KEYMONTHNAME2;
01682             o->val = i;
01683             o->flag = DateTimeSet_kMonth;
01684             return;
01685             }
01686 
01687         if (i < ii->numberOfYears) {
01688             if (equalidentifiers(ii->longYears[i], temp)) {
01689                 /*We have found a match*/
01690                 o->ty = VALTYPE_KEYYEARNAME;
01691                 o->val = i;
01692                 o->flag = DateTimeSet_kYear;
01693                 return;
01694                 }
01695             }
01696 
01697         if (i < ii->numberOfDays) {     /*should this be 10 to add yesterday, today, tommorow*/
01698             if (equalidentifiers(ii->longDaysOfWeek[i], temp)) {
01699                 /*We have found a match*/
01700                 o->ty = VALTYPE_KEYDAYNAME1;
01701                 o->val = i;
01702                 return;
01703                 }
01704 
01705             if (equalidentifiers(ii->shortDaysOfWeek[i], temp)) {
01706                 /*We have found a match*/
01707                 o->ty = VALTYPE_KEYDAYNAME2;
01708                 o->val = i;
01709                 return;
01710                 }
01711             }
01712         }   /*end for*/
01713 
01714     if (equalidentifiers(ii->morning, temp)) {
01715         /*We have found a match*/
01716         o->ty = VALTYPE_KEYTIMEAM;
01717         o->val = 1;
01718         return;
01719         }
01720 
01721     if (equalidentifiers(ii->evening, temp)) {
01722         /*We have found a match*/
01723         o->ty = VALTYPE_KEYTIMEPM;
01724         o->val = 2;
01725         return;
01726         }
01727 
01728     if (equalidentifiers(ii->military, temp)) {
01729         /*We have found a match*/
01730         o->ty = VALTYPE_KEYTIME24;
01731         o->val = 3;
01732         return;
01733         }
01734 
01735     if (equalidentifiers(ii->currency, temp)) {
01736         o->ty = VALTYPE_CURRENCY;
01737         return;
01738         }
01739 
01740     if (equalidentifiers(ii->intlCurrency, temp)) {
01741         o->ty = VALTYPE_CURRENCY;
01742         return;
01743         }
01744     } /*ValCheckForKeyWord*/
01745 
01746 
01747 static short ValGetCharType (char c)
01748     {
01749     if (isspace(c))
01750         return (VALTYPE_BLANK);
01751 
01752     if (isdigit(c))
01753         return (VALTYPE_NUMERIC);
01754 
01755     if (ispunct(c))
01756         return (VALTYPE_PUNC);
01757 
01758     return (VALTYPE_NONNUMERIC);
01759     } /*ValGetCharType*/
01760 
01761 /*
01762    ValParseOne - parses a string into %#, %B and %S
01763 
01764    ValParseTwo - converts a parse one string so that certain %S are
01765          better defined into %P, %Kx
01766 */
01767 static short ValParseOne (char * strIn, short cnt, Handle * tokenOut) {
01768     short fTokenCount;                  /*number of actual BRRCToke found*/
01769     short len;                          /*length of input string*/
01770     char * pos;                         /*current pointer into string for back reference*/
01771     char * curpos;                      /*current pointer into string for back reference*/
01772     short curTy;                        /*currently active token type*/
01773     char c;                             /*character from string*/
01774     short ty;                           /*Gets token type of 'c'*/
01775     Handle ho;                          /*handle to o*/
01776     tyvalidationtokenptr o;             /*pointer to a series of tyvalidationtoken structures*/
01777     short i;                            /*loop variable*/
01778     tyinternationalinfoptr ii;
01779 
01780 
01781     ii = getIntlInfo();
01782 
01783     if (ii == NULL)
01784         return (-1);
01785 
01786     fTokenCount = 0;
01787     *tokenOut = NULL;
01788 
01789     ho = NewHandle((sizeof(tyvalidationtoken)) * 100);
01790 
01791     if (!ho)
01792         return (-1);                            /*fError*/
01793 
01794     o = (tyvalidationtokenptr) HLock(ho);   /*lock it down*/
01795 
01796     if (!o) {
01797         DisposeHandle (ho);
01798         return (-2);
01799         }
01800 
01801     len = cnt;
01802 
01803     pos = strIn;
01804 
01805     (o + fTokenCount)->pos = pos;
01806     (o + fTokenCount)->ty = VALTYPE_NONE;
01807     (o + fTokenCount)->count = 0;
01808     curTy = VALTYPE_NONE;
01809 
01810     while (len > 0) {
01811         curpos = pos;
01812         c = ValNextChar(&pos);
01813         --len;
01814 
01815         ty = ValGetCharType(c);
01816 
01817         if ((curTy != ty) || (ty == VALTYPE_PUNC)) {/*we are changing types*/
01818             /* strip leading blanks */
01819             if ((fTokenCount != 0) || (ty != VALTYPE_BLANK))
01820                 ++fTokenCount;
01821             (o + fTokenCount)->ty = ty;
01822             (o + fTokenCount)->pos = curpos;
01823             (o + fTokenCount)->count = 1;
01824             (o + fTokenCount)->val = -1;
01825             (o + fTokenCount)->flag = 0L;
01826             curTy = ty;
01827             }
01828         else {
01829             ++((o + fTokenCount)->count);
01830             }
01831         }   /*endwhile*/
01832 
01833     for (i = 1; i <= fTokenCount; i++) {
01834 
01835         switch ((o + i)->ty) {
01836             case VALTYPE_BLANK:
01837                 break;
01838 
01839             case VALTYPE_NONNUMERIC:
01840                 ValCheckForKeyWord(&(o[i]));
01841                 break;
01842 
01843             case VALTYPE_NUMERIC:
01844                 (o + i)->val = charStringToLong((o + i)->pos, (o + i)->count);
01845 
01846                 (o + i)->flag = VALFLAG_ISDOLLARS | VALFLAG_ISCENTS | DateTimeSet_kYear;
01847 
01848                 if ((o + i)->val < 100)
01849                     (o + i)->flag |= DateTimeSet_kHundredth;
01850 
01851                 if ((o + i)->val < 60) {
01852                     (o + i)->flag |= DateTimeSet_kMinute;
01853                     (o + i)->flag |= DateTimeSet_kSecond;
01854                     }
01855 
01856                 if (((o + i)->val < 32) && ((o + i)->val > 0))
01857                     (o + i)->flag |= DateTimeSet_kDay;
01858 
01859                 if ((o + i)->val <= 24)
01860                     (o + i)->flag |= DateTimeSet_kHour;
01861 
01862                 if (((o + i)->val <= ii->numberOfMonths) && ((o + i)->val > 0))
01863                     (o + i)->flag |= DateTimeSet_kMonth;
01864 
01865                 break;
01866 
01867             case VALTYPE_PUNC:
01868                 c = *((o + i)->pos);
01869                 (o + i)->val = ValGetFullPunc(c, &((o + i)->flag));
01870                 break;
01871 
01872             default:
01873                 break;
01874         }                                       /*fEnd switch*/
01875     }                                           /*endfor*/
01876 
01877     /*re-allocate structure*/
01878 
01879     HUnlock(ho);
01880 
01881     ho = SetHandleSize(ho, (sizeof(tyvalidationtoken)) * (fTokenCount + 1));
01882 
01883     *tokenOut = ho;
01884 
01885     return (fTokenCount);
01886     } /*ValParseOne*/
01887 
01888 
01889 static short ValGetDateOrder (tyValidationOrderPtr orderRec, short ty)
01890     {
01891     tyinternationalinfoptr ii;
01892     short orderPos;
01893     char c, d;
01894     char * pos;
01895     bigstring p;
01896     boolean flYear, flDay, flMonth;
01897 
01898     flYear = FALSE;
01899     flDay = FALSE;
01900     flMonth = FALSE;
01901 
01902     orderPos = 0;
01903 
01904     ii = getIntlInfo();
01905 
01906     if (ii == NULL)
01907         return (0);
01908 
01909     if (ty == 0)                                /*then use short date order*/
01910         copystring (ii->shortDateFormatPattern, p);
01911     else
01912         copystring (ii->longDateFormatPattern, p);
01913 
01914     pos = stringbaseaddress(p);
01915 
01916     while (pos < (stringbaseaddress(p) + stringlength(p))) {
01917         c = ValNextChar(&pos);
01918 
01919         if (c == '%') {
01920             c = ValNextChar(&pos);
01921 
01922             if (c == '%') {
01923                 c = ValNextChar(&pos);
01924 
01925                 switch (c) {
01926                     case 'Y':
01927                         if (!flYear) {
01928                             (orderRec + orderPos)->item = DateTimeSet_kYear;
01929                             flYear = TRUE;
01930                             ++orderPos;
01931                             }
01932                         break;
01933 
01934                     case 'M':
01935                     case 'D':
01936                         d = ValNextChar(&pos);
01937 
01938                         if ((c == 'M') && ((d == 'N') || (d == '#'))) {
01939                             if (!flMonth) {
01940                                 (orderRec + orderPos)->item = DateTimeSet_kMonth;
01941                                 ++orderPos;
01942                                 flMonth = TRUE;
01943                                 }
01944                             }
01945 
01946                         if ((c == 'D') && (d == '#')) {
01947                             if (!flDay) {
01948                                 (orderRec + orderPos)->item = DateTimeSet_kDay;
01949                                 ++orderPos;
01950                                 flDay = TRUE;
01951                                 }
01952                             }
01953 
01954                         break;
01955 
01956                     default:
01957                         break;
01958                     }
01959                 }
01960             }
01961         } /*end while*/
01962 
01963 
01964     if (orderPos < 3) {                         /*default format does not do everything*/
01965         if (!flMonth) {
01966             (orderRec + orderPos)->item = DateTimeSet_kMonth;
01967             ++orderPos;
01968             }
01969         if (!flDay) {
01970             (orderRec + orderPos)->item = DateTimeSet_kDay;
01971             ++orderPos;
01972             }
01973         if (!flYear) {
01974             (orderRec + orderPos)->item = DateTimeSet_kYear;
01975             ++orderPos;
01976             }
01977         }
01978     return (orderPos);
01979     }
01980 
01981 
01982 static void ValDeleteFromOrder (
01983     tyValidationOrderPtr o,
01984     short * cnt,
01985     short field)
01986 
01987 {
01988     short i;
01989     boolean flStart;
01990 
01991     flStart = FALSE;
01992 
01993     for (i = 0; i < *cnt; i++)
01994     {
01995         if (flStart)
01996         {
01997             (o + i - 1)->item = (o + i)->item;
01998             (o + i - 1)->type = (o + i)->type;
01999         }
02000 
02001         if ((o + i)->item == field)
02002         {
02003             flStart = TRUE;
02004         }
02005     }
02006 
02007     if (flStart)
02008         *cnt = *cnt - 1;
02009 }                                               /*ValDeleteFromOrder*/
02010 
02011 
02012 boolean ValidDate (
02013    unsigned char * strIn,
02014    short cnt,
02015    tydaterecptr returnDT,
02016    tydaterecptr actualDT,
02017    unsigned long * validUnits,
02018    tyvalidationerrorptr err)
02019 
02020 {
02021     tyvalidationtokenptr o;
02022     Handle ho;
02023     short bC, uC, kC, pC, nC;
02024     short i;
02025     tyCharacterAttributes j;
02026     short tokCount;
02027     short dateF;
02028     boolean uniformP;
02029     tydaterec currentDT;
02030     short errSet;
02031     long pType;
02032     tyValidationOrder orderRec[6];
02033     short orderCnt;
02034     short op;
02035     short vu;
02036     short cYear, cCen;
02037     boolean flShortFormat;
02038 
02039     /**** FOR DATES ONLY! ****/
02040 
02041     tokCount = ValParseOne(strIn, cnt, &ho);
02042     
02043     if (tokCount < 0)
02044         return (false);
02045 
02046     o = (tyvalidationtokenptr) HLock(ho);
02047 
02048     bC = uC = kC = nC = pC = 0;                 /*I hate doing this*/
02049     uniformP = FALSE;
02050     flShortFormat = FALSE;
02051     dateF = 0;
02052 
02053     for (i = 1; i <= tokCount; i++) {
02054         switch ((o + i)->ty) {
02055             case VALTYPE_BLANK:
02056                 ++bC;
02057                 break;
02058 
02059             case VALTYPE_NONNUMERIC:
02060                 ++uC;
02061                 break;
02062 
02063             case VALTYPE_KEYDAYNAME1:
02064             case VALTYPE_KEYDAYNAME2:
02065                 dateF |= SCAN_DOW;
02066                 ++kC;
02067                 break;
02068 
02069             case VALTYPE_KEYMONTHNAME1:
02070             case VALTYPE_KEYMONTHNAME2:
02071                 dateF |= SCAN_MONTH;
02072                 ++kC;
02073                 break;
02074 
02075             case VALTYPE_KEYYEARNAME:
02076                 /* not yet supported */
02077                 break;
02078 
02079             case VALTYPE_KEYTIMEAM:
02080             case VALTYPE_KEYTIMEPM:
02081             case VALTYPE_KEYTIME24:
02082                 break;
02083 
02084             case VALTYPE_NUMERIC:
02085                 if (((o + i)->flag & (DateTimeSet_kYear | DateTimeSet_kMonth | DateTimeSet_kDay)) == DateTimeSet_kYear)
02086                     dateF |= SCAN_YEAR;
02087 
02088                 ++nC;
02089                 break;
02090 
02091             case VALTYPE_PUNC:
02092                 if (pC == 0) {
02093                     pType = (o + i)->val;
02094                     uniformP = TRUE;
02095                     }
02096                 else {
02097                     if (pType != (o + i)->val)
02098                         uniformP = FALSE;
02099                     }
02100 
02101                 ++pC;
02102                 break;
02103 
02104             default:
02105                 break;
02106             } /*fEnd switch*/
02107         } /*endfor*/
02108 
02109     getDateTime(&currentDT);
02110 
02111     cYear = currentDT.year;
02112     cCen = 100 * (cYear / 100);
02113 
02114     errSet = 0;
02115     vu = 0;
02116     op = 0;
02117 
02118     /************************************************************************
02119       Day of fWeek entries only have meaning if they are alone, i.e. a user
02120       enters Friday or Yesterday, etc.  With anything else it meaning is
02121       overridden.
02122     *************************************************************************/
02123 
02124     if ((dateF == SCAN_DOW) && (nC == 0) && (kC == 1))
02125         {
02126         /*process Day of Week FormatAndValidationKeywords only */
02127 
02128         /* find FormatAndValidationKeywords */
02129 
02130         i = 1;
02131         while (((o + i)->ty != VALTYPE_KEYDAYNAME1) && ((o + i)->ty != VALTYPE_KEYDAYNAME2)) {
02132             ++i;
02133             }
02134 
02135         /* set actual structure */
02136         if (actualDT != NULL) {
02137             actualDT->dayOfWeek = (short)(o + i)->val;
02138             }
02139 
02140         vu = DateTimeSet_kDayOfWeek;
02141 
02142         if ((o + i)->val > 6)                   /*handle yesterday, today, and tommorrow*/
02143             {
02144             addDurationToDateTime(&currentDT, ((short)((o + i)->val) - 8), DurationUnit_kDays);
02145             }
02146         else
02147             {
02148             j = ((short)(o + i)->val + 7) - currentDT.dayOfWeek;
02149 
02150             if (j > 6)
02151                 j = j - 7;
02152 
02153             addDurationToDateTime(&currentDT, (short)j, DurationUnit_kDays);
02154             }
02155         /*we are done here...*/
02156         goto ValidDateExit;
02157         }
02158 
02159 
02160     /********** Not DayOfWeek FormatAndValidationKeywords only *************/
02161 
02162     if ((dateF & SCAN_MONTH) != SCAN_MONTH)     /* we have no fMonth BR_FormatAndValidationKeywords*/
02163     {
02164         /*
02165           We know we are using the "short" date format since there are no
02166           meaningfull keywords, of course a number such as 5.25 qualifies
02167           and only becuase we are trying for a date we will BR_TRY for May 25th.
02168         */
02169 
02170         orderCnt = ValGetDateOrder(orderRec, 0);
02171 
02172         flShortFormat = TRUE;
02173 
02174         for (i = 0; i < orderCnt; i++)
02175         {
02176             orderRec[i].type = VALORDER_NUMERIC;
02177 
02178             if (orderRec[i].item == DateTimeSet_kYear)
02179             {
02180                 if ((dateF & SCAN_YEAR) == SCAN_YEAR)/* we have a fYear! */
02181                 {
02182                     orderRec[i].type = VALORDER_FIXEDNUMERIC;
02183                 }
02184             }
02185         }
02186 
02187         switch (nC)
02188         {
02189             case 1:
02190                 /*Number must be the fYear only*/
02191                 orderCnt = 1;
02192                 orderRec[0].item = DateTimeSet_kYear;
02193                 if ((dateF & SCAN_YEAR) == SCAN_YEAR)
02194                     orderRec[0].type = VALORDER_FIXEDNUMERIC;
02195                 else
02196                     orderRec[0].type = VALORDER_NUMERIC;
02197                 break;
02198 
02199             case 2:
02200                 /*Numbers must be fMonth/fYear or fDay/fMonth pair*/
02201                 if ((dateF & SCAN_YEAR) == SCAN_YEAR)
02202                 {
02203                     /*it must be the fMonth/fYear combination, fYear fFixed*/
02204                     /*we do not need to have fYear in list since it is fFixed*/
02205                     orderCnt = 1;
02206                     orderRec[0].item = DateTimeSet_kMonth;
02207                     orderRec[0].type = VALORDER_NUMERIC;
02208                 }
02209                 else
02210                 {
02211                     /*there is no determinate fYear so use fMonth/fDay combination*/
02212                     ValDeleteFromOrder(orderRec, &orderCnt, DateTimeSet_kYear);
02213                 }
02214                 break;
02215 
02216             case 3:
02217                 /*normal trio*/
02218                 break;
02219 
02220             default:
02221                 /*to many numbers or to few numbers*/
02222                 errSet = err_kTooManyNumberFields;
02223                 if (nC == 0)
02224                     errSet = err_kTooFewValues;
02225                 goto ValidDateExit;
02226                 break;
02227         }                                       /*fEnd switch*/
02228     }
02229     /*endif on short format*/
02230 
02231     else                                        /* we have the fMonth BR_FormatAndValidationKeywords */
02232         {
02233             orderCnt = ValGetDateOrder(orderRec, 1);
02234 
02235             ValDeleteFromOrder(orderRec, &orderCnt, DateTimeSet_kMonth);
02236 
02237             if ((dateF & SCAN_YEAR) == SCAN_YEAR)/* we have a fYear! */
02238             {
02239                 /*only need the fDay*/
02240                 ValDeleteFromOrder(orderRec, &orderCnt, DateTimeSet_kYear);
02241             }
02242         }
02243     /*
02244       do retreive.  it is this that would actually set the errors.
02245 
02246       go through each token, when you get a BR_FormatAndValidationKeywords or number BR_TRY to match it
02247       with the order record, if it is "fFixed" place it in catagory
02248     */
02249 
02250 
02251     for (i = 1; i <= tokCount; i++)
02252     {
02253         switch ((o + i)->ty)
02254         {
02255             case VALTYPE_KEYDAYNAME1:
02256             case VALTYPE_KEYDAYNAME2:
02257                 if (actualDT != NULL)
02258                     actualDT->dayOfWeek = (short)(o + i)->val;
02259 
02260                 vu |= DateTimeSet_kDayOfWeek;
02261                 currentDT.dayOfWeek = (short)(o + i)->val;
02262                 break;
02263 
02264             case VALTYPE_KEYMONTHNAME1:
02265             case VALTYPE_KEYMONTHNAME2:
02266                 if (actualDT != NULL)
02267                     actualDT->month = (short)(o + i)->val + 1;
02268 
02269                 vu |= DateTimeSet_kMonth;
02270 
02271                 currentDT.month = (short)(o + i)->val + 1;
02272                 break;
02273 
02274             case VALTYPE_KEYYEARNAME:
02275                 /* not yet supported */
02276                 break;
02277 
02278             case VALTYPE_PUNC:
02279                 if (flShortFormat)
02280                     j = CharAttr_kShortDate;
02281                 else
02282                     j = CharAttr_kLongDate;
02283 
02284                 if (!((o + i)->flag & j))
02285                     errSet = err_kInvalidPunctuation;
02286                 break;
02287 
02288             case VALTYPE_NUMERIC:
02289                 /*
02290                   has this token's valid areas already been consummed
02291                   if so then we have an fError.
02292                 */
02293                 if ((o + i)->flag & ((DateTimeSet_kYear | DateTimeSet_kMonth | DateTimeSet_kDay) ^ vu))
02294                 {
02295                     /*so far so good*/
02296                     /*
02297                       see what is left that we need.  if more then one item
02298                       then check order to see which it should be.
02299                     */
02300                     if (((o + i)->flag & (DateTimeSet_kYear | DateTimeSet_kMonth | DateTimeSet_kDay)) == DateTimeSet_kYear)
02301                     {
02302                         /*This item qualifies as a fYear only, apply it*/
02303                         if (actualDT != NULL)
02304                             actualDT->year = (short)(o + i)->val;
02305 
02306                         currentDT.year = (short)(o + i)->val;
02307                         vu |= DateTimeSet_kYear;
02308 
02309                         ++op; /*6.1b5 AR*/
02310                     }
02311                     else
02312                     {
02313                         /*the item is an indeterminate - use orderRec*/
02314 
02315                         /*Is the item specified in the order record needed?*/
02316                         if (orderRec[op].item & ((DateTimeSet_kYear | DateTimeSet_kMonth | DateTimeSet_kDay) ^ vu))
02317                         {
02318                             /*does order item fit token?*/
02319                             if (((o + i)->flag) & (orderRec[op].item))
02320                             {
02321                                 /*apply it*/
02322                                 switch (orderRec[op].item)
02323                                 {
02324                                     case DateTimeSet_kYear:
02325                                         if (actualDT != NULL)
02326                                             actualDT->year = (short)(o + i)->val;
02327 
02328                                         currentDT.year = (short)(o + i)->val;
02329                                         vu |= DateTimeSet_kYear;
02330                                         break;
02331 
02332                                     case DateTimeSet_kMonth:
02333                                         if (actualDT != NULL)
02334                                             actualDT->month = (short)(o + i)->val;
02335 
02336                                         currentDT.month = (short)(o + i)->val;
02337                                         vu |= DateTimeSet_kMonth;
02338                                         break;
02339 
02340                                     case DateTimeSet_kDay:
02341                                         if (actualDT != NULL)
02342                                             actualDT->day = (short)(o + i)->val;
02343 
02344                                         currentDT.day = (short)(o + i)->val;
02345                                         vu |= DateTimeSet_kDay;
02346                                         break;
02347 
02348                                     default:
02349                                         break;
02350                                 }               /*fEnd switch*/
02351 
02352                                 ++op;
02353                             }
02354 
02355                             else
02356                             {
02357                                 /*Item does not fit order position*/
02358                                 errSet = err_kOutOfOrder;
02359                             }
02360                         }
02361                         else
02362                         {
02363                             /*Item in order record already used*/
02364                             errSet = err_kItemUsed;
02365                         }
02366                     }                           /*endelse - indeterminate*/
02367                 }
02368                 else
02369                 {
02370                     /*item is an fError, already used*/
02371                     errSet = err_kItemUsed;
02372                 }
02373 
02374                 break;
02375 
02376             default:
02377                 break;
02378         }                                       /*fEnd switch*/
02379 
02380         if (errSet != 0)
02381             break;
02382     }                                           /*endfor*/
02383 
02384 ValidDateExit:
02385     if (validUnits != NULL)
02386         *validUnits = vu;
02387 
02388     if (vu == 0)                                /*no valid units, i.e. garbage*/
02389         errSet = err_kTooFewValues;
02390 
02391     vu |= DateTimeSet_kDay | DateTimeSet_kMonth | DateTimeSet_kYear;
02392 
02393     if ((currentDT.year < 100) && (currentDT.year > 0))
02394     {
02395         currentDT.year += cCen;
02396 
02397         if (currentDT.year < (unsigned short)(cYear - 50))
02398             currentDT.year += 100;
02399 
02400         if (currentDT.year > (unsigned short)(cYear + 50))
02401             currentDT.year = currentDT.year - 100;
02402     }
02403 
02405 
02406     if (returnDT != NULL)
02407         *returnDT = currentDT;
02408 
02409     if (err != NULL)
02410     {
02411         err->errorNumber = errSet;
02412 
02413         if (errSet != 0 && i <= tokCount)
02414         {
02415             err->stringPosition = (long)((o + i)->pos - (char *)strIn); // TRT - 29 Dec 2004
02416             err->auxilaryPointer = NULL;
02417         }
02418     }
02419 
02420     unlockhandle (ho);
02421     DisposeHandle (ho);
02422 
02423     if (errSet != 0)
02424         return (FALSE);
02425 
02426     return (TRUE);
02427 }
02428 
02429 
02430 
02431 
02432 
02433 
02434 boolean ValidTime (
02435    char * strIn,
02436    short cnt,
02437    tydaterecptr returnDT,
02438    tydaterecptr actualDT,
02439    unsigned long * validUnits,
02440    tyvalidationerrorptr err) {
02441 
02442    /*
02443    5.1.5b14 dmb: fixed bug where we disposed handle before checking errors
02444    */
02445 
02446     tyvalidationtokenptr o;
02447     Handle ho;
02448     short i;
02449     short tokCount;
02450     short errSet;
02451     short vu;
02452     short tlAM;
02453     tyinternationalinfo * ii;
02454     tydaterec currentDT;
02455 
02456     tokCount = ValParseOne(strIn, cnt, &ho);
02457 
02458     if (tokCount < 0)
02459         return (false);
02460 
02461     o = (tyvalidationtokenptr) HLock(ho);
02462 
02463     getDateTime(&currentDT);
02464     currentDT.hour = 0;
02465     currentDT.minute = 0;
02466     currentDT.second = 0;
02467     currentDT.hundredths = 0;
02468 
02469     /*
02470       do retreive.  it is this that would actually set the errors.
02471 
02472       go through each token, when you get a BR_FormatAndValidationKeywords or number BR_TRY to match it
02473       with the order record, if it is "fFixed" place it in catagory
02474     */
02475 
02476     errSet = 0;
02477     vu = 0;
02478     tlAM = 0;
02479 
02480     for (i = 1; i <= tokCount; i++)
02481     {
02482         switch ((o + i)->ty)
02483         {
02484             case VALTYPE_KEYTIMEAM:
02485                 tlAM = -1;
02486                 break;
02487 
02488             case VALTYPE_KEYTIMEPM:
02489                 tlAM = 1;
02490                 break;
02491 
02492             case VALTYPE_KEYTIME24:
02493                 break;                          /*has no real meaning*/
02494 
02495             case VALTYPE_PUNC:
02496                 if (!((o + i)->flag & CharAttr_kTime))
02497                     errSet = err_kInvalidPunctuation;
02498                 break;
02499 
02500             case VALTYPE_NUMERIC:
02501                 /*first fHour, then fMinute, then fSecond, then hundreth*/
02502                 if ((DateTimeSet_kHour & vu) == DateTimeSet_kHour)
02503                 {
02504                     /*Hour used*/
02505                     if ((DateTimeSet_kMinute & vu) == DateTimeSet_kMinute)
02506                     {
02507                         /*fMinute used*/
02508                         if ((DateTimeSet_kSecond & vu) == DateTimeSet_kSecond)
02509                         {
02510                             /*fSecond used*/
02511                             if ((DateTimeSet_kHundredth & vu) == DateTimeSet_kHundredth)
02512                             {
02513                                 errSet = err_kTooManyNumberFields;
02514                             }
02515                             else
02516                             {
02517                                 if (((o + i)->flag & DateTimeSet_kHundredth) == DateTimeSet_kHundredth)
02518                                 {
02519                                     if (actualDT != NULL)
02520                                         actualDT->hundredths = (short)(o + i)->val;
02521 
02522                                     currentDT.hundredths = (short)(o + i)->val;
02523                                     vu |= DateTimeSet_kHundredth;
02524                                 }
02525                                 else
02526                                 {
02527                                     errSet = err_kHundredthValueInvalid;
02528                                 }
02529                             }
02530                         }
02531                         else
02532                         {
02533                             if (((o + i)->flag & DateTimeSet_kSecond) == DateTimeSet_kSecond)
02534                             {
02535                                 if (actualDT != NULL)
02536                                     actualDT->second = (short)(o + i)->val;
02537 
02538                                 currentDT.second = (short)(o + i)->val;
02539                                 vu |= DateTimeSet_kSecond;
02540                             }
02541                             else
02542                             {
02543                                 errSet = err_kSecondValueInvalid;
02544                             }
02545                         }
02546                     }
02547                     else
02548                     {
02549                         if (((o + i)->flag & DateTimeSet_kMinute) == DateTimeSet_kMinute)
02550                         {
02551                             if (actualDT != NULL)
02552                                 actualDT->minute = (short)(o + i)->val;
02553 
02554                             currentDT.minute = (short)(o + i)->val;
02555                             vu |= DateTimeSet_kMinute;
02556                         }
02557                         else
02558                         {
02559                             errSet = err_kMinuteValueInvalid;
02560                         }
02561                     }
02562                 }
02563                 else
02564                 {
02565                     if (((o + i)->flag & DateTimeSet_kHour) == DateTimeSet_kHour)
02566                     {
02567                         if (actualDT != NULL)
02568                             actualDT->hour = (short)(o + i)->val;
02569 
02570                         currentDT.hour = (short)(o + i)->val;
02571                         vu |= DateTimeSet_kHour;
02572                     }
02573                     else
02574                     {
02575                         errSet = err_kHourValueInvalid;
02576                     }
02577                 }
02578 
02579                 break;
02580 
02581             default:
02582                 break;
02583         }                                       /*fEnd switch*/
02584 
02585         if (errSet != 0)
02586             break;
02587     }                                           /*endfor*/
02588 
02589 
02590     if (validUnits != NULL)
02591         *validUnits = vu;
02592 
02593     if (vu == 0)                                /*no valid units, i.e. garbage*/
02594         errSet = err_kTooFewValues;
02595 
02596     if (currentDT.hour > 12)
02597     {
02598         if (tlAM != 0)
02599             errSet = err_kAMorPMon24HourClock;
02600     }
02601     else
02602     {
02603         switch (tlAM)
02604         {
02605             case -1:
02606                 if (currentDT.hour == 12)
02607                     currentDT.hour = 0;
02608                 break;
02609 
02610             case 0:
02611                 ii = getIntlInfo();
02612 
02613                 if (ii->defaultTimeFormat == FALSE)/*we are on a 12 fHour clock*/
02614                 {
02615                     if (currentDT.hour != 0)
02616                     {
02617                         /* assume 8 to 11 is AM, 12 is PM 1 to 7 is PM */
02618                         if (currentDT.hour < 8)
02619                             currentDT.hour += 12;
02620                     }
02621                 }
02622                 break;
02623 
02624             case 1:
02625                 currentDT.hour += 12;
02626                 if (currentDT.hour == 24)
02627                     currentDT.hour = 12;
02628                 break;
02629 
02630             default:
02631                 break;
02632         }
02633     }
02634     
02635     if (returnDT != NULL)
02636         *returnDT = currentDT;
02637 
02638     if (err != NULL)
02639     {
02640         err->errorNumber = errSet;
02641 
02642         if (errSet != 0 && i <= tokCount)
02643         {
02644             err->stringPosition = (long)((o + i)->pos - (char *)strIn); // TRT - 29 Dec 2004
02645             err->auxilaryPointer = NULL;
02646         }
02647     }
02648 
02649     unlockhandle(ho);
02650     disposehandle (ho);
02651 
02652     if (errSet != 0)
02653         return (FALSE);
02654 
02655     return (TRUE);
02656 }
02657 
02658 #endif
02659 

Generated on Wed May 31 18:20:03 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6