naming abstraction
diff --git a/libasn1compiler/Makefile.am b/libasn1compiler/Makefile.am
index 590ae28..8993de2 100644
--- a/libasn1compiler/Makefile.am
+++ b/libasn1compiler/Makefile.am
@@ -9,15 +9,16 @@
 
 noinst_LTLIBRARIES = libasn1compiler.la
 
-libasn1compiler_la_SOURCES =			\
-	asn1compiler.c asn1compiler.h		\
-	asn1c_misc.c asn1c_misc.h		\
-	asn1c_out.c asn1c_out.h			\
-	asn1c_lang.c asn1c_lang.h		\
-	asn1c_save.c asn1c_save.h		\
-	asn1c_C.c asn1c_C.h			\
-	asn1c_constraint.c asn1c_constraint.h	\
-	asn1c_compat.c asn1c_compat.h		\
-	asn1c_ioc.c asn1c_ioc.h		\
-	asn1c_fdeps.c asn1c_fdeps.h		\
-	asn1c_internal.h
+libasn1compiler_la_SOURCES =                \
+    asn1compiler.c asn1compiler.h           \
+    asn1c_misc.c asn1c_misc.h               \
+    asn1c_out.c asn1c_out.h                 \
+    asn1c_lang.c asn1c_lang.h               \
+    asn1c_naming.c asn1c_naming.h           \
+    asn1c_save.c asn1c_save.h               \
+    asn1c_C.c asn1c_C.h                     \
+    asn1c_constraint.c asn1c_constraint.h   \
+    asn1c_compat.c asn1c_compat.h           \
+    asn1c_ioc.c asn1c_ioc.h                 \
+    asn1c_fdeps.c asn1c_fdeps.h             \
+    asn1c_internal.h
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index e5ec734..82d67ef 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -8,6 +8,7 @@
 #include "asn1c_out.h"
 #include "asn1c_misc.h"
 #include "asn1c_ioc.h"
+#include "asn1c_naming.h"
 #include <asn1print.h>
 #include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
 #include <asn1fix_export.h>	/* other exportables from libasn1fix */
@@ -140,15 +141,12 @@
 	if(expr->expr_type == ASN_BASIC_ENUMERATED || el_count) {
 		eidx = 0;
 		REDIR(OT_DEPS);
-		OUT("typedef enum ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" {\n");
+		OUT("typedef %s {\n", c_name(arg).members_enum);
 		TQ_FOR(v, &(expr->members), next) {
 			switch(v->expr_type) {
 			case A1TC_UNIVERVAL:
 				OUT("\t");
-				out_name_chain(arg, ONC_noflags);
-				OUT("_%s", MKID(v));
+				OUT("%s", c_member_name(arg, v));
 				OUT("\t= %s%s\n",
 					asn1p_itoa(v->value->value.v_integer),
 					(eidx+1 < el_count) ? "," : "");
@@ -167,9 +165,7 @@
 				return -1;
 			}
 		}
-		OUT("} e_");
-			out_name_chain(arg, ONC_noflags);
-		OUT(";\n");
+		OUT("} %s;\n", c_name(arg).members_name);
 		assert(eidx == el_count);
 	}
 
@@ -275,9 +271,7 @@
 	if(el_count) {
 		int eidx = 0;
 		REDIR(OT_DEPS);
-		OUT("typedef enum ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" {\n");
+		OUT("typedef %s {\n", c_name(arg).members_enum);
 		TQ_FOR(v, &(expr->members), next) {
 			if(v->expr_type != A1TC_UNIVERVAL) {
 				OUT("/* Unexpected BIT STRING element: %s */\n",
@@ -286,15 +280,12 @@
 			}
 			eidx++;
 			OUT("\t");
-			out_name_chain(arg, ONC_noflags);
-			OUT("_%s", MKID(v));
+			OUT("%s", c_member_name(arg, v));
 			OUT("\t= %s%s\n",
 				asn1p_itoa(v->value->value.v_integer),
 				(eidx < el_count) ? "," : "");
 		}
-		OUT("} e_");
-			out_name_chain(arg, ONC_noflags);
-		OUT(";\n");
+		OUT("} %s;\n", c_name(arg).members_name);
 		assert(eidx == el_count);
 	}
 
@@ -355,13 +346,10 @@
 			REDIR(OT_FWD_DEFS);
 			OUT("typedef ");
 		}
-		OUT("struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" {\n");
+		OUT("%s {\n", c_name(arg).full_name);
 	} else {
 		REDIR(OT_TYPE_DECLS);
-		OUT("typedef struct %s {\n",
-			MKID_safe(expr));
+		OUT("typedef %s {\n", c_name(arg).full_name);
 	}
 
 	TQ_FOR(v, &(expr->members), next) {
@@ -390,21 +378,16 @@
 	PCTX_DEF;
 
 	if (arg->embed && expr->_anonymous_type) {
-		OUT("} %s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-		out_name_chain(arg, ONC_avoid_keywords);
-		OUT("%s;\n", arg->embed ? "" : "_t");
+		OUT("} %s%s;\n", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 
 		REDIR(saved_target);
 
-		OUT("%s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-			out_name_chain(arg, ONC_avoid_keywords);
+		OUT("%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 	} else {
-		OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
-		expr->_anonymous_type ? "" :
-			arg->embed
-				? MKID_safe(expr)
-				: MKID(expr),
-		arg->embed ? "" : "_t");
+		OUT("} %s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).short_name);
 	}
 
 	return asn1c_lang_C_type_SEQUENCE_def(arg, ioc_tao.ioct ? &ioc_tao : 0);
@@ -550,10 +533,8 @@
 	OUT("asn_SEQUENCE_specifics_t asn_SPC_%s_specs_%d = {\n",
 		MKID(expr), expr->_type_unique_index);
 	INDENT(+1);
-	OUT("sizeof(struct ");
-		out_name_chain(arg, ONC_avoid_keywords); OUT("),\n");
-	OUT("offsetof(struct ");
-		out_name_chain(arg, ONC_avoid_keywords); OUT(", _asn_ctx),\n");
+	OUT("sizeof(%s),\n", c_name(arg).full_name);
+	OUT("offsetof(%s, _asn_ctx),\n", c_name(arg).full_name);
     emit_tag2member_reference(arg, expr, tag2el_count);
 	if(roms_count + aoms_count) {
 		OUT("asn_MAP_%s_oms_%d,\t/* Optional members */\n",
@@ -587,7 +568,7 @@
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
 	long mcount;
-	char *id;
+	const char *id;
 	int comp_mode = 0;	/* {root,ext=1,root,root,...} */
 	int saved_target = arg->target->target;
 
@@ -600,21 +581,16 @@
 	OUT(" * Method of determining the components presence\n");
 	OUT(" */\n");
 	mcount = 0;
-	OUT("typedef enum ");
-		out_name_chain(arg, ONC_noflags);
-	OUT("_PR {\n");
+	OUT("typedef %s {\n", c_name(arg).presence_enum);
 	TQ_FOR(v, &(expr->members), next) {
 		if(v->expr_type == A1TC_EXTENSIBLE) continue;
 		INDENTED(
-			out_name_chain(arg, ONC_noflags);
-			OUT("_PR_");
-			id = MKID(v);
-			OUT("%s,\t/* Member %s is present */\n",
-				id, id)
+			OUT("%s,", c_presence_name(arg, v));
+			OUT("\t/* Member %s is present */\n", MKID(v));
 		);
 		mcount++;
 	}
-	OUT("} "); out_name_chain(arg, ONC_noflags); OUT("_PR;\n");
+	OUT("} %s;\n", c_name(arg).presence_name);
 
 	REDIR(saved_target);
 
@@ -623,13 +599,10 @@
 			REDIR(OT_FWD_DEFS);
 			OUT("typedef ");
 		}
-		OUT("struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" {\n");
+		OUT("%s {\n", c_name(arg).full_name);
 	} else {
 		REDIR(OT_TYPE_DECLS);
-		OUT("typedef struct %s {\n",
-			MKID_safe(expr));
+		OUT("typedef %s {\n", c_name(arg).full_name);
 	}
 
 	TQ_FOR(v, &(expr->members), next) {
@@ -653,18 +626,16 @@
 	PCTX_DEF;
 
 	if (arg->embed && expr->_anonymous_type) {
-		OUT("} %s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-		out_name_chain(arg, ONC_avoid_keywords);
-		OUT("%s;\n", arg->embed ? "" : "_t");
+		OUT("} %s%s;\n", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 
 		REDIR(saved_target);
 
-		OUT("%s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-			out_name_chain(arg, ONC_avoid_keywords);
+		OUT("%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 	} else {
-		OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
-			expr->_anonymous_type ? "" : MKID_safe(expr),
-			arg->embed ? "" : "_t");
+		OUT("} %s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).short_name);
 	}
 
 	return asn1c_lang_C_type_SET_def(arg);
@@ -682,7 +653,7 @@
 	int tags_count;
 	int all_tags_count;
 	enum tvm_compat tv_mode;
-	char *p;
+	const char *p;
 	int saved_target = arg->target->target;
 
 	/*
@@ -780,15 +751,9 @@
 	OUT("asn_SET_specifics_t asn_SPC_%s_specs_%d = {\n",
 		MKID(expr), expr->_type_unique_index);
 	INDENTED(
-		OUT("sizeof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT("),\n");
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", _asn_ctx),\n");
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", _presence_map),\n");
+		OUT("sizeof(%s),\n", c_name(arg).full_name);
+		OUT("offsetof(%s, _asn_ctx),\n", c_name(arg).full_name);
+		OUT("offsetof(%s, _presence_map),\n", c_name(arg).full_name);
 		emit_tag2member_reference(arg, expr, tag2el_count);
 		p = MKID(expr);
 		if(tag2el_cxer)
@@ -833,11 +798,9 @@
 			REDIR(OT_FWD_DEFS);
 			OUT("typedef ");
 		}
-		OUT("struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" {\n");
+		OUT("%s {\n", c_name(arg).full_name);
 	} else {
-		OUT("typedef struct %s {\n", MKID_safe(expr));
+		OUT("typedef %s {\n", c_name(arg).full_name);
 	}
 
 	INDENT(+1);
@@ -892,18 +855,16 @@
 	PCTX_DEF;
 
 	if (arg->embed && expr->_anonymous_type) {
-		OUT("} %s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-		out_name_chain(arg, ONC_avoid_keywords);
-		OUT("%s;\n", arg->embed ? "" : "_t");
+		OUT("} %s%s;\n", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 
 		REDIR(saved_target);
 
-		OUT("%s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-			out_name_chain(arg, ONC_avoid_keywords);
+		OUT("%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 	} else {
-		OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
-			expr->_anonymous_type ? "" : MKID_safe(expr),
-			arg->embed ? "" : "_t");
+		OUT("} %s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).short_name);
 	}
 
 	/*
@@ -965,12 +926,8 @@
 	OUT("asn_SET_OF_specifics_t asn_SPC_%s_specs_%d = {\n",
 		MKID(expr), expr->_type_unique_index);
 	INDENTED(
-		OUT("sizeof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT("),\n");
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", _asn_ctx),\n");
+		OUT("sizeof(%s),\n", c_name(arg).full_name);
+		OUT("offsetof(%s, _asn_ctx),\n", c_name(arg).full_name);
 		{
 		int as_xvl = expr_as_xmlvaluelist(arg, v);
 		OUT("%d,\t/* XER encoding is %s */\n",
@@ -995,20 +952,16 @@
 asn1c_lang_C_type_CHOICE(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
-	char *id;
 	int saved_target = arg->target->target;
 
 	DEPENDENCIES;
 
 	REDIR(OT_DEPS);
 
-	OUT("typedef enum ");
-		out_name_chain(arg, ONC_noflags);
-	OUT("_PR {\n");
+	OUT("typedef %s {\n", c_name(arg).presence_enum);
 	INDENTED(
 		int skipComma = 1;
-		out_name_chain(arg, ONC_noflags);
-		OUT("_PR_NOTHING,\t/* No components present */\n");
+        OUT("%s,\t/* No components present */\n", c_presence_name(arg, 0));
 		TQ_FOR(v, &(expr->members), next) {
 			if(skipComma) skipComma = 0;
 			else if (v->expr_type == A1TC_EXTENSIBLE && !TQ_NEXT(v, next)) OUT("\n");
@@ -1018,13 +971,11 @@
 				skipComma = 1;
 				continue;
 			}
-			out_name_chain(arg, ONC_noflags);
-			id = MKID(v);
-			OUT("_PR_%s", id);
+            OUT("%s", c_presence_name(arg, v));
 		}
 		OUT("\n");
 	);
-	OUT("} "); out_name_chain(arg, ONC_noflags); OUT("_PR;\n");
+	OUT("} %s;\n", c_name(arg).presence_name);
 
 	REDIR(saved_target);
 
@@ -1033,15 +984,14 @@
 			REDIR(OT_FWD_DEFS);
 			OUT("typedef ");
 		}
-		OUT("struct "); out_name_chain(arg, ONC_avoid_keywords); OUT(" {\n");
+		OUT("%s {\n", c_name(arg).full_name);
 	} else {
 		REDIR(OT_TYPE_DECLS);
-		OUT("typedef struct %s {\n", MKID_safe(expr));
+		OUT("typedef %s {\n", c_name(arg).full_name);
 	}
 
 	INDENTED(
-		out_name_chain(arg, ONC_noflags);
-		OUT("_PR present;\n");
+		OUT("%s present;\n", c_name(arg).presence_name);
 		OUT("union ");
 		if(UNNAMED_UNIONS == 0) {
 			out_name_chain(arg, ONC_force_compound_name);
@@ -1058,21 +1008,16 @@
 	PCTX_DEF;
 
 	if (arg->embed && expr->_anonymous_type) {
-		OUT("} %s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-		out_name_chain(arg, ONC_avoid_keywords);
-		OUT("%s;\n", arg->embed ? "" : "_t");
+		OUT("} %s%s;\n", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 
 		REDIR(saved_target);
 
-		OUT("%s", (expr->marker.flags & EM_INDIRECT)?"*":"");
-			out_name_chain(arg, ONC_avoid_keywords);
+		OUT("%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).base_name);
 	} else {
-		OUT("} %s%s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
-			expr->_anonymous_type ? "" :
-				arg->embed
-					? MKID_safe(expr)
-					: MKID(expr),
-			arg->embed ? "" : "_t");
+		OUT("} %s%s", (expr->marker.flags & EM_INDIRECT)?"*":"",
+			c_name(arg).short_name);
 	}
 
 	return asn1c_lang_C_type_CHOICE_def(arg);
@@ -1219,18 +1164,10 @@
 	OUT("asn_CHOICE_specifics_t asn_SPC_%s_specs_%d = {\n",
 		MKID(expr), expr->_type_unique_index);
 	INDENTED(
-		OUT("sizeof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT("),\n");
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", _asn_ctx),\n");
-		OUT("offsetof(struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(", present),\n");
-		OUT("sizeof(((struct ");
-			out_name_chain(arg, ONC_avoid_keywords);
-		OUT(" *)0)->present),\n");
+		OUT("sizeof(%s),\n", c_name(arg).full_name);
+		OUT("offsetof(%s, _asn_ctx),\n", c_name(arg).full_name);
+		OUT("offsetof(%s, present),\n", c_name(arg).full_name);
+		OUT("sizeof(((%s *)0)->present),\n", c_name(arg).full_name);
 		emit_tag2member_reference(arg, expr, tag2el_count);
 		if(C99_MODE) OUT(".canonical_order = ");
 		if(cmap) OUT("asn_MAP_%s_cmap_%d,\t/* Canonically sorted */\n",
@@ -1306,7 +1243,7 @@
 	int all_tags_count;
 	enum tvm_compat tv_mode;
 	enum etd_spec etd_spec;
-	char *p;
+	const char *p;
 	int saved_target = arg->target->target;
 
 	if(arg->embed) {
@@ -2890,8 +2827,7 @@
     const char *tname = asn1c_type_name(arg, constraining_memb, TNF_SAFE);
     if(constraining_memb->marker.flags & EM_INDIRECT) {
         OUT("const void *memb_ptr = *(const void **)");
-        OUT("((const char *)parent_sptr + offsetof(struct ");
-            out_name_chain(arg, ONC_avoid_keywords);
+        OUT("((const char *)parent_sptr + offsetof(%s", c_name(arg).full_name);
         OUT(", %s));", MKID_safe(constraining_memb));
         OUT("if(!memb_ptr) return result;\n");
         OUT("\n");
@@ -2912,8 +2848,7 @@
     if(constraining_memb->marker.flags & EM_INDIRECT) {
         OUT("memb_ptr;\n");
     } else {
-        OUT("((const char *)parent_sptr + offsetof(struct ");
-            out_name_chain(arg, ONC_avoid_keywords);
+        OUT("((const char *)parent_sptr + offsetof(%s", c_name(arg).full_name);
         OUT(", %s));\n", MKID_safe(constraining_memb));
     }
     OUT("\n");
@@ -2987,9 +2922,7 @@
                || arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF);
         OUT("0,\n");
     } else {
-        OUT("offsetof(struct ");
-        out_name_chain(arg, ONC_avoid_keywords);
-        OUT(", ");
+        OUT("offsetof(%s, ", c_name(arg).full_name);
         if((arg->expr->expr_type == ASN_CONSTR_CHOICE
             || arg->expr->expr_type == ASN_CONSTR_OPEN_TYPE)
            && (!UNNAMED_UNIONS))
@@ -3372,7 +3305,7 @@
 static int
 out_name_chain(arg_t *arg, enum onc_flags onc_flags) {
 	asn1p_expr_t *expr = arg->expr;
-	char *id;
+	const char *id;
 
 	if((arg->flags & A1C_COMPOUND_NAMES
 	   || onc_flags & ONC_force_compound_name
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 99c275b..59cb497 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -42,7 +42,7 @@
  * Construct identifier from multiple parts.
  * Convert unsafe characters to underscores.
  */
-char *
+const char *
 asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
 	static char *storage;
 	static int storage_size;
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index ff6d672..f9f3c45 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -12,7 +12,7 @@
 	AMI_NODELIMITER       = 4,	/* Do not put delimiter, just concatenate */
 	AMI_USE_PREFIX        = 8,	/* Use Prefix when generating identifier */
 };
-char *asn1c_make_identifier(enum ami_flags_e, asn1p_expr_t *expr, ...);
+const char *asn1c_make_identifier(enum ami_flags_e, asn1p_expr_t *expr, ...);
 
 /*
  * Return the type name of the specified expression.
diff --git a/libasn1compiler/asn1c_naming.c b/libasn1compiler/asn1c_naming.c
new file mode 100644
index 0000000..6ab3c4a
--- /dev/null
+++ b/libasn1compiler/asn1c_naming.c
@@ -0,0 +1,137 @@
+#include "asn1c_internal.h"
+#include "asn1c_naming.h"
+#include "asn1c_misc.h"
+#include "asn1c_misc.h"
+#include <asn1_buffer.h>
+
+static abuf *
+construct_base_name(abuf *buf, arg_t *arg, int compound_names,
+                    int avoid_keywords) {
+    const char *id;
+
+    if(!buf) buf = abuf_new();
+
+    if(compound_names && arg->expr->parent_expr) {
+        arg_t tmparg = *arg;
+        tmparg.expr = arg->expr->parent_expr;
+        construct_base_name(buf, &tmparg, compound_names, 0);
+        if(buf->length) {
+            abuf_str(buf, "__"); /* component separator */
+        }
+    }
+
+    id = asn1c_make_identifier(
+        ((avoid_keywords && !buf->length) ? AMI_CHECK_RESERVED : 0), arg->expr,
+        0);
+
+    abuf_str(buf, id);
+
+    return buf;
+}
+
+static struct c_names
+c_name_impl(arg_t *arg, int avoid_keywords) {
+    asn1p_expr_type_e expr_type = arg->expr->expr_type;
+    struct c_names names;
+    int compound_names = 0;
+
+    static abuf b_base_name;
+    static abuf b_short_name;
+    static abuf b_full_name;
+    static abuf b_as_member;
+    static abuf b_presence_enum;
+    static abuf b_presence_name;
+    static abuf b_members_enum;
+    static abuf b_members_name;
+
+    abuf_clear(&b_base_name);
+    abuf_clear(&b_short_name);
+    abuf_clear(&b_full_name);
+    abuf_clear(&b_as_member);
+    abuf_clear(&b_presence_enum);
+    abuf_clear(&b_presence_name);
+    abuf_clear(&b_members_enum);
+    abuf_clear(&b_members_name);
+
+    if((arg->flags & A1C_COMPOUND_NAMES)) {
+        if((expr_type & ASN_CONSTR_MASK)
+           || expr_type == ASN_BASIC_ENUMERATED
+           || ((expr_type == ASN_BASIC_INTEGER
+                || expr_type == ASN_BASIC_BIT_STRING))) {
+            compound_names = 1;
+        }
+    }
+
+    abuf *base_name =
+        construct_base_name(NULL, arg, compound_names, avoid_keywords);
+    abuf *part_name =
+        construct_base_name(NULL, arg, compound_names, 0);
+    abuf *member_name =
+        construct_base_name(NULL, arg, 0, 1);
+
+    abuf_printf(&b_base_name, "%s", base_name->buffer);
+    if(!arg->expr->_anonymous_type) {
+        if(arg->embed) {
+            abuf_printf(&b_short_name, "%s", member_name->buffer);
+        } else {
+            abuf_printf(&b_short_name, "%s_t", member_name->buffer);
+        }
+    }
+    abuf_printf(&b_full_name, "struct %s", base_name->buffer);
+    abuf_printf(&b_as_member, "%s", member_name->buffer);
+    abuf_printf(&b_presence_enum, "enum %s_PR", part_name->buffer);
+    abuf_printf(&b_presence_name, "%s_PR", part_name->buffer);
+    abuf_printf(&b_members_enum, "enum %s", base_name->buffer);
+    abuf_printf(&b_members_name, "e_%s", part_name->buffer);
+
+    names.base_name = b_base_name.buffer;
+    names.short_name = b_short_name.buffer;
+    names.full_name = b_full_name.buffer;
+    names.as_member = b_as_member.buffer;
+    names.presence_enum = b_presence_enum.buffer;
+    names.presence_name = b_presence_name.buffer;
+    names.members_enum = b_members_enum.buffer;
+    names.members_name = b_members_name.buffer;
+
+    abuf_free(base_name);
+    abuf_free(part_name);
+    abuf_free(member_name);
+
+    return names;
+}
+
+struct c_names
+c_name(arg_t *arg) {
+    return c_name_impl(arg, 1);
+}
+
+const char *
+c_member_name(arg_t *arg, asn1p_expr_t *expr) {
+    static abuf ab;
+
+    abuf_clear(&ab);
+
+    abuf_printf(&ab, "%s_%s", c_name_impl(arg, 0).base_name,
+                asn1c_make_identifier(0, expr, 0));
+
+    return ab.buffer;
+}
+
+
+const char *
+c_presence_name(arg_t *arg, asn1p_expr_t *expr) {
+    static abuf ab;
+
+    abuf_clear(&ab);
+
+    if(expr) {
+        abuf_printf(&ab, "%s_PR_%s", c_name_impl(arg, 0).base_name,
+                    asn1c_make_identifier(0, expr, 0));
+    } else {
+        abuf_printf(&ab, "%s_PR_NOTHING", c_name_impl(arg, 0).base_name);
+    }
+
+    return ab.buffer;
+}
+
+
diff --git a/libasn1compiler/asn1c_naming.h b/libasn1compiler/asn1c_naming.h
new file mode 100644
index 0000000..2e0e88d
--- /dev/null
+++ b/libasn1compiler/asn1c_naming.h
@@ -0,0 +1,19 @@
+#ifndef	ASN1_COMPILER_NAMING_H
+#define	ASN1_COMPILER_NAMING_H
+
+struct c_names {
+    const char *base_name;     /* "foo" */
+    const char *short_name;    /* "foo_t", "e_foo" */
+    const char *full_name;     /* "struct foo", "enum foo" */
+    const char *as_member;     /* "foo" (not compounded) */
+    const char *presence_enum; /* "enum foo_PR" */
+    const char *presence_name; /* "foo_PR" */
+    const char *members_enum;  /* "enum foo" */
+    const char *members_name;  /* "e_foo" */
+};
+
+struct c_names c_name(arg_t *);
+const char *c_member_name(arg_t *, asn1p_expr_t *);     /* %s_%s */
+const char *c_presence_name(arg_t *, asn1p_expr_t *);   /* %s_PR_%s */
+
+#endif	/* ASN1_COMPILER_NAMING_H */
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index 76f312b..d43da4f 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -243,7 +243,7 @@
 	FILE *fp_c, *fp_h;
 	char *tmpname_c, *tmpname_h;
 	char *name_buf;
-	char *header_id;
+	const char *header_id;
 	const char *c_retained = "";
 	const char *h_retained = "";
 	char *filename;