aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1compiler/asn1c_save.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1compiler/asn1c_save.c')
-rw-r--r--libasn1compiler/asn1c_save.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
new file mode 100644
index 00000000..0e5b0fbc
--- /dev/null
+++ b/libasn1compiler/asn1c_save.c
@@ -0,0 +1,225 @@
+#include "asn1c_internal.h"
+
+static int asn1c_dump_streams(arg_t *arg);
+static int asn1c_print_streams(arg_t *arg);
+static int asn1c_save_streams(arg_t *arg);
+static int asn1c_copy_over(arg_t *arg, char *path);
+
+int
+asn1c_save_compiled_output(arg_t *arg, const char *datadir) {
+
+ (void)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))
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * Dump out the Makefile template and the rest of the support code.
+ */
+ if((arg->flags & A1C_PRINT_COMPILED) == 0
+ && (arg->flags & A1C_OMIT_SUPPORT_CODE) == 0) {
+ glob_t pg;
+ FILE *mkf;
+ char *p;
+ int i;
+
+ i = strlen(datadir) + sizeof("/*.[ch]");
+ p = alloca(i);
+ snprintf(p, i, "%s/*.[ch]", datadir);
+
+ memset(&pg, 0, sizeof(pg));
+ if(glob(p, GLOB_ERR
+#ifdef GLOB_TILDE
+ | GLOB_TILDE
+#endif /* GLOB_TILDE */
+ , NULL, &pg)) {
+ fprintf(stderr,
+ "Bad skeletons directory (-S) %s: %s\n",
+ datadir, strerror(errno));
+ return -1;
+ }
+
+ mkf = asn1c_open_file(arg, "Makefile.am", ".sample");
+ if(mkf == NULL) {
+ globfree(&pg);
+ perror("Makefile.am.sample");
+ return -1;
+ }
+
+ fprintf(mkf, "ASN_SRCS=");
+ 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 %s.h",
+ arg->expr->Identifier,
+ arg->expr->Identifier);
+ }
+ }
+ }
+
+ for(i = 0; i < pg.gl_pathc; i++) {
+ if(asn1c_copy_over(arg, pg.gl_pathv[i])) {
+ fprintf(mkf, ">>>ABORTED<<<");
+ fclose(mkf);
+ globfree(&pg);
+ return -1;
+ } else {
+ fprintf(mkf, "\t\\\n\t%s",
+ basename(pg.gl_pathv[i]));
+ }
+ }
+
+ fprintf(mkf, "\n\n");
+ fprintf(mkf, "lib_LTLIBRARIES=libsomething.la\n");
+ fprintf(mkf, "libsomething_la_SOURCES=${ASN_SRCS}\n");
+ fclose(mkf);
+ fprintf(stderr, "Generated Makefile.am.sample\n");
+ globfree(&pg);
+ }
+
+ return 0;
+}
+
+/*
+ * Dump the streams.
+ */
+static int
+asn1c_dump_streams(arg_t *arg) {
+ if(arg->flags & A1C_PRINT_COMPILED) {
+ return asn1c_print_streams(arg);
+ } else {
+ return asn1c_save_streams(arg);
+ }
+}
+
+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 = 0; i < OT_MAX; i++) {
+ out_chunk_t *ot;
+ if(TQ_FIRST(&cs->targets[i]) == NULL)
+ continue;
+
+ printf("\n/*** <<< %s [%s] >>> ***/\n\n",
+ _compiler_stream2str[i],
+ expr->Identifier);
+
+ TQ_FOR(ot, &(cs->targets[i]), next) {
+ fwrite(ot->buf, ot->len, 1, stdout);
+ }
+ }
+
+ return 0;
+}
+
+static int
+asn1c_save_streams(arg_t *arg) {
+ 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(arg, expr->Identifier, ".c");
+ fp_h = asn1c_open_file(arg, 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;
+ }
+
+ header_id = alloca(strlen(expr->Identifier) + 1);
+ if(1) {
+ char *src, *dst;
+ for(src = expr->Identifier, dst = header_id;
+ (*dst=*src); src++, dst++)
+ if(!isalnum(*src)) *dst = '_';
+ *dst = '\0';
+ }
+
+ fprintf(fp_h,
+ "#ifndef\t_%s_H_\n"
+ "#define\t_%s_H_\n"
+ "\n", header_id, header_id);
+
+ fprintf(fp_h, "#include <constr_TYPE.h>\n\n");
+
+ TQ_FOR(ot, &(cs->targets[OT_DEPS]), next)
+ fwrite(ot->buf, ot->len, 1, fp_h);
+ fprintf(fp_h, "\n");
+ TQ_FOR(ot, &(cs->targets[OT_TYPE_DECLS]), next)
+ fwrite(ot->buf, ot->len, 1, fp_h);
+ fprintf(fp_h, "\n");
+ TQ_FOR(ot, &(cs->targets[OT_FUNC_DECLS]), next)
+ fwrite(ot->buf, ot->len, 1, fp_h);
+
+ fprintf(fp_c, "#include <%s.h>\n\n", expr->Identifier);
+ TQ_FOR(ot, &(cs->targets[OT_STAT_DEFS]), next)
+ fwrite(ot->buf, ot->len, 1, fp_c);
+ TQ_FOR(ot, &(cs->targets[OT_CODE]), next)
+ fwrite(ot->buf, ot->len, 1, fp_c);
+
+ assert(OT_MAX == 5);
+
+ fprintf(fp_h, "\n#endif\t/* _%s_H_ */\n", header_id);
+
+ fclose(fp_c);
+ fclose(fp_h);
+ fprintf(stderr, "Compiled %s.c\n", expr->Identifier);
+ fprintf(stderr, "Compiled %s.h\n", expr->Identifier);
+ return 0;
+}
+
+static int
+asn1c_copy_over(arg_t *arg, char *path) {
+ char *fname = basename(path);
+
+ if(symlink(path, fname)) {
+ 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 0;
+ } else {
+ fprintf(stderr,
+ "Retaining local %s (%s suggested)\n",
+ fname, path);
+ 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 0;
+}
+