make one-pass parsing for object identifier
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 8203ffd..56d02b4 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -499,14 +499,17 @@
 		break;
 	case ST_DIGITS:
 		dec_value_end = lstop;
+		/* FALL THROUGH */
 	case ST_DIGITS_TRAILSPACE:
 		/* The last symbol encountered was a digit. */
-		switch(asn_strtol(dec_value_start, dec_value_end, &dec_value)) {
+		switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) {
 		case ASN_STRTOL_OK:
 			break;
 		case ASN_STRTOL_ERROR_RANGE:
 			return XPBD_DECODER_LIMIT;
 		case ASN_STRTOL_ERROR_INVAL:
+		case ASN_STRTOL_EXPECT_MORE:
+		case ASN_STRTOL_EXTRA_DATA:
 			return XPBD_BROKEN_ENCODING;
 		}
 		break;
@@ -950,15 +953,44 @@
 	return 0;
 }
 
+/*
+ * This function is going to be DEPRECATED soon.
+ */
 enum asn_strtol_result_e
 asn_strtol(const char *str, const char *end, long *lp) {
+    const char *endp = end;
+
+    switch(asn_strtol_lim(str, &endp, lp)) {
+    case ASN_STRTOL_ERROR_RANGE:
+        return ASN_STRTOL_ERROR_RANGE;
+    case ASN_STRTOL_ERROR_INVAL:
+        return ASN_STRTOL_ERROR_INVAL;
+    case ASN_STRTOL_EXPECT_MORE:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    case ASN_STRTOL_OK:
+        return ASN_STRTOL_OK;
+    case ASN_STRTOL_EXTRA_DATA:
+        return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+    }
+
+    return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtol(3).
+ */
+enum asn_strtol_result_e
+asn_strtol_lim(const char *str, const char **end, long *lp) {
 	int sign = 1;
 	long l;
 
 	const long upper_boundary = LONG_MAX / 10;
 	long last_digit_max = LONG_MAX % 10;
 
-	if(str >= end) return ASN_STRTOL_ERROR_INVAL;
+	if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
 
 	switch(*str) {
 	case '-':
@@ -966,11 +998,13 @@
 		sign = -1;
 	case '+':
 		str++;
+		if(str >= *end) {
+			*end = str;
+			return ASN_STRTOL_EXPECT_MORE;
+		}
 	}
 
-	if(str >= end) return ASN_STRTOL_ERROR_INVAL;
-
-	for(l = 0; str < end; str++) {
+	for(l = 0; str < (*end); str++) {
 		switch(*str) {
 		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
 		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
@@ -986,18 +1020,23 @@
 						l = -l * 10 - d;
 					}
 				} else {
+					*end = str;
 					return ASN_STRTOL_ERROR_RANGE;
 				}
 			} else {
+				*end = str;
 				return ASN_STRTOL_ERROR_RANGE;
 			}
 		    }
 		    continue;
 		default:
-			return ASN_STRTOL_ERROR_INVAL;
+		    *end = str;
+		    *lp = sign * l;
+		    return ASN_STRTOL_EXTRA_DATA;
 		}
 	}
 
+	*end = str;
 	*lp = sign * l;
 	return ASN_STRTOL_OK;
 }
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index 8164e9e..fe08b03 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -59,10 +59,15 @@
 
 /* A a reified version of strtol(3) with nicer error reporting. */
 enum asn_strtol_result_e {
-    ASN_STRTOL_ERROR_INVAL = -1,  /* Invalid input */
-    ASN_STRTOL_OK          =  0,  /* Conversion succeded */
-    ASN_STRTOL_ERROR_RANGE =  1,  /* Input out of range */
+    ASN_STRTOL_ERROR_RANGE = -3,  /* Input outside of numeric range for long type */
+    ASN_STRTOL_ERROR_INVAL = -2,  /* Invalid data encountered (e.g., "+-") */
+    ASN_STRTOL_EXPECT_MORE = -1,  /* More data expected (e.g. "+") */
+    ASN_STRTOL_OK          =  0,  /* Conversion succeded, number ends at (*end) */
+    ASN_STRTOL_EXTRA_DATA  =  1,  /* Conversion succeded, but the string has extra stuff */
 };
+enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l);
+
+/* The asn_strtol is going to be DEPRECATED soon */
 enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l);
 
 /*
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 2939f25..066d562 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -648,12 +648,11 @@
 	long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) {
 	unsigned int arcs_count = 0;
 	const char *oid_end;
-	const char *value_start;
 	enum {
 		ST_LEADSPACE,
 		ST_TAILSPACE,
+		ST_AFTERVALUE,	/* Next character ought to be '.' or a space */
 		ST_WAITDIGITS,	/* Next character is expected to be a digit */
-		ST_DIGITS	/* INVARIANT: value_start != 0 in this state */
 	} state = ST_LEADSPACE;
 
 	if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
@@ -665,13 +664,16 @@
 	if(oid_txt_length == -1)
 		oid_txt_length = strlen(oid_text);
 
-#define	_OID_CAPTURE_ARC(value_start, oid_text)		do {	\
+#define	_OID_CAPTURE_ARC(oid_text, oid_end)		do {	\
+	const char *endp = oid_end;				\
 	long value;						\
-	switch(asn_strtol(value_start, oid_text, &value)) {	\
+	switch(asn_strtol_lim(oid_text, &endp, &value)) {	\
+	case ASN_STRTOL_EXTRA_DATA:				\
 	case ASN_STRTOL_OK:					\
 		if(arcs_count < arcs_slots)			\
 			arcs[arcs_count] = value;		\
 		arcs_count++;					\
+		oid_text = endp - 1;				\
 		break;						\
 	case ASN_STRTOL_ERROR_RANGE:				\
 		if(opt_oid_text_end)				\
@@ -679,6 +681,7 @@
 		errno = ERANGE;					\
 		return -1;					\
 	case ASN_STRTOL_ERROR_INVAL:				\
+	case ASN_STRTOL_EXPECT_MORE:				\
 		if(opt_oid_text_end)				\
 			*opt_oid_text_end = oid_text;		\
 		errno = EINVAL;					\
@@ -693,23 +696,24 @@
 		case ST_LEADSPACE:
 		case ST_TAILSPACE:
 			continue;
-		case ST_DIGITS:
-			_OID_CAPTURE_ARC(value_start, oid_text);
+		case ST_AFTERVALUE:
 			state = ST_TAILSPACE;
 			continue;
 		case ST_WAITDIGITS:
-			break;
+			break;	/* Digits expected after ".", got whitespace */
 		}
+		break;
 	    case 0x2e:	/* '.' */
 		switch(state) {
 		case ST_LEADSPACE:
-		case ST_WAITDIGITS:
-			break;
 		case ST_TAILSPACE:
-			state = ST_WAITDIGITS;
+		case ST_WAITDIGITS:
+			if(opt_oid_text_end)
+				*opt_oid_text_end = oid_text;
+			errno = EINVAL;	/* Broken OID */
+			return -1;
 			break;
-		case ST_DIGITS:
-			_OID_CAPTURE_ARC(value_start, oid_text);
+		case ST_AFTERVALUE:
 			state = ST_WAITDIGITS;
 			continue;
 		}
@@ -718,14 +722,15 @@
 	    case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
 		switch(state) {
 		case ST_TAILSPACE:
-			state = ST_WAITDIGITS;
-			break;
+		case ST_AFTERVALUE:
+			if(opt_oid_text_end)
+				*opt_oid_text_end = oid_text;
+			errno = EINVAL;	/* "1. 1" => broken OID */
+			return -1;
 		case ST_LEADSPACE:
 		case ST_WAITDIGITS:
-			state = ST_DIGITS;
-			value_start = oid_text;
-			continue;
-		case ST_DIGITS:
+			_OID_CAPTURE_ARC(oid_text, oid_end);
+			state = ST_AFTERVALUE;
 			continue;
 		}
 		break;
@@ -744,12 +749,10 @@
 	switch(state) {
 	case ST_LEADSPACE:
 		return 0; /* No OID found in input data */
-	case ST_DIGITS:
-		_OID_CAPTURE_ARC(value_start, oid_text);
-		return arcs_count;
 	case ST_WAITDIGITS:
 		errno = EINVAL;	/* Broken OID */
 		return -1;
+	case ST_AFTERVALUE:
 	case ST_TAILSPACE:
 		return arcs_count;
 	}
diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c
index ce62bda..05b4993 100644
--- a/skeletons/tests/check-OIDs.c
+++ b/skeletons/tests/check-OIDs.c
@@ -228,7 +228,8 @@
 static void check_parse(const char *oid_txt, int retval) {
 	int ret;
 	long l[2];
-	const char *p;
+	const char *p = oid_txt - 13;
+	assert(p < oid_txt);
 
 	ret = OBJECT_IDENTIFIER_parse_arcs(oid_txt, -1, l, 2, &p);
 	printf("[%s] => %d == %d\n", oid_txt, ret, retval);
@@ -266,6 +267,7 @@
 	for(i = 0; i < ret; i++) {
 		if(i) printf(".");
 		printf("%ld", arcs[i]);
+		if(arcs[i] != i + 1) printf(" != %d\n", i + 1);
 		assert(arcs[i] == i + 1);
 	}
 	printf(": %d == %d\n", ret, expect_arcs);
@@ -383,9 +385,8 @@
 	CHECK_REGEN_OID(19);
 	CHECK_REGEN_OID(20);
 
-	check_parse("", -1);
-	check_parse(" ", -1);
-	check_parse(" ", -1);
+	check_parse("", 0);
+	check_parse(" ", 0);
 	check_parse(".", -1);
 	check_parse(" .", -1);
 	check_parse(".1", -1);
@@ -404,6 +405,10 @@
 	check_parse("  1.2  ", 2);
 	check_parse("1. 2", -1);
 	check_parse("1 .2", -1);
+	check_parse(" 1 .2", -1);
+	check_parse(" 1 .2 ", -1);
+	check_parse("1 .2 ", -1);
+	check_parse("1.+1", -1);
 	check_parse("10.30.234.234", 4);
 	check_parse("10.30.234.234 ", 4);
 	check_parse("10.30.234. 234 ", -1);