c3741bc6397e52c3ea431335f1b495f2829a1f6c
[com/asn1c.git] / libasn1compiler / asn1compiler.c
1 #include "asn1c_internal.h"
2 #include "asn1c_lang.h"
3 #include "asn1c_out.h"
4 #include "asn1c_save.h"
5 #include "asn1c_ioc.h"
6 #include "asn1c_naming.h"
7
8 static void default_logger_cb(int, const char *fmt, ...);
9 static int asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *);
10 static int asn1c_detach_streams(asn1p_expr_t *expr);
11
12 int
13 asn1_compile(asn1p_t *asn, const char *datadir, const char *destdir, enum asn1c_flags flags,
14                 int argc, int optc, char **argv) {
15         arg_t arg_s;
16         arg_t *arg = &arg_s;
17         asn1p_module_t *mod;
18         int ret;
19
20         c_name_clash_finder_init();
21
22         /*
23          * Initialize target language.
24          */
25         ret = asn1c_with_language(ASN1C_LANGUAGE_C);
26         assert(ret == 0);
27
28         memset(arg, 0, sizeof(*arg));
29         arg->default_cb = asn1c_compile_expr;
30         arg->logger_cb = default_logger_cb;
31         arg->flags = flags;
32         arg->asn = asn;
33
34         /*
35          * Compile each individual top level structure.
36          */
37         TQ_FOR(mod, &(asn->modules), mod_next) {
38                 TQ_FOR(arg->expr, &(mod->members), next) {
39                         arg->ns = asn1_namespace_new_from_module(mod, 0);
40
41                         compiler_streams_t *cs = NULL;
42
43                         if(asn1c_attach_streams(arg->expr))
44                                 return -1;
45
46                         cs = arg->expr->data;
47                         cs->target = OT_TYPE_DECLS;
48                         arg->target = cs;
49
50                         ret = asn1c_compile_expr(arg, NULL);
51                         if(ret) {
52                                 FATAL("Cannot compile \"%s\" (%x:%x) at line %d",
53                                         arg->expr->Identifier,
54                                         arg->expr->expr_type,
55                                         arg->expr->meta_type,
56                                         arg->expr->_lineno);
57                                 return ret;
58                         }
59
60                         asn1_namespace_free(arg->ns);
61                         arg->ns = 0;
62                 }
63         }
64
65         if(c_name_clash(arg)) {
66                 if(arg->flags & A1C_COMPOUND_NAMES) {
67                         FATAL("Name clashes encountered even with -fcompound-names flag");
68                         /* Proceed further for better debugging. */
69                 } else {
70                         FATAL("Use \"-fcompound-names\" flag to asn1c to resolve name clashes");
71                         if(arg->flags & A1C_PRINT_COMPILED) {
72                                 /* Proceed further for better debugging. */
73                         } else {
74                                 return -1;
75                         }
76                 }
77         }
78
79         DEBUG("Saving compiled data");
80
81         c_name_clash_finder_destroy();
82
83         /*
84          * Save or print out the compiled result.
85          */
86         if(asn1c_save_compiled_output(arg, datadir, destdir, argc, optc, argv))
87                 return -1;
88
89         TQ_FOR(mod, &(asn->modules), mod_next) {
90                 TQ_FOR(arg->expr, &(mod->members), next) {
91                         asn1c_detach_streams(arg->expr);
92                 }
93         }
94
95         return 0;
96 }
97
98 static int
99 asn1c_compile_expr(arg_t *arg, const asn1c_ioc_table_and_objset_t *opt_ioc) {
100         asn1p_expr_t *expr = arg->expr;
101         int (*type_cb)(arg_t *);
102         int ret;
103
104         assert((int)expr->meta_type >= AMT_INVALID);
105         assert(expr->meta_type < AMT_EXPR_META_MAX);
106         assert((int)expr->expr_type >= A1TC_INVALID);
107         assert(expr->expr_type < ASN_EXPR_TYPE_MAX);
108
109         type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb;
110         if(type_cb) {
111
112                 DEBUG("Compiling %s at line %d",
113                         expr->Identifier,
114                         expr->_lineno);
115
116                 if(expr->lhs_params && expr->spec_index == -1) {
117                         int i;
118                         ret = 0;
119                         DEBUG("Parameterized type %s at line %d: %s (%d)",
120                                 expr->Identifier, expr->_lineno,
121                                 expr->specializations.pspecs_count
122                                 ? "compiling" : "unused, skipping",
123                                 expr->specializations.pspecs_count);
124                         for(i = 0; i<expr->specializations.pspecs_count; i++) {
125                                 arg->expr = expr->specializations
126                                                 .pspec[i].my_clone;
127                                 ret = asn1c_compile_expr(arg, opt_ioc);
128                                 if(ret) break;
129                         }
130                         arg->expr = expr;       /* Restore */
131                 } else {
132                         ret = type_cb(arg);
133                 }
134         } else {
135                 ret = -1;
136                 /*
137                  * Even if the target language compiler does not know
138                  * how to compile the given expression, we know that
139                  * certain expressions need not to be compiled at all.
140                  */
141                 switch(expr->meta_type) {
142                 case AMT_OBJECT:
143                 case AMT_OBJECTCLASS:
144                 case AMT_OBJECTFIELD:
145                 case AMT_VALUE:
146                 case AMT_VALUESET:
147                         ret = 0;
148                         break;
149                 default:
150                         break;
151                 }
152         }
153
154         if(ret == -1) {
155                 FATAL("Cannot compile \"%s\" (%x:%x) at line %d",
156                         arg->expr->Identifier,
157                         arg->expr->expr_type,
158                         arg->expr->meta_type,
159                         arg->expr->_lineno);
160                 OUT("#error Cannot compile \"%s\" (%x/%x) at line %d\n",
161                         arg->expr->Identifier,
162                         arg->expr->meta_type,
163                         arg->expr->expr_type,
164                         arg->expr->_lineno
165                 );
166         }
167
168         return ret;
169 }
170
171 int
172 asn1c_attach_streams(asn1p_expr_t *expr) {
173         compiler_streams_t *cs;
174         int i;
175
176         if(expr->data)
177                 return 0;       /* Already attached? */
178
179         expr->data = calloc(1, sizeof(compiler_streams_t));
180         if(expr->data == NULL)
181                 return -1;
182
183         cs = expr->data;
184         for(i = 0; i < OT_MAX; i++) {
185                 TQ_INIT(&(cs->destination[i].chunks));
186         }
187
188         return 0;
189 }
190
191 int
192 asn1c_detach_streams(asn1p_expr_t *expr) {
193         compiler_streams_t *cs;
194         out_chunk_t *m;
195         int i;
196
197         if(!expr->data)
198                 return 0;       /* Already detached? */
199
200         cs = expr->data;
201         for(i = 0; i < OT_MAX; i++) {
202                 while((m = TQ_REMOVE(&(cs->destination[i].chunks), next))) {
203                         free(m->buf);
204                         free(m);
205                 }
206         }
207         free(expr->data);
208         expr->data = (void *)NULL;
209
210         return 0;
211 }
212
213 static void
214 default_logger_cb(int _severity, const char *fmt, ...) {
215         va_list ap;
216         char *pfx = "";
217
218         switch(_severity) {
219         case -1: pfx = "DEBUG: "; break;
220         case 0: pfx = "WARNING: "; break;
221         case 1: pfx = "FATAL: "; break;
222         }
223
224         fprintf(stderr, "%s", pfx);
225         va_start(ap, fmt);
226         vfprintf(stderr, fmt, ap);
227         va_end(ap);
228         fprintf(stderr, "\n");
229 }
230
231 static void
232 asn1c_debug_expr_naming(arg_t *arg) {
233     asn1p_expr_t *expr = arg->expr;
234
235     printf("%s: ", expr->Identifier);
236     printf("%s\n", c_names_format(c_name(arg)));
237
238     printf("\n");
239
240 }
241
242 void
243 asn1c_debug_type_naming(asn1p_t *asn, enum asn1c_flags flags,
244                         char **asn_type_names) {
245     arg_t arg_s;
246     arg_t *arg = &arg_s;
247         asn1p_module_t *mod;
248
249     memset(arg, 0, sizeof(*arg));
250         arg->logger_cb = default_logger_cb;
251         arg->flags = flags;
252         arg->asn = asn;
253
254         c_name_clash_finder_init();
255
256         /*
257          * Compile each individual top level structure.
258          */
259         TQ_FOR(mod, &(asn->modules), mod_next) {
260         int namespace_shown = 0;
261                 TQ_FOR(arg->expr, &(mod->members), next) {
262                         arg->ns = asn1_namespace_new_from_module(mod, 0);
263
264             for(char **t = asn_type_names; *t; t++) {
265                 if(strcmp(*t, arg->expr->Identifier) == 0) {
266                     if(!namespace_shown) {
267                         namespace_shown = 1;
268                         printf("Namespace %s\n",
269                                asn1_namespace_string(arg->ns));
270                     }
271                     asn1c_debug_expr_naming(arg);
272                 }
273             }
274
275             asn1_namespace_free(arg->ns);
276                         arg->ns = 0;
277                 }
278         }
279
280         c_name_clash_finder_destroy();
281 }
282