mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1151 lines
34 KiB
1151 lines
34 KiB
/*****************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1990 **/
|
|
/*****************************************************************/
|
|
|
|
/*
|
|
* File: pdate.c
|
|
* this module contains routines for parsing date/time.
|
|
* Exports: LUI_ParseDateTime()
|
|
* This function reads a string containing date/time, and
|
|
* returns the number of seconds passed since midnight 1/1/70.
|
|
* LUI_ParseDate()
|
|
* As LUI_ParseDateTime, but only date, no time.
|
|
* LUI_ParseTime(), LUI_ParseTime12(), LUI_ParseTime24()
|
|
* As LUI_ParseDateTime, but only time, no date.
|
|
*
|
|
* Improvements:
|
|
* we currently copy FAR input string into own NEAR buffer for
|
|
* sscanf() to work. We should be able to use nsscanf() without
|
|
* having to do the copy - if & when nsscanf() works.
|
|
*
|
|
* instead of allocating the date/time format data statically,
|
|
* we should be able to do this dynamically
|
|
*
|
|
* History:
|
|
* who when what
|
|
* ------------------------
|
|
* chuckc 5/31/89 new code
|
|
*/
|
|
|
|
/*-- includes --*/
|
|
|
|
#define INCL_DOS
|
|
#include <stdio.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <lmcons.h>
|
|
//#include <lui.h>
|
|
#include <string.h>
|
|
//#include <error.h>
|
|
//#include <malloc.h>
|
|
//#include <apperr.h>
|
|
//#include <apperr2.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
//#include <apiutil.h>
|
|
|
|
#ifdef DOS3
|
|
#include <dos.h>
|
|
#endif
|
|
|
|
#include "luiint.h"
|
|
#include "luitext.h"
|
|
#include "tests.h"
|
|
|
|
/*-- manifests --*/
|
|
#define ERROR_GEN_FAILURE -1
|
|
#define ERROR_BAD_ARGUMENTS -2
|
|
|
|
extern
|
|
PVOID
|
|
Heap;
|
|
|
|
/* max number of fields for either date or time */
|
|
#define PD_MAX_FIELDS 5
|
|
|
|
/* are we reading a NUMBER, AM/PM selector or MONTHS */
|
|
#define PD_END_MARKER 0
|
|
#define PD_NUMBER 1
|
|
#define PD_AMPM 2
|
|
#define PD_MONTHS 3
|
|
|
|
/* time formats */
|
|
#define PD_24HR 0
|
|
#define PD_AM 1
|
|
#define PD_PM 2
|
|
|
|
/* internal error code */
|
|
#define PD_SUCCESS 0
|
|
#define PD_ERROR_NO_MATCH 1
|
|
#define PD_ERROR_INTERNAL 2
|
|
#define PD_ERROR_END_OF_INPUT 3
|
|
|
|
/* indices */
|
|
#define DAYS 0
|
|
#define MONTHS 1
|
|
#define YEARS 2
|
|
#define HOURS 0
|
|
#define MINUTES 1
|
|
#define SECONDS 2
|
|
#define AMPM 3
|
|
|
|
#define WHITE_SPACE " \t\n"
|
|
#define DIGITS "0123456789"
|
|
//#define NEXT_CHAR(p) (IS_LEAD_BYTE(*p)?p+2:p+1)
|
|
#define NEXT_CHAR(p) (p+1)
|
|
|
|
/*-- types internal to this module --*/
|
|
|
|
/* describe how we expect to parse a field within a date or time */
|
|
typedef struct date_field_desc {
|
|
char * sep ; /* the separator before this field */
|
|
char * fmt ; /* format descriptor, scanf() style */
|
|
unsigned char typ ; /* NUMBER or AMPM or MONTHS */
|
|
unsigned char pos ; /* position - depends on country */
|
|
} date_fdesc ;
|
|
|
|
/* an array of short values, each corresponding to a field read */
|
|
typedef short date_data[PD_MAX_FIELDS] ;
|
|
|
|
/*-- forward declarations --*/
|
|
|
|
SHORT WParseDate( date_fdesc **d_desc ,
|
|
date_fdesc **t_desc ,
|
|
char *inbuf ,
|
|
char **nextchr,
|
|
PLARGE_INTEGER time ) ;
|
|
|
|
SHORT setup_data( char **bufferp ,
|
|
char **freep,
|
|
USHORT slist_bufsiz ,
|
|
char * * local_inbuf,
|
|
PCHAR inbuf,
|
|
SHORT country,
|
|
PULONG parselen ) ;
|
|
|
|
int read_format( char * * inbuf,
|
|
date_fdesc *desc,
|
|
date_data data ) ;
|
|
|
|
SHORT convert_to_abs( date_data d_data,
|
|
date_data t_data,
|
|
PLARGE_INTEGER time) ;
|
|
|
|
SHORT convert_to_24hr( date_data time ) ;
|
|
|
|
void advance_date( date_data d_data) ;
|
|
|
|
long seconds_since_1970( date_data d_data,
|
|
date_data t_data ) ;
|
|
|
|
long days_so_far( SHORT d, SHORT m, SHORT y ) ;
|
|
|
|
/*-- data --*/
|
|
|
|
searchlist ampm_data[] = {
|
|
{"AM", PD_AM},
|
|
{"A.M.", PD_AM},
|
|
{"A", PD_AM},
|
|
{"PM", PD_PM},
|
|
{"P.M.", PD_PM},
|
|
{"P", PD_PM},
|
|
{0,0}
|
|
} ;
|
|
|
|
searchlist months_data[] = {
|
|
{"January", 1},
|
|
{"February", 2},
|
|
{"March", 3},
|
|
{"April", 4},
|
|
{"May", 5},
|
|
{"June", 6},
|
|
{"July", 7},
|
|
{"August", 8},
|
|
{"September", 9},
|
|
{"October", 10},
|
|
{"November", 11},
|
|
{"December", 12},
|
|
{"Jan", 1},
|
|
{"Feb", 2},
|
|
{"Mar", 3},
|
|
{"Apr", 4},
|
|
{"May", 5},
|
|
{"Jun", 6},
|
|
{"Jul", 7},
|
|
{"Aug", 8},
|
|
{"Sep",9},
|
|
{"Oct", 10},
|
|
{"Nov", 11},
|
|
{"Dec", 12},
|
|
{0,0}
|
|
} ;
|
|
|
|
#define MONTHS_IN_YEAR (12)
|
|
#define NUM_AMPM_LIST (sizeof(ampm_data)/sizeof(ampm_data[0]))
|
|
#define NUM_MONTHS_LIST (sizeof(months_data)/sizeof(months_data[0]))
|
|
#define SLIST_BUFSIZ (640)
|
|
|
|
/*
|
|
* NOTE - we init the first 12 hardwired months
|
|
* and get the rest from the message file
|
|
*/
|
|
searchlist ampm_list[NUM_AMPM_LIST + 2] = {
|
|
{LUI_txt_am,PD_AM},
|
|
{LUI_txt_pm,PD_PM},
|
|
} ;
|
|
searchlist months_list[NUM_MONTHS_LIST + MONTHS_IN_YEAR] = {
|
|
{LUI_txt_january,1},
|
|
{LUI_txt_february,2},
|
|
{LUI_txt_march,3},
|
|
{LUI_txt_april,4},
|
|
{LUI_txt_may,5},
|
|
{LUI_txt_june,6},
|
|
{LUI_txt_july,7},
|
|
{LUI_txt_august,8},
|
|
{LUI_txt_september,9},
|
|
{LUI_txt_october,10},
|
|
{LUI_txt_november,11},
|
|
{LUI_txt_december,12},
|
|
} ;
|
|
|
|
/*
|
|
* built in formats for scanf - we will add to these strings as needed
|
|
* when we read stuff from DosGetCtryInfo(). Note that a string is
|
|
* defined to be anything which is not a known separator.
|
|
*/
|
|
char pd_fmt_null[1] = "" ;
|
|
char pd_fmt_d_sep1[8] = "/-" ; /* date separator for NUMBERs */
|
|
char pd_fmt_d_sep2[8] = "/,- \t" ; /* date separator for MONTHs */
|
|
char pd_fmt_t_sep[8] = ":" ; /* time separator */
|
|
char pd_fmt_number[8] = "%d" ; /* a number */
|
|
char pd_fmt_string[16] = "%[^-, /:\t" ; /* string, needs ] at end */
|
|
|
|
/*-- date descriptors (despite verbosity, not as big at it seems) --*/
|
|
|
|
date_fdesc d_desc1[] = { /* eg. 3-31-89 */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_d_sep1, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_d_sep1, pd_fmt_number, PD_NUMBER, 2 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc d_desc2[] = { /* eg. 5 Jun 89 */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_d_sep2, pd_fmt_string, PD_MONTHS, 1 },
|
|
{pd_fmt_d_sep2, pd_fmt_number, PD_NUMBER, 2 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc d_desc3[] = { /* eg. Jun 5 89 */
|
|
{pd_fmt_null, pd_fmt_string, PD_MONTHS, 1 },
|
|
{pd_fmt_d_sep2, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_d_sep2, pd_fmt_number, PD_NUMBER, 2 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc d_desc4[] = { /* eg. 3-31 */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_d_sep1, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc d_desc5[] = { /* eg. 5 Jun */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_d_sep2, pd_fmt_string, PD_MONTHS, 1 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc d_desc6[] = { /* eg. Jun 5 */
|
|
{pd_fmt_null, pd_fmt_string, PD_MONTHS, 1 },
|
|
{pd_fmt_d_sep2, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
/*-- time descriptors --*/
|
|
|
|
date_fdesc t_desc1[] = { /* eg. 1:00:00pm */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 2 },
|
|
{pd_fmt_null, pd_fmt_string, PD_AMPM, 3 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc t_desc2[] = { /* eg. 13:00:00 */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 2 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc t_desc3[] = { /* eg. 1:00pm */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_null, pd_fmt_string, PD_AMPM, 3 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc t_desc4[] = { /* eg. 13:00 */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_t_sep, pd_fmt_number, PD_NUMBER, 1 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
date_fdesc t_desc5[] = { /* eg. 1pm */
|
|
{pd_fmt_null, pd_fmt_number, PD_NUMBER, 0 },
|
|
{pd_fmt_null, pd_fmt_string, PD_AMPM, 3 },
|
|
{pd_fmt_null, pd_fmt_null, PD_END_MARKER, 0 }
|
|
} ;
|
|
|
|
/*-- possible dates & times --*/
|
|
|
|
/*
|
|
* NOTE - for all the below time/date descriptors, we
|
|
* employ a greedy mechanism - always try longest match first.
|
|
*/
|
|
|
|
/* this is the order we try to parse a date */
|
|
date_fdesc *possible_dates[] = {
|
|
d_desc1, d_desc2,
|
|
d_desc3, d_desc4,
|
|
d_desc5, d_desc6,
|
|
NULL
|
|
} ;
|
|
|
|
/* this is the order we try to parse a time */
|
|
date_fdesc *possible_times[] = {
|
|
t_desc1, t_desc2,
|
|
t_desc3, t_desc4,
|
|
t_desc5, NULL
|
|
} ;
|
|
|
|
/* this is the order we try to parse a 12 hour time */
|
|
date_fdesc *possible_times12[] = {
|
|
t_desc1, t_desc3,
|
|
t_desc5, NULL
|
|
} ;
|
|
|
|
/* this is the order we try to parse a time */
|
|
date_fdesc *possible_times24[] = {
|
|
t_desc2, t_desc4,
|
|
NULL
|
|
} ;
|
|
|
|
|
|
/*-- exported routines --*/
|
|
|
|
/*
|
|
* Name: LUI_ParseDateTime
|
|
* will parse the input string (null terminated) for a
|
|
* date & time or time & date combination. Valid dates
|
|
* include:
|
|
* 2,June,1989 6/2/89 6/2
|
|
* Valid times include:
|
|
* 2pm 14:00 2:00P.M.
|
|
* Full details of formats are documented in pdate.txt,
|
|
* note that Country Information will be used.
|
|
*
|
|
* Args: PCHAR inbuf - string to parse
|
|
* PLONG time - will contain time in seconds since midnight 1/1/70
|
|
* corresponding to the date if successfully parsed.
|
|
* Undefined otherwise.
|
|
* PULONG parselen - length of string parsed
|
|
* USHORT reserved - not used for now, must be zero.
|
|
*
|
|
* Returns: 0 if parse successfully,
|
|
* ERROR_BAD_ARGUMENTS - cannot parse illegal date/time format
|
|
* ERROR_GEN_FAILURE - internal error
|
|
* Globals: Indirectly, all date/time descriptors, month/year info in this
|
|
* file. No globals outside of this file is used. However, malloc
|
|
* is called to allocate memory.
|
|
* s: (none) - but see setup_data()
|
|
* Remarks: (none)
|
|
* Updates: (none)
|
|
*/
|
|
SHORT LUI_ParseDateTime(
|
|
PCHAR inbuf,
|
|
PLARGE_INTEGER time,
|
|
PULONG parselen,
|
|
USHORT reserved
|
|
)
|
|
{
|
|
char *buffer, *local_inbuf, *nextchr ;
|
|
char *freep; /* pointer to buffer malloc'd by
|
|
setup data */
|
|
short res ;
|
|
|
|
/* pacify compiler */
|
|
if (reserved) ;
|
|
|
|
/* will grab memory, setup d_desc, t_desc, local_inbuf */
|
|
if (setup_data(&buffer,&freep,SLIST_BUFSIZ,&local_inbuf,inbuf,0,parselen)
|
|
!= 0)
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
/* call the worker function */
|
|
res = WParseDate(possible_dates,possible_times,local_inbuf,&nextchr,time) ;
|
|
*parselen += (nextchr - local_inbuf) ;
|
|
RtlFreeHeap(Heap, 0, freep) ;
|
|
return(res) ;
|
|
}
|
|
|
|
/*
|
|
* Name: LUI_ParseDate
|
|
* will parse the input string (null terminated) for a
|
|
* date. Valid dates include:
|
|
* 2,June,1989 6/2/89 6/2
|
|
* Full details of formats are documented in pdate.txt,
|
|
* note that Country Information will be used.
|
|
*
|
|
* Args: PCHAR inbuf - string to parse
|
|
* PLONG time - will contain time in seconds since midnight 1/1/70
|
|
* corresponding to the date if successfully parsed
|
|
* (assuming time=midnight). Undefined otherwise.
|
|
* PULONG parselen - length of string parsed
|
|
* USHORT reserved - not used for now, must be zero.
|
|
*
|
|
* Returns: 0 if parse successfully,
|
|
* ERROR_BAD_ARGUMENTS - cannot parse illegal date/time format
|
|
* ERROR_GEN_FAILURE - internal error
|
|
* Globals: Indirectly, all date/time descriptors, month/year info in this
|
|
* file. No globals outside of this file is used.
|
|
* s: (none) - but see setup_data()
|
|
* Remarks: (none)
|
|
* Updates: (none)
|
|
*/
|
|
SHORT LUI_ParseDate(
|
|
PCHAR inbuf,
|
|
PLARGE_INTEGER time,
|
|
PULONG parselen,
|
|
USHORT reserved
|
|
)
|
|
{
|
|
char *buffer, *local_inbuf, *nextchr ;
|
|
char *freep; /* pointer to buffer malloc'd by
|
|
setup data */
|
|
short res ;
|
|
|
|
/* pacify compiler */
|
|
if (reserved) ;
|
|
|
|
/* will grab memory, setup d_desc, t_desc, local_inbuf */
|
|
if (setup_data(&buffer,&freep,SLIST_BUFSIZ,&local_inbuf,inbuf,0,parselen)
|
|
!= 0)
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
/* call the worker function */
|
|
res = WParseDate(possible_dates,NULL,local_inbuf,&nextchr,time) ;
|
|
*parselen += (nextchr - local_inbuf) ;
|
|
RtlFreeHeap(Heap, 0, freep) ;
|
|
return(res) ;
|
|
}
|
|
|
|
/*
|
|
* Name: LUI_ParseTime
|
|
* will parse the input string (null terminated) for a
|
|
* time. Valid times include:
|
|
* 2pm 14:00 2:00P.M.
|
|
* Full details of formats are documented in pdate.txt,
|
|
* note that Country Information will be used.
|
|
*
|
|
* Args: PCHAR inbuf - string to parse
|
|
* PLONG time - will contain time in seconds since midnight 1/1/70
|
|
* corresponding to the date if successfully parsed
|
|
* (assuming day=today). If the time has already
|
|
* passed for today, we'll take tomorrow. Time is
|
|
* not defined if the parsing fails.
|
|
* PULONG parselen - length of string parsed
|
|
* USHORT reserved - not used for now, must be zero.
|
|
*
|
|
* Returns: 0 if parse successfully,
|
|
* ERROR_BAD_ARGUMENTS - cannot parse illegal date/time format
|
|
* ERROR_GEN_FAILURE - internal error
|
|
* Globals: Indirectly, all date/time descriptors, month/year info in this
|
|
* file. No globals outside of this file is used.
|
|
* s: (none) - but see setup_data()
|
|
* Remarks: (none)
|
|
* Updates: (none)
|
|
*/
|
|
SHORT LUI_ParseTime(PCHAR inbuf ,
|
|
PLARGE_INTEGER time ,
|
|
PULONG parselen,
|
|
USHORT reserved
|
|
)
|
|
|
|
{
|
|
char *buffer, *local_inbuf, *nextchr ;
|
|
char *freep; /* pointer to buffer malloc'd by
|
|
setup data */
|
|
short res ;
|
|
|
|
/* pacify compiler */
|
|
if (reserved) ;
|
|
|
|
/* will grab memory, setup d_desc, t_desc, local_inbuf */
|
|
if (setup_data(&buffer,&freep,SLIST_BUFSIZ,&local_inbuf,inbuf,0,parselen)
|
|
!= 0)
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
/* call the worker function */
|
|
res = WParseDate(NULL,possible_times,local_inbuf,&nextchr,time) ;
|
|
*parselen += (nextchr - local_inbuf) ;
|
|
RtlFreeHeap(Heap, 0, freep) ;
|
|
return(res) ;
|
|
}
|
|
|
|
/*
|
|
* Name: LUI_ParseTime12
|
|
* as LUI_ParseTime, except only 12 hour formats
|
|
* 2:00pm is ok, 2:00 is not.
|
|
*/
|
|
SHORT LUI_ParseTime12(PCHAR inbuf ,
|
|
PLARGE_INTEGER time ,
|
|
PULONG parselen,
|
|
USHORT reserved
|
|
)
|
|
|
|
{
|
|
char *buffer, *local_inbuf, *nextchr ;
|
|
char *freep; /* pointer to buffer malloc'd by
|
|
setup data */
|
|
short res ;
|
|
|
|
/* pacify compiler */
|
|
if (reserved) ;
|
|
|
|
/* will grab memory, setup d_desc, t_desc, local_inbuf */
|
|
if (setup_data(&buffer,&freep,SLIST_BUFSIZ,&local_inbuf,inbuf,0,parselen)
|
|
!= 0)
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
/* call the worker function */
|
|
res = WParseDate(NULL,possible_times12,local_inbuf,&nextchr,time) ;
|
|
*parselen += (nextchr - local_inbuf) ;
|
|
RtlFreeHeap(Heap, 0, freep) ;
|
|
return(res) ;
|
|
}
|
|
|
|
/*
|
|
* Name: LUI_ParseTime24
|
|
* as LUI_ParseTime, except only 24 hour formats
|
|
* 2:00 is ok, 2:00am is not.
|
|
*/
|
|
SHORT LUI_ParseTime24(
|
|
PCHAR inbuf ,
|
|
PLARGE_INTEGER time ,
|
|
PULONG parselen,
|
|
USHORT reserved
|
|
)
|
|
{
|
|
char *buffer, *local_inbuf, *nextchr ;
|
|
char *freep; /* pointer to buffer malloc'd by
|
|
setup data */
|
|
short res ;
|
|
|
|
/* pacify compiler */
|
|
if (reserved) ;
|
|
|
|
/* will grab memory, setup d_desc, t_desc, local_inbuf */
|
|
if (setup_data(&buffer,&freep,SLIST_BUFSIZ,&local_inbuf,inbuf,0,parselen)
|
|
!= 0)
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
/* call the worker function */
|
|
res = WParseDate(NULL,possible_times24,local_inbuf,&nextchr,time) ;
|
|
*parselen += (nextchr - local_inbuf) ;
|
|
RtlFreeHeap(Heap, 0, freep) ;
|
|
return(res) ;
|
|
}
|
|
|
|
|
|
|
|
/*-- internal routines for setting up & reading formats --*/
|
|
|
|
/*
|
|
* setup the field descriptors for date and time,
|
|
* using info from DosGetCtryInfo()
|
|
*
|
|
* we also grab memory here, & split it into 2 - first
|
|
* part for the above, second part for our local copy of
|
|
* the input string in inbuf.
|
|
*
|
|
* side effects - update bufferp, local_inbuf, parselen,
|
|
* and the allocated memory is initialised.
|
|
*/
|
|
SHORT
|
|
setup_data(
|
|
char **bufferp ,
|
|
char **freep ,
|
|
USHORT slist_bufsiz ,
|
|
char * * local_inbuf,
|
|
PCHAR inbuf,
|
|
SHORT country ,
|
|
PULONG parselen
|
|
)
|
|
|
|
{
|
|
USHORT bytesread ;
|
|
// COUNTRYCODE country_code ;
|
|
// COUNTRYINFO country_info ;
|
|
short first_time = TRUE ;
|
|
//#ifdef DOS3
|
|
// union REGS regs;
|
|
// struct SREGS sregs;
|
|
// COUNTRYINFO far * cinfo_ptr ;
|
|
//#endif
|
|
|
|
// country_code.country = country ;
|
|
// country_code.codepage = 0x0000 ; /* default */
|
|
|
|
/* skip white space */
|
|
inbuf += (*parselen = strspn(inbuf,WHITE_SPACE)) ;
|
|
|
|
/* grab memory */
|
|
if ( (*bufferp = RtlAllocateHeap(Heap, 0, SLIST_BUFSIZ+strlen(inbuf)+1)) == NULL )
|
|
return(ERROR_GEN_FAILURE) ;
|
|
|
|
*freep = *bufferp;
|
|
|
|
/*
|
|
* setup local_inbuf
|
|
*/
|
|
*local_inbuf = *bufferp + slist_bufsiz ;
|
|
strcpy((PCHAR)*local_inbuf, inbuf) ;
|
|
|
|
/*
|
|
* Get strings for AM/PM
|
|
*/
|
|
if (ILUI_setup_list(*bufferp,slist_bufsiz,2,&bytesread,ampm_data,ampm_list))
|
|
{
|
|
RtlFreeHeap(Heap, 0, *bufferp) ;
|
|
return(PD_ERROR_INTERNAL) ;
|
|
}
|
|
slist_bufsiz -= bytesread ;
|
|
*bufferp += bytesread ;
|
|
|
|
/*
|
|
* Get strings for months
|
|
*/
|
|
if (ILUI_setup_list(*bufferp,slist_bufsiz,MONTHS_IN_YEAR,&bytesread,
|
|
months_data,months_list))
|
|
{
|
|
RtlFreeHeap(Heap, 0, *bufferp) ;
|
|
return(PD_ERROR_INTERNAL) ;
|
|
}
|
|
/*
|
|
* no need to the rest if already done
|
|
*/
|
|
if (!first_time)
|
|
return(0) ;
|
|
first_time = FALSE ;
|
|
|
|
/*
|
|
* Get country info
|
|
*/
|
|
//#ifndef DOS3
|
|
// if (DosGetCtryInfo(sizeof(country_info),
|
|
// &country_code, &country_info, &bytesread))
|
|
// {
|
|
// strcat(pd_fmt_string,"]") ; /* terminate string format */
|
|
// return(0) ; /* just ignore if cant get */
|
|
// }
|
|
//#else
|
|
// /*
|
|
// * NOTE: The following code works only with DOS version >= 3.
|
|
// */
|
|
//
|
|
//
|
|
// cinfo_ptr = (COUNTRYINFO far *)&country_info;
|
|
// sregs.ds = FP_SEG(cinfo_ptr);
|
|
// /*
|
|
// * The following will map the structure returned by DOS to the OS/2
|
|
// * COUNTRYINFO struct.
|
|
// */
|
|
// regs.x.dx = FP_OFF(cinfo_ptr)+sizeof(COUNTRYCODE);
|
|
// regs.x.ax = 0x3800; /* Get country with AL = 0 (use current country).*/
|
|
// regs.x.bx = 0;
|
|
// intdosx( ®s, ®s, &sregs );
|
|
//
|
|
// if ( regs.x.cflag ) /* if error, return error */
|
|
// {
|
|
// strcat(pd_fmt_string,"]") ; /* terminate string format */
|
|
// return(0) ; /* just ignore if cant get */
|
|
// }
|
|
// else
|
|
// {
|
|
// /* fill in the buffer as promised */
|
|
// country_code.country = regs.x.bx;
|
|
// country_info.country = regs.x.bx;
|
|
// }
|
|
//#endif
|
|
//
|
|
// /* append date separator */
|
|
// if (strchr(pd_fmt_d_sep1,country_info.szDateSeparator[0]) == NULL)
|
|
// strcat(pd_fmt_d_sep1,country_info.szDateSeparator) ;
|
|
// if (strchr(pd_fmt_d_sep2,country_info.szDateSeparator[0]) == NULL)
|
|
// strcat(pd_fmt_d_sep2,country_info.szDateSeparator) ;
|
|
// if (strchr(pd_fmt_string,country_info.szDateSeparator[0]) == NULL)
|
|
// strcat(pd_fmt_string,country_info.szDateSeparator) ;
|
|
//
|
|
// /* append time separator */
|
|
// if (strchr(pd_fmt_t_sep,country_info.szTimeSeparator[0]) == NULL)
|
|
// strcat(pd_fmt_t_sep,country_info.szTimeSeparator) ;
|
|
// if (strchr(pd_fmt_string,country_info.szTimeSeparator[0]) == NULL)
|
|
// strcat(pd_fmt_string,country_info.szTimeSeparator) ;
|
|
//
|
|
strcat(pd_fmt_string,"]") ; /* terminate string format */
|
|
|
|
// /* swap order of fields as needed */
|
|
// switch (country_info.fsDateFmt) {
|
|
// case 0x0000:
|
|
// /* this is the initialised state */
|
|
// break ;
|
|
// case 0x0001:
|
|
// d_desc1[0].pos = d_desc4[0].pos = 0 ;
|
|
// d_desc1[1].pos = d_desc4[1].pos = 1 ;
|
|
// break ;
|
|
// case 0x0002:
|
|
// d_desc1[0].pos = d_desc2[0].pos = 2 ;
|
|
// d_desc1[1].pos = d_desc2[1].pos = 1 ;
|
|
// d_desc1[2].pos = d_desc2[2].pos = 0 ;
|
|
// break ;
|
|
// default:
|
|
// break ; /* assume USA */
|
|
// }
|
|
return(0) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* try reading inbuf using the descriptors in d_desc & t_desc.
|
|
* Returns 0 if ok, error code otherwise.
|
|
* If read ok, the number of secs since 1/1/70 is stored in time.
|
|
*
|
|
* inbuf -> string to parse
|
|
* d_desc -> array of date descriptors
|
|
* t_desc -> array of time descriptors
|
|
* nextchr -> will point to end of string parsed
|
|
* time -> will contain time parsed
|
|
*/
|
|
SHORT WParseDate(d_desc,t_desc,inbuf,nextchr,time)
|
|
date_fdesc **d_desc ;
|
|
date_fdesc **t_desc ;
|
|
char *inbuf ;
|
|
char **nextchr ;
|
|
PLARGE_INTEGER time ;
|
|
{
|
|
int d_index, t_index, res ;
|
|
date_data d_data, t_data ;
|
|
|
|
/*
|
|
* initialise
|
|
*/
|
|
*nextchr = inbuf ;
|
|
memset(d_data,0,sizeof(d_data)) ;
|
|
memset(t_data,0,sizeof(t_data)) ;
|
|
|
|
/*
|
|
* try all date followed by time combinations
|
|
*/
|
|
if (d_desc != NULL)
|
|
for (d_index = 0; d_desc[d_index] != NULL; d_index++)
|
|
{
|
|
if ((res = read_format(nextchr,d_desc[d_index],d_data)) == 0)
|
|
{
|
|
/* if time not required, quit here */
|
|
if (t_desc == NULL)
|
|
{
|
|
return ( convert_to_abs(d_data,t_data,time) ) ;
|
|
}
|
|
|
|
/* else we have match for date, see if we can do time */
|
|
for (t_index = 0; t_desc[t_index] != NULL; t_index++)
|
|
{
|
|
res = read_format(nextchr,t_desc[t_index],t_data) ;
|
|
if (res == 0 || res == PD_ERROR_END_OF_INPUT)
|
|
{
|
|
return ( convert_to_abs(d_data,t_data,time) ) ;
|
|
}
|
|
}
|
|
/* exhausted times formats, backtrack & try next date format */
|
|
*nextchr = inbuf ;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* reset & try all time followed by date combinations
|
|
*/
|
|
*nextchr = inbuf ;
|
|
memset(d_data,0,sizeof(d_data)) ;
|
|
if (t_desc != NULL)
|
|
for (t_index = 0; t_desc[t_index] != NULL; t_index++)
|
|
{
|
|
if ((res = read_format(nextchr,t_desc[t_index],t_data)) == 0)
|
|
{
|
|
/* if date not required, quit here */
|
|
if (d_desc == NULL)
|
|
{
|
|
return ( convert_to_abs(d_data,t_data,time) ) ;
|
|
}
|
|
|
|
/* we have match for time, see if we can do date */
|
|
for (d_index = 0; d_desc[d_index] != NULL; d_index++)
|
|
{
|
|
res = read_format(nextchr,d_desc[d_index],d_data) ;
|
|
if (res == 0 || res == PD_ERROR_END_OF_INPUT)
|
|
{
|
|
return ( convert_to_abs(d_data,t_data,time) ) ;
|
|
}
|
|
}
|
|
/* exhausted date formats, back track, try next time format */
|
|
*nextchr = inbuf ;
|
|
}
|
|
}
|
|
*nextchr = inbuf ;
|
|
return(ERROR_BAD_ARGUMENTS) ; /* we give up */
|
|
}
|
|
|
|
/*
|
|
* try reading inbuf using the descriptor desc.
|
|
* the fields read are stored in order in 'data'.
|
|
* Returns 0 if ok, error code otherwise.
|
|
*/
|
|
int read_format(inbuf, desc, data)
|
|
char * * inbuf ;
|
|
date_fdesc * desc ;
|
|
date_data data ;
|
|
{
|
|
char buffer[128] ;
|
|
char *ptr, *oldptr ;
|
|
date_fdesc *entry ;
|
|
short res, i ;
|
|
int count;
|
|
|
|
/*
|
|
* initialize & preliminary checks
|
|
*/
|
|
if (*inbuf == NULL || **inbuf=='\0')
|
|
return(PD_ERROR_END_OF_INPUT) ;
|
|
memset(data, 0, sizeof(date_data)) ;
|
|
ptr = *inbuf ;
|
|
oldptr = NULL ;
|
|
|
|
|
|
/*
|
|
* for all fields => we break out when hit END_MARKER
|
|
*/
|
|
for (i=0 ; ; i++)
|
|
{
|
|
SHORT value_read ;
|
|
|
|
entry = &desc[i] ;
|
|
if (entry->typ == PD_END_MARKER)
|
|
break ; /* no more descriptors */
|
|
|
|
/*
|
|
* find the separator - the ptr may or may not have moved
|
|
* as a result of the last read operation. If we read a number,
|
|
* scanf() would have stopped at the first non-numeric char, which
|
|
* may not be the separator. We would in this case have moved the
|
|
* ptr ourselves after the scanf().
|
|
*
|
|
* In the case of a string like "JAN", scanf() would have stopped at a
|
|
* separator and we wouldnt have moved it ourselves after the scanf().
|
|
* So we advance it now to the separator.
|
|
*/
|
|
if (ptr == oldptr) /* ptr unmoved, we need to move it */
|
|
{
|
|
if (entry->sep[0] == '\0')
|
|
return(PD_ERROR_INTERNAL) ; /* cant have NULL separator */
|
|
if ((ptr = (char *)strpbrk(ptr,entry->sep)) == NULL)
|
|
return(PD_ERROR_NO_MATCH) ; /* cant find separator */
|
|
ptr = NEXT_CHAR(ptr) ;
|
|
}
|
|
else /* already moved */
|
|
{
|
|
if (entry->sep[0] != '\0') /* for NULL separator, do nothing */
|
|
{
|
|
if (*ptr && !strchr(entry->sep,*ptr)) /* are we at separator */
|
|
return(PD_ERROR_NO_MATCH) ; /* cant find separator */
|
|
if (*ptr)
|
|
ptr = NEXT_CHAR(ptr) ; /* advance past separator */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* if we get here, we are past the separator, can go read an item
|
|
*/
|
|
ptr += strspn(ptr,WHITE_SPACE) ; /* skip white space */
|
|
if ((count = sscanf(ptr,entry->fmt,&buffer[0])) != 1)
|
|
return(PD_ERROR_NO_MATCH) ;
|
|
|
|
/*
|
|
* successfully read an item, get value & update pointers
|
|
*/
|
|
res = 0 ;
|
|
if (entry->typ == PD_AMPM)
|
|
res = ILUI_traverse_slist(buffer,ampm_list,&value_read) ;
|
|
else if (entry->typ == PD_MONTHS)
|
|
res = ILUI_traverse_slist(buffer,months_list,&value_read) ;
|
|
else
|
|
value_read = *(USHORT *)(&buffer[0]) ;
|
|
if (res || value_read < 0)
|
|
return(PD_ERROR_NO_MATCH) ;
|
|
|
|
data[entry->pos] = value_read ;
|
|
oldptr = ptr ;
|
|
if (entry->typ == PD_NUMBER)
|
|
ptr += strspn(ptr,DIGITS) ; /* skip past number */
|
|
}
|
|
|
|
/*
|
|
* no more descriptors, see if we are at end
|
|
*/
|
|
if (ptr == oldptr) /* ptr unmoved, we need to move it */
|
|
{
|
|
/* need to advance to WHITE_SPACE or end */
|
|
if ((ptr = (char *)strpbrk(oldptr, WHITE_SPACE)) == NULL)
|
|
{
|
|
ptr = (char *)strchr(oldptr, '\0'); /* if not found, take end */
|
|
}
|
|
}
|
|
|
|
ptr += strspn(ptr,WHITE_SPACE) ; /* skip white space */
|
|
*inbuf = ptr ; /* update inbuf */
|
|
return(0) ; /* SUCCESSFUL */
|
|
}
|
|
|
|
|
|
/*---- time conversion ----*/
|
|
|
|
#define IS_LEAP(y) ((y % 4 == 0) && (y % 100 != 0 || y % 400 == 0))
|
|
#define DAYS_IN_YEAR(y) (IS_LEAP(y) ? 366 : 365)
|
|
#define DAYS_IN_MONTH(m,y) (IS_LEAP(y) ? _days_month_leap[m] : _days_month[m])
|
|
#define SECS_IN_DAY (60L * 60L * 24L)
|
|
#define SECS_IN_HOUR (60L * 60L)
|
|
#define SECS_IN_MINUTE (60L)
|
|
|
|
short _days_month_leap[] = { 31,29,31,30,31,30,31,31,30,31,30,31 } ;
|
|
short _days_month[] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
|
|
|
|
/*
|
|
* convert date & time in d_data & t_data (these in dd mm yy and
|
|
* HH MM SS AMPM) to the number of seconds since 1/1/70.
|
|
* The result is stored in timep.
|
|
* Returns 0 if ok, error code otherwise.
|
|
*
|
|
* Note - date is either completely unset (all zero),
|
|
* or is fully set, or has day and months set with
|
|
* year==0.
|
|
*/
|
|
SHORT convert_to_abs( d_data, t_data, timep)
|
|
date_data d_data;
|
|
date_data t_data;
|
|
PLARGE_INTEGER timep ;
|
|
{
|
|
// long total_secs, current_time_in_seconds ;
|
|
TIME_FIELDS time_struct;
|
|
LARGE_INTEGER current_time;
|
|
|
|
// *timep = 0L ;
|
|
if (convert_to_24hr(t_data) != 0)
|
|
return(ERROR_BAD_ARGUMENTS) ;
|
|
|
|
NtQuerySystemTime(¤t_time) ;
|
|
|
|
RtlTimeToTimeFields(¤t_time, &time_struct);
|
|
|
|
// dprintf(("Current time: %d-%d-%d %d:%d:%d.%d\n", time_struct.Day,
|
|
// time_struct.Month, time_struct.Year, time_struct.Hour,
|
|
// time_struct.Minute, time_struct.Second, time_struct.Milliseconds));
|
|
|
|
// RtlTimeToSecondsSince1970(¤t_time, ¤t_time_in_seconds);
|
|
|
|
/* check for default values */
|
|
if (d_data[DAYS] == 0 && d_data[MONTHS] == 0 && d_data[YEARS] == 0) {
|
|
/* whole date's been left out */
|
|
d_data[DAYS] = time_struct.Day ;
|
|
d_data[MONTHS] = time_struct.Month ;
|
|
d_data[YEARS] = time_struct.Year ;
|
|
|
|
// if (!RtlTimeToSecondsSince1970(¤t_time, &total_secs))
|
|
// return(ERROR_BAD_ARGUMENTS) ;
|
|
//
|
|
// if (total_secs < current_time_in_seconds)
|
|
// {
|
|
// /*
|
|
// * if the time parsed is earlier than the current time,
|
|
// * and the date has been left out, we advance to the
|
|
// * next day.
|
|
// */
|
|
// advance_date(d_data) ;
|
|
// total_secs = seconds_since_1970(d_data,t_data) ;
|
|
// }
|
|
} else {
|
|
if (d_data[YEARS] == 0 && d_data[MONTHS] != 0 && d_data[DAYS] != 0) {
|
|
/* year's been left out */
|
|
d_data[YEARS] = time_struct.Year ;
|
|
// total_secs = seconds_since_1970(d_data,t_data) ;
|
|
// if (total_secs < current_time_in_seconds)
|
|
// {
|
|
// ++d_data[YEARS] ;
|
|
// total_secs = seconds_since_1970(d_data,t_data) ;
|
|
// }
|
|
}
|
|
}
|
|
// else
|
|
// total_secs = seconds_since_1970(d_data,t_data) ; /* no need defaults */
|
|
//
|
|
// if (total_secs < 0)
|
|
// return(ERROR_BAD_ARGUMENTS) ;
|
|
// *timep = total_secs ;
|
|
|
|
if (d_data[YEARS] < 70) {
|
|
d_data[YEARS] += 2000;
|
|
} else {
|
|
if (d_data[YEARS] < 100) {
|
|
d_data[YEARS] += 1900;
|
|
}
|
|
}
|
|
time_struct.Day = d_data[DAYS];
|
|
time_struct.Month = d_data[MONTHS];
|
|
time_struct.Year = d_data[YEARS];
|
|
time_struct.Hour = t_data[HOURS];
|
|
time_struct.Minute = t_data[MINUTES];
|
|
time_struct.Second = t_data[SECONDS];
|
|
time_struct.Milliseconds = 0;
|
|
|
|
// dprintf(("New time: %d-%d-%d %d:%d:%d.%d\n", time_struct.Day,
|
|
// time_struct.Month, time_struct.Year, time_struct.Hour,
|
|
// time_struct.Minute, time_struct.Second, time_struct.Milliseconds));
|
|
|
|
if (RtlTimeFieldsToTime(&time_struct, timep)==FALSE) {
|
|
return (ERROR_BAD_ARGUMENTS);
|
|
}
|
|
return(0) ;
|
|
}
|
|
|
|
// /*
|
|
// * count the total number of seconds since 1/1/70
|
|
// */
|
|
// long seconds_since_1970(d_data,t_data)
|
|
// date_data d_data, t_data ;
|
|
// {
|
|
// long days ;
|
|
//
|
|
// days = days_so_far(d_data[DAYS],d_data[MONTHS],d_data[YEARS]) ;
|
|
// if (days < 0)
|
|
// return(-1) ;
|
|
// return ( days * SECS_IN_DAY +
|
|
// (long) t_data[HOURS] * SECS_IN_HOUR +
|
|
// (long) t_data[MINUTES] * SECS_IN_MINUTE +
|
|
// (long) t_data[SECONDS] ) ;
|
|
// }
|
|
//
|
|
// /*
|
|
// * given day/month/year, returns how many days
|
|
// * have passed since 1/1/70
|
|
// * Returns -1 if there is an error.
|
|
// */
|
|
// long days_so_far(d,m,y)
|
|
// SHORT d,m,y ;
|
|
// {
|
|
// SHORT tmp_year ;
|
|
// long count = 0 ;
|
|
//
|
|
// /* check for validity */
|
|
// if ((y < 0) || (y > 99 && y < 1970)) return(-1) ;
|
|
// if (m < 1 || m > 12) return(-1) ;
|
|
// if (d < 1 || d > DAYS_IN_MONTH(m-1,y)) return(-1) ;
|
|
//
|
|
// /* a bit of intelligence */
|
|
// if (y < 70)
|
|
// y += 2000 ;
|
|
// else if (y < 100)
|
|
// y += 1900 ;
|
|
//
|
|
// /* count the days due to years */
|
|
// tmp_year = y-(SHORT )1 ;
|
|
// while (tmp_year >= 1970)
|
|
// {
|
|
// count += DAYS_IN_YEAR(tmp_year) ; /* agreed, this could be faster */
|
|
// --tmp_year ;
|
|
// }
|
|
//
|
|
// /* count the days due to months */
|
|
// while (m > 1)
|
|
// {
|
|
// count += DAYS_IN_MONTH(m-2,y) ; /* agreed, this could be faster */
|
|
// --m ;
|
|
// }
|
|
//
|
|
// /* finally, the days */
|
|
// count += d - 1 ;
|
|
// return(count) ;
|
|
// }
|
|
|
|
/*
|
|
* convert time in t_data to the 24 hour format
|
|
* returns 0 if ok, -1 otherwise.
|
|
*/
|
|
SHORT convert_to_24hr(t_data)
|
|
date_data t_data ;
|
|
{
|
|
/* no negative values allowed */
|
|
if (t_data[HOURS] < 0 || t_data[MINUTES] < 0 || t_data[SECONDS] < 0)
|
|
return(-1) ;
|
|
|
|
/* check minutes and seconds */
|
|
if ( t_data[MINUTES] > 59 || t_data[SECONDS] > 59)
|
|
return(-1) ;
|
|
|
|
/* now check the hour & convert if need */
|
|
if (t_data[AMPM] == PD_PM)
|
|
{
|
|
if (t_data[HOURS] > 12 || t_data[HOURS] < 1)
|
|
return(-1) ;
|
|
t_data[HOURS] += 12 ;
|
|
if (t_data[HOURS] == 24)
|
|
t_data[HOURS] = 12 ;
|
|
}
|
|
else if (t_data[AMPM] == PD_AM)
|
|
{
|
|
if (t_data[HOURS] > 12 || t_data[HOURS] < 1)
|
|
return(-1) ;
|
|
if (t_data[HOURS] == 12)
|
|
t_data[HOURS] = 0 ;
|
|
}
|
|
else if (t_data[AMPM] == PD_24HR)
|
|
{
|
|
if (t_data[HOURS] > 23)
|
|
return(-1) ;
|
|
}
|
|
else
|
|
return(-1) ;
|
|
|
|
return( 0 ) ;
|
|
}
|
|
|
|
/*
|
|
* advance the date in d_data by one day
|
|
*/
|
|
void advance_date(d_data)
|
|
date_data d_data ;
|
|
{
|
|
/* assume all values already in valid range */
|
|
if ( d_data[DAYS] != DAYS_IN_MONTH(d_data[MONTHS]-1,d_data[YEARS]) )
|
|
++d_data[DAYS] ; /* increase day */
|
|
else /* can't increase day */
|
|
{
|
|
d_data[DAYS] = 1 ; /* set to 1st, try increase month */
|
|
if (d_data[MONTHS] != 12)
|
|
++d_data[MONTHS] ; /* increase month */
|
|
else /* can't increase month */
|
|
{
|
|
d_data[MONTHS] = 1 ; /* set to Jan, and */
|
|
++d_data[YEARS] ; /* increase year */
|
|
}
|
|
}
|
|
}
|