show constraint
diff --git a/libasn1print/asn1print.c b/libasn1print/asn1print.c
index 486f025..d4e24bc 100644
--- a/libasn1print/asn1print.c
+++ b/libasn1print/asn1print.c
@@ -4,6 +4,7 @@
 #include <errno.h>
 #include <assert.h>
 
+#include <asn1_buffer.h>
 #include <asn1_namespace.h>
 #include <asn1parser.h>
 #include <asn1fix_export.h>
@@ -11,6 +12,14 @@
 
 #include "asn1print.h"
 
+static abuf all_output_;
+
+typedef enum {
+    PRINT_STDOUT,
+    GLOBAL_BUFFER,
+} print_method_e;
+static print_method_e print_method_;
+
 #define	INDENT(fmt, args...)    do {        \
         if(!(flags & APF_NOINDENT)) {       \
             int tmp_i = level;              \
@@ -21,29 +30,50 @@
 
 static int asn1print_module(asn1p_t *asn, asn1p_module_t *mod, enum asn1print_flags flags);
 static int asn1print_oid(int prior_len, asn1p_oid_t *oid, enum asn1print_flags flags);
-static int asn1print_ref(asn1p_ref_t *ref, enum asn1print_flags flags);
-static int asn1print_tag(asn1p_expr_t *tc, enum asn1print_flags flags);
-static int asn1print_params(asn1p_paramlist_t *pl,enum asn1print_flags flags);
-static int asn1print_with_syntax(asn1p_wsyntx_t *wx, enum asn1print_flags flags);
-static int asn1print_constraint(asn1p_constraint_t *, enum asn1print_flags);
-static int asn1print_value(asn1p_value_t *val, enum asn1print_flags flags);
+static int asn1print_ref(const asn1p_ref_t *ref, enum asn1print_flags flags);
+static int asn1print_tag(const asn1p_expr_t *tc, enum asn1print_flags flags);
+static int asn1print_params(const asn1p_paramlist_t *pl,enum asn1print_flags flags);
+static int asn1print_with_syntax(const asn1p_wsyntx_t *wx, enum asn1print_flags flags);
+static int asn1print_constraint(const asn1p_constraint_t *, enum asn1print_flags);
+static int asn1print_value(const asn1p_value_t *val, enum asn1print_flags flags);
 static int asn1print_expr(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags, int level);
 static int asn1print_expr_dtd(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags, int level);
 
 /* Check printf's error code, to be pedantic. */
 static int safe_printf(const char *fmt, ...) {
+    int ret;
     va_list ap;
     va_start(ap, fmt);
-    int ret = vprintf(fmt, ap);
+
+    switch(print_method_) {
+    case PRINT_STDOUT:
+        ret = vprintf(fmt, ap);
+        break;
+    case GLOBAL_BUFFER:
+        ret = abuf_vprintf(&all_output_, fmt, ap);
+        break;
+    }
     assert(ret >= 0);
     va_end(ap);
+
     return ret;
 }
 
 /* Pedantically check fwrite's return value. */
-static size_t safe_fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream) {
-    size_t ret = fwrite(ptr, 1, size * nitems, stream);
-    assert(ret == size * nitems);
+static size_t safe_fwrite(const void *ptr, size_t size) {
+    size_t ret;
+
+    switch(print_method_) {
+    case PRINT_STDOUT:
+        ret = fwrite(ptr, 1, size, stdout);
+        assert(ret == size);
+        break;
+    case GLOBAL_BUFFER:
+        abuf_add_bytes(&all_output_, ptr, size);
+        ret = size;
+        break;
+    }
+
     return ret;
 }
 
@@ -170,7 +200,7 @@
 }
 
 static int
-asn1print_ref(asn1p_ref_t *ref, enum asn1print_flags flags) {
+asn1print_ref(const asn1p_ref_t *ref, enum asn1print_flags flags) {
 
 	(void)flags;	/* Unused argument */
 
@@ -183,8 +213,8 @@
 }
 
 static int
-asn1print_tag(asn1p_expr_t *tc, enum asn1print_flags flags) {
-	struct asn1p_type_tag_s *tag = &tc->tag;
+asn1print_tag(const asn1p_expr_t *tc, enum asn1print_flags flags) {
+	const struct asn1p_type_tag_s *tag = &tc->tag;
 
 	(void)flags;	/* Unused argument */
 
@@ -194,7 +224,7 @@
 }
 
 static int
-asn1print_value(asn1p_value_t *val, enum asn1print_flags flags) {
+asn1print_value(const asn1p_value_t *val, enum asn1print_flags flags) {
 
 	if(val == NULL)
 		return 0;
@@ -236,22 +266,22 @@
 	case ATV_STRING:
 		{
 			char *p = (char *)val->value.string.buf;
-			putchar('"');
+			safe_printf("\"");
 			if(strchr(p, '"')) {
 				/* Mask quotes */
 				for(; *p; p++) {
 					if(*p == '"')
-						putchar(*p);
-					putchar(*p);
+						safe_printf("%c", *p);
+                    safe_printf("%c", *p);
 				}
 			} else {
-				fputs(p, stdout);
+				safe_printf("%s", p);
 			}
-			putchar('"');
+			safe_printf("\"");
 		}
 		return 0;
 	case ATV_UNPARSED:
-		fputs((char *)val->value.string.buf, stdout);
+		safe_printf("%s", (char *)val->value.string.buf);
 		return 0;
 	case ATV_BITVECTOR:
 		{
@@ -267,14 +297,14 @@
 				for(i = 0; i < bits; i++) {
 					uint8_t uc;
 					uc = bitvector[i>>3];
-					putchar(((uc >> (7-(i%8)))&1)?'1':'0');
+					safe_printf("%c", ((uc >> (7-(i%8)))&1)?'1':'0');
 				}
 				safe_printf("'B");
 			} else {
 				char hextable[16] = "0123456789ABCDEF";
 				for(i = 0; i < (bits>>3); i++) {
-					putchar(hextable[bitvector[i] >> 4]);
-					putchar(hextable[bitvector[i] & 0x0f]);
+					safe_printf("%c", hextable[bitvector[i] >> 4]);
+					safe_printf("%c", hextable[bitvector[i] & 0x0f]);
 				}
 				safe_printf("'H");
 			}
@@ -294,8 +324,18 @@
 	return 0;
 }
 
+const char *
+asn1p_constraint_string(const asn1p_constraint_t *ct) {
+    size_t old_len = all_output_.length;
+    print_method_e old_method = print_method_;
+    print_method_ = GLOBAL_BUFFER;
+    asn1print_constraint(ct, APF_NOINDENT);
+    print_method_ = old_method;
+    return &all_output_.buffer[old_len];
+}
+
 static int
-asn1print_constraint(asn1p_constraint_t *ct, enum asn1print_flags flags) {
+asn1print_constraint(const asn1p_constraint_t *ct, enum asn1print_flags flags) {
 	int symno = 0;
 
 	if(ct == 0) return 0;
@@ -353,8 +393,7 @@
 				asn1p_constraint_t *cel = ct->elements[i];
 				if(i) safe_printf(", ");
 				safe_fwrite(cel->value->value.string.buf,
-					1, cel->value->value.string.size,
-					stdout);
+					cel->value->value.string.size);
 				if(cel->el_count) {
 					assert(cel->el_count == 1);
 					safe_printf(" ");
@@ -374,8 +413,7 @@
 	case ACT_CT_CTDBY:
 		safe_printf("CONSTRAINED BY ");
 		assert(ct->value->type == ATV_UNPARSED);
-		safe_fwrite(ct->value->value.string.buf,
-			1, ct->value->value.string.size, stdout);
+		safe_fwrite(ct->value->value.string.buf, ct->value->value.string.size);
 		break;
 	case ACT_CT_CTNG:
 		safe_printf("CONTAINING ");
@@ -399,13 +437,13 @@
 					"", "(" };
 			unsigned int i;
 			for(i = 0; i < ct->el_count; i++) {
-				if(i) fputs(symtable[symno], stdout);
-				if(ct->type == ACT_CA_CRC) fputs("{", stdout);
+				if(i) safe_printf("%s", symtable[symno]);
+				if(ct->type == ACT_CA_CRC) safe_printf("{");
 				asn1print_constraint(ct->elements[i], flags);
-				if(ct->type == ACT_CA_CRC) fputs("}", stdout);
+				if(ct->type == ACT_CA_CRC) safe_printf("}");
 				if(i+1 < ct->el_count
 				&& ct->type == ACT_CA_SET)
-					fputs(")", stdout);
+					safe_printf(")");
 			}
 		}
 		break;
@@ -426,7 +464,7 @@
 }
 
 static int
-asn1print_params(asn1p_paramlist_t *pl, enum asn1print_flags flags) {
+asn1print_params(const asn1p_paramlist_t *pl, enum asn1print_flags flags) {
 	if(pl) {
 		int i;
 		safe_printf("{");
@@ -445,9 +483,9 @@
 }
 
 static int
-asn1print_with_syntax(asn1p_wsyntx_t *wx, enum asn1print_flags flags) {
+asn1print_with_syntax(const asn1p_wsyntx_t *wx, enum asn1print_flags flags) {
 	if(wx) {
-		asn1p_wsyntx_chunk_t *wc;
+		const asn1p_wsyntx_chunk_t *wc;
 		TQ_FOR(wc, &(wx->chunks), next) {
 		  switch(wc->type) {
 		  case WC_LITERAL:
@@ -468,7 +506,7 @@
 }
 
 static int
-asn1print_crange_value(asn1cnst_edge_t *edge, int as_char) {
+asn1print_crange_value(const asn1cnst_edge_t *edge, int as_char) {
 	switch(edge->type) {
 	case ARE_MIN: safe_printf("MIN"); break;
 	case ARE_MAX: safe_printf("MAX"); break;
diff --git a/libasn1print/asn1print.h b/libasn1print/asn1print.h
index 02ac4be..1666b99 100644
--- a/libasn1print/asn1print.h
+++ b/libasn1print/asn1print.h
@@ -15,5 +15,6 @@
  */
 int asn1print(asn1p_t *asn, enum asn1print_flags flags);
 
+const char *asn1p_constraint_string(const asn1p_constraint_t *ct);
 
 #endif	/* ASN1PRINT_H */