Initial version of asn1c
[com/asn1c.git] / libasn1compiler / asn1c_fdeps.c
diff --git a/libasn1compiler/asn1c_fdeps.c b/libasn1compiler/asn1c_fdeps.c
new file mode 100644 (file)
index 0000000..60a52cb
--- /dev/null
@@ -0,0 +1,251 @@
+#include "asn1c_internal.h"
+#include "asn1c_fdeps.h"
+
+static asn1c_dep_filename *asn1c_dep_filename_new(const char *filename);
+static void asn1c_dep_add(asn1c_dep_chain *dlist, const char *filename,
+                         int lineno, int column);
+static asn1c_dep_chain *asn1c_dep_chain_new(void);
+
+static asn1c_dep_chain *
+asn1c_dep_chains_add_new(asn1c_dep_chainset *deps,
+                         enum asn1c_dep_section section, int active) {
+    asn1c_dep_chain *dc = asn1c_dep_chain_new();
+    asn1c_tagged_dep_chain *tc = calloc(1, sizeof(*tc));
+    tc->chain = dc;
+    tc->section = section;
+    tc->activated.active = active;
+
+    deps->chains = realloc(deps->chains,
+                           sizeof(deps->chains[0]) * (deps->chains_count + 1));
+    assert(deps->chains);
+    deps->chains[deps->chains_count] = tc;
+    deps->chains_count++;
+
+    return dc;
+}
+
+void
+asn1c_activate_dependency(asn1c_dep_chainset *deps, const char *data,
+                          const char *by) {
+    char fname_scratch[PATH_MAX];
+
+    if(!deps || !data || !*data) {
+        return;
+    }
+
+    assert(deps->chains_count);
+
+    const char *fname = data;
+    if(*data == '#') {
+        const char *start = data;
+        const char *end = 0;
+
+        start = strchr(data, '<');
+        if(start) {
+            start++;
+            end = strchr(start, '>');
+        } else if((start = strchr(data, '\"'))) {
+            start++;
+            end = strchr(start, '\"');
+        }
+        if(end) {
+            assert((end-start) + 1 < (ssize_t)sizeof(fname_scratch));
+            memcpy(fname_scratch, start, end - start);
+            fname_scratch[end-start] = '\0';
+            fname = fname_scratch;
+        } else {
+            return;
+        }
+    }
+
+    for(size_t i = 0; i < deps->chains_count; i++) {
+        asn1c_tagged_dep_chain *ch = deps->chains[i];
+        if(!ch->activated.active && ch->chain->deps_count > 0
+           && strcmp(ch->chain->deps[0]->filename, fname) == 0) {
+            ch->activated.by = strdup(by);
+            ch->activated.active = 1;
+
+            for(size_t j = 0; j < ch->chain->deps_count; j++) {
+                asn1c_activate_dependency(deps, ch->chain->deps[j]->filename,
+                                          by);
+            }
+        }
+    }
+}
+
+asn1c_dep_chainset *
+asn1c_read_file_dependencies(arg_t *arg, const char *datadir) {
+       char buf[4096];
+       asn1c_dep_chainset *deps;
+       FILE *f;
+    int lineno = 0;
+
+       if(!datadir || strlen(datadir) > sizeof(buf) / 2) {
+               errno = EINVAL;
+               return NULL;
+       } else {
+               sprintf(buf, "%s/file-dependencies", datadir);
+       }
+
+       f = fopen(buf, "r");
+       if(!f) return NULL;
+
+       deps = calloc(1, sizeof(*deps));
+       assert(deps);
+    enum asn1c_dep_section section = FDEP_COMMON_FILES;
+    int activate = 0;
+
+    while(fgets(buf, sizeof(buf), f)) {
+               char *p = strchr(buf, '#');
+               if(p) *p = '\0';        /* Remove comments */
+
+        lineno++;
+
+        asn1c_dep_chain *dc = asn1c_dep_chains_add_new(deps, section, activate);
+
+        for(p = strtok(buf, " \t\r\n"); p;
+                               p = strtok(NULL, " \t\r\n")) {
+
+                       /*
+                        * Special "prefix" section.
+                        */
+                       if(strchr(p, ':')) {
+                               if(strcmp(p, "COMMON-FILES:") == 0) {
+                                       section = FDEP_COMMON_FILES;
+                    activate = 1;
+                               } else if(strcmp(p, "CONVERTER:") == 0) {
+                    activate = 1;
+                                       section = FDEP_CONVERTER;
+                               } else if((arg->flags & A1C_GEN_OER)
+                                         && strcmp(p, "CODEC-OER:") == 0) {
+                    activate = 0;
+                                       section = FDEP_CODEC_OER;
+                               } else if((arg->flags & A1C_GEN_PER)
+                                         && strcmp(p, "CODEC-PER:") == 0) {
+                    activate = 0;
+                                       section = FDEP_CODEC_PER;
+                               } else {
+                                       section = FDEP_IGNORE;
+                    activate = 0;
+                }
+                break;
+                       }
+
+            asn1c_dep_add(dc, p, lineno, p - buf);
+        }
+       }
+
+       fclose(f);
+
+    /* A single filename by itself means that we should include that */
+    for(size_t i = 0; i < deps->chains_count; i++) {
+        asn1c_tagged_dep_chain *ch = deps->chains[i];
+        if(!ch->activated.active && ch->chain->deps_count == 1) {
+            asn1c_activate_dependency(deps, ch->chain->deps[0]->filename,
+                                      "implicit");
+        }
+    }
+
+       return deps;
+}
+
+static asn1c_dep_filename *
+asn1c_dep_filename_new(const char *filename) {
+    asn1c_dep_filename *d;
+
+    assert(filename);
+
+    d = calloc(1, sizeof(*d));
+    assert(d);
+    d->filename = strdup(filename);
+    assert(d->filename);
+
+       return d;
+}
+
+static asn1c_dep_chain *
+asn1c_dep_chain_new() {
+    return calloc(1, sizeof(asn1c_dep_chain));
+}
+
+static void
+asn1c_dep_add(asn1c_dep_chain *dlist, const char *filename, int lineno, int column) {
+    asn1c_dep_filename *df = asn1c_dep_filename_new(filename);
+    df->lineno = lineno;
+    df->column = column;
+
+    dlist->deps =
+        realloc(dlist->deps, (dlist->deps_count + 1) * sizeof(dlist->deps[0]));
+    assert(dlist->deps);
+    dlist->deps[dlist->deps_count] = df;
+    dlist->deps_count += 1;
+}
+
+static int
+asn1c_dep_has_filename(const asn1c_dep_chain *dlist, const char *filename) {
+    for(size_t i = 0; i < dlist->deps_count; i++) {
+        if(strcmp(dlist->deps[i]->filename, filename) == 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+asn1c_dep_chain *
+asn1c_deps_flatten(const asn1c_dep_chainset *deps,
+                   enum asn1c_dep_section include_section) {
+    asn1c_dep_chain *dlist;
+
+       if(!deps) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       dlist = asn1c_dep_chain_new();
+
+       for(size_t i = 0; i < deps->chains_count; i++) {
+        asn1c_tagged_dep_chain *tc = deps->chains[i];
+        asn1c_dep_chain *dc = tc->chain;
+
+        if(!tc->activated.active) {
+            continue;
+        }
+        if((tc->section & include_section) == 0) {
+            continue;
+        }
+
+        for(size_t j = 0; j < dc->deps_count; j++) {
+            if(!asn1c_dep_has_filename(dlist, dc->deps[j]->filename))  {
+                asn1c_dep_add(dlist, dc->deps[j]->filename, dc->deps[j]->lineno,
+                              dc->deps[j]->column);
+            }
+        }
+    }
+
+       return dlist;
+}
+
+void
+asn1c_dep_chain_free(asn1c_dep_chain *dc) {
+    if(dc) {
+        for(size_t i = 0; i < dc->deps_count; i++) {
+            asn1c_dep_filename *df = dc->deps[i];
+            free(df->filename);
+            free(df);
+        }
+        free(dc->deps);
+    }
+}
+
+void
+asn1c_dep_chainset_free(asn1c_dep_chainset *deps) {
+       if(deps) {
+        for(size_t i = 0; i < deps->chains_count; i++) {
+            asn1c_dep_chain_free(deps->chains[i]->chain);
+            free(deps->chains[i]->activated.by);
+            free(deps->chains[i]);
+        }
+        free(deps->chains);
+        free(deps);
+    }
+}