%W% Here are changes to GNU's gcc-2.7.2.1 "c-common.c" file that allow strftime formats to be checked against what GNU's glibc-1.09.1 "strftime" accepts. Formats are also checked for specifications that may or must print only the last two digits of years. --Arthur David Olson, 1996-09-08 *** 1.1/c-common.c Sun Sep 8 16:18:09 1996 --- 1/c-common.c Sun Sep 8 16:18:09 1996 *************** *** 556,561 **** --- 556,566 ---- || !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__"))) is_scan = 1; + else if (TREE_CODE (format_type) == IDENTIFIER_NODE + && (!strcmp (IDENTIFIER_POINTER (format_type), "strftime") + || !strcmp (IDENTIFIER_POINTER (format_type), + "__strftime__"))) + is_scan = 2; else { error ("unrecognized format specifier for `%s'"); *************** *** 725,730 **** --- 730,749 ---- { NULL } }; + /* + ** Only format characters recognized by glibc 2.0's strftime (as of 1996-08-19) handled. + ** XPG4 'E' and 'O' modifier stuff is not handled since glibc strftime does not. + ** "2" is used to for formats which MUST do years as only two digits; + ** "3" is used for formats which MAY do years as only two digits (depending on locale). + */ + + static format_char_info time_char_table[] = { + { "Dy", 0, NULL, NULL, NULL, NULL, NULL, "-_2" }, + { "xc", 0, NULL, NULL, NULL, NULL, NULL, "-_3" }, + { "aAbhBdeHIkljMmnpRrsSTtUVWwXYzZ", 0, NULL, NULL, NULL, NULL, NULL, "-_" }, + { NULL } + }; + typedef struct function_format_info { struct function_format_info *next; /* next structure on the list */ tree name; /* identifier such as "printf" */ *************** *** 757,771 **** record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0); record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0); record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0); } /* Record information for argument format checking. FUNCTION_IDENT is the identifier node for the name of the function to check (its decl ! need not exist yet). IS_SCAN is true for scanf-type format checking; ! false indicates printf-style format checking. FORMAT_NUM is the number of the argument which is the format control string (starting from 1). FIRST_ARG_NUM is the number of the first actual argument to check ! against teh format string, or zero if no checking is not be done (e.g. for varargs such as vfprintf). */ void --- 776,792 ---- record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0); record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0); record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0); + record_function_format (get_identifier ("strftime"), NULL_TREE, 2, 3, 0); } /* Record information for argument format checking. FUNCTION_IDENT is the identifier node for the name of the function to check (its decl ! need not exist yet). ! IS_SCAN is 1 for scanf-type format checking; 2 indicates strftime-style format checking; ! 0 indicates printf-style format checking. FORMAT_NUM is the number of the argument which is the format control string (starting from 1). FIRST_ARG_NUM is the number of the first actual argument to check ! against the format string, or zero if no checking is not be done (e.g. for varargs such as vfprintf). */ void *************** *** 928,934 **** } flag_chars[0] = 0; suppressed = wide = precise = FALSE; ! if (info->is_scan) { suppressed = *format_chars == '*'; if (suppressed) --- 949,956 ---- } flag_chars[0] = 0; suppressed = wide = precise = FALSE; ! aflag = 0; ! if (info->is_scan == 1) { suppressed = *format_chars == '*'; if (suppressed) *************** *** 936,942 **** while (isdigit (*format_chars)) ++format_chars; } ! else { /* See if we have a number followed by a dollar sign. If we do, it is an operand number, so set PARAMS to that operand. */ --- 958,964 ---- while (isdigit (*format_chars)) ++format_chars; } ! else if (info->is_scan == 0) { /* See if we have a number followed by a dollar sign. If we do, it is an operand number, so set PARAMS to that operand. */ *************** *** 966,972 **** } } ! while (*format_chars != 0 && index (" +#0-", *format_chars) != 0) { if (index (flag_chars, *format_chars) != 0) { --- 988,994 ---- } } ! while (*format_chars != 0 && index (" +#0-_", *format_chars) != 0) { if (index (flag_chars, *format_chars) != 0) { *************** *** 1067,1072 **** --- 1089,1096 ---- } } } + if (info->is_scan != 2) + { if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'q' || *format_chars == 'L') length_char = *format_chars++; *************** *** 1080,1085 **** --- 1104,1110 ---- aflag = 1; format_chars++; } + } if (suppressed && length_char != 0) { sprintf (message, *************** *** 1094,1100 **** continue; } format_chars++; ! fci = info->is_scan ? scan_char_table : print_char_table; while (fci->format_chars != 0 && index (fci->format_chars, format_char) == 0) ++fci; --- 1119,1130 ---- continue; } format_chars++; ! if (info->is_scan == 0) ! fci = print_char_table; ! else if (info->is_scan == 1) ! fci = scan_char_table; ! else ! fci = time_char_table; while (fci->format_chars != 0 && index (fci->format_chars, format_char) == 0) ++fci; *************** *** 1117,1122 **** --- 1147,1164 ---- format_char); warning (message); } + if (index (fci->flag_chars, '2') != 0) + { + sprintf (message, "`%c' format only yields last two digits of years", + format_char); + warning (message); + } + if (index (fci->flag_chars, '3') != 0) + { + sprintf (message, "`%c' format may only yield last two digits of years in some locales", + format_char); + warning (message); + } if (precise && index (fci->flag_chars, 'p') == 0) { sprintf (message, "precision used with `%c' format", *************** *** 1129,1135 **** format_char); warning (message); } ! if (info->is_scan && format_char == '[') { /* Skip over scan set, in case it happens to have '%' in it. */ if (*format_chars == '^') --- 1171,1177 ---- format_char); warning (message); } ! if (info->is_scan == 1 && format_char == '[') { /* Skip over scan set, in case it happens to have '%' in it. */ if (*format_chars == '^') *************** *** 1182,1188 **** case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break; case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break; } ! if (wanted_type == 0) { sprintf (message, "use of `%c' length character with `%c' type character", --- 1224,1230 ---- case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break; case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break; } ! if (info->is_scan != 2 && wanted_type == 0) { sprintf (message, "use of `%c' length character with `%c' type character",