blob: a98a8e533104afbe2cd724fe37452f4153bfa525 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1c_internal.h"
Lev Walkin79f54952004-08-13 16:58:19 +00002#include "asn1c_compat.h"
Lev Walkinacd9f8b2004-08-19 13:29:03 +00003#include "asn1c_fdeps.h"
Lev Walkin59004fa2004-08-20 13:37:01 +00004#include "asn1c_lang.h"
5#include "asn1c_misc.h"
6#include "asn1c_save.h"
7#include "asn1c_out.h"
Lev Walkinf15320b2004-06-03 03:38:44 +00008
Frank Morgner8a759ad2013-05-16 13:32:49 +02009#ifndef HAVE_SYMLINK
10#define symlink(a,b) (errno=ENOSYS, -1)
11#endif
12
Lev Walkinf2b2f372016-03-14 02:23:48 -070013/* Pedantically check fprintf's return value. */
14static int safe_fprintf(FILE *fp, const char *fmt, ...) {
15 va_list ap;
16 va_start(ap, fmt);
17 int ret = vfprintf(fp, fmt, ap);
18 va_end(ap);
19 assert(ret >= 0);
20 return ret;
21}
22
23/* Pedantically check fwrite's return value. */
24static size_t safe_fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream) {
25 size_t ret = fwrite(ptr, 1, size * nitems, stream);
26 assert(ret == size * nitems);
27 return ret;
28}
29
Lev Walkin34944f22010-10-07 08:25:37 +000030#define HINCLUDE(s) \
31 ((arg->flags & A1C_INCLUDES_QUOTED) \
Lev Walkinf2b2f372016-03-14 02:23:48 -070032 ? safe_fprintf(fp_h, "#include \"%s\"\n", s) \
33 : safe_fprintf(fp_h, "#include <%s>\n", s)) \
Lev Walkin34944f22010-10-07 08:25:37 +000034
Lev Walkin5f4dbb72017-11-11 14:52:11 -080035enum include_type_result {
36 TI_NOT_INCLUDED,
37 TI_INCLUDED_FROM_BULK,
38 TI_INCLUDED_FROM_CMDLINE
39};
40
Jon Ringle6431b1c2017-11-15 01:22:02 -050041static int asn1c_dump_streams(arg_t *arg, asn1c_dep_chainset *, const char *, int, char **);
Lev Walkinf15320b2004-06-03 03:38:44 +000042static int asn1c_print_streams(arg_t *arg);
Lev Walkinda672c42017-11-18 11:57:39 -080043static int asn1c_save_streams(arg_t *arg, asn1c_dep_chainset *, const char *,
44 int, char **);
45static int asn1c_copy_over(arg_t *arg, const char *destdir, const char *path,
46 const char *msg);
Lev Walkin4604d032005-03-04 08:52:50 +000047static int identical_files(const char *fname1, const char *fname2);
Lev Walkin66adab42006-09-23 02:52:12 +000048static int need_to_generate_pdu_collection(arg_t *arg);
Lev Walkin5f4dbb72017-11-11 14:52:11 -080049static abuf *generate_pdu_collection(arg_t *arg);
Jon Ringle6431b1c2017-11-15 01:22:02 -050050static int generate_pdu_collection_file(arg_t *arg, const char *destdir);
Lev Walkinc46b7cb2006-08-18 02:27:55 +000051static int generate_preamble(arg_t *, FILE *, int optc, char **argv);
Lev Walkin5f4dbb72017-11-11 14:52:11 -080052static enum include_type_result include_type_to_pdu_collection(arg_t *arg);
53static int pdu_collection_has_unused_types(arg_t *arg);
Lev Walkin66adab42006-09-23 02:52:12 +000054static const char *generate_pdu_C_definition(void);
Lev Walkin5230c642017-09-26 18:10:06 -070055static void asn1c__cleanup_pdu_type(void);
Lev Walkin5f4dbb72017-11-11 14:52:11 -080056static int asn1c__pdu_type_lookup(const char *typename);
Lev Walkinf15320b2004-06-03 03:38:44 +000057
Lev Walkin8a85b362017-09-26 22:54:44 -070058static int
Lev Walkin7d5d9302017-11-13 22:17:20 -080059asn1c__save_library_makefile(arg_t *arg, const asn1c_dep_chainset *deps,
Lev Walkinda672c42017-11-18 11:57:39 -080060 const char *datadir, const char *destdir,
61 const char *makefile_name) {
62 asn1p_module_t *mod;
Lev Walkin8a85b362017-09-26 22:54:44 -070063 FILE *mkf;
Lev Walkinf15320b2004-06-03 03:38:44 +000064
Jon Ringle6431b1c2017-11-15 01:22:02 -050065 mkf = asn1c_open_file(destdir, makefile_name, "", 0);
Lev Walkinacd9f8b2004-08-19 13:29:03 +000066 if(mkf == NULL) {
Lev Walkin8a85b362017-09-26 22:54:44 -070067 perror(makefile_name);
Lev Walkinacd9f8b2004-08-19 13:29:03 +000068 return -1;
69 }
Lev Walkinf15320b2004-06-03 03:38:44 +000070
Jon Ringle7871abf2017-11-13 21:29:40 -050071 safe_fprintf(mkf, "ASN_MODULE_SRCS=");
Lev Walkinb85a8132005-08-18 13:38:19 +000072 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
73 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkinacd9f8b2004-08-19 13:29:03 +000074 if(asn1_lang_map[arg->expr->meta_type]
75 [arg->expr->expr_type].type_cb) {
Jon Ringle6431b1c2017-11-15 01:22:02 -050076 safe_fprintf(mkf, "\t\\\n\t%s%s.c", destdir,
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080077 asn1c_make_identifier(AMI_MASK_ONLY_SPACES, arg->expr, 0));
Lev Walkinf15320b2004-06-03 03:38:44 +000078 }
79 }
Lev Walkinacd9f8b2004-08-19 13:29:03 +000080 }
Jon Ringle7871abf2017-11-13 21:29:40 -050081 safe_fprintf(mkf, "\n\nASN_MODULE_HDRS=");
Lev Walkinb85a8132005-08-18 13:38:19 +000082 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
83 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkind29bbce2004-09-23 22:19:14 +000084 if(asn1_lang_map[arg->expr->meta_type]
85 [arg->expr->expr_type].type_cb) {
Lev Walkinda672c42017-11-18 11:57:39 -080086 safe_fprintf(
87 mkf, "\t\\\n\t%s%s.h", destdir,
88 asn1c_make_identifier(AMI_MASK_ONLY_SPACES, arg->expr, 0));
89 }
Lev Walkind29bbce2004-09-23 22:19:14 +000090 }
91 }
Lev Walkinf2b2f372016-03-14 02:23:48 -070092 safe_fprintf(mkf, "\n\n");
Lev Walkinf15320b2004-06-03 03:38:44 +000093
Lev Walkinacd9f8b2004-08-19 13:29:03 +000094 /*
Lev Walkin8a85b362017-09-26 22:54:44 -070095 * Move necessary skeleton files and add them to Makefile.am.targets.
Lev Walkinacd9f8b2004-08-19 13:29:03 +000096 */
Lev Walkin7d5d9302017-11-13 22:17:20 -080097 asn1c_dep_chain *dlist = asn1c_deps_flatten(deps, ~FDEP_CONVERTER);
98 if(dlist) {
99 char dstpath[PATH_MAX];
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000100 char *dir_end;
Lev Walkin4efbfb72005-02-25 14:20:30 +0000101 size_t dlen = strlen(datadir);
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000102
Lev Walkin7d5d9302017-11-13 22:17:20 -0800103 assert(dlen < (sizeof(dstpath) / 2 - 2));
104 memcpy(dstpath, datadir, dlen);
105 dir_end = dstpath + dlen;
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000106 *dir_end++ = '/';
107
Jon Ringle7871abf2017-11-13 21:29:40 -0500108 for(size_t i = 0; i < dlist->deps_count; i++) {
109 char where[32]; /* Location of the */
110 char *what_kind; /* HDRS or SRCS */
111 const asn1c_dep_filename *dep_file = dlist->deps[i];
Lev Walkin7d5d9302017-11-13 22:17:20 -0800112 char *fname = dep_file->filename;
Lev Walkind29bbce2004-09-23 22:19:14 +0000113 char *dotH;
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000114
Lev Walkin7d5d9302017-11-13 22:17:20 -0800115 assert(strlen(fname) < (sizeof(dstpath) / 2));
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000116 strcpy(dir_end, fname);
117
Jon Ringle7871abf2017-11-13 21:29:40 -0500118 if(arg->flags & A1C_DEBUG) {
119 snprintf(where, sizeof(where), "(line %d col %d)",
120 dep_file->lineno, dep_file->column);
121 } else {
122 where[0] = '\0';
123 }
Lev Walkind1c28aa2017-11-11 18:04:26 -0800124
Lev Walkinda672c42017-11-18 11:57:39 -0800125 if(asn1c_copy_over(arg, destdir, dstpath, where) == -1) {
126 safe_fprintf(mkf, ">>>ABORTED<<<");
Lev Walkinf15320b2004-06-03 03:38:44 +0000127 fclose(mkf);
Lev Walkinf15320b2004-06-03 03:38:44 +0000128 return -1;
Lev Walkind29bbce2004-09-23 22:19:14 +0000129 }
Lev Walkinf218e782006-09-12 06:21:18 +0000130
Jon Ringle7871abf2017-11-13 21:29:40 -0500131 /* HDRS versus SRCS */
132 dotH = strrchr(fname, 'h');
133 if(dotH && fname < dotH && dotH[-1] == '.' && !dotH[1]) {
134 what_kind = "HDRS";
135 } else {
136 what_kind = "SRCS";
137 }
Lev Walkinda672c42017-11-18 11:57:39 -0800138 safe_fprintf(mkf, "ASN_MODULE_%s+=%s%s\n", what_kind, destdir,
139 fname);
140 }
Bi-Ruei, Chiu6f348942016-11-08 15:41:23 +0800141
Lev Walkin7d5d9302017-11-13 22:17:20 -0800142 asn1c_dep_chain_free(dlist);
Lev Walkin8a85b362017-09-26 22:54:44 -0700143 }
144
145 safe_fprintf(
146 mkf,
147 "\n"
148 "ASN_MODULE_CFLAGS=%s%s",
149 (arg->flags & A1C_GEN_OER) ? "" : "-DASN_DISABLE_OER_SUPPORT ",
150 (arg->flags & A1C_GEN_PER) ? "" : "-DASN_DISABLE_PER_SUPPORT ");
151
152 safe_fprintf(
153 mkf,
154 "\n\n"
Jon Ringlef71745a2017-11-13 23:54:13 -0500155 "lib_LTLIBRARIES+=libasncodec.la\n"
Lev Walkin8a85b362017-09-26 22:54:44 -0700156 "libasncodec_la_SOURCES="
Jon Ringle7871abf2017-11-13 21:29:40 -0500157 "$(ASN_MODULE_SRCS) $(ASN_MODULE_HDRS)\n"
Jon Ringlef71745a2017-11-13 23:54:13 -0500158 "libasncodec_la_CPPFLAGS=-I$(top_srcdir)/%s\n"
159 "libasncodec_la_CFLAGS=$(ASN_MODULE_CFLAGS)\n"
160 "libasncodec_la_LDFLAGS=-lm\n", destdir);
Lev Walkin8a85b362017-09-26 22:54:44 -0700161 fclose(mkf);
Lev Walkinda672c42017-11-18 11:57:39 -0800162 safe_fprintf(stderr, "Generated %s%s\n", destdir, makefile_name);
Lev Walkin8a85b362017-09-26 22:54:44 -0700163
164 return 0;
165}
166
167static int
Lev Walkinda672c42017-11-18 11:57:39 -0800168asn1c__save_example_mk_makefile(arg_t *arg, const asn1c_dep_chainset *deps,
169 const char *datadir, const char *destdir,
170 const char *makefile_name,
Jon Ringle3016fd52017-11-15 02:06:47 -0500171 const char *library_makefile_name, int argc,
172 char **argv) {
Lev Walkinda672c42017-11-18 11:57:39 -0800173 FILE *mkf;
174 asn1c_dep_chain *dlist = asn1c_deps_flatten(deps, FDEP_CONVERTER);
Lev Walkin8a85b362017-09-26 22:54:44 -0700175
Lev Walkinda672c42017-11-18 11:57:39 -0800176 /* Generate converter-example.mk snippet */
177 mkf = asn1c_open_file(destdir, makefile_name, "", 0);
178 if(mkf == NULL) {
179 perror(makefile_name);
180 return -1;
181 }
182 safe_fprintf(
183 mkf,
184 "include %s%s\n\n"
185 "LIBS += -lm\n"
186 "CFLAGS += $(ASN_MODULE_CFLAGS) %s%s-I.\n"
187 "ASN_LIBRARY ?= libasncodec.a\n"
188 "ASN_PROGRAM ?= converter-example\n"
189 "ASN_PROGRAM_SRCS ?= ",
190 destdir, library_makefile_name,
191 (arg->flags & A1C_PDU_TYPE) ? generate_pdu_C_definition() : "",
192 need_to_generate_pdu_collection(arg) ? "-DASN_PDU_COLLECTION " : "");
Lev Walkin8a85b362017-09-26 22:54:44 -0700193
Lev Walkinda672c42017-11-18 11:57:39 -0800194 if(dlist) {
195 for(size_t i = 0; i < dlist->deps_count; i++) {
196 char dstpath[PATH_MAX];
197 int ret = snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir,
198 dlist->deps[i]->filename);
199 assert(ret > 0 && (size_t)ret < sizeof(dstpath));
200 if(asn1c_copy_over(arg, destdir, dstpath, "implicit") == -1) {
201 safe_fprintf(mkf, ">>>ABORTED<<<");
202 fclose(mkf);
203 return -1;
Jon Ringle6431b1c2017-11-15 01:22:02 -0500204 }
Lev Walkinda672c42017-11-18 11:57:39 -0800205 safe_fprintf(mkf, "\\\n\t%s%s", destdir, dlist->deps[i]->filename);
206 }
207 asn1c_dep_chain_free(dlist);
208 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000209
Lev Walkinda672c42017-11-18 11:57:39 -0800210 if(need_to_generate_pdu_collection(arg)) {
211 safe_fprintf(mkf, "\\\n\t%spdu_collection.c", destdir);
212 if(generate_pdu_collection_file(arg, destdir)) {
213 return -1;
214 }
215 }
Lev Walkin59b176e2005-11-26 11:25:14 +0000216
Lev Walkinda672c42017-11-18 11:57:39 -0800217 safe_fprintf(
218 mkf,
219 "\n\nall: $(ASN_PROGRAM)\n"
220 "\n$(ASN_PROGRAM): $(ASN_LIBRARY) $(ASN_PROGRAM_SRCS:.c=.o)"
221 "\n\t$(CC) $(CFLAGS) $(CPPFLAGS) -o $(ASN_PROGRAM) "
222 "$(ASN_PROGRAM_SRCS:.c=.o) $(LDFLAGS) $(ASN_LIBRARY) $(LIBS)\n"
223 "\n$(ASN_LIBRARY): $(ASN_MODULE_SRCS:.c=.o)"
224 "\n\t$(AR) rcs $@ $(ASN_MODULE_SRCS:.c=.o)\n"
225 "\n.SUFFIXES:"
226 "\n.SUFFIXES: .c .o\n"
227 "\n.c.o:"
228 "\n\t$(CC) $(CFLAGS) -o $@ -c $<\n"
229 "\nclean:"
230 "\n\trm -f $(ASN_PROGRAM) $(ASN_LIBRARY)"
231 "\n\trm -f $(ASN_MODULE_SRCS:.c=.o) $(ASN_PROGRAM_SRCS:.c=.o)\n"
232 "\nregen: regenerate-from-asn1-source\n"
233 "\nregenerate-from-asn1-source:\n\t");
Lev Walkin866cff12005-03-05 00:50:53 +0000234
Lev Walkinda672c42017-11-18 11:57:39 -0800235 for(int i = 0; i < argc; i++)
236 safe_fprintf(mkf, "%s%s", i ? " " : "", argv[i]);
Johannes Lode35ad7e62020-05-22 01:26:10 +0200237 safe_fprintf(mkf, "\n\n");
Lev Walkin866cff12005-03-05 00:50:53 +0000238
Lev Walkinda672c42017-11-18 11:57:39 -0800239 fclose(mkf);
240 safe_fprintf(stderr, "Generated %s%s\n", destdir, makefile_name);
Jon Ringle3016fd52017-11-15 02:06:47 -0500241
Jon Ringle6431b1c2017-11-15 01:22:02 -0500242 return 0;
Lev Walkin8a85b362017-09-26 22:54:44 -0700243}
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000244
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800245static int
Jon Ringle1029a6e2017-11-14 10:13:07 -0500246asn1c__save_example_am_makefile(arg_t *arg, const asn1c_dep_chainset *deps, const char *datadir,
247 const char *destdir, const char *makefile_name,
248 const char *library_makefile_name, int argc,
249 char **argv) {
250 FILE *mkf;
251 asn1c_dep_chain *dlist = asn1c_deps_flatten(deps, FDEP_CONVERTER);
252
253 /* Generate example.am snippet */
254 mkf = asn1c_open_file(destdir, makefile_name, "", 0);
255 if(mkf == NULL) {
Jon Ringle1029a6e2017-11-14 10:13:07 -0500256 return -1;
257 }
258 safe_fprintf(mkf,
259 "include %s%s\n\n"
260 "bin_PROGRAMS += asn1convert\n"
261 "asn1convert_CFLAGS = $(ASN_MODULE_CFLAGS) %s%s\n"
262 "asn1convert_CPPFLAGS = -I$(top_srcdir)/%s\n"
263 "asn1convert_LDADD = libasncodec.la\n"
264 "asn1convert_SOURCES = ",
265 destdir, library_makefile_name,
266 (arg->flags & A1C_PDU_TYPE) ? generate_pdu_C_definition() : "",
267 need_to_generate_pdu_collection(arg) ? "-DASN_PDU_COLLECTION " : "", destdir);
268
269 if(dlist) {
270 for(size_t i = 0; i < dlist->deps_count; i++) {
271 char dstpath[PATH_MAX];
272 int ret = snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir,
273 dlist->deps[i]->filename);
274 assert(ret > 0 && (size_t)ret < sizeof(dstpath));
275 if(asn1c_copy_over(arg, destdir, dstpath, "implicit") == -1) {
276 safe_fprintf(mkf, ">>>ABORTED<<<");
277 fclose(mkf);
278 return -1;
279 }
280 safe_fprintf(mkf, "\\\n\t%s%s", destdir, dlist->deps[i]->filename);
281 }
282 asn1c_dep_chain_free(dlist);
283 }
284
285 if(need_to_generate_pdu_collection(arg)) {
286 safe_fprintf(mkf, "\\\n\t%spdu_collection.c", destdir);
287 if(generate_pdu_collection_file(arg, destdir))
288 return -1;
289 }
290
291 safe_fprintf(mkf,
292 "\nregen: regenerate-from-asn1-source\n"
293 "\nregenerate-from-asn1-source:\n\t");
294
295 for(int i = 0; i < argc; i++)
296 safe_fprintf(mkf, "%s%s", i ? " " : "", argv[i]);
297 safe_fprintf(mkf, "\n\n");
298
299 fclose(mkf);
300 safe_fprintf(stderr, "Generated %s%s\n", destdir, makefile_name);
301
302 return 0;
303}
304
Jon Ringle3aa33c02017-11-14 11:16:03 -0500305static int
306asn1c__save_autotools_example(const char *destdir,
307 const char *program_makefile_name) {
308 FILE *fd;
309 const char* confac = "configure.ac";
310 const char* makeam = "Makefile.am";
311
312 if ((access(confac, F_OK) != -1)
313 || (access(makeam, F_OK) != -1))
314 {
315 safe_fprintf(stderr, "Refusing to overwrite existing '%s' or '%s'\n", confac, makeam);
316 return -1;
317 }
318
319 fd = asn1c_open_file("", confac, "", 0);
320 if(fd == NULL) {
321 perror(confac);
322 return -1;
323 }
324
325 safe_fprintf(fd,
326 "AC_INIT([asn1convert],[0.1])\n"
327 "AM_INIT_AUTOMAKE([-Werror foreign subdir-objects])\n"
328 "AC_PREREQ([2.62])\n"
329 "AC_PROG_CC\n"
330 "LT_INIT\n"
331 "AM_SILENT_RULES([yes])\n"
332 "AC_CONFIG_FILES([Makefile])\n"
333 "AC_OUTPUT\n");
334 fclose(fd);
335 safe_fprintf(stderr, "Generated minimal example %s\n", confac);
336
337 fd = asn1c_open_file("", makeam, "", 0);
338 if(fd == NULL) {
339 perror(makeam);
340 return -1;
341 }
342
343 safe_fprintf(fd,
344 "bin_PROGRAMS =\n"
345 "lib_LTLIBRARIES =\n"
346 "include %s%s\n\n",
347 destdir, program_makefile_name);
348
349 fclose(fd);
350 safe_fprintf(stderr, "Generated minimal example %s\n", makeam);
351 safe_fprintf(stderr, "\nRun the following to generate a configure script:\n");
352 safe_fprintf(stderr, "$ autoreconf --force --install\n");
353 return 0;
354}
355
356static int
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800357can_generate_pdu_collection(arg_t *arg) {
358 abuf *buf = generate_pdu_collection(arg);
359 if(!buf) {
360 return -1;
361 }
362 abuf_free(buf);
363 return 0;
364}
365
Lev Walkin8a85b362017-09-26 22:54:44 -0700366int
Jon Ringle6431b1c2017-11-15 01:22:02 -0500367asn1c_save_compiled_output(arg_t *arg, const char *datadir, const char *destdir,
368 int argc, int optc, char **argv) {
Lev Walkin8a85b362017-09-26 22:54:44 -0700369 int ret = -1;
Lev Walkin5230c642017-09-26 18:10:06 -0700370
Jon Ringle1029a6e2017-11-14 10:13:07 -0500371 const char* example_am_makefile = "Makefile.am.asn1convert";
Jon Ringle3016fd52017-11-15 02:06:47 -0500372 const char* program_makefile = "converter-example.mk";
Jon Ringle6431b1c2017-11-15 01:22:02 -0500373 const char* library_makefile = "Makefile.am.libasncodec";
374
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800375 /*
376 * Early check that we can properly generate PDU collection.
377 */
378 if(can_generate_pdu_collection(arg) == -1) {
379 return -1;
380 }
381
Lev Walkin7d5d9302017-11-13 22:17:20 -0800382 asn1c_dep_chainset *deps;
Lev Walkin8a85b362017-09-26 22:54:44 -0700383 do {
384 asn1p_module_t *mod;
385
386 deps = asn1c_read_file_dependencies(arg, datadir);
387 if(!deps && datadir) {
388 WARNING(
389 "Cannot read file-dependencies information "
390 "from %s\n",
391 datadir);
392 }
393
394 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
395 TQ_FOR(arg->expr, &(mod->members), next) {
396 if(asn1_lang_map[arg->expr->meta_type][arg->expr->expr_type]
397 .type_cb) {
Lev Walkinda672c42017-11-18 11:57:39 -0800398 ret = asn1c_dump_streams(arg, deps, destdir, optc, argv);
399 if(ret) break;
Lev Walkin8a85b362017-09-26 22:54:44 -0700400 }
401 }
402 }
403
404 /*
405 * Dump out the Makefile template and the rest of the support code.
406 */
407 if((arg->flags & A1C_PRINT_COMPILED)
408 || (arg->flags & A1C_OMIT_SUPPORT_CODE)) {
409 ret = 0; /* Success */
410 break;
411 }
412
Lev Walkinda672c42017-11-18 11:57:39 -0800413 if(ret) break;
414
Jon Ringle6431b1c2017-11-15 01:22:02 -0500415 ret = asn1c__save_library_makefile(arg, deps, datadir, destdir,
416 library_makefile);
Lev Walkin8a85b362017-09-26 22:54:44 -0700417 if(ret) break;
Lev Walkind1c28aa2017-11-11 18:04:26 -0800418
419 if(arg->flags & A1C_GEN_EXAMPLE) {
Jon Ringle3016fd52017-11-15 02:06:47 -0500420 ret = asn1c__save_example_mk_makefile(arg, deps, datadir, destdir,
421 program_makefile,
422 library_makefile, argc, argv);
Lev Walkind1c28aa2017-11-11 18:04:26 -0800423 if(ret) break;
Jon Ringle1029a6e2017-11-14 10:13:07 -0500424 ret = asn1c__save_example_am_makefile(arg, deps, datadir, destdir,
425 example_am_makefile,
426 library_makefile, argc, argv);
427 if(ret) break;
Jon Ringle3aa33c02017-11-14 11:16:03 -0500428
429 if(arg->flags & A1C_GEN_AUTOTOOLS_EXAMPLE) {
430 ret = asn1c__save_autotools_example(destdir, example_am_makefile);
431 if(ret) break;
432 }
Lev Walkind1c28aa2017-11-11 18:04:26 -0800433 }
Lev Walkin8a85b362017-09-26 22:54:44 -0700434 } while(0);
435
Lev Walkin7d5d9302017-11-13 22:17:20 -0800436 asn1c_dep_chainset_free(deps);
Lev Walkin8a85b362017-09-26 22:54:44 -0700437 asn1c__cleanup_pdu_type();
438
439 return ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000440}
441
442/*
443 * Dump the streams.
444 */
445static int
Lev Walkinda672c42017-11-18 11:57:39 -0800446asn1c_dump_streams(arg_t *arg, asn1c_dep_chainset *deps, const char *destdir,
447 int optc, char **argv) {
Lev Walkin7d5d9302017-11-13 22:17:20 -0800448 if(arg->flags & A1C_PRINT_COMPILED) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000449 return asn1c_print_streams(arg);
450 } else {
Jon Ringle6431b1c2017-11-15 01:22:02 -0500451 return asn1c_save_streams(arg, deps, destdir, optc, argv);
Lev Walkinf15320b2004-06-03 03:38:44 +0000452 }
453}
454
455static int
456asn1c_print_streams(arg_t *arg) {
457 compiler_streams_t *cs = arg->expr->data;
458 asn1p_expr_t *expr = arg->expr;
459 int i;
460
Lev Walkin64399722004-08-11 07:17:22 +0000461 for(i = 1; i < OT_MAX; i++) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000462 out_chunk_t *ot;
Lev Walkin59004fa2004-08-20 13:37:01 +0000463 if(TQ_FIRST(&cs->destination[i].chunks) == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000464 continue;
465
466 printf("\n/*** <<< %s [%s] >>> ***/\n\n",
467 _compiler_stream2str[i],
468 expr->Identifier);
469
Lev Walkin59004fa2004-08-20 13:37:01 +0000470 TQ_FOR(ot, &(cs->destination[i].chunks), next) {
Lev Walkinf2b2f372016-03-14 02:23:48 -0700471 safe_fwrite(ot->buf, ot->len, 1, stdout);
Lev Walkinf15320b2004-06-03 03:38:44 +0000472 }
473 }
474
475 return 0;
476}
477
478static int
Lev Walkinda672c42017-11-18 11:57:39 -0800479asn1c_save_streams(arg_t *arg, asn1c_dep_chainset *deps, const char *destdir,
480 int optc, char **argv) {
Lev Walkin7d5d9302017-11-13 22:17:20 -0800481 asn1p_expr_t *expr = arg->expr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000482 compiler_streams_t *cs = expr->data;
483 out_chunk_t *ot;
484 FILE *fp_c, *fp_h;
Lev Walkin4604d032005-03-04 08:52:50 +0000485 char *tmpname_c, *tmpname_h;
Lev Walkina4f8e942017-10-08 19:28:20 -0700486 char name_buf[FILENAME_MAX];
Lev Walkinb46156d2017-09-05 02:53:05 -0700487 const char *header_id;
Lev Walkin4604d032005-03-04 08:52:50 +0000488 const char *c_retained = "";
489 const char *h_retained = "";
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800490 char *filename;
Lev Walkinf15320b2004-06-03 03:38:44 +0000491
492 if(cs == NULL) {
Lev Walkinf2b2f372016-03-14 02:23:48 -0700493 safe_fprintf(stderr, "Cannot compile %s at line %d\n",
Lev Walkinf15320b2004-06-03 03:38:44 +0000494 expr->Identifier, expr->_lineno);
495 return -1;
496 }
497
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800498 filename = strdup(asn1c_make_identifier(AMI_MASK_ONLY_SPACES, expr, (char*)0));
Jon Ringle6431b1c2017-11-15 01:22:02 -0500499 fp_c = asn1c_open_file(destdir, filename, ".c", &tmpname_c);
Lev Walkinda672c42017-11-18 11:57:39 -0800500 if(fp_c == NULL) {
501 return -1;
502 }
503 fp_h = asn1c_open_file(destdir, filename, ".h", &tmpname_h);
504 if(fp_h == NULL) {
505 unlink(tmpname_c);
506 free(tmpname_c);
507 fclose(fp_c);
508 return -1;
509 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000510
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000511 generate_preamble(arg, fp_c, optc, argv);
512 generate_preamble(arg, fp_h, optc, argv);
Lev Walkinc3b8f6d2004-06-03 05:06:25 +0000513
Lev Walkina00d6b32006-03-21 03:40:38 +0000514 header_id = asn1c_make_identifier(0, expr, NULL);
Lev Walkinf2b2f372016-03-14 02:23:48 -0700515 safe_fprintf(fp_h,
Lev Walkinf15320b2004-06-03 03:38:44 +0000516 "#ifndef\t_%s_H_\n"
517 "#define\t_%s_H_\n"
518 "\n", header_id, header_id);
519
Lev Walkinf2b2f372016-03-14 02:23:48 -0700520 safe_fprintf(fp_h, "\n");
Lev Walkin34944f22010-10-07 08:25:37 +0000521 HINCLUDE("asn_application.h");
Lev Walkinf15320b2004-06-03 03:38:44 +0000522
Lev Walkinb9b8b952005-03-05 00:33:27 +0000523#define SAVE_STREAM(fp, idx, msg, actdep) do { \
Lev Walkin866cff12005-03-05 00:50:53 +0000524 if(TQ_FIRST(&(cs->destination[idx].chunks)) && *msg) \
Lev Walkinf2b2f372016-03-14 02:23:48 -0700525 safe_fprintf(fp, "\n/* %s */\n", msg); \
Lev Walkinc8285712005-03-04 22:18:20 +0000526 TQ_FOR(ot, &(cs->destination[idx].chunks), next) { \
Lev Walkin7d5d9302017-11-13 22:17:20 -0800527 if(actdep) asn1c_activate_dependency(deps, ot->buf, header_id); \
Lev Walkinf2b2f372016-03-14 02:23:48 -0700528 safe_fwrite(ot->buf, ot->len, 1, fp); \
Lev Walkinc8285712005-03-04 22:18:20 +0000529 } \
530} while(0)
531
Lev Walkinb9b8b952005-03-05 00:33:27 +0000532 SAVE_STREAM(fp_h, OT_INCLUDES, "Including external dependencies", 1);
Lev Walkin3d551c02005-07-15 18:49:41 +0000533
Lev Walkinf2b2f372016-03-14 02:23:48 -0700534 safe_fprintf(fp_h, "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
Lev Walkinb9b8b952005-03-05 00:33:27 +0000535 SAVE_STREAM(fp_h, OT_DEPS, "Dependencies", 0);
536 SAVE_STREAM(fp_h, OT_FWD_DECLS, "Forward declarations", 0);
Bi-Ruei, Chiu9b87e5b2016-06-06 00:23:16 +0800537 SAVE_STREAM(fp_h, OT_FWD_DEFS, "Forward definitions", 0);
Lev Walkinb9b8b952005-03-05 00:33:27 +0000538 SAVE_STREAM(fp_h, OT_TYPE_DECLS, expr->Identifier, 0);
539 SAVE_STREAM(fp_h, OT_FUNC_DECLS,"Implementation", 0);
Lev Walkinf2b2f372016-03-14 02:23:48 -0700540 safe_fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n");
Lev Walkin3dcaafa2004-08-11 05:21:32 +0000541
Lev Walkinae5540f2006-02-19 04:26:37 +0000542 if(!(arg->flags & A1C_NO_INCLUDE_DEPS))
543 SAVE_STREAM(fp_h, OT_POST_INCLUDE, "Referred external types", 1);
544
Lev Walkinf2b2f372016-03-14 02:23:48 -0700545 safe_fprintf(fp_h, "\n#endif\t/* _%s_H_ */\n", header_id);
Lev Walkin47370392006-02-19 04:30:15 +0000546
Lev Walkin34944f22010-10-07 08:25:37 +0000547 HINCLUDE("asn_internal.h");
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800548 safe_fprintf(fp_c, "#include \"%s.h\"\n\n", filename);
Lev Walkinb9b8b952005-03-05 00:33:27 +0000549 if(arg->flags & A1C_NO_INCLUDE_DEPS)
Lev Walkin866cff12005-03-05 00:50:53 +0000550 SAVE_STREAM(fp_c, OT_POST_INCLUDE, "", 1);
Lev Walkin9de6cd82017-08-10 05:47:46 -0700551 TQ_FOR(ot, &(cs->destination[OT_IOC_TABLES].chunks), next)
552 safe_fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin59004fa2004-08-20 13:37:01 +0000553 TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next)
Lev Walkinf2b2f372016-03-14 02:23:48 -0700554 safe_fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin59004fa2004-08-20 13:37:01 +0000555 TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next)
Lev Walkinf2b2f372016-03-14 02:23:48 -0700556 safe_fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin725883b2006-10-09 12:07:58 +0000557 TQ_FOR(ot, &(cs->destination[OT_CTDEFS].chunks), next)
Lev Walkinf2b2f372016-03-14 02:23:48 -0700558 safe_fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin59004fa2004-08-20 13:37:01 +0000559 TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
Lev Walkinf2b2f372016-03-14 02:23:48 -0700560 safe_fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkinf15320b2004-06-03 03:38:44 +0000561
Lev Walkin9de6cd82017-08-10 05:47:46 -0700562 assert(OT_MAX == 13); /* Protection from reckless changes */
Lev Walkinf15320b2004-06-03 03:38:44 +0000563
564 fclose(fp_c);
565 fclose(fp_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000566
Jon Ringle6431b1c2017-11-15 01:22:02 -0500567 int ret = snprintf(name_buf, sizeof(name_buf), "%s%s.c", destdir, filename);
Lev Walkina4f8e942017-10-08 19:28:20 -0700568 assert(ret > 0 && ret < (ssize_t)sizeof(name_buf));
Lev Walkin4604d032005-03-04 08:52:50 +0000569
Lev Walkin4604d032005-03-04 08:52:50 +0000570 if(identical_files(name_buf, tmpname_c)) {
571 c_retained = " (contents unchanged)";
572 unlink(tmpname_c);
573 } else {
574 if(rename(tmpname_c, name_buf)) {
575 unlink(tmpname_c);
576 perror(tmpname_c);
Lev Walkina895afb2005-10-06 10:09:34 +0000577 free(tmpname_c);
578 free(tmpname_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000579 return -1;
580 }
581 }
582
Jon Ringle6431b1c2017-11-15 01:22:02 -0500583 sprintf(name_buf, "%s%s.h", destdir, filename);
Lev Walkin4604d032005-03-04 08:52:50 +0000584 if(identical_files(name_buf, tmpname_h)) {
585 h_retained = " (contents unchanged)";
586 unlink(tmpname_h);
587 } else {
588 if(rename(tmpname_h, name_buf)) {
589 unlink(tmpname_h);
590 perror(tmpname_h);
Lev Walkina895afb2005-10-06 10:09:34 +0000591 free(tmpname_c);
592 free(tmpname_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000593 return -1;
594 }
595 }
596
597 free(tmpname_c);
598 free(tmpname_h);
599
Jon Ringle6431b1c2017-11-15 01:22:02 -0500600 safe_fprintf(stderr, "Compiled %s%s.c%s\n",
601 destdir, filename, c_retained);
602 safe_fprintf(stderr, "Compiled %s%s.h%s\n",
603 destdir, filename, h_retained);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800604 free(filename);
Lev Walkinf15320b2004-06-03 03:38:44 +0000605 return 0;
606}
607
Lev Walkin4604d032005-03-04 08:52:50 +0000608static int
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000609generate_preamble(arg_t *arg, FILE *fp, int optc, char **argv) {
Lev Walkinf2b2f372016-03-14 02:23:48 -0700610 safe_fprintf(fp,
Lev Walkin8253ea92006-03-17 01:47:57 +0000611 "/*\n"
612 " * Generated by asn1c-" VERSION " (http://lionet.info/asn1c)\n"
613 " * From ASN.1 module \"%s\"\n"
614 " * \tfound in \"%s\"\n",
615 arg->expr->module->ModuleName,
616 arg->expr->module->source_file_name);
617 if(optc > 1) {
618 int i;
Lev Walkinf2b2f372016-03-14 02:23:48 -0700619 safe_fprintf(fp, " * \t`asn1c ");
Lev Walkin8253ea92006-03-17 01:47:57 +0000620 for(i = 1; i < optc; i++)
Lev Walkinf2b2f372016-03-14 02:23:48 -0700621 safe_fprintf(fp, "%s%s", i>1?" ":"", argv[i]);
622 safe_fprintf(fp, "`\n");
Lev Walkin8253ea92006-03-17 01:47:57 +0000623 }
Lev Walkinf2b2f372016-03-14 02:23:48 -0700624 safe_fprintf(fp, " */\n\n");
Lev Walkin8253ea92006-03-17 01:47:57 +0000625 return 0;
626}
627
628static int
Lev Walkin4604d032005-03-04 08:52:50 +0000629identical_files(const char *fname1, const char *fname2) {
Lev Walkina895afb2005-10-06 10:09:34 +0000630 char buf[2][4096];
Lev Walkin4604d032005-03-04 08:52:50 +0000631 FILE *fp1, *fp2;
632 size_t olen, nlen;
633 int retval = 1; /* Files are identical */
634
Lev Walkin93659562010-11-20 09:47:13 -0800635#ifndef _WIN32
Lev Walkina895afb2005-10-06 10:09:34 +0000636 struct stat sb;
637
638 if(lstat(fname1, &sb) || !S_ISREG(sb.st_mode)
639 || lstat(fname2, &sb) || !S_ISREG(sb.st_mode)) {
640 return 0; /* Files are not identical */
641 }
642#endif
643
Lev Walkin4604d032005-03-04 08:52:50 +0000644 fp1 = fopen(fname1, "r");
645 if(!fp1) { return 0; }
646 fp2 = fopen(fname2, "r");
647 if(!fp2) { fclose(fp1); return 0; }
648
649 while((olen = fread(buf[0], 1, sizeof(buf[0]), fp1))) {
650 nlen = fread(buf[1], 1, olen, fp2);
651 if(nlen != olen || memcmp(buf[0], buf[1], nlen)) {
652 retval = 0;
653 break;
654 }
655 }
656 nlen = fread(buf[1], 1, 1, fp2);
657 if(nlen) retval = 0;
658
659 fclose(fp1);
660 fclose(fp2);
661 return retval;
662}
663
Lev Walkin4efbfb72005-02-25 14:20:30 +0000664/*
665 * Copy file for real.
666 */
667static int
668real_copy(const char *src, const char *dst) {
Lev Walkina895afb2005-10-06 10:09:34 +0000669 unsigned char buf[4096];
670 char *tmpname;
Lev Walkin4efbfb72005-02-25 14:20:30 +0000671 FILE *fpsrc, *fpdst;
672 size_t len;
673 int retval = 0;
674
Lev Walkin4604d032005-03-04 08:52:50 +0000675 if(identical_files(src, dst))
676 return retval; /* Success, no need to copy for real. */
677
678 fpsrc = fopen(src, "r");
Lev Walkin4efbfb72005-02-25 14:20:30 +0000679 if(!fpsrc) { errno = EIO; return -1; }
Jon Ringle6431b1c2017-11-15 01:22:02 -0500680 fpdst = asn1c_open_file(NULL, dst, "", &tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000681 if(!fpdst) { fclose(fpsrc); errno = EIO; return -1; }
682
683 while(!feof(fpsrc)) {
684 len = fread(buf, 1, sizeof(buf), fpsrc);
Lev Walkinf2b2f372016-03-14 02:23:48 -0700685 if(safe_fwrite(buf, 1, len, fpdst) != len) {
Lev Walkina895afb2005-10-06 10:09:34 +0000686 perror(tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000687 errno = EIO;
688 retval = -1;
689 break;
690 }
691 }
Lev Walkin4efbfb72005-02-25 14:20:30 +0000692 fclose(fpsrc);
693 fclose(fpdst);
Lev Walkina895afb2005-10-06 10:09:34 +0000694
695 /* Check if copied correctly, and rename into a permanent name */
696 if(retval) {
697 unlink(tmpname);
698 } else if(rename(tmpname, dst)) {
699 unlink(tmpname);
700 perror(tmpname);
701 retval = -1;
702 }
703 free(tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000704 return retval;
705}
706
Lev Walkinf15320b2004-06-03 03:38:44 +0000707static int
Lev Walkinda672c42017-11-18 11:57:39 -0800708asn1c_copy_over(arg_t *arg, const char *destdir, const char *path,
709 const char *msg) {
Lev Walkin93659562010-11-20 09:47:13 -0800710#ifdef _WIN32
Lev Walkina895afb2005-10-06 10:09:34 +0000711 int use_real_copy = 1;
712#else
Lev Walkin2655eb32013-03-25 19:09:04 -0700713 int use_real_copy = !(arg->flags & A1C_LINK_SKELETONS);
Lev Walkina895afb2005-10-06 10:09:34 +0000714#endif
Lev Walkind9bd7752004-06-05 08:17:50 +0000715
Jon Ringle6431b1c2017-11-15 01:22:02 -0500716 const char *fname = a1c_basename(path, destdir);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000717 if(!fname
Lev Walkina895afb2005-10-06 10:09:34 +0000718 || (use_real_copy ? real_copy(path, fname) : symlink(path, fname))
Lev Walkin4efbfb72005-02-25 14:20:30 +0000719 ) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000720 if(errno == EEXIST) {
721 struct stat sb1, sb2;
722 if(stat(path, &sb1) == 0
723 && stat(fname, &sb2) == 0
724 && sb1.st_dev == sb2.st_dev
725 && sb1.st_ino == sb2.st_ino) {
726 /*
727 * Nothing to do.
728 */
Lev Walkinf2b2f372016-03-14 02:23:48 -0700729 safe_fprintf(stderr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000730 "File %s is already here as %s\n",
731 path, fname);
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000732 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000733 } else {
Lev Walkinf2b2f372016-03-14 02:23:48 -0700734 safe_fprintf(stderr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000735 "Retaining local %s (%s suggested)\n",
736 fname, path);
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000737 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000738 }
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000739 } else if(errno == ENOENT) {
740 /* Ignore this */
741 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000742 } else {
Lev Walkinf2b2f372016-03-14 02:23:48 -0700743 safe_fprintf(stderr, "%s %s -> %s failed: %s\n",
Lev Walkina895afb2005-10-06 10:09:34 +0000744 use_real_copy ? "Copy" : "Symlink",
Lev Walkinf15320b2004-06-03 03:38:44 +0000745 path, fname, strerror(errno));
746 return -1;
747 }
748 }
749
Lev Walkin7d5d9302017-11-13 22:17:20 -0800750 const int has_msg = msg && *msg;
751 safe_fprintf(stderr, "%s %s\t-> %s%s%s\n",
752 use_real_copy ? "Copied" : "Symlinked", path, fname,
753 has_msg ? " " : "", has_msg ? msg : "");
Lev Walkinf15320b2004-06-03 03:38:44 +0000754
Lev Walkin7d5d9302017-11-13 22:17:20 -0800755 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000756}
757
Lev Walkin59b176e2005-11-26 11:25:14 +0000758
759static int
Lev Walkinda672c42017-11-18 11:57:39 -0800760generate_pdu_collection_file(arg_t *arg, const char *destdir) {
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800761 abuf *buf = generate_pdu_collection(arg);
762 assert(buf);
Lev Walkin59b176e2005-11-26 11:25:14 +0000763
Jon Ringle6431b1c2017-11-15 01:22:02 -0500764 FILE *fp = asn1c_open_file(destdir, "pdu_collection", ".c", 0);
Lev Walkin59b176e2005-11-26 11:25:14 +0000765 if(fp == NULL) {
766 perror("pdu_collection.c");
767 return -1;
768 }
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800769 safe_fwrite(buf->buffer, buf->length, 1, fp);
770 fclose(fp);
Lev Walkin59b176e2005-11-26 11:25:14 +0000771
Lev Walkinf2b2f372016-03-14 02:23:48 -0700772 safe_fprintf(stderr, "Generated pdu_collection.c\n");
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800773 return 0;
774}
Lev Walkin59b176e2005-11-26 11:25:14 +0000775
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800776static abuf *
777generate_pdu_collection(arg_t *arg) {
778 asn1p_module_t *mod;
779 abuf *buf = abuf_new();
780
781 abuf_printf(buf, "/*\n * Generated by asn1c-" VERSION
782 " (http://lionet.info/asn1c)\n */\n\n");
Lev Walkin3be49192017-11-11 16:13:32 -0800783 abuf_printf(buf,
784 "struct asn_TYPE_descriptor_s;\t"
785 "/* Forward declaration */\n\n");
786
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800787
788 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
789 TQ_FOR(arg->expr, &(mod->members), next) {
790 if(include_type_to_pdu_collection(arg) == TI_NOT_INCLUDED) continue;
791 abuf_printf(buf,
Lev Walkin3be49192017-11-11 16:13:32 -0800792 "extern struct asn_TYPE_descriptor_s "
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800793 "asn_DEF_%s;\n",
794 asn1c_make_identifier(0, arg->expr, NULL));
795 }
796 }
797
798 abuf_printf(buf, "\n\n");
799 abuf_printf(buf, "struct asn_TYPE_descriptor_s *asn_pdu_collection[] = {\n");
800 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
801 int mod_printed = 0;
802 TQ_FOR(arg->expr, &(mod->members), next) {
803 switch(include_type_to_pdu_collection(arg)) {
804 case TI_NOT_INCLUDED:
805 continue;
806 case TI_INCLUDED_FROM_BULK:
807 /* Increment */
808 asn1c__pdu_type_lookup(arg->expr->Identifier);
809 break;
810 case TI_INCLUDED_FROM_CMDLINE:
811 break;
812 }
813 if(!mod_printed++) {
814 abuf_printf(buf, "\t/* From module %s in %s */\n",
815 arg->expr->module->ModuleName,
816 arg->expr->module->source_file_name);
817 }
818 abuf_printf(buf, "\t&asn_DEF_%s,\t\n",
819 asn1c_make_identifier(0, arg->expr, NULL));
820 }
821 }
822
823 abuf_printf(buf, "\t0\n};\n\n");
824
825 if(pdu_collection_has_unused_types(arg)) {
826 abuf_free(buf);
827 return NULL;
828 }
829
830 return buf;
Lev Walkin59b176e2005-11-26 11:25:14 +0000831}
832
Lev Walkin66adab42006-09-23 02:52:12 +0000833static struct PDUType {
834 char *typename;
835 int used;
836} *pduType;
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800837static size_t pduTypes;
Lev Walkin66adab42006-09-23 02:52:12 +0000838
839static const char *
840generate_pdu_C_definition(void) {
Lev Walkina4f3d462017-08-05 22:40:14 -0700841 const char *src;
842 char *def;
Lev Walkin66adab42006-09-23 02:52:12 +0000843 char *dst;
Lev Walkina4f3d462017-08-05 22:40:14 -0700844 if(pduTypes == 0) return "";
845 def = malloc(strlen(pduType[0].typename) + 20);
846 assert(def);
847 strcpy(def, "-DPDU=");
848 for(src = pduType[0].typename, dst = def + 6; *src; src++, dst++) {
849 if((*dst = *src) == '-') {
850 *dst = '_';
851 }
852 }
853 *dst++ = ' ';
854 *dst = 0;
855 return def;
Lev Walkin66adab42006-09-23 02:52:12 +0000856}
857
858void
859asn1c__add_pdu_type(const char *ctypename) {
860 char *typename = strdup(ctypename);
861 assert(typename && *typename);
862
863 pduType = realloc(pduType, sizeof(pduType[0]) * (pduTypes + 1));
864 assert(pduType);
865 pduType[pduTypes].used = 0;
866 pduType[pduTypes].typename = typename;
867 pduTypes++;
868}
869
Lev Walkin5230c642017-09-26 18:10:06 -0700870static void
871asn1c__cleanup_pdu_type() {
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800872 for(size_t i = 0; i < pduTypes; i++) {
Lev Walkin5230c642017-09-26 18:10:06 -0700873 free(pduType[i].typename);
874 }
875 free(pduType);
876 pduType = NULL;
877 pduTypes = 0;
878}
879
Lev Walkin66adab42006-09-23 02:52:12 +0000880static int
881asn1c__pdu_type_lookup(const char *typename) {
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800882 for(size_t i = 0; i < pduTypes; i++) {
883 struct PDUType *pt = &pduType[i];
884 if(strcmp(pt->typename, typename) == 0) {
885 pt->used++;
886 return 1;
887 }
888 }
889 return 0;
Lev Walkin66adab42006-09-23 02:52:12 +0000890}
891
892static int
893need_to_generate_pdu_collection(arg_t *arg) {
Lev Walkin3be49192017-11-11 16:13:32 -0800894 /* If -pdu=all or -pdu=auto are given, we need to generate one. */
Lev Walkin66adab42006-09-23 02:52:12 +0000895 if(arg->flags & (A1C_PDU_ALL|A1C_PDU_AUTO))
896 return 1;
Lev Walkin3be49192017-11-11 16:13:32 -0800897
898 /*
899 * If no -pdu=... flags were given, need to do it, too,
900 * effectively producing -pdu=auto.
901 */
902 if(!(arg->flags & (A1C_PDU_ALL | A1C_PDU_AUTO | A1C_PDU_TYPE))) return 1;
903
904 if(arg->flags & A1C_PDU_TYPE) {
905 return (pduTypes > 1) ? 1 : 0;
906 }
Lev Walkin66adab42006-09-23 02:52:12 +0000907 return 0;
908}
909
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800910static int
911pdu_collection_has_unused_types(arg_t *arg) {
912 int ret = 0;
913
914 for(size_t i = 0; i < pduTypes; i++) {
915 struct PDUType *pt = &pduType[i];
916 if(!pt->used) {
917 FATAL("Unknown ASN.1 type specified in -pdu=%s", pt->typename);
918 ret = -1;
919 }
920 }
921
922 return ret;
Lev Walkin66adab42006-09-23 02:52:12 +0000923}
924
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800925static enum include_type_result
Lev Walkin66adab42006-09-23 02:52:12 +0000926include_type_to_pdu_collection(arg_t *arg) {
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800927 if(!asn1_lang_map[arg->expr->meta_type][arg->expr->expr_type].type_cb)
928 return 0;
Lev Walkin66adab42006-09-23 02:52:12 +0000929
Lev Walkin8c44dff2017-08-26 17:17:27 -0700930 /* Parameterized types can't serve as PDU's without instantiation. */
Lev Walkin48e82d12017-10-19 03:06:35 -0700931 if(arg->expr->lhs_params) {
Lev Walkin8c44dff2017-08-26 17:17:27 -0700932 return 0;
Lev Walkin48e82d12017-10-19 03:06:35 -0700933 }
Lev Walkin8c44dff2017-08-26 17:17:27 -0700934
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800935 if((arg->flags & A1C_PDU_ALL)
Lev Walkin3be49192017-11-11 16:13:32 -0800936 /* -pdu=auto */
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800937 || ((arg->flags & A1C_PDU_AUTO) && !arg->expr->_type_referenced)
Lev Walkin3be49192017-11-11 16:13:32 -0800938 /* No -pdu=... whatsoever, act as if -pdu=auto */
939 || (!(arg->flags & (A1C_PDU_ALL | A1C_PDU_AUTO | A1C_PDU_TYPE))
940 && !arg->expr->_type_referenced)
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800941 || asn1c__pdu_type_lookup(arg->expr->Identifier)) {
942 return 1;
943 }
Lev Walkin66adab42006-09-23 02:52:12 +0000944
Lev Walkin5f4dbb72017-11-11 14:52:11 -0800945 return 0;
Lev Walkin66adab42006-09-23 02:52:12 +0000946}