asn1c/libasn1compiler/asn1c_save.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;
}