From 741b170ff37b25055c72a059e805222fc333d139 Mon Sep 17 00:00:00 2001 From: Bob Dubner <rdubner@symas.com> Date: Mon, 18 Dec 2023 20:57:49 -0500 Subject: [PATCH] Polished TEST-FORMATTED-DATETIME --- libgcobol/intrinsic.cc | 161 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 14 deletions(-) diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc index 8db085774726..df98b3433bfb 100644 --- a/libgcobol/intrinsic.cc +++ b/libgcobol/intrinsic.cc @@ -3323,13 +3323,14 @@ __gg__year_to_yyyy( cblc_field_t *dest, static int -gets_int(int digits, char *p, char *pend) +gets_int(int ndigits, char *p, char *pend, int *digits) { // This routine returns the value of the integer at p. If there is something // wrong with the integer, it returns a negative number, the value being the // position (starting at 1) where the problem is. int retval = 0; - for(int i=1; i<=digits; i++) + memset(digits, 0xFF, ndigits * sizeof(int)); + for(int i=1; i<=ndigits; i++) { if(p >= pend) { @@ -3345,7 +3346,8 @@ gets_int(int digits, char *p, char *pend) break; } retval *= 10; - retval += ch - internal_0; + retval += ch & 0xF; + digits[i-1] = ch & 0xF; } return retval; } @@ -3361,7 +3363,29 @@ gets_year(char *p, char *pend, struct cobol_tm &ctm) // where a four-character range with a year value of 1601 became impossible. int retval = 0; - int YYYY = gets_int(4, p, pend); + int digits[4]; + int YYYY = gets_int(4, p, pend, digits); + + if( digits[0] == -1 || digits[0] == 0 ) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } + if( digits[0] == 0 && digits[1] < 5) + { + return 2; + } + if( digits[2] == -1 ) + { + return 4; + } + if( digits[3] == -1 ) + { + return 4; + } if( YYYY >= 0 ) { @@ -3405,8 +3429,18 @@ gets_month(char *p, char *pend, struct cobol_tm &ctm) // Returns either zero, or else the ordinal position of where the input // processing failed. + int digits[2]; int retval = 0; - int MM = gets_int(2, p, pend); + int MM = gets_int(2, p, pend, digits); + + if( digits[0] == -1 || digits[0] > 1) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } if( MM >= 0 ) { if( MM == 0 ) @@ -3441,8 +3475,18 @@ gets_day(char *p, char *pend, struct cobol_tm &ctm) // The assumption is that YYYY and MM were populated before arriving here + int digits[2]; int retval = 0; - int DD = gets_int(2, p, pend); + int DD = gets_int(2, p, pend, digits); + + if( digits[0] == -1 || digits[0] > 3) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } if(DD >= 0) { if( DD >= 0 ) @@ -3501,7 +3545,8 @@ gets_day_of_week(char *p, char *pend, struct cobol_tm &ctm) { // This is just a simple D, for day-of-week. The COBOL spec is that // it be 1 to 7, 1 being Monday - int day_of_week = gets_int(1, p, pend); + int digits[1]; + int day_of_week = gets_int(1, p, pend, digits); if( day_of_week<0 || day_of_week >7) { // The single character at source is no good: @@ -3548,7 +3593,20 @@ int gets_day_of_year(char *p, char *pend, struct cobol_tm &ctm) { // This is a three-digit day-of-year, 001 through 365,366 - int DDD = gets_int(3, p, pend); + int digits[3]; + int DDD = gets_int(3, p, pend, digits); + if( digits[0] == -1 || digits[0] > 3) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } + if( digits[2] == -1 ) + { + return 3; + } if( DDD < 0 ) { return -DDD; @@ -3592,7 +3650,16 @@ int gets_week(char *p, char *pend, struct cobol_tm &ctm) { // This is a two-digit value, 01 through 52,53 - int ww = gets_int(2, p, pend); + int digits[2]; + int ww = gets_int(2, p, pend, digits); + if( digits[0] == -1 || digits[0] > 5 ) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } if( ww < 0 ) { return -ww; @@ -3623,7 +3690,18 @@ int gets_hours(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) { // This is a two-digit value, 01 through 23 - int hh = gets_int(2, p, pend); + int digits[2]; + int hh = gets_int(2, p, pend, digits); + + if( digits[0] == -1 || digits[0] > 2 ) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } + if( hh < 0 ) { return -hh; @@ -3657,7 +3735,17 @@ int gets_minutes(char *p, char *pend, struct cobol_tm &ctm, bool in_offset) { // This is a two-digit value, 01 through 59 - int mm = gets_int(2, p, pend); + int digits[2]; + int mm = gets_int(2, p, pend, digits); + if( digits[0] == -1 || digits[0] > 5 ) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } + if( mm < 0 ) { return -mm; @@ -3685,7 +3773,16 @@ int gets_seconds(char *p, char *pend, struct cobol_tm &ctm) { // This is a two-digit value, 01 through 59 - int ss = gets_int(2, p, pend); + int digits[2]; + int ss = gets_int(2, p, pend, digits); + if( digits[0] == -1 || digits[0] > 5 ) + { + return 1; + } + if( digits[1] == -1 ) + { + return 2; + } if( ss < 0 ) { return -ss; @@ -3797,10 +3894,37 @@ fill_cobol_tm(cobol_tm &ctm, if( ch == internal_plus ) { // This flags a following hhmm offset. It needs to match a '+' or '-' - if( *source != internal_plus && *source != internal_minus ) + if( *source != internal_plus + && *source != internal_minus + && *source != internal_zero) { break; } + if( *source == internal_zero ) + { + // The next four characters have to be zeroes + if( source[1] != internal_zero ) + { + retval += 1; + break; + } + if( source[2] != internal_zero ) + { + retval += 2; + break; + } + if( source[3] != internal_zero ) + { + retval += 3; + break; + } + if( source[4] != internal_zero ) + { + retval += 4; + break; + } + } + in_offset = true; bump = 1; goto proceed; @@ -3945,6 +4069,13 @@ fill_cobol_tm(cobol_tm &ctm, if( ch == internal_Z || ch == internal_z ) { + // This has to be the end of the road + if( toupper(source[0]) != 'Z' ) + { + retval += 0; + break; + } + convert_to_zulu(ctm); bump = 1; goto proceed; @@ -3958,10 +4089,12 @@ proceed: source += bump; } - if( format >= format_end ) + if( format >= format_end && source >= source_end) { // This means we processed the entire format string without seeing an error retval = 0; + + // Otherwise, either the format or source was too short } return retval; } -- GitLab