[nasm:master] preproc: add %require directive

nasm-bot for H. Peter Anvin (Intel) hpa at zytor.com
Fri Jun 5 11:54:08 PDT 2020


Commit-ID:  dfa39a189becb17312b602d650e83f89d79e21bd
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=dfa39a189becb17312b602d650e83f89d79e21bd
Author:     H. Peter Anvin (Intel) <hpa at zytor.com>
AuthorDate: Tue, 26 May 2020 16:31:33 -0700
Committer:  H. Peter Anvin (Intel) <hpa at zytor.com>
CommitDate: Fri, 5 Jun 2020 11:50:40 -0700

preproc: add %require directive

Most programming languages these days have a "require" directive,
which is analogous to %include except that it automatically
guards against multiple inclusion. This is useful enough to add,
since with nasm_realpath() we can now to this (mostly) reliably.

Signed-off-by: H. Peter Anvin (Intel) <hpa at zytor.com>


---
 asm/pptok.dat    |  1 +
 asm/preproc.c    | 87 +++++++++++++++++++++++++++++++++++++++++++++-----------
 test/require.asm |  2 ++
 3 files changed, 73 insertions(+), 17 deletions(-)

diff --git a/asm/pptok.dat b/asm/pptok.dat
index b6285c36..9b890a19 100644
--- a/asm/pptok.dat
+++ b/asm/pptok.dat
@@ -94,6 +94,7 @@
 %push
 %rep
 %repl
+%require
 %rotate
 %stacksize
 %undef
diff --git a/asm/preproc.c b/asm/preproc.c
index 793df558..7d001fa7 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -2162,10 +2162,11 @@ static Context *get_ctx(const char *name, const char **namep)
  * the end of the path.
  *
  * Note: for INC_PROBE the function returns NULL at all times;
- * instead look for the
+ * instead look for a filename in *slpath.
  */
 enum incopen_mode {
     INC_NEEDED,                 /* File must exist */
+    INC_REQUIRED,               /* File must exist, but only open once/pass */
     INC_OPTIONAL,               /* Missing is OK */
     INC_PROBE                   /* Only an existence probe */
 };
@@ -2210,41 +2211,88 @@ static FILE *inc_fopen_search(const char *file, char **slpath,
  * Open a file, or test for the presence of one (depending on omode),
  * considering the include path.
  */
+struct file_hash_entry {
+    const char *path;
+    struct file_hash_entry *full; /* Hash entry for the full path */
+    int64_t include_pass; /* Pass in which last included (for %require) */
+};
+
 static FILE *inc_fopen(const char *file,
                        struct strlist *dhead,
                        const char **found_path,
                        enum incopen_mode omode,
                        enum file_flags fmode)
 {
+    struct file_hash_entry **fhep;
+    struct file_hash_entry *fhe = NULL;
     struct hash_insert hi;
-    void **hp;
-    char *path;
+    const char *path = NULL;
     FILE *fp = NULL;
-
-    hp = hash_find(&FileHash, file, &hi);
-    if (hp) {
-        path = *hp;
-        if (path || omode != INC_NEEDED) {
-            strlist_add(dhead, path ? path : file);
+    const int64_t pass = pass_count();
+    bool skip_open = (omode == INC_PROBE);
+
+    fhep = (struct file_hash_entry **)hash_find(&FileHash, file, &hi);
+    if (fhep) {
+        fhe = *fhep;
+        if (fhe) {
+            path = fhe->path;
+            skip_open |= (omode == INC_REQUIRED) &&
+                (fhe->full->include_pass >= pass);
         }
     } else {
         /* Need to do the actual path search */
-        fp = inc_fopen_search(file, &path, omode, fmode);
+        char *pptr;
+        fp = inc_fopen_search(file, &pptr, omode, fmode);
+        path = pptr;
 
         /* Positive or negative result */
-        hash_add(&hi, nasm_strdup(file), path);
+        if (path) {
+            nasm_new(fhe);
+            fhe->path = path;
+            fhe->full = fhe;    /* It is *possible*... */
+        }
+        hash_add(&hi, nasm_strdup(file), fhe);
+
+        /*
+         * Add a hash entry for the canonical path if there isn't one
+         * already. Try to get the unique name from the OS best we can.
+         * Note that ->path and ->full->path can be different, and that
+         * is okay (we don't want to print out a full canonical path
+         * in messages, for example.)
+         */
+        if (path) {
+            char *fullpath = nasm_realpath(path);
+
+            if (!strcmp(file, fullpath)) {
+                nasm_free(fullpath);
+            } else {
+                struct file_hash_entry **fullp, *full;
+                fullp = (struct file_hash_entry **)
+                    hash_find(&FileHash, fullpath, &hi);
+
+                if (fullp) {
+                    full = *fullp;
+                    nasm_free(fullpath);
+                } else {
+                    nasm_new(full);
+                    full->path = fullpath;
+                    full->full = full;
+                    hash_add(&hi, path, full);
+                }
+                fhe->full = full;
+            }
+        }
 
         /*
          * Add file to dependency path.
          */
-        if (path || omode != INC_NEEDED)
-            strlist_add(dhead, file);
+        strlist_add(dhead, path ? path : file);
     }
 
     if (path && !fp && omode != INC_PROBE)
         fp = nasm_open_read(path, fmode);
 
-    if (omode == INC_NEEDED && !fp) {
+    if (omode < INC_OPTIONAL && !fp) {
         if (!path)
             errno = ENOENT;
 
@@ -2252,6 +2300,9 @@ static FILE *inc_fopen(const char *file,
                       file, strerror(errno));
     }
 
+    if (fp)
+        fhe->full->include_pass = pass;
+
     if (found_path)
         *found_path = path;
 
@@ -3586,6 +3637,7 @@ static int do_directive(Token *tline, Token **output)
         goto done;
 
     case PP_INCLUDE:
+    case PP_REQUIRE:
         t = tline->next = expand_smacro(tline->next);
         t = skip_white(t);
 
@@ -3601,10 +3653,11 @@ static int do_directive(Token *tline, Token **output)
         inc->next = istk;
         found_path = NULL;
         inc->fp = inc_fopen(p, deplist, &found_path,
-                            (pp_mode == PP_DEPS)
-                            ? INC_OPTIONAL : INC_NEEDED, NF_TEXT);
+                            (pp_mode == PP_DEPS) ? INC_OPTIONAL :
+                            (op == PP_REQUIRE) ? INC_REQUIRED :
+                            INC_NEEDED, NF_TEXT);
         if (!inc->fp) {
-            /* -MG given but file not found */
+            /* -MG given but file not found, or repeated %require */
             nasm_free(inc);
         } else {
             inc->fname = src_set_fname(found_path ? found_path : p);
diff --git a/test/require.asm b/test/require.asm
new file mode 100644
index 00000000..169c5638
--- /dev/null
+++ b/test/require.asm
@@ -0,0 +1,2 @@
+%require 'require.asm'
+	db 1


More information about the Nasm-commits mailing list