Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Compile with gcc -Wall -Wextra -pedantic -std=c17 -D_POSIX_C_SOURCE=2
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <assert.h>
- #include <stdlib.h>
- // Counts the number of assignments that should be made by scanf and alike.
- // Assumes a valid format string. If it's not valid, behavior is undefined.
- int count_assignments(const char *fmt) {
- int ret = 0;
- // Note that n is removed, because it suppresses assignments
- static const char specifiers[] = "diouxaefgcspAEFGX";
- static const char singlelength[] = "hljztL";
- static const char doublelength[] = "hl";
- while(*fmt) {
- if(*fmt == '%') {
- fmt++;
- // Skip width modification
- while(isdigit(*fmt)) fmt++;
- // Check length modification
- if(strchr(singlelength, *fmt)) {
- fmt++;
- if(strchr(doublelength, *fmt)) {
- fmt++;
- goto READ_SPECIFIER;
- }
- goto READ_SPECIFIER;
- }
- if(*fmt == '[') {
- while(*fmt != ']') fmt++;
- ret++;
- goto END;
- }
- goto READ_SPECIFIER;
- }
- goto END;
- READ_SPECIFIER:
- if(strchr(specifiers, *fmt))
- ret++;
- END:
- fmt++;
- }
- return ret;
- }
- // Calculate how many arguments a format string should have by creating a .c file which
- // is compiled and the number of warnings are counted. This value is treated as the number
- // of arguments the format strings wants.
- size_t get_no_warnings(const char *fmt)
- {
- FILE *fp = fopen("warning.c", "w");
- if(!fp) {
- perror("Error opening file");
- exit(EXIT_FAILURE);
- }
- fprintf(fp, "#include <stdio.h>\n\nint main(void) {\n\tscanf(\"%s\");\n}\n", fmt);
- fclose(fp);
- fp = popen("gcc warning.c -Wall -Wextra -pedantic 2>&1 | grep \"warning: format\" | wc -l", "r");
- if(!fp) {
- perror("Error executing command");
- exit(EXIT_FAILURE);
- }
- char output[100];
- fgets(output, sizeof(output), fp);
- size_t ret;
- if(sscanf(output, "%zu", &ret) != 1) {
- perror("Error reading output");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- int main(void)
- {
- struct test_case {
- const char *fmt;
- const unsigned n;
- } test_cases[] = {
- { "foo", 0 },
- { "%s", 1 },
- { "%d%d", 2 },
- { "%lld", 1 },
- { "%%", 0 },
- { "%d%%%d", 2 },
- { "%2333d%c%33f", 3 },
- { "%[bar]", 1 },
- { "%*d", 0 },
- { "%*22d", 0 },
- { "%d%p%c", 3 }
- };
- for(size_t i=0; i<sizeof test_cases/sizeof test_cases[0]; i++) {
- struct test_case tc = test_cases[i];
- size_t count = count_assignments(tc.fmt);
- size_t warnings = get_no_warnings(tc.fmt);
- printf("%s %u %zu %zu\n", tc.fmt, tc.n, count, warnings);
- assert(count == tc.n);
- assert(count == warnings);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement