work in 128-bit integer values while compiling
diff --git a/asn1c/unber.c b/asn1c/unber.c
index 5c525e7..f8588e2 100644
--- a/asn1c/unber.c
+++ b/asn1c/unber.c
@@ -40,6 +40,7 @@
 #include <OBJECT_IDENTIFIER.c>
 #include <RELATIVE-OID.c>
 #include <asn_codecs_prim.c>
+#include <asn1p_integer.c>
 
 #undef COPYRIGHT
 #define COPYRIGHT "Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>\n"
@@ -164,10 +165,10 @@
     PD_EOF = 1,
 } pd_code_e;
 static pd_code_e process_deeper(const char *fname, FILE *fp,
-                                asn1c_integer_t *offset, int level,
+                                size_t *offset, int level,
                                 ssize_t limit, ber_tlv_len_t *frame_size,
                                 ber_tlv_len_t effective_size, int expect_eoc);
-static void print_TL(int fin, asn1c_integer_t offset, int level, int constr,
+static void print_TL(int fin, size_t offset, int level, int constr,
                      ssize_t tlen, ber_tlv_tag_t, ber_tlv_len_t,
                      ber_tlv_len_t effective_frame_size);
 static int print_V(const char *fname, FILE *fp, ber_tlv_tag_t, ber_tlv_len_t);
@@ -179,7 +180,7 @@
 process(const char *fname) {
     FILE *fp;
     pd_code_e pdc;
-    asn1c_integer_t offset = 0;   /* Stream decoding position */
+    size_t offset = 0;   /* Stream decoding position */
     ber_tlv_len_t frame_size = 0; /* Single frame size */
 
     if(strcmp(fname, "-")) {
@@ -197,8 +198,7 @@
      */
     for(; offset < skip_bytes; offset++) {
         if(fgetc(fp) == -1) {
-            fprintf(stderr, "%s: input source (%" PRIdASN
-                            " bytes) "
+            fprintf(stderr, "%s: input source (%zu bytes) "
                             "has less data than \"-s %d\" switch "
                             "wants to skip\n",
                     fname, offset, skip_bytes);
@@ -224,7 +224,7 @@
  * Process the TLV recursively.
  */
 static pd_code_e
-process_deeper(const char *fname, FILE *fp, asn1c_integer_t *offset, int level,
+process_deeper(const char *fname, FILE *fp, size_t *offset, int level,
                ssize_t limit, ber_tlv_len_t *frame_size,
                ber_tlv_len_t effective_size, int expect_eoc) {
     unsigned char tagbuf[32];
@@ -245,8 +245,7 @@
         if(limit >= 0 && tblen >= limit) {
             fprintf(stderr,
                     "%s: Too long TL sequence (%ld >= %ld)"
-                    " at %" PRIdASN
-                    ". "
+                    " at %zu. "
                     "Broken or maliciously constructed file\n",
                     fname, (long)tblen, (long)limit, *offset);
             return PD_FAILED;
@@ -258,7 +257,7 @@
             if(limit > 0 || expect_eoc) {
                 fprintf(stderr,
                         "%s: Unexpected end of file (TL)"
-                        " at %" PRIdASN "\n",
+                        " at %zu\n",
                         fname, *offset);
                 return PD_FAILED;
             } else {
@@ -276,7 +275,7 @@
         case -1:
             fprintf(stderr,
                     "%s: Fatal error decoding tag"
-                    " at %" PRIdASN "+%ld\n",
+                    " at %zu+%ld\n",
                     fname, *offset, (long)tblen);
             return PD_FAILED;
         case 0:
@@ -294,7 +293,7 @@
         case -1:
             fprintf(stderr,
                     "%s: Fatal error decoding value length"
-                    " at %" PRIdASN "\n",
+                    " at %zu\n",
                     fname, *offset + t_len);
             return PD_FAILED;
         case 0:
@@ -386,7 +385,7 @@
 }
 
 static void
-print_TL(int fin, asn1c_integer_t offset, int level, int constr, ssize_t tlen,
+print_TL(int fin, size_t offset, int level, int constr, ssize_t tlen,
          ber_tlv_tag_t tlv_tag, ber_tlv_len_t tlv_len,
          ber_tlv_len_t effective_size) {
     if(fin && !constr) {
@@ -400,7 +399,7 @@
     printf(constr ? ((tlv_len == -1) ? "I" : "C") : "P");
 
     /* Print out the offset of this boundary, even if closing tag */
-    if(!minimalistic) printf(" O=\"%" PRIdASN "\"", offset);
+    if(!minimalistic) printf(" O=\"%zu\"", offset);
 
     printf(" T=\"");
     ber_tlv_tag_fwrite(tlv_tag, stdout);
@@ -573,7 +572,7 @@
     switch(etype) {
     case ASN_BASIC_INTEGER:
     case ASN_BASIC_ENUMERATED:
-        printf("%" PRIdASN, collector);
+        printf("%s", asn1p_itoa(collector));
         break;
     case ASN_BASIC_OBJECT_IDENTIFIER:
         if(vbuf) {
@@ -590,7 +589,7 @@
                 printf(" F>");
                 for(i = 0; i < arcno; i++) {
                     if(i) printf(".");
-                    printf("%" PRIuASN, arcs[i]);
+                    printf("%s", asn1p_itoa(arcs[i]));
                 }
                 FREEMEM(vbuf);
                 vbuf = 0;
@@ -611,7 +610,7 @@
                 printf(" F>");
                 for(i = 0; i < arcno; i++) {
                     if(i) printf(".");
-                    printf("%" PRIuASN, arcs[i]);
+                    printf("%s", asn1p_itoa(arcs[i]));
                 }
                 FREEMEM(vbuf);
                 vbuf = 0;
diff --git a/configure.ac b/configure.ac
index de23065..e30b126 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,6 +123,8 @@
 AC_TYPE_OFF_T
 AC_TYPE_SIZE_T
 AC_STRUCT_TM
+AC_CHECK_TYPE([__int128],
+    [AC_DEFINE(HAVE_128_BIT_INT, 1, [Have 128-bit integer])])
 AC_CHECK_TYPE(intmax_t, int64_t)
 
 dnl Test if we should test features that depend on 64-bitness.
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 1c1fb95..54025d3 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -9,6 +9,7 @@
 #include "asn1c_misc.h"
 #include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
 #include <asn1fix_export.h>	/* other exportables from libasn1fix */
+#include <asn1parser.h>
 
 typedef struct tag2el_s {
 	struct asn1p_type_tag_s el_tag;
@@ -143,8 +144,8 @@
 				OUT("\t");
 				out_name_chain(arg, ONC_noflags);
 				OUT("_%s", MKID(v));
-				OUT("\t= %" PRIdASN "%s\n",
-					v->value->value.v_integer,
+				OUT("\t= %s%s\n",
+					asn1p_itoa(v->value->value.v_integer),
 					(eidx+1 < el_count) ? "," : "");
 				v2e[eidx].name = v->Identifier;
 				v2e[eidx].value = v->value->value.v_integer;
@@ -184,8 +185,8 @@
 		qsort(v2e, el_count, sizeof(v2e[0]), compar_enumMap_byValue);
 		for(eidx = 0; eidx < el_count; eidx++) {
 			v2e[eidx].idx = eidx;
-			OUT("\t{ %" PRIdASN ",\t%ld,\t\"%s\" }%s\n",
-				v2e[eidx].value,
+			OUT("\t{ %s,\t%ld,\t\"%s\" }%s\n",
+				asn1p_itoa(v2e[eidx].value),
 				(long)strlen(v2e[eidx].name), v2e[eidx].name,
 				(eidx + 1 < el_count) ? "," : "");
 		}
@@ -197,10 +198,10 @@
 			MKID(expr), expr->_type_unique_index);
 		qsort(v2e, el_count, sizeof(v2e[0]), compar_enumMap_byName);
 		for(eidx = 0; eidx < el_count; eidx++) {
-			OUT("\t%d%s\t/* %s(%" PRIdASN ") */\n",
+			OUT("\t%d%s\t/* %s(%s) */\n",
 				v2e[eidx].idx,
 				(eidx + 1 < el_count) ? "," : "",
-				v2e[eidx].name, v2e[eidx].value);
+				v2e[eidx].name, asn1p_itoa(v2e[eidx].value));
 		}
 		if(map_extensions)
 			OUT("\t/* This list is extensible */\n");
@@ -282,8 +283,8 @@
 			OUT("\t");
 			out_name_chain(arg, ONC_noflags);
 			OUT("_%s", MKID(v));
-			OUT("\t= %" PRIdASN "%s\n",
-				v->value->value.v_integer,
+			OUT("\t= %s%s\n",
+				asn1p_itoa(v->value->value.v_integer),
 				(eidx < el_count) ? "," : "");
 		}
 		OUT("} e_");
@@ -1628,7 +1629,7 @@
 	case TC_NOCLASS:
 		break;
 	}
-	OUT(" | (%" PRIdASN " << 2))", tag->tag_value);
+	OUT(" | (%s << 2))", asn1p_itoa(tag->tag_value));
 
 	return 0;
 }
@@ -1993,12 +1994,12 @@
 		if(type) OUT("(%s", type);
 		OUT("(");
 		if(range->left.type == ARE_VALUE)
-			OUT("%" PRIdASN, range->left.value);
+			OUT("%s", asn1p_itoa(range->left.value));
 		else
 			OUT("MIN");
 		OUT("..");
 		if(range->right.type == ARE_VALUE)
-			OUT("%" PRIdASN, range->right.value);
+			OUT("%s", asn1p_itoa(range->right.value));
 		else
 			OUT("MAX");
 		if(range->extensible) OUT(",...");
@@ -2073,7 +2074,7 @@
         if(range->left.type == ARE_VALUE && range->right.type == ARE_VALUE
            && range->left.value == range->right.value
            && range->left.value >= 0) {
-            OUT("%" PRIdASN "", range->left.value);
+            OUT("%s", asn1p_itoa(range->left.value));
         } else {
             OUT("-1");
         }
@@ -2183,12 +2184,12 @@
 		if(type) OUT("(%s", type);
 		OUT("(");
 		if(range->left.type == ARE_VALUE)
-			OUT("%" PRIdASN, range->left.value);
+			OUT("%s", asn1p_itoa(range->left.value));
 		else
 			OUT("MIN");
 		OUT("..");
 		if(range->right.type == ARE_VALUE)
-			OUT("%" PRIdASN, range->right.value);
+			OUT("%s", asn1p_itoa(range->right.value));
 		else
 			OUT("MAX");
 		if(range->extensible) OUT(",...");
@@ -2462,17 +2463,17 @@
 		if(fits_long && !expr->marker.default_value->value.v_integer)
 			expr->marker.flags &= ~EM_INDIRECT;
 		if(!out) {
-			OUT("asn_DFL_%d_set_%" PRIdASN
-				",\t/* DEFAULT %" PRIdASN " */\n",
+			OUT("asn_DFL_%d_set_%s,",
 				expr->_type_unique_index,
-				expr->marker.default_value->value.v_integer,
-				expr->marker.default_value->value.v_integer);
+				asn1p_itoa(expr->marker.default_value->value.v_integer));
+            OUT("\t/* DEFAULT %s */\n",
+				asn1p_itoa(expr->marker.default_value->value.v_integer));
 			return 1;
 		}
 		REDIR(OT_STAT_DEFS);
-		OUT("static int asn_DFL_%d_set_%" PRIdASN "(int set_value, void **sptr) {\n",
+		OUT("static int asn_DFL_%d_set_%s(int set_value, void **sptr) {\n",
 			expr->_type_unique_index,
-			expr->marker.default_value->value.v_integer);
+			asn1p_itoa(expr->marker.default_value->value.v_integer));
 		INDENT(+1);
 		OUT("%s *st = *sptr;\n", asn1c_type_name(arg, expr, TNF_CTYPE));
 		OUT("\n");
@@ -2484,8 +2485,8 @@
 		OUT("\n");
 		OUT("if(set_value) {\n");
 		INDENT(+1);
-		OUT("/* Install default value %" PRIdASN " */\n",
-			expr->marker.default_value->value.v_integer);
+		OUT("/* Install default value %s */\n",
+			asn1p_itoa(expr->marker.default_value->value.v_integer));
 		if(fits_long) {
 			OUT("*st = ");
 			OINT(expr->marker.default_value->value.v_integer);
@@ -2499,17 +2500,17 @@
 		INDENT(-1);
 		OUT("} else {\n");
 		INDENT(+1);
-		OUT("/* Test default value %" PRIdASN " */\n",
-			expr->marker.default_value->value.v_integer);
+		OUT("/* Test default value %s */\n",
+			asn1p_itoa(expr->marker.default_value->value.v_integer));
 		if(fits_long) {
-			OUT("return (*st == %" PRIdASN ");\n",
-				expr->marker.default_value->value.v_integer);
+			OUT("return (*st == %s);\n",
+				asn1p_itoa(expr->marker.default_value->value.v_integer));
 		} else {
 			OUT("long value;\n");
 			OUT("if(asn_INTEGER2long(st, &value))\n");
 			OUT("\treturn -1;\n");
-			OUT("return (value == %" PRIdASN ");\n",
-				expr->marker.default_value->value.v_integer);
+			OUT("return (value == %s);\n",
+				asn1p_itoa(expr->marker.default_value->value.v_integer));
 		}
 		INDENT(-1);
 		OUT("}\n");
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index 80d8c3d..0330dbf 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -125,18 +125,20 @@
 /*
  * Format LONG_MIN according to C90 rules.
  */
-#define OINT(iv)	do {					\
-	if(iv == (-2147483647L - 1))				\
-		OUT("(-2147483647L - 1)");			\
-	else							\
-		OUT("%" PRIdASN, iv);				\
-} while(0)
+#define OINT(iv)                       \
+    do {                               \
+        if(iv == (-2147483647L - 1))   \
+            OUT("(-2147483647L - 1)"); \
+        else                           \
+            OUT("%s", asn1p_itoa(iv)); \
+    } while(0)
 
-#define OINTS(iv)	do {					\
-	if(iv == (-2147483647L - 1))				\
-		OUT("(-2147483647L - 1)");			\
-	else							\
-		OUT("% " PRIdASN, iv);				\
-} while(0)
+#define OINTS(iv)                                              \
+    do {                                                       \
+        if(iv == (-2147483647L - 1))                           \
+            OUT("(-2147483647L - 1)");                         \
+        else                                                   \
+            OUT("%s%s", (iv >= 0) ? " " : "", asn1p_itoa(iv)); \
+    } while(0)
 
 #endif	/* ASN1_COMPILED_OUTPUT_H */
diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c
index 5b85464..fc61a97 100644
--- a/libasn1fix/asn1fix_crange.c
+++ b/libasn1fix/asn1fix_crange.c
@@ -157,7 +157,7 @@
 	case ARE_MIN:	strcpy(buf, "MIN"); break;
 	case ARE_MAX:	strcpy(buf, "MAX"); break;
 	case ARE_VALUE:
-		snprintf(buf, sizeof(buf), "%" PRIdASN, edge->value);
+		snprintf(buf, sizeof(buf), "%s", asn1p_itoa(edge->value));
         break;
     default:
         assert(!"edge->type");
@@ -258,9 +258,9 @@
 	switch(val->type) {
 	case ATV_INTEGER:
 		if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
-			FATAL("Integer %" PRIdASN " value invalid "
+			FATAL("Integer %s value invalid "
 				"for %s constraint at line %d",
-				val->value.v_integer,
+				asn1p_itoa(val->value.v_integer),
 				asn1p_constraint_type2str(type), lineno);
 			return -1;
 		}
diff --git a/libasn1fix/asn1fix_enum.c b/libasn1fix/asn1fix_enum.c
index 399cb62..ac543f2 100644
--- a/libasn1fix/asn1fix_enum.c
+++ b/libasn1fix/asn1fix_enum.c
@@ -115,16 +115,19 @@
 			if (eval > max_value_ext) {
 				max_value_ext = eval;
 			} else {
-				FATAL(
+                char max_value_buf[128];
+                asn1p_itoa_s(max_value_buf, sizeof(max_value_buf),
+                             max_value_ext);
+                FATAL(
 					"Enumeration %s at line %d: "
-					"Explicit value \"%s(%" PRIdASN ")\" "
+					"Explicit value \"%s(%s)\" "
 					"is not greater "
-					"than previous values (max %" PRIdASN ")",
+					"than previous values (max %s)",
 					expr->Identifier,
 					ev->_lineno,
 					ev->Identifier,
-					eval,
-					max_value_ext);
+					asn1p_itoa(eval),
+					max_value_buf);
 				rvalue = -1;
 			}
 		}
@@ -143,12 +146,12 @@
 			if (used_vals[uv_idx] == eval) {
 				FATAL(
 					"Enumeration %s at line %d: "
-					"Explicit value \"%s(%" PRIdASN ")\" "
+					"Explicit value \"%s(%s)\" "
 					"collides with previous values",
 					expr->Identifier,
 					ev->_lineno,
 					ev->Identifier,
-					eval);
+					asn1p_itoa(eval));
 				rvalue = -1;
 				unique = 0;
 			}
diff --git a/libasn1fix/asn1fix_misc.c b/libasn1fix/asn1fix_misc.c
index 88e8d18..e5f4f79 100644
--- a/libasn1fix/asn1fix_misc.c
+++ b/libasn1fix/asn1fix_misc.c
@@ -50,8 +50,7 @@
 			memcpy(buf + sizeof(buf) - 4, "...", 4);
 		return buf;
 	case ATV_INTEGER:
-		ret = snprintf(buf, sizeof(buf), "%" PRIdASN,
-			v->value.v_integer);
+		ret = snprintf(buf, sizeof(buf), "%s", asn1p_itoa(v->value.v_integer));
 		if(ret >= (ssize_t)sizeof(buf))
 			memcpy(buf + sizeof(buf) - 4, "...", 4);
 		return buf;
diff --git a/libasn1parser/Makefile.am b/libasn1parser/Makefile.am
index 65a4f3e..bf9127d 100644
--- a/libasn1parser/Makefile.am
+++ b/libasn1parser/Makefile.am
@@ -19,6 +19,7 @@
 	asn1p_param.c asn1p_param.h	\
 	asn1p_class.c asn1p_class.h	\
 	asn1p_ref.c asn1p_ref.h		\
+	asn1p_integer.c asn1p_integer.h	\
 	asn1p_list.h
 
 asn1parser.h: asn1p_expr_str.h
diff --git a/libasn1parser/asn1p_expr.c b/libasn1parser/asn1p_expr.c
index 6065a7a..7a24d06 100644
--- a/libasn1parser/asn1p_expr.c
+++ b/libasn1parser/asn1p_expr.c
@@ -312,7 +312,7 @@
 		break;
 	}
 	buf += snprintf(buf + strlen(buf), end - buf,
-		"%" PRIdASN "]", tag->tag_value);
+		"%s]", asn1p_itoa(tag->tag_value));
 	assert((unsigned int)(buf - end) > sizeof(" IMPLICIT "));
 
 	switch(tag->tag_mode) {
diff --git a/libasn1parser/asn1p_integer.c b/libasn1parser/asn1p_integer.c
new file mode 100644
index 0000000..98cfe08
--- /dev/null
+++ b/libasn1parser/asn1p_integer.c
@@ -0,0 +1,165 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "asn1p_integer.h"
+
+#define ASN_INTEGER_MAX    \
+    (~((asn1c_integer_t)0) \
+     & ~((asn1c_integer_t)1 << (8 * sizeof(asn1c_integer_t) - 1)))
+#define ASN_INTEGER_MIN (-(ASN_INTEGER_MAX)-1)
+
+/*
+ * 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/strtoimax(3).
+ */
+enum strtox_result_e {
+    STRTOX_ERROR_RANGE = -3, /* Input outside of supported numeric range */
+    STRTOX_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */
+    STRTOX_EXPECT_MORE = -1, /* More data expected (e.g. "+") */
+    STRTOX_OK = 0,           /* Conversion succeded, number ends at (*end) */
+    STRTOX_EXTRA_DATA =
+        1 /* Conversion succeded, but the string has extra stuff */
+};
+
+static enum strtox_result_e
+strtoaint_lim(const char *str, const char **end, asn1c_integer_t *intp) {
+	const asn1c_integer_t upper_boundary = ASN_INTEGER_MAX / 10;
+	int last_digit_max = ASN_INTEGER_MAX % 10;
+	int sign = 1;
+	asn1c_integer_t value;
+
+	if(str >= *end) return STRTOX_ERROR_INVAL;
+
+	switch(*str) {
+	case '-':
+		last_digit_max++;
+		sign = -1;
+		/* FALL THROUGH */
+	case '+':
+		str++;
+		if(str >= *end) {
+			*end = str;
+			return STRTOX_EXPECT_MORE;
+		}
+	}
+
+	for(value = 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: {
+			int d = *str - '0';
+			if(value < upper_boundary) {
+				value = value * 10 + d;
+			} else if(value == upper_boundary) {
+				if(d <= last_digit_max) {
+					if(sign > 0) {
+						value = value * 10 + d;
+					} else {
+						sign = 1;
+						value = -value * 10 - d;
+					}
+				} else {
+					*end = str;
+					return STRTOX_ERROR_RANGE;
+				}
+			} else {
+				*end = str;
+				return STRTOX_ERROR_RANGE;
+			}
+		    }
+		    continue;
+		default:
+		    *end = str;
+		    *intp = sign * value;
+		    return STRTOX_EXTRA_DATA;
+		}
+	}
+
+	*end = str;
+	*intp = sign * value;
+	return STRTOX_OK;
+}
+
+int
+asn1p_atoi(const char *ptr, asn1c_integer_t *value) {
+    const char *end = ptr + strlen(ptr);
+    if(strtoaint_lim(ptr, &end, value) == STRTOX_OK) {
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+const char *asn1p_itoa(asn1c_integer_t v) {
+    static char static_buf[128];
+    int ret = asn1p_itoa_s(static_buf, sizeof(static_buf), v);
+    if(ret > 0) {
+        assert(ret < sizeof(static_buf));
+        return static_buf;
+    } else {
+        return NULL;
+    }
+}
+
+int asn1p_itoa_s(char *buf, size_t size, asn1c_integer_t v) {
+    char tmp_buf[128];
+
+    if(v >= LONG_MIN && v < LONG_MAX) {
+        int ret = snprintf(buf, size, "%ld", (long)v);
+        if(ret < 0 || ret >= size) {
+            return -1;
+        }
+        return ret;
+    }
+
+    int sign = 0;
+    if(v < 0) {
+        if(v == ASN_INTEGER_MIN) {
+            switch(sizeof(v)) {
+            case 16:
+                if(size < 41)
+                    return -1;
+                memcpy(buf, "-170141183460469231731687303715884105729", 41);
+                return 41;
+            case 8:
+                if(size < 21)
+                    return -1;
+                memcpy(buf, "-9223372036854775809", 21);
+                return 21;
+            default:
+                assert(!"unreachable");
+            }
+        }
+
+        sign = -1;
+        v = -v; /* Ditch the sign */
+    }
+
+    assert(v > 1000000000L);
+    char restbuf[10] = "000000000\0";
+    const char *rest = asn1p_itoa((long)(v % 1000000000L));
+    size_t restlen = strlen(rest);
+    assert(restlen <= 9);
+    memcpy(restbuf + (9 - restlen), rest, restlen);
+    rest = restbuf;
+
+    const char *head = asn1p_itoa(v / 1000000000L);
+    assert(head);
+    int ret = snprintf(tmp_buf, sizeof(tmp_buf), "%s%s%s", sign ? "-" : "",
+                       head, rest);
+    assert(ret > 0 && ret < sizeof(tmp_buf));
+    if(size <= ret)
+        return -1;
+    memcpy(buf, tmp_buf, ret);
+    buf[ret] = '\0';
+    return ret;
+}
+
diff --git a/libasn1parser/asn1p_integer.h b/libasn1parser/asn1p_integer.h
new file mode 100644
index 0000000..7cd6058
--- /dev/null
+++ b/libasn1parser/asn1p_integer.h
@@ -0,0 +1,45 @@
+#ifndef	ASN1P_INTEGER_H
+#define	ASN1P_INTEGER_H
+
+#ifdef	HAVE_CONFIG_H
+#include "config.h"
+#endif	/* HAVE_CONFIG_H */
+
+#ifdef	HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif	/* HAVE_SYS_TYPES_H */
+#ifdef	HAVE_INTTYPES_H
+#include <inttypes.h>		/* POSIX 1003.1-2001, C99 */
+#else	/* HAVE_INTTYPES_H */
+#ifdef	HAVE_STDINT_H
+#include <stdint.h>		/* SUSv2+ */
+#endif	/* HAVE_STDINT_H */
+#endif	/* HAVE_INTTYPES_H */
+
+/*
+ * Basic integer type used in numerous places.
+ * ASN.1 does not define any limits on this number, so it must be sufficiently
+ * large to accomodate typical inputs. It does not have to be a dynamically
+ * allocated type with potentially unlimited width: consider the width of
+ * an integer defined here as one of the "compiler limitations".
+ * NOTE: this is NOT a type for ASN.1 "INTEGER" type representation, this
+ * type is used by the compiler itself to handle large integer values
+ * specified inside ASN.1 grammar.
+ */
+#ifdef  HAVE_128_BIT_INT
+typedef	__int128 asn1c_integer_t;
+#else
+typedef	intmax_t asn1c_integer_t;
+#endif
+
+int asn1p_atoi(const char *ptr, asn1c_integer_t *r_value);
+const char *asn1p_itoa(asn1c_integer_t value);   /* Ptr to a static buf */
+/*
+ * Return values:
+ * -1: The value did not fit in the buffer.
+ * >0: The length in bytes of the stringified numeric value.
+ */
+int asn1p_itoa_s(char *buf, size_t size,
+                 asn1c_integer_t value); /* Return -1 on error, or length. */
+
+#endif	/* ASN1P_INTEGER_H */
diff --git a/libasn1parser/asn1parser.c b/libasn1parser/asn1parser.c
index 42982c6..405c880 100644
--- a/libasn1parser/asn1parser.c
+++ b/libasn1parser/asn1parser.c
@@ -165,23 +165,3 @@
 	}
 	return 0;
 }
-
-
-int
-asn1p_atoi(const char *ptr, asn1c_integer_t *value) {
-	errno = 0;	/* Clear the error code */
-
-	if(sizeof(*value) <= sizeof(int)) {
-		*value = strtol(ptr, 0, 10);
-	} else {
-#ifdef	HAVE_STRTOIMAX
-		*value = strtoimax(ptr, 0, 10);
-#elif	HAVE_STRTOLL
-		*value = strtoll(ptr, 0, 10);
-#else
-		*value = strtol(ptr, 0, 10);
-#endif
-	}
-
-	return errno == 0 ? 0 : -1;
-}
diff --git a/libasn1parser/asn1parser.h b/libasn1parser/asn1parser.h
index 4e6f288..8f1a3b2 100644
--- a/libasn1parser/asn1parser.h
+++ b/libasn1parser/asn1parser.h
@@ -8,36 +8,7 @@
 #include "config.h"
 #endif	/* HAVE_CONFIG_H */
 
-#ifdef	HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif	/* HAVE_SYS_TYPES_H */
-#ifdef	HAVE_INTTYPES_H
-#include <inttypes.h>		/* POSIX 1003.1-2001, C99 */
-#else	/* HAVE_INTTYPES_H */
-#ifdef	HAVE_STDINT_H
-#include <stdint.h>		/* SUSv2+ */
-#endif	/* HAVE_STDINT_H */
-#endif	/* HAVE_INTTYPES_H */
-
-/*
- * Basic integer type used in numerous places.
- * ASN.1 does not define any limits on this number, so it must be sufficiently
- * large to accomodate typical inputs. It does not have to be a dynamically
- * allocated type with potentially unlimited width: consider the width of
- * an integer defined here as one of the "compiler limitations".
- * NOTE: this is NOT a type for ASN.1 "INTEGER" type representation, this
- * type is used by the compiler itself to handle large integer values
- * specified inside ASN.1 grammar.
- */
-typedef	intmax_t asn1c_integer_t;
-#ifdef	PRIdMAX
-#define	PRIdASN	PRIdMAX
-#define	PRIuASN	PRIuMAX
-#else
-#define	PRIdASN	"lld"	/* Or j? */
-#define	PRIuASN	"llu"	/* Or j? */
-#endif
-
+#include "asn1p_integer.h"
 #include "asn1p_list.h"
 #include "asn1p_oid.h"		/* Object identifiers (OIDs) */
 #include "asn1p_module.h"	/* ASN.1 definition module */
@@ -69,7 +40,6 @@
 asn1p_t	*asn1p_parse_buffer(const char *buffer, int size /* = -1 */,
 	enum asn1p_flags);
 
-int asn1p_atoi(const char *ptr, asn1c_integer_t *r_value);
 int asn1p_lex_destroy();
 
 #endif	/* ASN1PARSER_H */
diff --git a/libasn1print/asn1print.c b/libasn1print/asn1print.c
index 9d0004f..037e713 100644
--- a/libasn1print/asn1print.c
+++ b/libasn1print/asn1print.c
@@ -156,11 +156,11 @@
 		if(arcname) {
 			accum += safe_printf("%s", arcname);
 			if(oid->arcs[ac].number >= 0) {
-				accum += safe_printf("(%" PRIdASN ")",
-					oid->arcs[ac].number);
+				accum += safe_printf("(%s)",
+					asn1p_itoa(oid->arcs[ac].number));
 			}
 		} else {
-			accum += safe_printf("%" PRIdASN, oid->arcs[ac].number);
+			accum += safe_printf("%s", asn1p_itoa(oid->arcs[ac].number));
 		}
 	}
 	safe_printf(" }");
@@ -214,7 +214,7 @@
 			val->value.v_type, flags, 0);
 		return 0;
 	case ATV_INTEGER:
-		safe_printf("%" PRIdASN, val->value.v_integer);
+		safe_printf("%s", asn1p_itoa(val->value.v_integer));
 		return 0;
 	case ATV_MIN: safe_printf("MIN"); return 0;
 	case ATV_MAX: safe_printf("MAX"); return 0;
@@ -476,7 +476,7 @@
 		if(as_char) {
 			safe_printf("\"%c\"", (unsigned char)edge->value);
 		} else {
-			safe_printf("%" PRIdASN, edge->value);
+			safe_printf("%s", asn1p_itoa(edge->value));
 		}
 	}
 	return 0;