summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/lexer.l4
-rw-r--r--dimension/main.c47
-rw-r--r--dimension/parse.c27
-rw-r--r--dimension/utility.c66
-rw-r--r--dimension/utility.h8
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)))