@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / utils / adt / datetime . c , v 1.144 2005 / 05 / 24 02 : 09 : 45 momjian Exp $
* $ PostgreSQL : pgsql / src / backend / utils / adt / datetime . c , v 1.145 2005 / 05 / 26 02 : 04 : 13 neilc Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -699,21 +699,23 @@ TrimTrailingZeros(char *str)
}
}
/* ParseDateTime()
* Break string into tokens based on a date / time context .
* Returns 0 if successful , DTERR code if bogus input detected .
*
* timestr - the input string
* lowstr - workspace for field string storage ( must be large enough for
* a copy of the input string , including trailing null )
* workbuf - workspace for field string storage . This must be
* larger than the largest legal input for this datetime type - -
* some additional space will be needed to NUL terminate fields .
* buflen - the size of workbuf
* field [ ] - pointers to field strings are returned in this array
* ftype [ ] - field type indicators are returned in this array
* maxfields - dimensions of the above two arrays
* * numfields - set to the actual number of fields detected
*
* The fields extracted from the input are stored as separate , null - terminated
* strings in the workspace at lowstr . Any text is converted to lower case .
* The fields extracted from the input are stored as separate ,
* null - terminated strings in the workspace at workbuf . Any text is
* converted to lower case .
*
* Several field types are assigned :
* DTK_NUMBER - digits and ( possibly ) a decimal point
@ -729,12 +731,27 @@ TrimTrailingZeros(char *str)
* DTK_DATE can hold Posix time zones ( GMT - 8 )
*/
int
ParseDateTime ( const char * timestr , char * lowstr ,
ParseDateTime ( const char * timestr , char * workbuf , size_t buflen ,
char * * field , int * ftype , int maxfields , int * numfields )
{
int nf = 0 ;
const char * cp = timestr ;
char * lp = lowstr ;
char * bufp = workbuf ;
const char * bufend = workbuf + buflen ;
/*
* Set the character pointed - to by " bufptr " to " newchar " , and
* increment " bufptr " . " end " gives the end of the buffer - - we
* return an error if there is no space left to append a character
* to the buffer . Note that " bufptr " is evaluated twice .
*/
# define APPEND_CHAR(bufptr, end, newchar) \
do \
{ \
if ( ( ( bufptr ) + 1 ) > = ( end ) ) \
return DTERR_BAD_FORMAT ; \
* ( bufptr ) + + = newchar ; \
} while ( 0 )
/* outer loop through fields */
while ( * cp ! = ' \0 ' )
@ -749,23 +766,23 @@ ParseDateTime(const char *timestr, char *lowstr,
/* Record start of current field */
if ( nf > = maxfields )
return DTERR_BAD_FORMAT ;
field [ nf ] = l p;
field [ nf ] = buf p;
/* leading digit? then date or time */
if ( isdigit ( ( unsigned char ) * cp ) )
{
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
/* time field? */
if ( * cp = = ' : ' )
{
ftype [ nf ] = DTK_TIME ;
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) | |
( * cp = = ' : ' ) | | ( * cp = = ' . ' ) )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
}
/* date field? allow embedded text month */
else if ( * cp = = ' - ' | | * cp = = ' / ' | | * cp = = ' . ' )
@ -773,13 +790,13 @@ ParseDateTime(const char *timestr, char *lowstr,
/* save delimiting character to use later */
char delim = * cp ;
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
/* second field is all digits? then no embedded text month */
if ( isdigit ( ( unsigned char ) * cp ) )
{
ftype [ nf ] = ( ( delim = = ' . ' ) ? DTK_NUMBER : DTK_DATE ) ;
while ( isdigit ( ( unsigned char ) * cp ) )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
/*
* insist that the delimiters match to get a
@ -788,16 +805,16 @@ ParseDateTime(const char *timestr, char *lowstr,
if ( * cp = = delim )
{
ftype [ nf ] = DTK_DATE ;
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) | | * cp = = delim )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
}
}
else
{
ftype [ nf ] = DTK_DATE ;
while ( isalnum ( ( unsigned char ) * cp ) | | * cp = = delim )
* lp + + = pg_tolower ( ( unsigned char ) * cp + + ) ;
APPEND_CHAR ( bufp , bufend , pg_tolower ( ( unsigned char ) * cp + + ) ) ;
}
}
@ -811,9 +828,9 @@ ParseDateTime(const char *timestr, char *lowstr,
/* Leading decimal point? Then fractional seconds... */
else if ( * cp = = ' . ' )
{
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
ftype [ nf ] = DTK_NUMBER ;
}
@ -825,9 +842,9 @@ ParseDateTime(const char *timestr, char *lowstr,
else if ( isalpha ( ( unsigned char ) * cp ) )
{
ftype [ nf ] = DTK_STRING ;
* lp + + = pg_tolower ( ( unsigned char ) * cp + + ) ;
APPEND_CHAR ( bufp , bufend , pg_tolower ( ( unsigned char ) * cp + + ) ) ;
while ( isalpha ( ( unsigned char ) * cp ) )
* lp + + = pg_tolower ( ( unsigned char ) * cp + + ) ;
APPEND_CHAR ( bufp , bufend , pg_tolower ( ( unsigned char ) * cp + + ) ) ;
/*
* Full date string with leading text month ? Could also be a
@ -838,15 +855,15 @@ ParseDateTime(const char *timestr, char *lowstr,
char delim = * cp ;
ftype [ nf ] = DTK_DATE ;
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) | | * cp = = delim )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
}
}
/* sign? then special or numeric timezone */
else if ( * cp = = ' + ' | | * cp = = ' - ' )
{
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
/* soak up leading whitespace */
while ( isspace ( ( unsigned char ) * cp ) )
cp + + ;
@ -854,18 +871,18 @@ ParseDateTime(const char *timestr, char *lowstr,
if ( isdigit ( ( unsigned char ) * cp ) )
{
ftype [ nf ] = DTK_TZ ;
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
while ( isdigit ( ( unsigned char ) * cp ) | |
* cp = = ' : ' | | * cp = = ' . ' )
* lp + + = * cp + + ;
APPEND_CHAR ( bufp , bufend , * cp + + ) ;
}
/* special? */
else if ( isalpha ( ( unsigned char ) * cp ) )
{
ftype [ nf ] = DTK_SPECIAL ;
* lp + + = pg_tolower ( ( unsigned char ) * cp + + ) ;
APPEND_CHAR ( bufp , bufend , pg_tolower ( ( unsigned char ) * cp + + ) ) ;
while ( isalpha ( ( unsigned char ) * cp ) )
* lp + + = pg_tolower ( ( unsigned char ) * cp + + ) ;
APPEND_CHAR ( bufp , bufend , pg_tolower ( ( unsigned char ) * cp + + ) ) ;
}
/* otherwise something wrong... */
else
@ -882,7 +899,7 @@ ParseDateTime(const char *timestr, char *lowstr,
return DTERR_BAD_FORMAT ;
/* force in a delimiter after each field */
* l p+ + = ' \0 ' ;
* buf p+ + = ' \0 ' ;
nf + + ;
}