88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.111 2003/08/05 17:39:19 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.112 2003/08/05 18:30:21 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -699,30 +699,54 @@ TrimTrailingZeros(char *str)
699699
700700
701701/* ParseDateTime()
702- * Break string into tokens based on a date/time context.
702+ * Break string into tokens based on a date/time context.
703+ * Returns 0 if successful, -1 if bogus input detected.
704+ *
705+ * timestr - the input string
706+ * lowstr - workspace for field string storage (must be large enough for
707+ * a copy of the input string, including trailing null)
708+ * field[] - pointers to field strings are returned in this array
709+ * ftype[] - field type indicators are returned in this array
710+ * maxfields - dimensions of the above two arrays
711+ * *numfields - set to the actual number of fields detected
712+ *
713+ * The fields extracted from the input are stored as separate, null-terminated
714+ * strings in the workspace at lowstr. Any text is converted to lower case.
715+ *
703716 * Several field types are assigned:
704717 * DTK_NUMBER - digits and (possibly) a decimal point
705718 * DTK_DATE - digits and two delimiters, or digits and text
706719 * DTK_TIME - digits, colon delimiters, and possibly a decimal point
707720 * DTK_STRING - text (no digits)
708721 * DTK_SPECIAL - leading "+" or "-" followed by text
709722 * DTK_TZ - leading "+" or "-" followed by digits
723+ *
710724 * Note that some field types can hold unexpected items:
711725 * DTK_NUMBER can hold date fields (yy.ddd)
712726 * DTK_STRING can hold months (January) and time zones (PST)
713727 * DTK_DATE can hold Posix time zones (GMT-8)
714728 */
715729int
716- ParseDateTime (char * timestr , char * lowstr ,
730+ ParseDateTime (const char * timestr , char * lowstr ,
717731 char * * field , int * ftype , int maxfields , int * numfields )
718732{
719733 int nf = 0 ;
720- char * cp = timestr ;
734+ const char * cp = timestr ;
721735 char * lp = lowstr ;
722736
723737 /* outer loop through fields */
724738 while (* cp != '\0' )
725739 {
740+ /* Ignore spaces between fields */
741+ if (isspace ((unsigned char ) * cp ))
742+ {
743+ cp ++ ;
744+ continue ;
745+ }
746+
747+ /* Record start of current field */
748+ if (nf >= maxfields )
749+ return -1 ;
726750 field [nf ] = lp ;
727751
728752 /* leading digit? then date or time */
@@ -745,32 +769,32 @@ ParseDateTime(char *timestr, char *lowstr,
745769 else if ((* cp == '-' ) || (* cp == '/' ) || (* cp == '.' ))
746770 {
747771 /* save delimiting character to use later */
748- char * dp = cp ;
772+ char delim = * cp ;
749773
750774 * lp ++ = * cp ++ ;
751775 /* second field is all digits? then no embedded text month */
752776 if (isdigit ((unsigned char ) * cp ))
753777 {
754- ftype [nf ] = ((* dp == '.' ) ? DTK_NUMBER : DTK_DATE );
778+ ftype [nf ] = ((delim == '.' ) ? DTK_NUMBER : DTK_DATE );
755779 while (isdigit ((unsigned char ) * cp ))
756780 * lp ++ = * cp ++ ;
757781
758782 /*
759783 * insist that the delimiters match to get a
760784 * three-field date.
761785 */
762- if (* cp == * dp )
786+ if (* cp == delim )
763787 {
764788 ftype [nf ] = DTK_DATE ;
765789 * lp ++ = * cp ++ ;
766- while (isdigit ((unsigned char ) * cp ) || (* cp == * dp ))
790+ while (isdigit ((unsigned char ) * cp ) || (* cp == delim ))
767791 * lp ++ = * cp ++ ;
768792 }
769793 }
770794 else
771795 {
772796 ftype [nf ] = DTK_DATE ;
773- while (isalnum ((unsigned char ) * cp ) || (* cp == * dp ))
797+ while (isalnum ((unsigned char ) * cp ) || (* cp == delim ))
774798 * lp ++ = tolower ((unsigned char ) * cp ++ );
775799 }
776800 }
@@ -809,20 +833,14 @@ ParseDateTime(char *timestr, char *lowstr,
809833 */
810834 if ((* cp == '-' ) || (* cp == '/' ) || (* cp == '.' ))
811835 {
812- char * dp = cp ;
836+ char delim = * cp ;
813837
814838 ftype [nf ] = DTK_DATE ;
815839 * lp ++ = * cp ++ ;
816- while (isdigit ((unsigned char ) * cp ) || (* cp == * dp ))
840+ while (isdigit ((unsigned char ) * cp ) || (* cp == delim ))
817841 * lp ++ = * cp ++ ;
818842 }
819843 }
820- /* skip leading spaces */
821- else if (isspace ((unsigned char ) * cp ))
822- {
823- cp ++ ;
824- continue ;
825- }
826844 /* sign? then special or numeric timezone */
827845 else if ((* cp == '+' ) || (* cp == '-' ))
828846 {
@@ -851,12 +869,11 @@ ParseDateTime(char *timestr, char *lowstr,
851869 else
852870 return -1 ;
853871 }
854- /* ignore punctuation but use as delimiter */
872+ /* ignore other punctuation but use as delimiter */
855873 else if (ispunct ((unsigned char ) * cp ))
856874 {
857875 cp ++ ;
858876 continue ;
859-
860877 }
861878 /* otherwise, something is not right... */
862879 else
@@ -865,14 +882,12 @@ ParseDateTime(char *timestr, char *lowstr,
865882 /* force in a delimiter after each field */
866883 * lp ++ = '\0' ;
867884 nf ++ ;
868- if (nf > MAXDATEFIELDS )
869- return -1 ;
870885 }
871886
872887 * numfields = nf ;
873888
874889 return 0 ;
875- } /* ParseDateTime() */
890+ }
876891
877892
878893/* DecodeDateTime()
0 commit comments