diff options
-rw-r--r-- | src/color.c | 31 | ||||
-rw-r--r-- | src/config.c | 30 | ||||
-rw-r--r-- | src/config.h | 3 | ||||
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | test/config.c | 113 | ||||
-rw-r--r-- | test/meson.build | 1 |
6 files changed, 165 insertions, 21 deletions
diff --git a/src/color.c b/src/color.c index 3fd9516..4b6b356 100644 --- a/src/color.c +++ b/src/color.c @@ -1,3 +1,4 @@ +#include <errno.h> #include <stdlib.h> #include <string.h> #include "color.h" @@ -10,15 +11,22 @@ struct color hex_to_color(const char *hex) } uint32_t val = 0; + int64_t tmp; size_t len = strlen(hex); + errno = 0; if (len == 3) { char str[] = { hex[0], hex[0], hex[1], hex[1], hex[2], hex[2], '\0'}; - val = strtol(str, NULL, 16); + char *endptr; + tmp = strtol(str, &endptr, 16); + if (errno || *endptr != '\0' || tmp < 0) { + return (struct color) { -1, -1, -1, -1 }; + } + val = tmp; val <<= 8; val |= 0xFFu; } else if (len == 4) { @@ -28,13 +36,28 @@ struct color hex_to_color(const char *hex) hex[2], hex[2], hex[3], hex[3], '\0'}; - val = strtol(str, NULL, 16); + char *endptr; + tmp = strtol(str, &endptr, 16); + if (errno || *endptr != '\0' || tmp < 0) { + return (struct color) { -1, -1, -1, -1 }; + } + val = tmp; } else if (len == 6) { - val = strtol(hex, NULL, 16); + char *endptr; + tmp = strtol(hex, &endptr, 16); + if (errno || *endptr != '\0' || tmp < 0) { + return (struct color) { -1, -1, -1, -1 }; + } + val = tmp; val <<= 8; val |= 0xFFu; } else if (len == 8) { - val = strtol(hex, NULL, 16); + char *endptr; + tmp = strtol(hex, &endptr, 16); + if (errno || *endptr != '\0' || tmp < 0) { + return (struct color) { -1, -1, -1, -1 }; + } + val = tmp; } else { return (struct color) { -1, -1, -1, -1 }; } diff --git a/src/config.c b/src/config.c index 0cfd566..99a4494 100644 --- a/src/config.c +++ b/src/config.c @@ -710,11 +710,9 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const return !err; } -void config_apply(struct tofi *tofi, const char *option, const char *value) +bool config_apply(struct tofi *tofi, const char *option, const char *value) { - if (!parse_option(tofi, "", 0, option, value)) { - exit(EXIT_FAILURE); - }; + return parse_option(tofi, "", 0, option, value); } uint32_t fixup_percentage(uint32_t value, uint32_t base, bool is_percent, uint32_t scale, bool use_scale) @@ -905,6 +903,9 @@ uint32_t parse_char(const char *filename, size_t lineno, const char *str, bool * ch = utf8_to_utf32_validate(tmp); if (ch == (uint32_t)-2 || ch == (uint32_t)-1 || *utf8_next_char(tmp) != '\0') { PARSE_ERROR(filename, lineno, "Failed to parse \"%s\" as a character.\n", str); + if (err) { + *err = true; + } } free(tmp); @@ -961,13 +962,13 @@ uint32_t parse_uint32(const char *filename, size_t lineno, const char *str, bool { errno = 0; char *endptr; - int32_t ret = strtoul(str, &endptr, 0); - if (endptr == str) { + int64_t ret = strtoul(str, &endptr, 0); + if (endptr == str || *endptr != '\0') { PARSE_ERROR(filename, lineno, "Failed to parse \"%s\" as unsigned int.\n", str); if (err) { *err = true; } - } else if (errno || ret < 0) { + } else if (errno || ret < 0 || ret > UINT32_MAX) { PARSE_ERROR(filename, lineno, "Unsigned int value \"%s\" out of range.\n", str); if (err) { *err = true; @@ -980,13 +981,13 @@ int32_t parse_int32(const char *filename, size_t lineno, const char *str, bool * { errno = 0; char *endptr; - int32_t ret = strtol(str, &endptr, 0); - if (endptr == str) { + int64_t ret = strtol(str, &endptr, 0); + if (endptr == str || *endptr != '\0') { PARSE_ERROR(filename, lineno, "Failed to parse \"%s\" as int.\n", str); if (err) { *err = true; } - } else if (errno) { + } else if (errno || ret < INT32_MIN || ret > INT32_MAX) { PARSE_ERROR(filename, lineno, "Int value \"%s\" out of range.\n", str); if (err) { *err = true; @@ -999,14 +1000,14 @@ struct uint32_percent parse_uint32_percent(const char *filename, size_t lineno, { errno = 0; char *endptr; - int32_t val = strtoul(str, &endptr, 0); + int64_t val = strtoul(str, &endptr, 0); bool percent = false; - if (endptr == str) { + if (endptr == str || (*endptr != '\0' && *endptr != '%')) { PARSE_ERROR(filename, lineno, "Failed to parse \"%s\" as unsigned int.\n", str); if (err) { *err = true; } - } else if (errno || val < 0) { + } else if (errno || val < 0 || val > UINT32_MAX) { PARSE_ERROR(filename, lineno, "Unsigned int value \"%s\" out of range.\n", str); if (err) { *err = true; @@ -1022,7 +1023,8 @@ struct uint32_percent parse_uint32_percent(const char *filename, size_t lineno, struct directional parse_directional(const char *filename, size_t lineno, const char *str, bool *err) { - int32_t values[4]; + /* One extra value to act as a sentinel for too many values in str. */ + int32_t values[5]; char *saveptr = NULL; char *tmp = xstrdup(str); char *val = strtok_r(tmp, ",", &saveptr); diff --git a/src/config.h b/src/config.h index 8dbd241..a9f0c56 100644 --- a/src/config.h +++ b/src/config.h @@ -1,10 +1,11 @@ #ifndef TOFI_CONFIG_H #define TOFI_CONFIG_H +#include <stdbool.h> #include "tofi.h" void config_load(struct tofi *tofi, const char *filename); -void config_apply(struct tofi *tofi, const char *option, const char *value); +bool config_apply(struct tofi *tofi, const char *option, const char *value); void config_fixup_values(struct tofi *tofi); #endif /* TOFI_CONFIG_H */ @@ -935,14 +935,18 @@ static void parse_args(struct tofi *tofi, int argc, char *argv[]) opt = getopt_long(argc, argv, short_options, long_options, &option_index); while (opt != -1) { if (opt == 0) { - config_apply(tofi, long_options[option_index].name, optarg); + if (!config_apply(tofi, long_options[option_index].name, optarg)) { + exit(EXIT_FAILURE); + } } else if (opt == 'k') { /* * Backwards compatibility for --late-keyboard-init not * taking an argument. */ if (optarg) { - config_apply(tofi, long_options[option_index].name, optarg); + if (!config_apply(tofi, long_options[option_index].name, optarg)) { + exit(EXIT_FAILURE); + } } else { tofi->late_keyboard_init = true; } diff --git a/test/config.c b/test/config.c new file mode 100644 index 0000000..c69e25b --- /dev/null +++ b/test/config.c @@ -0,0 +1,113 @@ +#include <assert.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "config.h" +#include "tofi.h" +#include "tap.h" + +void is_valid(const char *option, const char *value, const char *message) +{ + struct tofi tofi; + bool res = config_apply(&tofi, option, value); + tap_is(res, true, message); +} + +void isnt_valid(const char *option, const char *value, const char *message) +{ + struct tofi tofi; + bool res = config_apply(&tofi, option, value); + tap_is(res, false, message); +} + +int main(int argc, char *argv[]) +{ + setlocale(LC_ALL, ""); + + tap_version(14); + + /* Anchors */ + is_valid("anchor", "top-left", "Anchor top-left"); + is_valid("anchor", "top", "Anchor top"); + is_valid("anchor", "top-right", "Anchor top-right"); + is_valid("anchor", "right", "Anchor right"); + is_valid("anchor", "bottom-right", "Anchor bottom-right"); + is_valid("anchor", "bottom", "Anchor bottom"); + is_valid("anchor", "bottom-left", "Anchor bottom-left"); + is_valid("anchor", "left", "Anchor left"); + is_valid("anchor", "center", "Anchor center"); + isnt_valid("anchor", "left-bottom", "Invalid anchor"); + + /* Bools */ + is_valid("horizontal", "tRuE", "Boolean true"); + is_valid("horizontal", "fAlSe", "Boolean false"); + isnt_valid("horizontal", "truefalse", "Invalid boolean"); + + /* Password characters */ + is_valid("hidden-character", "O", "Single Latin character"); + is_valid("hidden-character", "Д", "Single Cyrillic character"); + is_valid("hidden-character", "Ξ", "Single Greek character"); + is_valid("hidden-character", "ọ", "Single character with decomposed diacritic"); + is_valid("hidden-character", "漢", "Single CJK character"); + isnt_valid("hidden-character", "ae", "Multiple characters"); + + /* Colours */ + is_valid("text-color", "46B", "Three character color without hash"); + is_valid("text-color", "#46B", "Three character color with hash"); + is_valid("text-color", "46BA", "Four character color without hash"); + is_valid("text-color", "#46BA", "Four character color with hash"); + is_valid("text-color", "4466BB", "Six character color without hash"); + is_valid("text-color", "#4466BB", "Six character color with hash"); + is_valid("text-color", "4466BBAA", "Eight character color without hash"); + is_valid("text-color", "#4466BBAA", "Eight character color with hash"); + isnt_valid("text-color", "4466BBA", "Five character color without hash"); + isnt_valid("text-color", "#4466BBA", "Five character color with hash"); + isnt_valid("text-color", "9GB", "Three character color with invalid characters"); + isnt_valid("text-color", "95GB", "Four character color with invalid characters"); + isnt_valid("text-color", "95XGUB", "Six character color with invalid characters"); + isnt_valid("text-color", "950-4GBY", "Eight character color with invalid characters"); + isnt_valid("text-color", "-99", "Negative two character color"); + isnt_valid("text-color", "-999", "Negative three character color"); + isnt_valid("text-color", "-9999", "Negative four character color"); + isnt_valid("text-color", "-99999", "Negative five character color"); + isnt_valid("text-color", "-999999", "Negative six character color"); + isnt_valid("text-color", "-9999999", "Negative seven character color"); + isnt_valid("text-color", "-99999999", "Negative eight character color"); + + /* Signed values */ + is_valid("result-spacing", "-2147483648", "INT32 Min"); + is_valid("result-spacing", "2147483647", "INT32 Max"); + isnt_valid("result-spacing", "-2147483649", "INT32 Min - 1"); + isnt_valid("result-spacing", "2147483648", "INT32 Max + 1"); + isnt_valid("result-spacing", "6A", "INT32 invalid character"); + + /* Unsigned values */ + is_valid("corner-radius", "0", "UINT32 0"); + is_valid("corner-radius", "4294967295", "UINT32 Max"); + isnt_valid("corner-radius", "4294967296", "UINT32 Max + 1"); + isnt_valid("corner-radius", "-1", "UINT32 -1"); + isnt_valid("corner-radius", "6A", "UINT32 invalid character"); + + /* Unsigned percentages */ + is_valid("width", "0", "UINT32 0 percent without sign"); + is_valid("width", "0%", "UINT32 0 percent with sign"); + is_valid("width", "4294967295", "UINT32 Max percent without sign"); + is_valid("width", "4294967295%", "UINT32 Max percent with sign"); + isnt_valid("width", "4294967296", "UINT32 Max + 1 percent without sign"); + isnt_valid("width", "4294967296%", "UINT32 Max + 1 percent with sign"); + isnt_valid("width", "-1", "UINT32 -1 percent without sign"); + isnt_valid("width", "-1%", "UINT32 -1 percent with sign"); + + /* Directional values */ + is_valid("prompt-background-padding", "0", "Single directional value"); + is_valid("prompt-background-padding", "0,1", "Two directional values"); + is_valid("prompt-background-padding", "0,1,-2", "Three directional values"); + is_valid("prompt-background-padding", "0,1,-2,3", "Four directional values"); + isnt_valid("prompt-background-padding", "0,1,-2,3,-4", "Five directional values"); + isnt_valid("prompt-background-padding", "0,1,-2,3,-4,5", "Six directional values"); + + tap_plan(); + + return EXIT_SUCCESS; +} diff --git a/test/meson.build b/test/meson.build index 49f6870..45df68f 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,4 +1,5 @@ tests = [ + 'config', 'utf8' ] |