-X for XML DTD

diff --git a/libasn1print/asn1print.c b/libasn1print/asn1print.c
index 4132204..a6c3edb 100644
--- a/libasn1print/asn1print.c
+++ b/libasn1print/asn1print.c
@@ -10,7 +10,7 @@
 #include "asn1print.h"
 
 #define	INDENT(fmt, args...)	do {					\
-		int __i = level; while(__i--) putchar(' ');		\
+		int __i = level; while(__i--) printf("    ");		\
 		printf(fmt, ##args);					\
 	} while(0)
 
@@ -22,8 +22,8 @@
 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_expr(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags,
-		int level);
+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);
 
 /*
  * Print the contents of the parsed ASN tree.
@@ -38,6 +38,9 @@
 		return -1;
 	}
 
+	if(flags & APF_PRINT_XML_DTD)
+		printf("<!-- XML DTD generated by asn1c-" VERSION " -->\n\n");
+
 	TQ_FOR(mod, &(asn->modules), mod_next) {
 		if(modno++) printf("\n");
 		asn1print_module(asn, mod, flags);
@@ -50,12 +53,28 @@
 asn1print_module(asn1p_t *asn, asn1p_module_t *mod, enum asn1print_flags flags) {
 	asn1p_expr_t *tc;
 
+	if(flags & APF_PRINT_XML_DTD)
+		printf("<!-- ASN.1 module\n");
+
 	printf("%s ", mod->Identifier);
 	if(mod->module_oid) {
 		asn1print_oid(mod->module_oid, flags);
 		printf("\n");
 	}
 
+	if(flags & APF_PRINT_XML_DTD) {
+		if(mod->source_file_name
+		&& strcmp(mod->source_file_name, "-"))
+			printf("found in %s", mod->source_file_name);
+		printf(" -->\n\n");
+
+		TQ_FOR(tc, &(mod->members), next) {
+			asn1print_expr_dtd(asn, mod, tc, flags, 0);
+		}
+
+		return 0;
+	}
+
 	printf("DEFINITIONS");
 
 	if(mod->module_flags & MSF_TAG_INSTRUCTIONS)
@@ -442,7 +461,7 @@
 	int SEQ_OF = 0;
 
 	if(flags & APF_LINE_COMMENTS)
-	INDENT("-- #line %d\n", tc->_lineno);
+		INDENT("-- #line %d\n", tc->_lineno);
 	if(tc->Identifier)
 		INDENT("%s", tc->Identifier);
 
@@ -539,7 +558,7 @@
 			/*
 			 * Print the expression as it were a stand-alone type.
 			 */
-			asn1print_expr(asn, mod, se, flags, level + 4);
+			asn1print_expr(asn, mod, se, flags, level + 1);
 			if((se->marker.flags & EM_DEFAULT) == EM_DEFAULT) {
 				printf(" DEFAULT ");
 				asn1print_value(se->marker.default_value, flags);
@@ -614,3 +633,115 @@
 	return 0;
 }
 
+
+static int
+asn1print_expr_dtd(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, enum asn1print_flags flags, int level) {
+	asn1p_expr_t *se;
+	int expr_unordered = 0;
+
+	switch(expr->meta_type) {
+	case AMT_TYPE:
+	case AMT_TYPEREF:
+		break;
+	default:
+		if(expr->expr_type == A1TC_UNIVERVAL)
+			break;
+		return 0;
+	}
+
+	if(!expr->Identifier) return 0;
+
+	if(expr->expr_type == ASN_CONSTR_CHOICE
+	|| expr->expr_type == ASN_CONSTR_SEQUENCE_OF
+	|| expr->expr_type == ASN_CONSTR_SET_OF
+	|| expr->expr_type == ASN_CONSTR_SET
+	|| expr->expr_type == ASN_BASIC_INTEGER
+	|| expr->expr_type == ASN_BASIC_ENUMERATED) {
+		expr_unordered = 1;
+	}
+
+	if(flags & APF_LINE_COMMENTS)
+		INDENT("<!-- #line %d -->\n", expr->_lineno);
+	INDENT("<!ELEMENT %s", expr->Identifier);
+
+	if(expr->expr_type == A1TC_REFERENCE) {
+		se = asn1f_find_terminal_type_ex(asn, expr);
+		if(!se) {
+			printf("(ANY)");
+			return 0;
+		}
+		expr = se;
+	}
+
+	if(TQ_FIRST(&expr->members)) {
+		int extensible = 0;
+		printf(" (");
+		TQ_FOR(se, &(expr->members), next) {
+			if(se->expr_type == A1TC_EXTENSIBLE) {
+				extensible = 1;
+				continue;
+			} else if(!se->Identifier
+					&& se->expr_type == A1TC_REFERENCE) {
+				asn1print_ref(se->reference, flags);
+			} else if(se->Identifier) {
+				printf("%s", se->Identifier);
+			} else {
+				printf("ANY");
+			}
+			if(expr->expr_type != ASN_CONSTR_SET
+			&& expr->expr_type != ASN_CONSTR_CHOICE
+			&& expr->expr_type != ASN_BASIC_INTEGER
+			&& expr->expr_type != ASN_BASIC_ENUMERATED) {
+				if(expr_unordered)
+					printf("*");
+				else if(se->marker.flags)
+					printf("?");
+			}
+			if(TQ_NEXT(se, next)
+			&& TQ_NEXT(se, next)->expr_type != A1TC_EXTENSIBLE) {
+				printf(expr_unordered?"|":", ");
+			}
+		}
+		if(extensible) {
+			printf(expr_unordered?"|":", ");
+			printf("ANY");
+			if(expr->expr_type != ASN_CONSTR_SET
+			&& expr->expr_type != ASN_CONSTR_CHOICE
+			&& expr->expr_type != ASN_BASIC_INTEGER
+			&& expr->expr_type != ASN_BASIC_ENUMERATED)
+				printf("*");
+		}
+
+		printf(")");
+		if(expr->expr_type == ASN_CONSTR_SET)
+			printf("*");
+
+	} else if((expr->expr_type & ASN_CONSTR_MASK)
+		|| expr->expr_type == ASN_BASIC_NULL) {
+		printf(" EMPTY");
+	} else if(expr->expr_type == A1TC_UNIVERVAL) {
+		printf(" EMPTY");
+	} else if(expr->expr_type == ASN_TYPE_ANY) {
+		printf(" ANY"); 
+	} else if(expr->expr_type == ASN_BASIC_BIT_STRING
+		|| expr->expr_type == ASN_BASIC_OBJECT_IDENTIFIER
+		|| expr->expr_type == ASN_BASIC_RELATIVE_OID
+		|| expr->expr_type == ASN_BASIC_UTCTime
+		|| expr->expr_type == ASN_BASIC_GeneralizedTime
+	) {
+		printf(" (#CDATA)");
+	} else {
+		printf(" (#PCDATA)");
+	}
+	printf(">\n");
+
+	/*
+	 * Display the descendants (children) of the current type.
+	 */
+	TQ_FOR(se, &(expr->members), next) {
+		if(se->expr_type == A1TC_EXTENSIBLE) continue;
+		asn1print_expr_dtd(asn, mod, se, flags, level + 1);
+	}
+
+	return 0;
+}