blob: d71db199ddf800ef2111e713705ac464c1f4c4cd [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
Lev Walkin34944f22010-10-07 08:25:37 +00009#define HINCLUDE(s) \
10 ((arg->flags & A1C_INCLUDES_QUOTED) \
11 ? fprintf(fp_h, "#include \"%s\"\n", s) \
12 : fprintf(fp_h, "#include <%s>\n", s)) \
13
Lev Walkinc46b7cb2006-08-18 02:27:55 +000014static int asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *, int, char **);
Lev Walkinf15320b2004-06-03 03:38:44 +000015static int asn1c_print_streams(arg_t *arg);
Lev Walkinc46b7cb2006-08-18 02:27:55 +000016static int asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *, int, char **);
Lev Walkinf15320b2004-06-03 03:38:44 +000017static int asn1c_copy_over(arg_t *arg, char *path);
Lev Walkin4604d032005-03-04 08:52:50 +000018static int identical_files(const char *fname1, const char *fname2);
Lev Walkin66adab42006-09-23 02:52:12 +000019static int need_to_generate_pdu_collection(arg_t *arg);
Lev Walkin59b176e2005-11-26 11:25:14 +000020static int generate_pdu_collection_file(arg_t *arg);
Lev Walkinc46b7cb2006-08-18 02:27:55 +000021static int generate_preamble(arg_t *, FILE *, int optc, char **argv);
Lev Walkin66adab42006-09-23 02:52:12 +000022static int include_type_to_pdu_collection(arg_t *arg);
23static void pdu_collection_print_unused_types(arg_t *arg);
24static const char *generate_pdu_C_definition(void);
Lev Walkinf15320b2004-06-03 03:38:44 +000025
26int
Lev Walkin866cff12005-03-05 00:50:53 +000027asn1c_save_compiled_output(arg_t *arg, const char *datadir,
Lev Walkin8253ea92006-03-17 01:47:57 +000028 int argc, int optc, char **argv) {
Lev Walkinacd9f8b2004-08-19 13:29:03 +000029 asn1c_fdeps_t *deps = 0;
Lev Walkinacd9f8b2004-08-19 13:29:03 +000030 asn1c_fdeps_t *dlist;
Lev Walkinb85a8132005-08-18 13:38:19 +000031 asn1p_module_t *mod;
Lev Walkin59b176e2005-11-26 11:25:14 +000032 FILE *mkf; /* Makefile.am.sample */
Lev Walkin866cff12005-03-05 00:50:53 +000033 int i;
Lev Walkinf15320b2004-06-03 03:38:44 +000034
Lev Walkinacd9f8b2004-08-19 13:29:03 +000035 deps = asn1c_read_file_dependencies(arg, datadir);
36 if(!deps && datadir) {
37 WARNING("Cannot read file-dependencies information "
38 "from %s\n", datadir);
39 }
Lev Walkinf15320b2004-06-03 03:38:44 +000040
Lev Walkinb85a8132005-08-18 13:38:19 +000041 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
42 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +000043 if(asn1_lang_map[arg->expr->meta_type]
44 [arg->expr->expr_type].type_cb) {
Lev Walkinc46b7cb2006-08-18 02:27:55 +000045 if(asn1c_dump_streams(arg, deps, optc, argv))
Lev Walkinf15320b2004-06-03 03:38:44 +000046 return -1;
47 }
48 }
49 }
50
51 /*
52 * Dump out the Makefile template and the rest of the support code.
53 */
Lev Walkinacd9f8b2004-08-19 13:29:03 +000054 if((arg->flags & A1C_PRINT_COMPILED)
55 || (arg->flags & A1C_OMIT_SUPPORT_CODE)) {
56 return 0; /* Finished */
57 }
Lev Walkinf15320b2004-06-03 03:38:44 +000058
Lev Walkin4604d032005-03-04 08:52:50 +000059 mkf = asn1c_open_file("Makefile.am", ".sample", 0);
Lev Walkinacd9f8b2004-08-19 13:29:03 +000060 if(mkf == NULL) {
61 perror("Makefile.am.sample");
62 return -1;
63 }
Lev Walkinf15320b2004-06-03 03:38:44 +000064
Lev Walkinacd9f8b2004-08-19 13:29:03 +000065 fprintf(mkf, "ASN_MODULE_SOURCES=");
Lev Walkinb85a8132005-08-18 13:38:19 +000066 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
67 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkinacd9f8b2004-08-19 13:29:03 +000068 if(asn1_lang_map[arg->expr->meta_type]
69 [arg->expr->expr_type].type_cb) {
Lev Walkind29bbce2004-09-23 22:19:14 +000070 fprintf(mkf, "\t\\\n\t%s.c",
Lev Walkinacd9f8b2004-08-19 13:29:03 +000071 arg->expr->Identifier);
Lev Walkinf15320b2004-06-03 03:38:44 +000072 }
73 }
Lev Walkinacd9f8b2004-08-19 13:29:03 +000074 }
Lev Walkind29bbce2004-09-23 22:19:14 +000075 fprintf(mkf, "\n\nASN_MODULE_HEADERS=");
Lev Walkinb85a8132005-08-18 13:38:19 +000076 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
77 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkind29bbce2004-09-23 22:19:14 +000078 if(asn1_lang_map[arg->expr->meta_type]
79 [arg->expr->expr_type].type_cb) {
80 fprintf(mkf, "\t\\\n\t%s.h",
81 arg->expr->Identifier);
82 }
83 }
84 }
85 fprintf(mkf, "\n\n");
Lev Walkinf15320b2004-06-03 03:38:44 +000086
Lev Walkinacd9f8b2004-08-19 13:29:03 +000087 /*
88 * Move necessary skeleton files and add them to Makefile.am.sample.
89 */
90 dlist = asn1c_deps_makelist(deps);
91 if(dlist) {
92 char buf[8129];
93 char *dir_end;
Lev Walkin4efbfb72005-02-25 14:20:30 +000094 size_t dlen = strlen(datadir);
Lev Walkinacd9f8b2004-08-19 13:29:03 +000095
Lev Walkin4efbfb72005-02-25 14:20:30 +000096 assert(dlen < (sizeof(buf) / 2 - 2));
97 memcpy(buf, datadir, dlen);
98 dir_end = buf + dlen;
Lev Walkinacd9f8b2004-08-19 13:29:03 +000099 *dir_end++ = '/';
100
101 for(i = 0; i < dlist->el_count; i++) {
Lev Walkinf218e782006-09-12 06:21:18 +0000102 char *what_class; /* MODULE or CONVERTER */
103 char *what_kind; /* HEADERS or SOURCES */
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000104 char *fname = dlist->elements[i]->filename;
Lev Walkind29bbce2004-09-23 22:19:14 +0000105 char *dotH;
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000106
107 assert(strlen(fname) < (sizeof(buf) / 2));
108 strcpy(dir_end, fname);
109
110 if(asn1c_copy_over(arg, buf) == -1) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000111 fprintf(mkf, ">>>ABORTED<<<");
112 fclose(mkf);
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 return -1;
Lev Walkind29bbce2004-09-23 22:19:14 +0000114 }
Lev Walkinf218e782006-09-12 06:21:18 +0000115
116 /* MODULE data versus CONVERTER data */
117 switch(dlist->elements[i]->usage) {
118 case FDEP_CONVERTER: what_class = "CONVERTER"; break;
119 default: what_class= "MODULE"; break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000120 }
Lev Walkinf218e782006-09-12 06:21:18 +0000121
122 /* HEADERS versus SOURCES */
123 dotH = strrchr(fname, 'h');
124 if(dotH && fname<dotH && dotH[-1] == '.' && !dotH[1])
125 what_kind = "HEADERS";
126 else
127 what_kind = "SOURCES";
128 fprintf(mkf, "ASN_%s_%s+=%s\n",
129 what_class, what_kind, fname);
Lev Walkinf15320b2004-06-03 03:38:44 +0000130 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000131 }
132
Lev Walkin66adab42006-09-23 02:52:12 +0000133 if(need_to_generate_pdu_collection(arg)) {
Lev Walkinf218e782006-09-12 06:21:18 +0000134 fprintf(mkf, "ASN_CONVERTER_SOURCES+=pdu_collection.c\n");
Lev Walkin59b176e2005-11-26 11:25:14 +0000135 if(generate_pdu_collection_file(arg))
136 return -1;
137 }
138
Lev Walkind29bbce2004-09-23 22:19:14 +0000139 fprintf(mkf, "\n\n"
140 "lib_LTLIBRARIES=libsomething.la\n"
141 "libsomething_la_SOURCES="
142 "$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS)\n"
143 "\n"
144 "# This file may be used as an input for make(3)\n"
145 "# Remove the lines below to convert it into a pure .am file\n"
146 "TARGET = progname\n"
Lev Walkin66adab42006-09-23 02:52:12 +0000147 "CFLAGS +=%s%s -I.\n"
Lev Walkinf218e782006-09-12 06:21:18 +0000148 "OBJS=${ASN_MODULE_SOURCES:.c=.o}"
149 " ${ASN_CONVERTER_SOURCES:.c=.o}\n"
Lev Walkind29bbce2004-09-23 22:19:14 +0000150 "\nall: $(TARGET)\n"
151 "\n$(TARGET): ${OBJS}"
152 "\n\t$(CC) $(CFLAGS) -o $(TARGET) ${OBJS} $(LDFLAGS) $(LIBS)\n"
153 "\n.SUFFIXES:"
154 "\n.SUFFIXES: .c .o\n"
155 "\n.c.o:"
156 "\n\t$(CC) $(CFLAGS) -o $@ -c $<\n"
157 "\nclean:"
158 "\n\trm -f $(TARGET)"
159 "\n\trm -f $(OBJS)\n"
Lev Walkin866cff12005-03-05 00:50:53 +0000160 "\nregen: regenerate-from-asn1-source\n"
161 "\nregenerate-from-asn1-source:\n\t"
Lev Walkin66adab42006-09-23 02:52:12 +0000162 , (arg->flags & A1C_PDU_TYPE)
163 ? generate_pdu_C_definition() : ""
164 , need_to_generate_pdu_collection(arg)
165 ? " -DASN_PDU_COLLECTION" : ""
Lev Walkind29bbce2004-09-23 22:19:14 +0000166 );
Lev Walkin866cff12005-03-05 00:50:53 +0000167
168 for(i = 0; i < argc; i++)
169 fprintf(mkf, "%s%s", i ? " " : "", argv[i]);
170 fprintf(mkf, "\n\n");
171
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000172 fclose(mkf);
173 fprintf(stderr, "Generated Makefile.am.sample\n");
174
Lev Walkinf15320b2004-06-03 03:38:44 +0000175 return 0;
176}
177
178/*
179 * Dump the streams.
180 */
181static int
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000182asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *deps, int optc, char **argv) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000183 if(arg->flags & A1C_PRINT_COMPILED) {
184 return asn1c_print_streams(arg);
185 } else {
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000186 return asn1c_save_streams(arg, deps, optc, argv);
Lev Walkinf15320b2004-06-03 03:38:44 +0000187 }
188}
189
190static int
191asn1c_print_streams(arg_t *arg) {
192 compiler_streams_t *cs = arg->expr->data;
193 asn1p_expr_t *expr = arg->expr;
194 int i;
195
Lev Walkin64399722004-08-11 07:17:22 +0000196 for(i = 1; i < OT_MAX; i++) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000197 out_chunk_t *ot;
Lev Walkin59004fa2004-08-20 13:37:01 +0000198 if(TQ_FIRST(&cs->destination[i].chunks) == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000199 continue;
200
201 printf("\n/*** <<< %s [%s] >>> ***/\n\n",
202 _compiler_stream2str[i],
203 expr->Identifier);
204
Lev Walkin59004fa2004-08-20 13:37:01 +0000205 TQ_FOR(ot, &(cs->destination[i].chunks), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000206 fwrite(ot->buf, ot->len, 1, stdout);
207 }
208 }
209
210 return 0;
211}
212
213static int
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000214asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps, int optc, char **argv) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000215 asn1p_expr_t *expr = arg->expr;
216 compiler_streams_t *cs = expr->data;
217 out_chunk_t *ot;
218 FILE *fp_c, *fp_h;
Lev Walkin4604d032005-03-04 08:52:50 +0000219 char *tmpname_c, *tmpname_h;
220 char *name_buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000221 char *header_id;
Lev Walkin4604d032005-03-04 08:52:50 +0000222 const char *c_retained = "";
223 const char *h_retained = "";
Lev Walkinf15320b2004-06-03 03:38:44 +0000224
225 if(cs == NULL) {
226 fprintf(stderr, "Cannot compile %s at line %d\n",
227 expr->Identifier, expr->_lineno);
228 return -1;
229 }
230
Lev Walkin4604d032005-03-04 08:52:50 +0000231 fp_c = asn1c_open_file(expr->Identifier, ".c", &tmpname_c);
232 fp_h = asn1c_open_file(expr->Identifier, ".h", &tmpname_h);
Lev Walkinf15320b2004-06-03 03:38:44 +0000233 if(fp_c == NULL || fp_h == NULL) {
Lev Walkin4604d032005-03-04 08:52:50 +0000234 if(fp_c) { unlink(tmpname_c); free(tmpname_c); fclose(fp_c); }
235 if(fp_h) { unlink(tmpname_h); free(tmpname_h); fclose(fp_h); }
Lev Walkinf15320b2004-06-03 03:38:44 +0000236 return -1;
237 }
238
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000239 generate_preamble(arg, fp_c, optc, argv);
240 generate_preamble(arg, fp_h, optc, argv);
Lev Walkinc3b8f6d2004-06-03 05:06:25 +0000241
Lev Walkina00d6b32006-03-21 03:40:38 +0000242 header_id = asn1c_make_identifier(0, expr, NULL);
Lev Walkinf15320b2004-06-03 03:38:44 +0000243 fprintf(fp_h,
244 "#ifndef\t_%s_H_\n"
245 "#define\t_%s_H_\n"
246 "\n", header_id, header_id);
247
Lev Walkin34944f22010-10-07 08:25:37 +0000248 fprintf(fp_h, "\n");
249 HINCLUDE("asn_application.h");
Lev Walkinf15320b2004-06-03 03:38:44 +0000250
Lev Walkinb9b8b952005-03-05 00:33:27 +0000251#define SAVE_STREAM(fp, idx, msg, actdep) do { \
Lev Walkin866cff12005-03-05 00:50:53 +0000252 if(TQ_FIRST(&(cs->destination[idx].chunks)) && *msg) \
Lev Walkinb9b8b952005-03-05 00:33:27 +0000253 fprintf(fp, "\n/* %s */\n", msg); \
Lev Walkinc8285712005-03-04 22:18:20 +0000254 TQ_FOR(ot, &(cs->destination[idx].chunks), next) { \
255 if(actdep) asn1c_activate_dependency(deps, 0, ot->buf); \
Lev Walkinb9b8b952005-03-05 00:33:27 +0000256 fwrite(ot->buf, ot->len, 1, fp); \
Lev Walkinc8285712005-03-04 22:18:20 +0000257 } \
258} while(0)
259
Lev Walkinb9b8b952005-03-05 00:33:27 +0000260 SAVE_STREAM(fp_h, OT_INCLUDES, "Including external dependencies", 1);
Lev Walkin3d551c02005-07-15 18:49:41 +0000261
262 fprintf(fp_h, "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
Lev Walkinb9b8b952005-03-05 00:33:27 +0000263 SAVE_STREAM(fp_h, OT_DEPS, "Dependencies", 0);
264 SAVE_STREAM(fp_h, OT_FWD_DECLS, "Forward declarations", 0);
265 SAVE_STREAM(fp_h, OT_TYPE_DECLS, expr->Identifier, 0);
266 SAVE_STREAM(fp_h, OT_FUNC_DECLS,"Implementation", 0);
Lev Walkin47370392006-02-19 04:30:15 +0000267 fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n");
Lev Walkin3dcaafa2004-08-11 05:21:32 +0000268
Lev Walkinae5540f2006-02-19 04:26:37 +0000269 if(!(arg->flags & A1C_NO_INCLUDE_DEPS))
270 SAVE_STREAM(fp_h, OT_POST_INCLUDE, "Referred external types", 1);
271
Lev Walkin47370392006-02-19 04:30:15 +0000272 fprintf(fp_h, "\n#endif\t/* _%s_H_ */\n", header_id);
273
Lev Walkin34944f22010-10-07 08:25:37 +0000274 HINCLUDE("asn_internal.h");
Lev Walkine8318b82005-03-06 09:29:03 +0000275 fprintf(fp_c, "#include \"%s.h\"\n\n", expr->Identifier);
Lev Walkinb9b8b952005-03-05 00:33:27 +0000276 if(arg->flags & A1C_NO_INCLUDE_DEPS)
Lev Walkin866cff12005-03-05 00:50:53 +0000277 SAVE_STREAM(fp_c, OT_POST_INCLUDE, "", 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000278 TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next)
Lev Walkinf15320b2004-06-03 03:38:44 +0000279 fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin59004fa2004-08-20 13:37:01 +0000280 TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next)
281 fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin725883b2006-10-09 12:07:58 +0000282 TQ_FOR(ot, &(cs->destination[OT_CTDEFS].chunks), next)
283 fwrite(ot->buf, ot->len, 1, fp_c);
Lev Walkin59004fa2004-08-20 13:37:01 +0000284 TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
Lev Walkinf15320b2004-06-03 03:38:44 +0000285 fwrite(ot->buf, ot->len, 1, fp_c);
286
Lev Walkin725883b2006-10-09 12:07:58 +0000287 assert(OT_MAX == 11); /* Protection from reckless changes */
Lev Walkinf15320b2004-06-03 03:38:44 +0000288
289 fclose(fp_c);
290 fclose(fp_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000291
292 name_buf = alloca(strlen(expr->Identifier) + 3);
293
294 sprintf(name_buf, "%s.c", expr->Identifier);
295 if(identical_files(name_buf, tmpname_c)) {
296 c_retained = " (contents unchanged)";
297 unlink(tmpname_c);
298 } else {
299 if(rename(tmpname_c, name_buf)) {
300 unlink(tmpname_c);
301 perror(tmpname_c);
Lev Walkina895afb2005-10-06 10:09:34 +0000302 free(tmpname_c);
303 free(tmpname_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000304 return -1;
305 }
306 }
307
308 sprintf(name_buf, "%s.h", expr->Identifier);
309 if(identical_files(name_buf, tmpname_h)) {
310 h_retained = " (contents unchanged)";
311 unlink(tmpname_h);
312 } else {
313 if(rename(tmpname_h, name_buf)) {
314 unlink(tmpname_h);
315 perror(tmpname_h);
Lev Walkina895afb2005-10-06 10:09:34 +0000316 free(tmpname_c);
317 free(tmpname_h);
Lev Walkin4604d032005-03-04 08:52:50 +0000318 return -1;
319 }
320 }
321
322 free(tmpname_c);
323 free(tmpname_h);
324
325 fprintf(stderr, "Compiled %s.c%s\n",
326 expr->Identifier, c_retained);
327 fprintf(stderr, "Compiled %s.h%s\n",
328 expr->Identifier, h_retained);
Lev Walkinf15320b2004-06-03 03:38:44 +0000329 return 0;
330}
331
Lev Walkin4604d032005-03-04 08:52:50 +0000332static int
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000333generate_preamble(arg_t *arg, FILE *fp, int optc, char **argv) {
Lev Walkin8253ea92006-03-17 01:47:57 +0000334 fprintf(fp,
335 "/*\n"
336 " * Generated by asn1c-" VERSION " (http://lionet.info/asn1c)\n"
337 " * From ASN.1 module \"%s\"\n"
338 " * \tfound in \"%s\"\n",
339 arg->expr->module->ModuleName,
340 arg->expr->module->source_file_name);
341 if(optc > 1) {
342 int i;
343 fprintf(fp, " * \t`asn1c ");
344 for(i = 1; i < optc; i++)
345 fprintf(fp, "%s%s", i>1?" ":"", argv[i]);
346 fprintf(fp, "`\n");
347 }
348 fprintf(fp, " */\n\n");
349 return 0;
350}
351
352static int
Lev Walkin4604d032005-03-04 08:52:50 +0000353identical_files(const char *fname1, const char *fname2) {
Lev Walkina895afb2005-10-06 10:09:34 +0000354 char buf[2][4096];
Lev Walkin4604d032005-03-04 08:52:50 +0000355 FILE *fp1, *fp2;
356 size_t olen, nlen;
357 int retval = 1; /* Files are identical */
358
Lev Walkin93659562010-11-20 09:47:13 -0800359#ifndef _WIN32
Lev Walkina895afb2005-10-06 10:09:34 +0000360 struct stat sb;
361
362 if(lstat(fname1, &sb) || !S_ISREG(sb.st_mode)
363 || lstat(fname2, &sb) || !S_ISREG(sb.st_mode)) {
364 return 0; /* Files are not identical */
365 }
366#endif
367
Lev Walkin4604d032005-03-04 08:52:50 +0000368 fp1 = fopen(fname1, "r");
369 if(!fp1) { return 0; }
370 fp2 = fopen(fname2, "r");
371 if(!fp2) { fclose(fp1); return 0; }
372
373 while((olen = fread(buf[0], 1, sizeof(buf[0]), fp1))) {
374 nlen = fread(buf[1], 1, olen, fp2);
375 if(nlen != olen || memcmp(buf[0], buf[1], nlen)) {
376 retval = 0;
377 break;
378 }
379 }
380 nlen = fread(buf[1], 1, 1, fp2);
381 if(nlen) retval = 0;
382
383 fclose(fp1);
384 fclose(fp2);
385 return retval;
386}
387
Lev Walkin4efbfb72005-02-25 14:20:30 +0000388/*
389 * Copy file for real.
390 */
391static int
392real_copy(const char *src, const char *dst) {
Lev Walkina895afb2005-10-06 10:09:34 +0000393 unsigned char buf[4096];
394 char *tmpname;
Lev Walkin4efbfb72005-02-25 14:20:30 +0000395 FILE *fpsrc, *fpdst;
396 size_t len;
397 int retval = 0;
398
Lev Walkin4604d032005-03-04 08:52:50 +0000399 if(identical_files(src, dst))
400 return retval; /* Success, no need to copy for real. */
401
402 fpsrc = fopen(src, "r");
Lev Walkin4efbfb72005-02-25 14:20:30 +0000403 if(!fpsrc) { errno = EIO; return -1; }
Lev Walkina895afb2005-10-06 10:09:34 +0000404 fpdst = asn1c_open_file(dst, "", &tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000405 if(!fpdst) { fclose(fpsrc); errno = EIO; return -1; }
406
407 while(!feof(fpsrc)) {
408 len = fread(buf, 1, sizeof(buf), fpsrc);
Lev Walkinc0e70712005-10-05 09:01:51 +0000409 if(fwrite(buf, 1, len, fpdst) != len) {
Lev Walkina895afb2005-10-06 10:09:34 +0000410 perror(tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000411 errno = EIO;
412 retval = -1;
413 break;
414 }
415 }
Lev Walkin4efbfb72005-02-25 14:20:30 +0000416 fclose(fpsrc);
417 fclose(fpdst);
Lev Walkina895afb2005-10-06 10:09:34 +0000418
419 /* Check if copied correctly, and rename into a permanent name */
420 if(retval) {
421 unlink(tmpname);
422 } else if(rename(tmpname, dst)) {
423 unlink(tmpname);
424 perror(tmpname);
425 retval = -1;
426 }
427 free(tmpname);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000428 return retval;
429}
430
Lev Walkinf15320b2004-06-03 03:38:44 +0000431static int
432asn1c_copy_over(arg_t *arg, char *path) {
Lev Walkin79f54952004-08-13 16:58:19 +0000433 char *fname;
Lev Walkin93659562010-11-20 09:47:13 -0800434#ifdef _WIN32
Lev Walkina895afb2005-10-06 10:09:34 +0000435 int use_real_copy = 1;
436#else
Lev Walkin2655eb32013-03-25 19:09:04 -0700437 int use_real_copy = !(arg->flags & A1C_LINK_SKELETONS);
Lev Walkina895afb2005-10-06 10:09:34 +0000438#endif
Lev Walkind9bd7752004-06-05 08:17:50 +0000439
Lev Walkin79f54952004-08-13 16:58:19 +0000440 fname = a1c_basename(path);
Lev Walkin4efbfb72005-02-25 14:20:30 +0000441 if(!fname
Lev Walkina895afb2005-10-06 10:09:34 +0000442 || (use_real_copy ? real_copy(path, fname) : symlink(path, fname))
Lev Walkin4efbfb72005-02-25 14:20:30 +0000443 ) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000444 if(errno == EEXIST) {
445 struct stat sb1, sb2;
446 if(stat(path, &sb1) == 0
447 && stat(fname, &sb2) == 0
448 && sb1.st_dev == sb2.st_dev
449 && sb1.st_ino == sb2.st_ino) {
450 /*
451 * Nothing to do.
452 */
453 fprintf(stderr,
454 "File %s is already here as %s\n",
455 path, fname);
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000456 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000457 } else {
458 fprintf(stderr,
459 "Retaining local %s (%s suggested)\n",
460 fname, path);
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000461 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000462 }
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000463 } else if(errno == ENOENT) {
464 /* Ignore this */
465 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000466 } else {
Lev Walkina895afb2005-10-06 10:09:34 +0000467 fprintf(stderr, "%s %s -> %s failed: %s\n",
468 use_real_copy ? "Copy" : "Symlink",
Lev Walkinf15320b2004-06-03 03:38:44 +0000469 path, fname, strerror(errno));
470 return -1;
471 }
472 }
473
Lev Walkina895afb2005-10-06 10:09:34 +0000474 fprintf(stderr, "%s %s\t-> %s\n",
475 use_real_copy ? "Copied" : "Symlinked", path, fname);
Lev Walkinf15320b2004-06-03 03:38:44 +0000476
Lev Walkinacd9f8b2004-08-19 13:29:03 +0000477 return 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000478}
479
Lev Walkin59b176e2005-11-26 11:25:14 +0000480
481static int
482generate_pdu_collection_file(arg_t *arg) {
483 asn1p_module_t *mod;
484 FILE *fp;
485
486 fp = asn1c_open_file("pdu_collection", ".c", 0);
487 if(fp == NULL) {
488 perror("pdu_collection.c");
489 return -1;
490 }
491
492 fprintf(fp,
493 "/*\n"
494 " * Generated by asn1c-" VERSION " (http://lionet.info/asn1c)\n"
495 " */\n\n");
496 fprintf(fp, "struct asn_TYPE_descriptor_s;\t"
497 "/* Forward declaration */\n\n");
498
499 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
500 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkin66adab42006-09-23 02:52:12 +0000501 if(!include_type_to_pdu_collection(arg))
Lev Walkin59b176e2005-11-26 11:25:14 +0000502 continue;
503 fprintf(fp, "extern struct asn_TYPE_descriptor_s "
504 "asn_DEF_%s;\n",
Lev Walkina00d6b32006-03-21 03:40:38 +0000505 asn1c_make_identifier(0, arg->expr, NULL));
Lev Walkin59b176e2005-11-26 11:25:14 +0000506 }
507 }
508
509 fprintf(fp, "\n\n");
510 fprintf(fp, "struct asn_TYPE_descriptor_s *asn_pdu_collection[] = {\n");
511 TQ_FOR(mod, &(arg->asn->modules), mod_next) {
512 int mod_printed = 0;
513 TQ_FOR(arg->expr, &(mod->members), next) {
Lev Walkin66adab42006-09-23 02:52:12 +0000514 if(!include_type_to_pdu_collection(arg))
Lev Walkin59b176e2005-11-26 11:25:14 +0000515 continue;
516 if(!mod_printed++)
517 fprintf(fp, "\t/* From module %s in %s */\n",
518 arg->expr->module->ModuleName,
519 arg->expr->module->source_file_name);
520 fprintf(fp, "\t&asn_DEF_%s,\t\n",
Lev Walkina00d6b32006-03-21 03:40:38 +0000521 asn1c_make_identifier(0, arg->expr, NULL));
Lev Walkin59b176e2005-11-26 11:25:14 +0000522 }
523 }
524
525 fprintf(fp, "\t0\n};\n\n");
526
Lev Walkin66adab42006-09-23 02:52:12 +0000527 pdu_collection_print_unused_types(arg);
528
Lev Walkin59b176e2005-11-26 11:25:14 +0000529 fclose(fp);
530 fprintf(stderr, "Generated pdu_collection.c\n");
531
532 return 0;
533}
534
Lev Walkin66adab42006-09-23 02:52:12 +0000535static struct PDUType {
536 char *typename;
537 int used;
538} *pduType;
539static int pduTypes;
540
541static const char *
542generate_pdu_C_definition(void) {
543 const char *src;
544 char *def;
545 char *dst;
546 if(pduTypes == 0) return "";
547 def = malloc(strlen(pduType[0].typename) + 20);
548 strcpy(def, " -DPDU=");
549 for(src = pduType[0].typename, dst = def + 7; *src; src++, dst++)
550 if((*dst = *src) == '-')
551 *dst = '_';
552 *dst = 0;
553 return def;
554}
555
556void
557asn1c__add_pdu_type(const char *ctypename) {
558 char *typename = strdup(ctypename);
559 assert(typename && *typename);
560
561 pduType = realloc(pduType, sizeof(pduType[0]) * (pduTypes + 1));
562 assert(pduType);
563 pduType[pduTypes].used = 0;
564 pduType[pduTypes].typename = typename;
565 pduTypes++;
566}
567
568static int
569asn1c__pdu_type_lookup(const char *typename) {
570 int i;
571 for(i = 0; i < pduTypes; i++) {
572 struct PDUType *pt = &pduType[i];
573 if(strcmp(pt->typename, typename) == 0) {
574 pt->used++;
575 return 1;
576 }
577 }
578 return 0;
579}
580
581static int
582need_to_generate_pdu_collection(arg_t *arg) {
583 if(arg->flags & (A1C_PDU_ALL|A1C_PDU_AUTO))
584 return 1;
585 if(arg->flags & A1C_PDU_TYPE)
586 return (pduTypes > 1) ? 1 : 0;
587 return 0;
588}
589
590static void
591pdu_collection_print_unused_types(arg_t *arg) {
592 int i;
593 for(i = 0; i < pduTypes; i++) {
594 struct PDUType *pt = &pduType[i];
595 if(!pt->used) {
596 WARNING("Missing type specified in -pdu=%s",
597 pt->typename);
598 }
599 }
600}
601
602static int
603include_type_to_pdu_collection(arg_t *arg) {
604 if(!asn1_lang_map[arg->expr->meta_type]
605 [arg->expr->expr_type].type_cb)
606 return 0;
607
608 if((arg->flags & A1C_PDU_ALL)
609 || ((arg->flags & A1C_PDU_AUTO) && !arg->expr->_type_referenced)
610 || asn1c__pdu_type_lookup(arg->expr->Identifier)) {
611 return 1;
612 }
613
614 return 0;
615}