-pdu=* changes

diff --git a/ChangeLog b/ChangeLog
index 6976a65..ffdabe9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
 
+0.9.22:	2006-Sep-22
+
+	* Added -pdu=all and -pdu=<type> switches to asn1c.
+
 0.9.21:	2006-Sep-17
 
 	* skeletons/standard-modules directory is now used for standard types.
diff --git a/asn1c/asn1c.1 b/asn1c/asn1c.1
index e3b2b1d..871e2b1 100644
--- a/asn1c/asn1c.1
+++ b/asn1c/asn1c.1
@@ -4,7 +4,7 @@
 .SH SYNOPSIS
 asn1c [\fB\-E\fR [\fB-F\fR] | \fB\-P\fR | \fB\-R\fR]
       [\fB\-S\fR\fIdir\fR] [\fB-X\fR]
-      [\fB\-W\fR\fIdebug-\fR...] [\fB\-f\fR\fIoption\fR] [\fB\-gen-\fR\fIoption\fR] [\fB\-pdu=\fR\fIoption\fR]
+      [\fB\-W\fR\fIdebug-\fR...] [\fB\-f\fR\fIoption\fR] [\fB\-gen-\fR\fIoption\fR] [\fB\-pdu=\fR{\fBall\fR|\fBauto\fR|\fIType\fR}\fR]
       [\fB\-print-\fR\fIoption\fR]
       \fIinfile\fR...
 .SH DESCRIPTION
@@ -30,7 +30,7 @@
 .TP
 \fICodecs Generation Options\fR
 .br
-.B \-gen-PER \-pdu=auto
+.B \-gen-PER \-pdu=\fR{\fBall\fR|\fBauto\fR|\fIType\fR}
 .TP
 \fIOutput Options\fR
 .br
@@ -75,7 +75,7 @@
 .B \-Wdebug-compiler
 Enable debugging during the actual compile time.
 .SH LANGUAGE OPTIONS
- .TP
+.TP
 .B \-fbless-SIZE
 Allow SIZE() constraint for INTEGER, ENUMERATED, and other types for which this
 constraint is normally prohibited by the standard. This is a violation of
@@ -119,8 +119,13 @@
 .B \-gen-PER
 Generate Packed Encoding Rules (PER) support code.
 .TP
-.B \-pdu=auto
-Generate PDU tables by discovering Protocol Data Units automatically.
+.B \-pdu=\fR{\fBall\fR|\fBauto\fR|\fIType\fR}
+Create a PDU table for specified types, or discover Protocol Data Units
+automatically. In case of -pdu=\fBall\fR, all ASN.1 types defined in
+all modules will form a PDU table. In case of -pdu=\fBauto\fR, all types
+not referenced by any other type will form a PDU table.
+If \fIType\fR is an ASN.1 type identifier, it is added to a PDU table.
+The last form may be specified multiple times to add any number of PDUs.
 .SH OUTPUT OPTIONS
 .TP
 .B \-print-constraints
diff --git a/asn1c/asn1c.c b/asn1c/asn1c.c
index 9b1a3fc..742a0b2 100644
--- a/asn1c/asn1c.c
+++ b/asn1c/asn1c.c
@@ -123,12 +123,19 @@
 	case 'p':
 		if(strncmp(optarg, "du=", 3) == 0) {
 			char *pduname = optarg + 3;
-			if(strcmp(pduname, "auto")) {
-				fprintf(stderr, "-pdu=%s: expected -pdu=auto\n",
+			if(strcmp(pduname, "all") == 0) {
+				asn1_compiler_flags |= A1C_PDU_ALL;
+			} else if(strcmp(pduname, "auto") == 0) {
+				asn1_compiler_flags |= A1C_PDU_AUTO;
+			} else if(pduname[0] >= 'A' && pduname[0] <= 'Z') {
+				asn1c__add_pdu_type(pduname);
+				asn1_compiler_flags |= A1C_PDU_TYPE;
+			} else {
+				fprintf(stderr, "-pdu=%s"
+					": expected -pdu={all|auto|Type}\n",
 					pduname);
 				exit(EX_USAGE);
 			}
-			asn1_compiler_flags |= A1C_PDU_AUTO;
 		} else if(strcmp(optarg, "rint-class-matrix") == 0) {
 			asn1_printer_flags |= APF_PRINT_CLASS_MATRIX;
 		} else if(strcmp(optarg, "rint-constraints") == 0) {
@@ -456,7 +463,7 @@
 "\n"
 
 "  -gen-PER              Generate PER support code\n"
-"  -pdu=auto             Generate PDU table (discover PDUs automatically)\n"
+"  -pdu={all|auto|Type}  Generate PDU table (discover PDUs automatically)\n"
 "\n"
 
 "  -print-class-matrix   Print out the collected object class matrix (debug)\n"
diff --git a/examples/sample.makefile.regen b/examples/sample.makefile.regen
index 5072c18..4c39f78 100755
--- a/examples/sample.makefile.regen
+++ b/examples/sample.makefile.regen
@@ -23,12 +23,14 @@
 	exit
 fi
 
+CMDOPTS="-pdu=${ASN1PDU} ${ASN1CMDOPTS} ${ASN1MODULES}"
+
 if test -x ../../asn1c/asn1c ; then
   echo "Compiling ${ASN1MODULES} using local compiler"
-  ../../asn1c/asn1c -S ../../skeletons ${ASN1CMDOPTS} ${ASN1MODULES} || exit $?
+  ../../asn1c/asn1c -S ../../skeletons ${CMDOPTS} || exit $?
 else
   echo "Compiling ${ASN1MODULES} using system compiler"
-  asn1c ${ASN1CMDOPTS} ${ASN1MODULES} || exit $?
+  asn1c ${CMDOPTS} || exit $?
 fi
 
 if test ! -f Makefile.am.sample ; then
@@ -36,15 +38,14 @@
 	exit 1
 fi
 
-ASN1DEFPDU=`echo "$ASN1PDU" | tr - _`
-CFLAGS="-DPDU=${ASN1DEFPDU}"
+EXTRA_CFLAGS=""
 if test -f config.h ; then
-	CFLAGS="-DHAVE_CONFIG_H $CFLAGS"
+	EXTRA_CFLAGS="-DHAVE_CONFIG_H $EXTRA_CFLAGS"
 fi
 
 set -x
 cat Makefile.am.sample						\
-	| sed -e "s/^CFLAGS += /CFLAGS += ${CFLAGS} /"		\
+	| sed -e "s/^CFLAGS += /CFLAGS += ${EXTRA_CFLAGS} /"	\
 	| sed -e "s/^all: /all: ${ASN1PDU}.c /"			\
 	| sed -e "s/progname/${PROGNAME}/"			\
 	> Makefile.$$
diff --git a/examples/sample.source.RRC/Makefile b/examples/sample.source.RRC/Makefile
index 1ff6d82..42ad07b 100644
--- a/examples/sample.source.RRC/Makefile
+++ b/examples/sample.source.RRC/Makefile
@@ -4740,7 +4740,7 @@
 # This file may be used as an input for make(3)
 # Remove the lines below to convert it into a pure .am file
 TARGET = rrc-dump
-CFLAGS += -DHAVE_CONFIG_H -DPDU=DL_DCCH_Message -DASN_PDU_COLLECTION -I.
+CFLAGS += -DHAVE_CONFIG_H  -DPDU=DL_DCCH_Message -DASN_PDU_COLLECTION -I.
 OBJS=${ASN_MODULE_SOURCES:.c=.o} ${ASN_CONVERTER_SOURCES:.c=.o}
 
 all: DL-DCCH-Message.c $(TARGET)
@@ -4761,7 +4761,7 @@
 regen: regenerate-from-asn1-source
 
 regenerate-from-asn1-source:
-	../../asn1c/asn1c -S ../../skeletons -fcompound-names -pdu=auto -gen-PER ../rrc.asn1
+	../../asn1c/asn1c -S ../../skeletons -pdu=DL-DCCH-Message -pdu=auto -fcompound-names -gen-PER ../rrc.asn1
 
 
 DL-DCCH-Message.c: ../sample.makefile.regen ../rrc.asn1
@@ -4770,7 +4770,7 @@
 	make
 
 regen-makefile:
-	ASN1CMDOPTS="-fcompound-names -pdu=auto -gen-PER" \
+	ASN1CMDOPTS="-pdu=auto -fcompound-names -gen-PER" \
 	ASN1MODULES="../rrc.asn1" \
 	ASN1PDU=DL-DCCH-Message \
 	PROGNAME=rrc-dump \
diff --git a/libasn1compiler/asn1c_internal.h b/libasn1compiler/asn1c_internal.h
index fdf953d..c37620c 100644
--- a/libasn1compiler/asn1c_internal.h
+++ b/libasn1compiler/asn1c_internal.h
@@ -51,7 +51,6 @@
 	struct compiler_streams *target;
 
 	asn1p_t		*asn;
-	//asn1p_module_t	*mod;
 	asn1p_expr_t	*expr;
 
 	int embed;
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index 06fc97d..4236e95 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -11,8 +11,12 @@
 static int asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *, int, char **);
 static int asn1c_copy_over(arg_t *arg, char *path);
 static int identical_files(const char *fname1, const char *fname2);
+static int need_to_generate_pdu_collection(arg_t *arg);
 static int generate_pdu_collection_file(arg_t *arg);
 static int generate_preamble(arg_t *, FILE *, int optc, char **argv);
+static int include_type_to_pdu_collection(arg_t *arg);
+static void pdu_collection_print_unused_types(arg_t *arg);
+static const char *generate_pdu_C_definition(void);
 
 int
 asn1c_save_compiled_output(arg_t *arg, const char *datadir,
@@ -121,7 +125,7 @@
 		}
 	}
 
-	if(arg->flags & A1C_PDU_AUTO) {
+	if(need_to_generate_pdu_collection(arg)) {
 		fprintf(mkf, "ASN_CONVERTER_SOURCES+=pdu_collection.c\n");
 		if(generate_pdu_collection_file(arg))
 			return -1;
@@ -135,7 +139,7 @@
 		"# This file may be used as an input for make(3)\n"
 		"# Remove the lines below to convert it into a pure .am file\n"
 		"TARGET = progname\n"
-		"CFLAGS +=%s -I.\n"
+		"CFLAGS +=%s%s -I.\n"
 		"OBJS=${ASN_MODULE_SOURCES:.c=.o}"
 		  " ${ASN_CONVERTER_SOURCES:.c=.o}\n"
 		"\nall: $(TARGET)\n"
@@ -150,7 +154,10 @@
 		"\n\trm -f $(OBJS)\n"
 		"\nregen: regenerate-from-asn1-source\n"
 		"\nregenerate-from-asn1-source:\n\t"
-		, (arg->flags & A1C_PDU_AUTO) ? " -DASN_PDU_COLLECTION" : ""
+		, (arg->flags & A1C_PDU_TYPE)
+			? generate_pdu_C_definition() : ""
+		, need_to_generate_pdu_collection(arg)
+			? " -DASN_PDU_COLLECTION" : ""
 	);
 
 	for(i = 0; i < argc; i++)
@@ -483,9 +490,7 @@
 
 	TQ_FOR(mod, &(arg->asn->modules), mod_next) {
 		TQ_FOR(arg->expr, &(mod->members), next) {
-			if(arg->expr->_type_referenced
-			|| !asn1_lang_map[arg->expr->meta_type]
-				[arg->expr->expr_type].type_cb)
+			if(!include_type_to_pdu_collection(arg))
 				continue;
 			fprintf(fp, "extern struct asn_TYPE_descriptor_s "
 				"asn_DEF_%s;\n",
@@ -498,9 +503,7 @@
 	TQ_FOR(mod, &(arg->asn->modules), mod_next) {
 		int mod_printed = 0;
 		TQ_FOR(arg->expr, &(mod->members), next) {
-			if(arg->expr->_type_referenced
-			|| !asn1_lang_map[arg->expr->meta_type]
-				[arg->expr->expr_type].type_cb)
+			if(!include_type_to_pdu_collection(arg))
 				continue;
 			if(!mod_printed++)
 			fprintf(fp, "\t/* From module %s in %s */\n",
@@ -513,9 +516,92 @@
 
 	fprintf(fp, "\t0\n};\n\n");
 
+	pdu_collection_print_unused_types(arg);
+
 	fclose(fp);
 	fprintf(stderr, "Generated pdu_collection.c\n");
 
 	return 0;
 }
 
+static struct PDUType {
+	char *typename;
+	int used;
+} *pduType;
+static int pduTypes;
+
+static const char *
+generate_pdu_C_definition(void) {
+	const char *src;
+	char *def;
+	char *dst;
+	if(pduTypes == 0) return "";
+	def = malloc(strlen(pduType[0].typename) + 20);
+	strcpy(def, " -DPDU=");
+	for(src = pduType[0].typename, dst = def + 7; *src; src++, dst++)
+		if((*dst = *src) == '-')
+			*dst = '_';
+	*dst = 0;
+	return def;
+}
+
+void
+asn1c__add_pdu_type(const char *ctypename) {
+	char *typename = strdup(ctypename);
+	assert(typename && *typename);
+
+	pduType = realloc(pduType, sizeof(pduType[0]) * (pduTypes + 1));
+	assert(pduType);
+	pduType[pduTypes].used = 0;
+	pduType[pduTypes].typename = typename;
+	pduTypes++;
+}
+
+static int
+asn1c__pdu_type_lookup(const char *typename) {
+	int i;
+	for(i = 0; i < pduTypes; i++) {
+		struct PDUType *pt = &pduType[i];
+		if(strcmp(pt->typename, typename) == 0) {
+			pt->used++;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int
+need_to_generate_pdu_collection(arg_t *arg) {
+	if(arg->flags & (A1C_PDU_ALL|A1C_PDU_AUTO))
+		return 1;
+	if(arg->flags & A1C_PDU_TYPE)
+		return (pduTypes > 1) ? 1 : 0;
+	return 0;
+}
+
+static void
+pdu_collection_print_unused_types(arg_t *arg) {
+	int i;
+	for(i = 0; i < pduTypes; i++) {
+		struct PDUType *pt = &pduType[i];
+		if(!pt->used) {
+			WARNING("Missing type specified in -pdu=%s",
+				pt->typename);
+		}
+	}
+}
+
+static int
+include_type_to_pdu_collection(arg_t *arg) {
+	if(!asn1_lang_map[arg->expr->meta_type]
+		[arg->expr->expr_type].type_cb)
+		return 0;
+
+	if((arg->flags & A1C_PDU_ALL)
+	|| ((arg->flags & A1C_PDU_AUTO) && !arg->expr->_type_referenced)
+	|| asn1c__pdu_type_lookup(arg->expr->Identifier)) {
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/libasn1compiler/asn1compiler.h b/libasn1compiler/asn1compiler.h
index 39352f9..6078262 100644
--- a/libasn1compiler/asn1compiler.h
+++ b/libasn1compiler/asn1compiler.h
@@ -62,10 +62,12 @@
 	 */
 	A1C_GEN_PER		= 0x1000,
 	/*
-	 * -pdu=auto
+	 * -pdu={all|auto|Type}
 	 * Generate PDU table
 	 */
-	A1C_PDU_AUTO		= 0x2000
+	A1C_PDU_ALL		= 0x2000,
+	A1C_PDU_AUTO		= 0x4000,
+	A1C_PDU_TYPE		= 0x8000
 };
 
 /*
@@ -74,4 +76,6 @@
 int asn1_compile(asn1p_t *asn, const char *datadir, enum asn1c_flags,
 	int argc, int optc, char **argv);
 
+void asn1c__add_pdu_type(const char *typename);
+
 #endif	/* ASN1_COMPILER_H */