mirror of https://gerrit.osmocom.org/asn1c
335 lines
7.8 KiB
C
335 lines
7.8 KiB
C
#include "asn1c_internal.h"
|
|
#include "asn1c_compat.h"
|
|
#include "asn1c_fdeps.h"
|
|
#include "asn1c_lang.h"
|
|
#include "asn1c_misc.h"
|
|
#include "asn1c_save.h"
|
|
#include "asn1c_out.h"
|
|
|
|
static int asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *);
|
|
static int asn1c_print_streams(arg_t *arg);
|
|
static int asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *);
|
|
static int asn1c_copy_over(arg_t *arg, char *path);
|
|
|
|
int
|
|
asn1c_save_compiled_output(arg_t *arg, const char *datadir) {
|
|
asn1c_fdeps_t *deps = 0;
|
|
FILE *mkf;
|
|
asn1c_fdeps_t *dlist;
|
|
|
|
deps = asn1c_read_file_dependencies(arg, datadir);
|
|
if(!deps && datadir) {
|
|
WARNING("Cannot read file-dependencies information "
|
|
"from %s\n", datadir);
|
|
}
|
|
|
|
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
|
|
TQ_FOR(arg->expr, &(arg->mod->members), next) {
|
|
if(asn1_lang_map[arg->expr->meta_type]
|
|
[arg->expr->expr_type].type_cb) {
|
|
if(asn1c_dump_streams(arg, deps))
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Dump out the Makefile template and the rest of the support code.
|
|
*/
|
|
if((arg->flags & A1C_PRINT_COMPILED)
|
|
|| (arg->flags & A1C_OMIT_SUPPORT_CODE)) {
|
|
return 0; /* Finished */
|
|
}
|
|
|
|
mkf = asn1c_open_file("Makefile.am", ".sample");
|
|
if(mkf == NULL) {
|
|
perror("Makefile.am.sample");
|
|
return -1;
|
|
}
|
|
|
|
fprintf(mkf, "ASN_MODULE_SOURCES=");
|
|
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
|
|
TQ_FOR(arg->expr, &(arg->mod->members), next) {
|
|
if(asn1_lang_map[arg->expr->meta_type]
|
|
[arg->expr->expr_type].type_cb) {
|
|
fprintf(mkf, "\t\\\n\t%s.c",
|
|
arg->expr->Identifier);
|
|
}
|
|
}
|
|
}
|
|
fprintf(mkf, "\n\nASN_MODULE_HEADERS=");
|
|
TQ_FOR(arg->mod, &(arg->asn->modules), mod_next) {
|
|
TQ_FOR(arg->expr, &(arg->mod->members), next) {
|
|
if(asn1_lang_map[arg->expr->meta_type]
|
|
[arg->expr->expr_type].type_cb) {
|
|
fprintf(mkf, "\t\\\n\t%s.h",
|
|
arg->expr->Identifier);
|
|
}
|
|
}
|
|
}
|
|
fprintf(mkf, "\n\n");
|
|
|
|
/*
|
|
* Move necessary skeleton files and add them to Makefile.am.sample.
|
|
*/
|
|
dlist = asn1c_deps_makelist(deps);
|
|
if(dlist) {
|
|
char buf[8129];
|
|
char *dir_end;
|
|
size_t dlen = strlen(datadir);
|
|
int i;
|
|
|
|
assert(dlen < (sizeof(buf) / 2 - 2));
|
|
memcpy(buf, datadir, dlen);
|
|
dir_end = buf + dlen;
|
|
*dir_end++ = '/';
|
|
|
|
for(i = 0; i < dlist->el_count; i++) {
|
|
char *fname = dlist->elements[i]->filename;
|
|
char *dotH;
|
|
|
|
assert(strlen(fname) < (sizeof(buf) / 2));
|
|
strcpy(dir_end, fname);
|
|
|
|
if(asn1c_copy_over(arg, buf) == -1) {
|
|
fprintf(mkf, ">>>ABORTED<<<");
|
|
fclose(mkf);
|
|
return -1;
|
|
}
|
|
dotH = strrchr(fname, 'h');
|
|
if(dotH && fname<dotH && dotH[-1] == '.' && !dotH[1]) {
|
|
fprintf(mkf, "ASN_MODULE_HEADERS+=%s\n", fname);
|
|
} else {
|
|
fprintf(mkf, "ASN_MODULE_SOURCES+=%s\n", fname);
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(mkf, "\n\n"
|
|
"lib_LTLIBRARIES=libsomething.la\n"
|
|
"libsomething_la_SOURCES="
|
|
"$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS)\n"
|
|
"\n"
|
|
"# This file may be used as an input for make(3)\n"
|
|
"# Remove the lines below to convert it into a pure .am file\n"
|
|
"TARGET = progname\n"
|
|
"CFLAGS += -I.\n"
|
|
"OBJS=${ASN_MODULE_SOURCES:.c=.o} $(TARGET).o\n"
|
|
"\nall: $(TARGET)\n"
|
|
"\n$(TARGET): ${OBJS}"
|
|
"\n\t$(CC) $(CFLAGS) -o $(TARGET) ${OBJS} $(LDFLAGS) $(LIBS)\n"
|
|
"\n.SUFFIXES:"
|
|
"\n.SUFFIXES: .c .o\n"
|
|
"\n.c.o:"
|
|
"\n\t$(CC) $(CFLAGS) -o $@ -c $<\n"
|
|
"\nclean:"
|
|
"\n\trm -f $(TARGET)"
|
|
"\n\trm -f $(OBJS)\n"
|
|
"\n"
|
|
);
|
|
fclose(mkf);
|
|
fprintf(stderr, "Generated Makefile.am.sample\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Dump the streams.
|
|
*/
|
|
static int
|
|
asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *deps) {
|
|
if(arg->flags & A1C_PRINT_COMPILED) {
|
|
return asn1c_print_streams(arg);
|
|
} else {
|
|
return asn1c_save_streams(arg, deps);
|
|
}
|
|
}
|
|
|
|
static int
|
|
asn1c_print_streams(arg_t *arg) {
|
|
compiler_streams_t *cs = arg->expr->data;
|
|
asn1p_expr_t *expr = arg->expr;
|
|
int i;
|
|
|
|
for(i = 1; i < OT_MAX; i++) {
|
|
out_chunk_t *ot;
|
|
if(TQ_FIRST(&cs->destination[i].chunks) == NULL)
|
|
continue;
|
|
|
|
printf("\n/*** <<< %s [%s] >>> ***/\n\n",
|
|
_compiler_stream2str[i],
|
|
expr->Identifier);
|
|
|
|
TQ_FOR(ot, &(cs->destination[i].chunks), next) {
|
|
fwrite(ot->buf, ot->len, 1, stdout);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps) {
|
|
asn1p_expr_t *expr = arg->expr;
|
|
compiler_streams_t *cs = expr->data;
|
|
out_chunk_t *ot;
|
|
FILE *fp_c, *fp_h;
|
|
char *header_id;
|
|
|
|
if(cs == NULL) {
|
|
fprintf(stderr, "Cannot compile %s at line %d\n",
|
|
expr->Identifier, expr->_lineno);
|
|
return -1;
|
|
}
|
|
|
|
fp_c = asn1c_open_file(expr->Identifier, ".c");
|
|
fp_h = asn1c_open_file(expr->Identifier, ".h");
|
|
if(fp_c == NULL || fp_h == NULL) {
|
|
if(fp_c) fclose(fp_c); /* lacks unlink() */
|
|
if(fp_h) fclose(fp_h); /* lacks unlink() */
|
|
return -1;
|
|
}
|
|
|
|
fprintf(fp_c,
|
|
"/*\n"
|
|
" * Generated by asn1c-" VERSION " (http://lionet.info/asn1c)\n"
|
|
" * From ASN.1 module \"%s\"\n"
|
|
" * \tfound in \"%s\"\n"
|
|
" */\n\n",
|
|
arg->mod->Identifier,
|
|
arg->mod->source_file_name
|
|
);
|
|
fprintf(fp_h,
|
|
"/*\n"
|
|
" * Generated by asn1c-" VERSION " (http://lionet.info/asn1c)\n"
|
|
" * From ASN.1 module \"%s\"\n"
|
|
" * \tfound in \"%s\"\n"
|
|
" */\n\n",
|
|
arg->mod->Identifier,
|
|
arg->mod->source_file_name
|
|
);
|
|
|
|
header_id = asn1c_make_identifier(0, expr->Identifier, NULL);
|
|
fprintf(fp_h,
|
|
"#ifndef\t_%s_H_\n"
|
|
"#define\t_%s_H_\n"
|
|
"\n", header_id, header_id);
|
|
|
|
fprintf(fp_h, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n");
|
|
|
|
fprintf(fp_h, "#include <asn_application.h>\n\n");
|
|
|
|
TQ_FOR(ot, &(cs->destination[OT_INCLUDES].chunks), next) {
|
|
asn1c_activate_dependency(deps, 0, ot->buf);
|
|
fwrite(ot->buf, ot->len, 1, fp_h);
|
|
}
|
|
fprintf(fp_h, "\n");
|
|
TQ_FOR(ot, &(cs->destination[OT_DEPS].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_h);
|
|
fprintf(fp_h, "\n");
|
|
TQ_FOR(ot, &(cs->destination[OT_TYPE_DECLS].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_h);
|
|
fprintf(fp_h, "\n");
|
|
TQ_FOR(ot, &(cs->destination[OT_FUNC_DECLS].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_h);
|
|
|
|
fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n\n"
|
|
"#endif\t/* _%s_H_ */\n",
|
|
header_id);
|
|
|
|
fprintf(fp_c, "#include <asn_internal.h>\n\n");
|
|
fprintf(fp_c, "#include <%s.h>\n\n", expr->Identifier); /* Myself */
|
|
TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_c);
|
|
TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_c);
|
|
TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
|
|
fwrite(ot->buf, ot->len, 1, fp_c);
|
|
|
|
assert(OT_MAX == 8);
|
|
|
|
fclose(fp_c);
|
|
fclose(fp_h);
|
|
fprintf(stderr, "Compiled %s.c\n", expr->Identifier);
|
|
fprintf(stderr, "Compiled %s.h\n", expr->Identifier);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Copy file for real.
|
|
*/
|
|
static int
|
|
real_copy(const char *src, const char *dst) {
|
|
unsigned char buf[8192];
|
|
FILE *fpsrc, *fpdst;
|
|
size_t len;
|
|
int retval = 0;
|
|
|
|
fpsrc = fopen(src, "rb");
|
|
if(!fpsrc) { errno = EIO; return -1; }
|
|
fpdst = fopen(src, "wb");
|
|
if(!fpdst) { fclose(fpsrc); errno = EIO; return -1; }
|
|
|
|
while(!feof(fpsrc)) {
|
|
len = fread(buf, 1, sizeof(buf), fpsrc);
|
|
if(fwrite(buf, 1, len, fpsrc) != len) {
|
|
errno = EIO;
|
|
retval = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fpsrc);
|
|
fclose(fpdst);
|
|
return retval;
|
|
}
|
|
|
|
static int
|
|
asn1c_copy_over(arg_t *arg, char *path) {
|
|
char *fname;
|
|
|
|
(void)arg; /* Unused argument */
|
|
|
|
fname = a1c_basename(path);
|
|
if(!fname
|
|
#ifdef WIN32
|
|
|| real_copy(path, fname)
|
|
#else
|
|
|| (1 ? symlink(path, fname) : real_copy(path, fname))
|
|
#endif
|
|
) {
|
|
if(errno == EEXIST) {
|
|
struct stat sb1, sb2;
|
|
if(stat(path, &sb1) == 0
|
|
&& stat(fname, &sb2) == 0
|
|
&& sb1.st_dev == sb2.st_dev
|
|
&& sb1.st_ino == sb2.st_ino) {
|
|
/*
|
|
* Nothing to do.
|
|
*/
|
|
fprintf(stderr,
|
|
"File %s is already here as %s\n",
|
|
path, fname);
|
|
return 1;
|
|
} else {
|
|
fprintf(stderr,
|
|
"Retaining local %s (%s suggested)\n",
|
|
fname, path);
|
|
return 1;
|
|
}
|
|
} else if(errno == ENOENT) {
|
|
/* Ignore this */
|
|
return 0;
|
|
} else {
|
|
fprintf(stderr, "Symlink %s -> %s failed: %s\n",
|
|
path, fname, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Symlinked %s\t-> %s\n", path, fname);
|
|
|
|
return 1;
|
|
}
|
|
|