db010729e8831e2cd026828c616c934ac445e087
[com/asn1c.git] / libasn1common / asn1_namespace.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6
7 #include "asn1_ref.h"
8 #include "asn1_buffer.h"
9 #include "asn1_namespace.h"
10
11 static void (*_add_standard_namespaces_cb)(asn1_namespace_t *);
12
13 void
14 asn1_namespace_add_standard_namespaces_callback(
15     void (*cb)(asn1_namespace_t *)) {
16     _add_standard_namespaces_cb = cb;
17 }
18
19 asn1_namespace_t *
20 asn1_namespace_new() {
21     asn1_namespace_t *ns = calloc(1, sizeof(*ns));
22
23     if(_add_standard_namespaces_cb) {
24         _add_standard_namespaces_cb(ns);
25     }
26
27     return ns;
28 }
29
30 void
31 asn1_namespace_free(asn1_namespace_t *ns) {
32     if(ns) {
33         for(size_t i = 0; i < ns->elements_count; i++) {
34             switch(ns->elements[i].selector) {
35             case NAM_SPACE:
36                 break;
37             case NAM_SYMBOL:
38                 free(ns->elements[i].u.symbol.identifier);
39                 break;
40             }
41         }
42         free(ns->elements);
43         free(ns);
44     }
45 }
46
47 asn1_namespace_t *
48 asn1_namespace_clone(const asn1_namespace_t *old_ns) {
49     asn1_namespace_t *new_ns = calloc(1, sizeof(*new_ns));
50
51     for(size_t i = 0; i < old_ns->elements_count; i++) {
52         switch(old_ns->elements[i].selector) {
53         case NAM_SPACE:
54             asn1_namespace_add_module(new_ns,
55                                        old_ns->elements[i].u.space.module,
56                                        old_ns->elements[i].u.space.stop_search);
57             break;
58         case NAM_SYMBOL:
59             asn1_namespace_add_symbol(
60                 new_ns, old_ns->elements[i].u.symbol.opt_governor,
61                 old_ns->elements[i].u.symbol.identifier,
62                 old_ns->elements[i].u.symbol.resolution);
63             break;
64         }
65     }
66
67     return new_ns;
68 }
69
70 static size_t
71 _add_element(asn1_namespace_t *ns) {
72     size_t idx = ns->elements_count;
73
74     if(ns->elements_count >= ns->elements_size) {
75         size_t elc = ns->elements_size ? ns->elements_size * 2 : 4;
76         ns->elements = realloc(ns->elements, sizeof(ns->elements[0]) * elc);
77         ns->elements_size = elc;
78     }
79
80     ns->elements_count++;
81     return idx;
82 }
83
84 void
85 asn1_namespace_add_symbol(asn1_namespace_t *ns,
86                           struct asn1p_ref_s *opt_governor,
87                           const char *identifier,
88                           struct asn1p_expr_s *resolved_argument) {
89     size_t idx = _add_element(ns);
90
91     ns->elements[idx].selector = NAM_SYMBOL;
92     ns->elements[idx].u.symbol.opt_governor = opt_governor;
93     ns->elements[idx].u.symbol.identifier = strdup(identifier);
94     ns->elements[idx].u.symbol.resolution = resolved_argument;
95 }
96
97 asn1_namespace_t *
98 asn1_namespace_new_from_module(struct asn1p_module_s *module, int stop_search) {
99     asn1_namespace_t *ns = asn1_namespace_new();
100     asn1_namespace_add_module(ns, module, stop_search);
101     return ns;
102 }
103
104 void
105 asn1_namespace_add_module(asn1_namespace_t *ns, struct asn1p_module_s *module,
106                           int stop_search) {
107     size_t idx = _add_element(ns);
108
109     ns->elements[idx].selector = NAM_SPACE,
110     ns->elements[idx].u.space.module = module;
111     ns->elements[idx].u.space.stop_search = stop_search;
112 }
113
114 const char *
115 asn1_namespace_string(const asn1_namespace_t *ns) {
116     static abuf ab;
117
118     abuf_clear(&ab);
119
120     if(ns) {
121         abuf_str(&ab, "{");
122         for(size_t i = 0; i < ns->elements_count; i++) {
123             if(i) abuf_str(&ab, ",");
124             switch(ns->elements[i].selector) {
125             case NAM_SPACE:
126                 abuf_printf(
127                     &ab, "M:\"%s\"%s",
128                     *(const char *const *)ns->elements[i].u.space.module,
129                     ns->elements[i].u.space.stop_search ? "!" : "");
130                 break;
131             case NAM_SYMBOL:
132                 abuf_printf(&ab, "S:\"%s%s%s\"",
133                             ns->elements[i].u.symbol.opt_governor
134                                 ? asn1p_ref_string(
135                                       ns->elements[i].u.symbol.opt_governor)
136                                 : "",
137                             ns->elements[i].u.symbol.opt_governor ? ":" : "",
138                             ns->elements[i].u.symbol.identifier);
139                 break;
140             }
141         }
142         abuf_str(&ab, "}");
143         return ab.buffer;
144     } else {
145         return "<no namespace>";
146     }
147 }
148