-fknown-extern-type support

diff --git a/libasn1fix/asn1fix.h b/libasn1fix/asn1fix.h
index 4847330..58ca537 100644
--- a/libasn1fix/asn1fix.h
+++ b/libasn1fix/asn1fix.h
@@ -27,4 +27,10 @@
 	enum asn1f_flags,
 	void (*error_log_callback)(int _severity, const char *fmt, ...));
 
+
+/*
+ * Explicitly mark type as known.
+ */
+int asn1f_make_known_external_type(const char *);
+
 #endif	/* ASN1FIX_H */
diff --git a/libasn1fix/asn1fix_dereft.c b/libasn1fix/asn1fix_dereft.c
index f0ec9a6..1f9b5bf 100644
--- a/libasn1fix/asn1fix_dereft.c
+++ b/libasn1fix/asn1fix_dereft.c
@@ -28,9 +28,19 @@
 	 */
 	type_expr = asn1f_find_terminal_type(arg, expr, 0);
 	if(type_expr == NULL) {
+		const char *type_name;
+
+		if(errno == EEXIST) {
+			/* Ignore missing type
+			 * if known to be defined externally:
+			 * -fknown-extern-type=<name>
+			 */
+			return 0;
+		}
+
+		type_name = asn1f_printable_reference(expr->reference);
 		FATAL("Unknown type \"%s\" referenced by \"%s\" at line %d",
-			asn1f_printable_reference(expr->reference),
-			expr->Identifier, expr->_lineno);
+			type_name, expr->Identifier, expr->_lineno);
 		return -1;
 	}
 
diff --git a/libasn1fix/asn1fix_internal.h b/libasn1fix/asn1fix_internal.h
index ff3b4e9..ac543cb 100644
--- a/libasn1fix/asn1fix_internal.h
+++ b/libasn1fix/asn1fix_internal.h
@@ -1,6 +1,10 @@
 #ifndef	_ASN1FIX_INTERNAL_H_
 #define	_ASN1FIX_INTERNAL_H_
 
+#ifdef	HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 /*
  * System headers required in various modules.
  */
diff --git a/libasn1fix/asn1fix_misc.c b/libasn1fix/asn1fix_misc.c
index a9a5378..4ea9495 100644
--- a/libasn1fix/asn1fix_misc.c
+++ b/libasn1fix/asn1fix_misc.c
@@ -1,5 +1,5 @@
 #include "asn1fix_internal.h"
-
+#include "asn1fix.h"
 
 char const *
 asn1f_printable_reference(asn1p_ref_t *ref) {
@@ -274,3 +274,59 @@
 	return count;
 }
 
+
+static char **known_types;
+static int known_types_count;
+static int known_types_size;
+
+static int _known_types_cmp(const void *ap, const void *bp) {
+	const char *a = *(const char * const *)ap;
+	const char *b = *(const char * const *)bp;
+	return strcmp(a, b);
+}
+
+int
+asn1f_make_known_external_type(const char *type_name) {
+	char *tname;
+
+	/* Check for duplicates */
+	if(asn1f_check_known_external_type(type_name) == 0) {
+		errno = EEXIST;
+		return -1;
+	}
+
+	/* Ensure enough space */
+	if(known_types_count <= known_types_size) {
+		int n = known_types_size ? known_types_size << 1 : 4;
+		void *p;
+		p = realloc(known_types, n * sizeof(known_types[0]));
+		if(!p) return -1;
+		known_types = p;
+		known_types_size = n;
+	}
+
+	tname = strdup(type_name);
+	if(!tname) return -1;
+
+	known_types[known_types_count++] = tname;
+
+#ifdef	HAVE_MERGESORT
+	mergesort
+#else
+	qsort
+#endif
+	(known_types, known_types_count, sizeof(known_types[0]),
+		_known_types_cmp);
+
+	return 0;
+}
+
+int
+asn1f_check_known_external_type(const char *type_name) {
+	void *p = bsearch(&type_name, known_types, known_types_count,
+		sizeof(known_types[0]), _known_types_cmp);
+	if(p) return 0;
+	errno = ESRCH;
+	return -1;
+}
+
diff --git a/libasn1fix/asn1fix_misc.h b/libasn1fix/asn1fix_misc.h
index e88e432..a586faa 100644
--- a/libasn1fix/asn1fix_misc.h
+++ b/libasn1fix/asn1fix_misc.h
@@ -44,4 +44,9 @@
  */
 int asn1f_count_children(asn1p_expr_t *parent);
 
+/*
+ * Check if type is explicitly known.
+ */
+int asn1f_check_known_external_type(const char *);
+
 #endif	/* _ASN1FIX_MISC_H_ */
diff --git a/libasn1fix/asn1fix_retrieve.c b/libasn1fix/asn1fix_retrieve.c
index 0dfcce4..f2f91d5 100644
--- a/libasn1fix/asn1fix_retrieve.c
+++ b/libasn1fix/asn1fix_retrieve.c
@@ -228,12 +228,17 @@
 	}
 	if(ref_tc == NULL) {
 		DEBUG("Module \"%s\" does not contain \"%s\" "
-			"mentioned at line %d",
+			"mentioned at line %d: %s",
 			src_mod->Identifier,
 			identifier,
-			ref->_lineno
+			ref->_lineno,
+			strerror(errno)
 		);
-		errno = ESRCH;
+		if(asn1f_check_known_external_type(identifier) == 0) {
+			errno = EEXIST; /* Exists somewhere */
+		} else {
+			errno = ESRCH;
+		}
 		return NULL;
 	}
 
@@ -312,8 +317,9 @@
 	 */
 	tc = asn1f_lookup_symbol(arg, ref, &mod);
 	if(tc == NULL) {
-		DEBUG("\tSymbol \"%s\" not found",
-			asn1f_printable_reference(ref));
+		DEBUG("\tSymbol \"%s\" not found: %s",
+			asn1f_printable_reference(ref),
+			strerror(errno));
 		return NULL;
 	}