8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.144 2005/05/24 02:09:45 momjian Exp $
11
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.145 2005/05/26 02:04:13 neilc Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -699,21 +699,23 @@ TrimTrailingZeros(char *str)
699
699
}
700
700
}
701
701
702
-
703
702
/* ParseDateTime()
704
703
* Break string into tokens based on a date/time context.
705
704
* Returns 0 if successful, DTERR code if bogus input detected.
706
705
*
707
706
* timestr - the input string
708
- * lowstr - workspace for field string storage (must be large enough for
709
- * a copy of the input string, including trailing null)
707
+ * workbuf - workspace for field string storage. This must be
708
+ * larger than the largest legal input for this datetime type --
709
+ * some additional space will be needed to NUL terminate fields.
710
+ * buflen - the size of workbuf
710
711
* field[] - pointers to field strings are returned in this array
711
712
* ftype[] - field type indicators are returned in this array
712
713
* maxfields - dimensions of the above two arrays
713
714
* *numfields - set to the actual number of fields detected
714
715
*
715
- * The fields extracted from the input are stored as separate, null-terminated
716
- * strings in the workspace at lowstr. Any text is converted to lower case.
716
+ * The fields extracted from the input are stored as separate,
717
+ * null-terminated strings in the workspace at workbuf. Any text is
718
+ * converted to lower case.
717
719
*
718
720
* Several field types are assigned:
719
721
* DTK_NUMBER - digits and (possibly) a decimal point
@@ -729,12 +731,27 @@ TrimTrailingZeros(char *str)
729
731
* DTK_DATE can hold Posix time zones (GMT-8)
730
732
*/
731
733
int
732
- ParseDateTime (const char * timestr , char * lowstr ,
734
+ ParseDateTime (const char * timestr , char * workbuf , size_t buflen ,
733
735
char * * field , int * ftype , int maxfields , int * numfields )
734
736
{
735
737
int nf = 0 ;
736
738
const char * cp = timestr ;
737
- char * lp = lowstr ;
739
+ char * bufp = workbuf ;
740
+ const char * bufend = workbuf + buflen ;
741
+
742
+ /*
743
+ * Set the character pointed-to by "bufptr" to "newchar", and
744
+ * increment "bufptr". "end" gives the end of the buffer -- we
745
+ * return an error if there is no space left to append a character
746
+ * to the buffer. Note that "bufptr" is evaluated twice.
747
+ */
748
+ #define APPEND_CHAR (bufptr , end , newchar ) \
749
+ do \
750
+ { \
751
+ if (((bufptr) + 1) >= (end)) \
752
+ return DTERR_BAD_FORMAT; \
753
+ *(bufptr)++ = newchar; \
754
+ } while (0)
738
755
739
756
/* outer loop through fields */
740
757
while (* cp != '\0' )
@@ -749,37 +766,37 @@ ParseDateTime(const char *timestr, char *lowstr,
749
766
/* Record start of current field */
750
767
if (nf >= maxfields )
751
768
return DTERR_BAD_FORMAT ;
752
- field [nf ] = lp ;
769
+ field [nf ] = bufp ;
753
770
754
771
/* leading digit? then date or time */
755
772
if (isdigit ((unsigned char ) * cp ))
756
773
{
757
- * lp ++ = * cp ++ ;
774
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
758
775
while (isdigit ((unsigned char ) * cp ))
759
- * lp ++ = * cp ++ ;
776
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
760
777
761
778
/* time field? */
762
779
if (* cp == ':' )
763
780
{
764
781
ftype [nf ] = DTK_TIME ;
765
- * lp ++ = * cp ++ ;
782
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
766
783
while (isdigit ((unsigned char ) * cp ) ||
767
784
(* cp == ':' ) || (* cp == '.' ))
768
- * lp ++ = * cp ++ ;
785
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
769
786
}
770
787
/* date field? allow embedded text month */
771
788
else if (* cp == '-' || * cp == '/' || * cp == '.' )
772
789
{
773
790
/* save delimiting character to use later */
774
791
char delim = * cp ;
775
792
776
- * lp ++ = * cp ++ ;
793
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
777
794
/* second field is all digits? then no embedded text month */
778
795
if (isdigit ((unsigned char ) * cp ))
779
796
{
780
797
ftype [nf ] = ((delim == '.' ) ? DTK_NUMBER : DTK_DATE );
781
798
while (isdigit ((unsigned char ) * cp ))
782
- * lp ++ = * cp ++ ;
799
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
783
800
784
801
/*
785
802
* insist that the delimiters match to get a
@@ -788,16 +805,16 @@ ParseDateTime(const char *timestr, char *lowstr,
788
805
if (* cp == delim )
789
806
{
790
807
ftype [nf ] = DTK_DATE ;
791
- * lp ++ = * cp ++ ;
808
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
792
809
while (isdigit ((unsigned char ) * cp ) || * cp == delim )
793
- * lp ++ = * cp ++ ;
810
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
794
811
}
795
812
}
796
813
else
797
814
{
798
815
ftype [nf ] = DTK_DATE ;
799
816
while (isalnum ((unsigned char ) * cp ) || * cp == delim )
800
- * lp ++ = pg_tolower ((unsigned char ) * cp ++ );
817
+ APPEND_CHAR ( bufp , bufend , pg_tolower ((unsigned char ) * cp ++ ) );
801
818
}
802
819
}
803
820
@@ -811,9 +828,9 @@ ParseDateTime(const char *timestr, char *lowstr,
811
828
/* Leading decimal point? Then fractional seconds... */
812
829
else if (* cp == '.' )
813
830
{
814
- * lp ++ = * cp ++ ;
831
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
815
832
while (isdigit ((unsigned char ) * cp ))
816
- * lp ++ = * cp ++ ;
833
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
817
834
818
835
ftype [nf ] = DTK_NUMBER ;
819
836
}
@@ -825,9 +842,9 @@ ParseDateTime(const char *timestr, char *lowstr,
825
842
else if (isalpha ((unsigned char ) * cp ))
826
843
{
827
844
ftype [nf ] = DTK_STRING ;
828
- * lp ++ = pg_tolower ((unsigned char ) * cp ++ );
845
+ APPEND_CHAR ( bufp , bufend , pg_tolower ((unsigned char ) * cp ++ ) );
829
846
while (isalpha ((unsigned char ) * cp ))
830
- * lp ++ = pg_tolower ((unsigned char ) * cp ++ );
847
+ APPEND_CHAR ( bufp , bufend , pg_tolower ((unsigned char ) * cp ++ ) );
831
848
832
849
/*
833
850
* Full date string with leading text month? Could also be a
@@ -838,34 +855,34 @@ ParseDateTime(const char *timestr, char *lowstr,
838
855
char delim = * cp ;
839
856
840
857
ftype [nf ] = DTK_DATE ;
841
- * lp ++ = * cp ++ ;
858
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
842
859
while (isdigit ((unsigned char ) * cp ) || * cp == delim )
843
- * lp ++ = * cp ++ ;
860
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
844
861
}
845
862
}
846
863
/* sign? then special or numeric timezone */
847
864
else if (* cp == '+' || * cp == '-' )
848
865
{
849
- * lp ++ = * cp ++ ;
866
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
850
867
/* soak up leading whitespace */
851
868
while (isspace ((unsigned char ) * cp ))
852
869
cp ++ ;
853
870
/* numeric timezone? */
854
871
if (isdigit ((unsigned char ) * cp ))
855
872
{
856
873
ftype [nf ] = DTK_TZ ;
857
- * lp ++ = * cp ++ ;
874
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
858
875
while (isdigit ((unsigned char ) * cp ) ||
859
876
* cp == ':' || * cp == '.' )
860
- * lp ++ = * cp ++ ;
877
+ APPEND_CHAR ( bufp , bufend , * cp ++ ) ;
861
878
}
862
879
/* special? */
863
880
else if (isalpha ((unsigned char ) * cp ))
864
881
{
865
882
ftype [nf ] = DTK_SPECIAL ;
866
- * lp ++ = pg_tolower ((unsigned char ) * cp ++ );
883
+ APPEND_CHAR ( bufp , bufend , pg_tolower ((unsigned char ) * cp ++ ) );
867
884
while (isalpha ((unsigned char ) * cp ))
868
- * lp ++ = pg_tolower ((unsigned char ) * cp ++ );
885
+ APPEND_CHAR ( bufp , bufend , pg_tolower ((unsigned char ) * cp ++ ) );
869
886
}
870
887
/* otherwise something wrong... */
871
888
else
@@ -882,7 +899,7 @@ ParseDateTime(const char *timestr, char *lowstr,
882
899
return DTERR_BAD_FORMAT ;
883
900
884
901
/* force in a delimiter after each field */
885
- * lp ++ = '\0' ;
902
+ * bufp ++ = '\0' ;
886
903
nf ++ ;
887
904
}
888
905
0 commit comments