Introduce strtonum(), which works like string_to_number(), but passes
back the 'end' pointer. It is useful where you want to do boundary
checking yet work with strings that are not entirely slurped by
strtoul(), e.g.:

	s = "1/2"; /* one half */
	if (!strtonum(s, &end, &value, 0, 5))
		error("Zero-length string, or value out of bounds");
	if (*end != '/')
		error("Malformed string");
	info->param1 = value;
	if (!strtonum(end + 1, &end, &value, 2, 4))
		error("..");
	if (*end != '\0')
		error("Malformed string");
	info->param2 = value;

Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
diff --git a/xtables.c b/xtables.c
index b8c2c6f..4313f5b 100644
--- a/xtables.c
+++ b/xtables.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -199,6 +200,49 @@
 	return result;
 }
 
+/*
+ * strtonum{,l} - string to number conversion
+ *
+ * If @end is NULL, we assume the caller does not want
+ * a case like "15a", so reject it.
+ */
+bool strtonuml(const char *s, char **end, unsigned long *value,
+               unsigned long min, unsigned long max)
+{
+	unsigned long v;
+	char *my_end;
+
+	errno = 0;
+	v = strtoul(s, &my_end, 0);
+
+	if (my_end == s)
+		return false;
+	if (end != NULL)
+		*end = my_end;
+
+	if (errno != ERANGE && min <= v && (max == 0 || v <= max)) {
+		if (value != NULL)
+			*value = v;
+		if (end == NULL)
+			return *my_end == '\0';
+		return true;
+	}
+
+	return false;
+}
+
+bool strtonum(const char *s, char **end, unsigned int *value,
+                  unsigned int min, unsigned int max)
+{
+	unsigned long v;
+	bool ret;
+
+	ret = strtonuml(s, end, &v, min, max);
+	if (value != NULL)
+		*value = v;
+	return ret;
+}
+
 int service_to_port(const char *name, const char *proto)
 {
 	struct servent *service;