summaryrefslogtreecommitdiffstats
path: root/color.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2019-01-02 17:00:40 -0500
committerTavian Barnes <tavianator@tavianator.com>2019-01-02 17:01:06 -0500
commit29a49f5d150911428a35943be8d9fc226865eb1b (patch)
tree35ca4aa4fd793e6398c7943cee0b1732f29419c0 /color.c
parent7fc7e98df2ea9c34dd1e0cb188554bed933a16df (diff)
downloadbfs-29a49f5d150911428a35943be8d9fc226865eb1b.tar.xz
color: Check format strings + args for cfprintf()
%{cc} is now ${cc} to avoid warnings about an unrecognized format specifier, and %P and %L are now %pP and %pL to make them look more like standard format strings.
Diffstat (limited to 'color.c')
-rw-r--r--color.c187
1 files changed, 105 insertions, 82 deletions
diff --git a/color.c b/color.c
index 9a19990..5807184 100644
--- a/color.c
+++ b/color.c
@@ -486,116 +486,139 @@ int cvfprintf(CFILE *cfile, const char *format, va_list args) {
int error = errno;
for (const char *i = format; *i; ++i) {
- const char *percent = strchr(i, '%');
- if (!percent) {
- if (fputs(i, file) == EOF) {
- return -1;
- }
- break;
- }
-
- size_t len = percent - i;
- if (fwrite(i, 1, len, file) != len) {
+ size_t verbatim = strcspn(i, "%$");
+ if (fwrite(i, 1, verbatim, file) != verbatim) {
return -1;
}
- i = percent + 1;
+ i += verbatim;
switch (*i) {
case '%':
- if (fputc('%', file) == EOF) {
- return -1;
- }
- break;
+ switch (*++i) {
+ case '%':
+ if (fputc('%', file) == EOF) {
+ return -1;
+ }
+ break;
- case 'c':
- if (fputc(va_arg(args, int), file) == EOF) {
- return -1;
- }
- break;
+ case 'c':
+ if (fputc(va_arg(args, int), file) == EOF) {
+ return -1;
+ }
+ break;
- case 'd':
- if (fprintf(file, "%d", va_arg(args, int)) < 0) {
- return -1;
- }
- break;
+ case 'd':
+ if (fprintf(file, "%d", va_arg(args, int)) < 0) {
+ return -1;
+ }
+ break;
- case 'g':
- if (fprintf(file, "%g", va_arg(args, double)) < 0) {
- return -1;
- }
- break;
+ case 'g':
+ if (fprintf(file, "%g", va_arg(args, double)) < 0) {
+ return -1;
+ }
+ break;
- case 's':
- if (fputs(va_arg(args, const char *), file) == EOF) {
- return -1;
- }
- break;
+ case 's':
+ if (fputs(va_arg(args, const char *), file) == EOF) {
+ return -1;
+ }
+ break;
+
+ case 'z':
+ ++i;
+ if (*i != 'u') {
+ goto invalid;
+ }
+ if (fprintf(file, "%zu", va_arg(args, size_t)) < 0) {
+ return -1;
+ }
+ break;
- case 'z':
- ++i;
- if (*i != 'u') {
+ case 'm':
+ if (fputs(strerror(error), file) == EOF) {
+ return -1;
+ }
+ break;
+
+ case 'p':
+ switch (*++i) {
+ case 'P':
+ if (print_path(cfile, va_arg(args, const struct BFTW *)) != 0) {
+ return -1;
+ }
+ break;
+
+ case 'L':
+ if (print_link(cfile, va_arg(args, const struct BFTW *)) != 0) {
+ return -1;
+ }
+ break;
+
+ default:
+ goto invalid;
+ }
+
+ break;
+
+ default:
goto invalid;
}
- if (fprintf(file, "%zu", va_arg(args, size_t)) < 0) {
- return -1;
- }
break;
- case 'm':
- if (fputs(strerror(error), file) == EOF) {
- return -1;
- }
- break;
+ case '$':
+ switch (*++i) {
+ case '$':
+ if (fputc('$', file) == EOF) {
+ return -1;
+ }
+ break;
- case 'P':
- if (print_path(cfile, va_arg(args, const struct BFTW *)) != 0) {
- return -1;
- }
- break;
+ case '{': {
+ ++i;
+ const char *end = strchr(i, '}');
+ if (!end) {
+ goto invalid;
+ }
+ if (!colors) {
+ i = end;
+ break;
+ }
- case 'L':
- if (print_link(cfile, va_arg(args, const struct BFTW *)) != 0) {
- return -1;
- }
- break;
+ size_t len = end - i;
+ char name[len + 1];
+ memcpy(name, i, len);
+ name[len] = '\0';
+
+ const char **esc = get_color(colors, name);
+ if (!esc) {
+ goto invalid;
+ }
+ if (*esc) {
+ if (print_esc(*esc, file) != 0) {
+ return -1;
+ }
+ }
- case '{': {
- ++i;
- const char *end = strchr(i, '}');
- if (!end) {
- goto invalid;
- }
- if (!colors) {
i = end;
break;
}
- size_t len = end - i;
- char name[len + 1];
- memcpy(name, i, len);
- name[len] = '\0';
-
- const char **esc = get_color(colors, name);
- if (!esc) {
+ default:
goto invalid;
}
- if (*esc) {
- if (print_esc(*esc, file) != 0) {
- return -1;
- }
- }
-
- i = end;
break;
- }
default:
- invalid:
- assert(false);
- errno = EINVAL;
- return -1;
+ return 0;
}
+
}
return 0;
+
+invalid:
+ assert(false);
+ errno = EINVAL;
+ return -1;
}