diff options
Diffstat (limited to 'dimension')
-rw-r--r-- | dimension/lexer.l | 4 | ||||
-rw-r--r-- | dimension/main.c | 47 | ||||
-rw-r--r-- | dimension/parse.c | 27 | ||||
-rw-r--r-- | dimension/utility.c | 66 | ||||
-rw-r--r-- | dimension/utility.h | 8 |
5 files changed, 104 insertions, 48 deletions
diff --git a/dimension/lexer.l b/dimension/lexer.l index c948cc9..dbafec2 100644 --- a/dimension/lexer.l +++ b/dimension/lexer.l @@ -102,7 +102,7 @@ int token = DMNSN_T_LEX_ERROR; size_t string_length = 0, string_extent = 8; -unsigned long wchar; +unsigned int wchar; /* Silence some warnings */ (void)yyunput; @@ -351,7 +351,7 @@ unsigned long wchar; <DMNSN_STRING_ESCAPE>"'" STRCAT("'", 1); yy_pop_state(yyscanner); <DMNSN_STRING_ESCAPE>"\"" STRCAT("\"", 1); yy_pop_state(yyscanner); <DMNSN_STRING_ESCAPE>"u"[[:digit:]aAbBcCdDeEfF]{4} { - wchar = strtoul(yytext + 1, NULL, 16); + dmnsn_strtoui(&wchar, yytext + 1, 16); STRCAT("", 2); lvalp->value[string_length - 2] = wchar/256; lvalp->value[string_length - 1] = wchar%256; diff --git a/dimension/main.c b/dimension/main.c index 80bc6e6..26f131c 100644 --- a/dimension/main.c +++ b/dimension/main.c @@ -104,48 +104,35 @@ main(int argc, char **argv) break; case 'w': - { - char *endptr; - width = strtol(optarg, &endptr, 10); - if (*endptr != '\0' || endptr == optarg || width <= 0) { - fprintf(stderr, "Invalid argument to --width!\n"); - print_usage(stderr, argv[0]); - return EXIT_FAILURE; - } - break; + if (!dmnsn_strtoi(&width, optarg, 10) || width <= 0) { + fprintf(stderr, "Invalid argument to --width!\n"); + print_usage(stderr, argv[0]); + return EXIT_FAILURE; } case 'h': - { - char *endptr; - height = strtol(optarg, &endptr, 10); - if (*endptr != '\0' || endptr == optarg || height <= 0) { - fprintf(stderr, "Invalid argument to --height!\n"); - print_usage(stderr, argv[0]); - return EXIT_FAILURE; - } - break; + if (!dmnsn_strtoi(&height, optarg, 10) || height <= 0) { + fprintf(stderr, "Invalid argument to --height!\n"); + print_usage(stderr, argv[0]); + return EXIT_FAILURE; } + break; case DMNSN_OPT_THREADS: - { - char *endptr; - nthreads = strtol(optarg, &endptr, 10); - if (*endptr != '\0' || endptr == optarg || nthreads <= 0) { - fprintf(stderr, "Invalid argument to --threads!\n"); - print_usage(stderr, argv[0]); - return EXIT_FAILURE; - } - break; + if (!dmnsn_strtoi(&nthreads, optarg, 10) || nthreads <= 0) { + fprintf(stderr, "Invalid argument to --threads!\n"); + print_usage(stderr, argv[0]); + return EXIT_FAILURE; } + break; case DMNSN_OPT_QUALITY: { - char *endptr; - quality = strtoul(optarg, &endptr, 0); - if (*endptr != '\0' || endptr == optarg) { + unsigned int iqual; + if (!dmnsn_strtoui(&iqual, optarg, 0)) { fprintf(stderr, "Invalid argument to --quality!\n"); print_usage(stderr, argv[0]); return EXIT_FAILURE; } + quality = iqual; break; } case DMNSN_OPT_STRICT: diff --git a/dimension/parse.c b/dimension/parse.c index 58e645e..198a4b8 100644 --- a/dimension/parse.c +++ b/dimension/parse.c @@ -733,26 +733,21 @@ dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) break; case DMNSN_AST_VAL: { - errno = 0; - char *endptr; - long l = strtol(rhs.ptr, &endptr, 0); - if (*endptr != '\0' || endptr == rhs.ptr - || (l != 0 && errno == ERANGE)) - { - errno = 0; - double d = strtod(rhs.ptr, &endptr); - if (*endptr != '\0' || endptr == rhs.ptr) { - dmnsn_diagnostic(astnode.location, "invalid numeric string '%s'", - (const char *)rhs.ptr); - ret.type = DMNSN_AST_NONE; - } else if (d != 0 && errno == ERANGE) { + long l; + if (dmnsn_strtol(&l, rhs.ptr, 0)) { + dmnsn_make_ast_integer(&ret, l); + } else { + double d; + if (dmnsn_strtod(&d, rhs.ptr)) { + dmnsn_make_ast_float(&ret, d); + } else if (errno == ERANGE) { dmnsn_diagnostic(astnode.location, "float value overflowed"); ret.type = DMNSN_AST_NONE; } else { - dmnsn_make_ast_float(&ret, d); + dmnsn_diagnostic(astnode.location, "invalid numeric string '%s'", + (const char *)rhs.ptr); + ret.type = DMNSN_AST_NONE; } - } else { - dmnsn_make_ast_integer(&ret, l); } break; } diff --git a/dimension/utility.c b/dimension/utility.c index cb6d70d..88d7f79 100644 --- a/dimension/utility.c +++ b/dimension/utility.c @@ -18,9 +18,75 @@ *************************************************************************/ #include "utility.h" +#include <ctype.h> +#include <errno.h> +#include <limits.h> #include <stdarg.h> #include <stdio.h> +bool +dmnsn_strtoi(int *n, const char *nptr, int base) +{ + long ln; + bool ret = dmnsn_strtol(&ln, nptr, base); + *n = ln; + return ret && ln <= INT_MAX && ln >= INT_MIN; +} + +bool +dmnsn_strtol(long *n, const char *nptr, int base) +{ + char *endptr; + errno = 0; + *n = strtol(nptr, &endptr, base); + return *endptr == '\0' && endptr != nptr && errno == 0; +} + +bool +dmnsn_strtoui(unsigned int *n, const char *nptr, int base) +{ + /* Skip leading whitespace to detect a leading minus sign */ + while (isspace(*nptr)) { + ++nptr; + } + bool neg = false; + if (nptr[0] == '-') { + ++nptr; + if (nptr[0] == '-' || nptr[0] == '+') { + return false; + } + neg = true; + } + + unsigned long ln; + bool ret = dmnsn_strtoul(&ln, nptr, base); + if (neg) { + *n = -ln; + } else { + *n = ln; + } + return ret && (ln <= UINT_MAX || nptr[0] == '-'); +} + +bool +dmnsn_strtoul(unsigned long *n, const char *nptr, int base) +{ + char *endptr; + errno = 0; + *n = strtoul(nptr, &endptr, base); + return *endptr == '\0' && endptr != nptr && errno == 0; +} + +bool +dmnsn_strtod(double *n, const char *nptr) +{ + char *endptr; + errno = 0; + *n = strtod(nptr, &endptr); + return *endptr == '\0' && endptr != nptr + && (errno == 0 || (errno == ERANGE && *n == 0.0)); +} + void dmnsn_diagnostic(dmnsn_parse_location location, const char *format, ...) { diff --git a/dimension/utility.h b/dimension/utility.h index 1c0a98b..13cfdf5 100644 --- a/dimension/utility.h +++ b/dimension/utility.h @@ -21,6 +21,14 @@ #define UTILITY_H #include "parse.h" /* For dmnsn_parse_location */ +#include <stdbool.h> + +/* Wrappers for strtol and strtoul, and some added ones */ +bool dmnsn_strtoi(int *n, const char *nptr, int base); +bool dmnsn_strtol(long *n, const char *nptr, int base); +bool dmnsn_strtoui(unsigned int *n, const char *nptr, int base); +bool dmnsn_strtoul(unsigned long *n, const char *nptr, int base); +bool dmnsn_strtod(double *n, const char *nptr); #if defined(__GNUC__) || defined(__attribute__) #define DMNSN_PRINTF_WARN(f, a) __attribute__((format (printf, f, a))) |