Initial version of asn1c
[com/asn1c.git] / libasn1compiler / asn1c_naming.c
diff --git a/libasn1compiler/asn1c_naming.c b/libasn1compiler/asn1c_naming.c
new file mode 100644 (file)
index 0000000..c892fcf
--- /dev/null
@@ -0,0 +1,327 @@
+#include "asn1c_internal.h"
+#include "asn1c_naming.h"
+#include "asn1c_misc.h"
+#include <asn1_buffer.h>
+#include <genhash.h>
+
+struct intl_name {
+    asn1p_expr_t *expr;
+    asn1p_expr_t *clashes_with;
+    const char *name;
+    TQ_ENTRY(struct intl_name) next;
+};
+
+genhash_t *used_names_hash;
+
+static void
+name_entry_destroy(void *np) {
+    struct intl_name *n = np;
+
+    union {
+        const char *c_buf;
+        char *nc_buf;
+    } const_cast;
+
+    asn1p_expr_free(n->expr);
+    asn1p_expr_free(n->clashes_with);
+    const_cast.c_buf = n->name;
+    free(const_cast.nc_buf);
+    free(n);
+}
+
+void
+c_name_clash_finder_init() {
+    assert(used_names_hash == NULL);
+    used_names_hash =
+        genhash_new(cmpf_string, hashf_string, NULL, name_entry_destroy);
+    assert(used_names_hash);
+}
+
+void
+c_name_clash_finder_destroy() {
+    genhash_destroy(used_names_hash);
+    used_names_hash = NULL;
+}
+
+static void
+register_global_name(asn1p_expr_t *expr, const char *name) {
+    struct intl_name *n;
+
+    n = genhash_get(used_names_hash, (const void *)name);
+    if(n) {
+        if(!(expr->_mark & TM_NAMEGIVEN) && (expr != n->expr)) {
+            n->clashes_with = expr;
+            expr->ref_cnt++;
+            return;
+        }
+    }
+
+    if(expr->_mark & TM_NAMEGIVEN)
+        return;
+
+    char *name_copy = strdup(name);
+
+    n = calloc(1, sizeof(*n));
+    assert(n);
+    n->expr = expr;
+    expr->ref_cnt++;
+    n->name = name_copy;
+    int ret = genhash_add(used_names_hash, name_copy, n);
+    assert(ret == 0);
+}
+
+int
+c_name_clash(arg_t *arg) {
+    struct intl_name *n;
+    size_t n_clashes = 0;
+    const size_t max_clashes = 5;
+
+    genhash_iter_t iter;
+
+    genhash_iter_init(&iter, used_names_hash, 0);
+    while(genhash_iter(&iter, NULL, (void *)&n)) {
+        if(n->clashes_with) {
+            if(n_clashes++ > max_clashes) continue;
+            FATAL(
+                "Name \"%s\" is generated by %s.%s at line %s:%d and "
+                "%s.%s at line %s:%d",
+                n->name, n->expr->module->ModuleName, n->expr->Identifier,
+                n->expr->module->source_file_name, n->expr->_lineno,
+                n->clashes_with->module->ModuleName,
+                n->clashes_with->Identifier,
+                n->clashes_with->module->source_file_name,
+                n->clashes_with->_lineno);
+        }
+    }
+
+    genhash_iter_done(&iter);
+
+    if(n_clashes > max_clashes) {
+        FATAL("... %zu more name clashes not shown", n_clashes - max_clashes);
+    }
+
+    return n_clashes > 0;
+}
+
+
+static abuf *
+construct_base_name(abuf *buf, asn1p_expr_t *expr, int compound_names,
+                    int avoid_keywords, enum ami_flags_e flag) {
+    const char *id;
+
+    assert(buf);
+
+    if(compound_names && expr->parent_expr) {
+        construct_base_name(buf, expr->parent_expr, compound_names, 0, flag);
+        if(buf->length) {
+            abuf_str(buf, "__"); /* component separator */
+        }
+    }
+
+    id = asn1c_make_identifier(
+        ((avoid_keywords && !buf->length) ? AMI_CHECK_RESERVED : 0) | flag, expr, 0);
+
+    abuf_str(buf, id);
+
+    return buf;
+}
+
+static struct c_names
+c_name_impl(arg_t *arg, asn1p_expr_t *expr, int avoid_keywords) {
+    asn1p_expr_type_e expr_type = expr->expr_type;
+    struct c_names names;
+    int compound_names = 0;
+
+    static abuf b_type_asn_name;
+    static abuf b_type_part_name;
+    static abuf b_type_base_name;
+    static abuf b_type_c_name;
+    static abuf b_type_constrained_c_name;
+    static abuf b_asn_name;
+    static abuf b_part_name;
+    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_type_asn_name);
+    abuf_clear(&b_type_part_name);
+    abuf_clear(&b_type_base_name);
+    abuf_clear(&b_type_c_name);
+    abuf_clear(&b_type_constrained_c_name);
+    abuf_clear(&b_asn_name);
+    abuf_clear(&b_base_name);
+    abuf_clear(&b_part_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);
+
+    abuf_str(&b_type_asn_name, asn1c_type_name(arg, expr, TNF_UNMODIFIED));
+    abuf_str(&b_type_part_name, asn1c_type_name(arg, expr, TNF_SAFE));
+    abuf_str(&b_type_base_name, asn1c_type_name(arg, expr, TNF_SAFE));
+    abuf_str(&b_type_c_name, asn1c_type_name(arg, expr, TNF_CTYPE));
+    abuf_str(&b_type_constrained_c_name,
+             asn1c_type_name(arg, expr, TNF_CONSTYPE));
+
+
+    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;
+        }
+    }
+
+    construct_base_name(&b_asn_name, expr, 0, 0, 0);
+    construct_base_name(&b_part_name, expr, 0, 0, AMI_USE_PREFIX);
+    construct_base_name(&b_base_name, expr, compound_names, avoid_keywords, 0);
+    construct_base_name(&b_as_member, expr, 0, 1, 0);
+
+    static abuf tmp_compoundable_part_name;
+    static abuf compound_part_name;
+    abuf_clear(&tmp_compoundable_part_name);
+    abuf_clear(&compound_part_name);
+    construct_base_name(&tmp_compoundable_part_name, expr, compound_names, 0, 0);
+    construct_base_name(&compound_part_name, expr, 1, 0, 0);
+
+    if(strlen(asn1c_prefix()) == 0) {
+        if(!expr->_anonymous_type) {
+            if(arg->embed) {
+                abuf_printf(&b_short_name, "%s", b_as_member.buffer);
+            } else {
+                abuf_printf(&b_short_name, "%s_t", b_as_member.buffer);
+            }
+        }
+        abuf_printf(&b_full_name, "struct %s", b_base_name.buffer);
+        abuf_printf(&b_presence_enum, "enum %s_PR", tmp_compoundable_part_name.buffer);
+        abuf_printf(&b_presence_name, "%s_PR", tmp_compoundable_part_name.buffer);
+        abuf_printf(&b_members_enum, "enum %s", b_base_name.buffer);
+        abuf_printf(&b_members_name, "e_%s", tmp_compoundable_part_name.buffer);
+   } else {
+        if(!expr->_anonymous_type) {
+            if(arg->embed) {
+                abuf_printf(&b_short_name, "%s%s", asn1c_prefix(), b_as_member.buffer);
+            } else {
+                abuf_printf(&b_short_name, "%s%s_t", asn1c_prefix(), b_as_member.buffer);
+            }
+        }
+        abuf_printf(&b_full_name, "struct %s%s", asn1c_prefix(), b_base_name.buffer);
+        abuf_printf(&b_presence_enum, "enum %s%s_PR", asn1c_prefix(), tmp_compoundable_part_name.buffer);
+        abuf_printf(&b_presence_name, "%s%s_PR", asn1c_prefix(), tmp_compoundable_part_name.buffer);
+        abuf_printf(&b_members_enum, "enum %s%s", asn1c_prefix(), b_base_name.buffer);
+        abuf_printf(&b_members_name, "e_%s%s", asn1c_prefix(), tmp_compoundable_part_name.buffer);
+    }
+
+    names.type.asn_name = b_type_asn_name.buffer;
+    names.type.base_name = b_type_base_name.buffer;
+    names.type.part_name = b_type_part_name.buffer;
+    names.type.c_name = b_type_c_name.buffer;
+    names.type.constrained_c_name = b_type_constrained_c_name.buffer;
+    names.asn_name = b_asn_name.buffer;
+    names.part_name = b_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;
+    names.compound_name = compound_part_name.buffer;
+
+    /* A _subset_ of names is checked against being globally unique */
+    register_global_name(expr, names.base_name);
+    register_global_name(expr, names.full_name);
+    register_global_name(expr, names.presence_enum);
+    register_global_name(expr, names.presence_name);
+    register_global_name(expr, names.members_enum);
+    register_global_name(expr, names.members_name);
+
+    expr->_mark |= TM_NAMEGIVEN;
+
+    return names;
+}
+
+struct c_names
+c_name(arg_t *arg) {
+    return c_name_impl(arg, arg->expr, 1);
+}
+
+struct c_names
+c_expr_name(arg_t *arg, asn1p_expr_t *expr) {
+    return c_name_impl(arg, expr, 1);
+}
+
+const char *
+c_member_name(arg_t *arg, asn1p_expr_t *expr) {
+    static abuf ab;
+
+    abuf_clear(&ab);
+
+    /* NB: do not use part_name, doesn't work for -fcompound-names */
+    abuf_str(&ab, asn1c_prefix());
+    abuf_str(&ab, c_name_impl(arg, arg->expr, 0).base_name);
+    abuf_str(&ab, "_");
+    abuf_str(&ab, 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);
+
+    abuf_str(&ab, asn1c_prefix());
+    if(expr) {
+        /* NB: do not use part_name, doesn't work for -fcompound-names */
+        abuf_str(&ab, c_name_impl(arg, arg->expr, 0).base_name);
+        abuf_str(&ab, "_PR_");
+        abuf_str(&ab, asn1c_make_identifier(0, expr, 0));
+    } else {
+        abuf_printf(&ab, "%s_PR_NOTHING",
+                    c_name_impl(arg, arg->expr, 0).base_name);
+    }
+
+    return ab.buffer;
+}
+
+const char *
+c_names_format(struct c_names ns) {
+    static abuf nbuf;
+    abuf_clear(&nbuf);
+
+#define FMT_COMPONENT(x) abuf_printf(&nbuf, " ." #x "=\"%s\",", ns.x);
+
+    abuf_str(&nbuf, "{");
+    FMT_COMPONENT(type.asn_name);
+    FMT_COMPONENT(type.part_name);
+    FMT_COMPONENT(type.base_name);
+    FMT_COMPONENT(type.c_name);
+    FMT_COMPONENT(type.constrained_c_name);
+    FMT_COMPONENT(asn_name);
+    FMT_COMPONENT(part_name);
+    FMT_COMPONENT(base_name);
+    FMT_COMPONENT(full_name);
+    FMT_COMPONENT(short_name);
+    FMT_COMPONENT(full_name);
+    FMT_COMPONENT(as_member);
+    FMT_COMPONENT(presence_enum);
+    FMT_COMPONENT(presence_name);
+    FMT_COMPONENT(members_enum);
+    FMT_COMPONENT(members_name);
+    abuf_printf(&nbuf, " .members_name=\"%s\" }", ns.members_name);
+    return nbuf.buffer;
+}
+