]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Teach c-pp how to replace configure-script-like @tokens@, giving us a much simpler...
authorstephan <stephan@noemail.net>
Sat, 27 Sep 2025 11:38:35 +0000 (11:38 +0000)
committerstephan <stephan@noemail.net>
Sat, 27 Sep 2025 11:38:35 +0000 (11:38 +0000)
FossilOrigin-Name: ffd5c8eaa89250a043b573c3eb66693dfec087a5b5eef184ae6d7bfbcf61235a

ext/wasm/GNUmakefile
ext/wasm/c-pp.c
ext/wasm/mkwasmbuilds.c
manifest
manifest.uuid

index d0786ea46b9e92393dca43c94eb77da4230d094a..bcd45c58f88a494a9d4f39579c56d8f57b674165 100644 (file)
@@ -207,7 +207,7 @@ b.cp = $(call b.mkdir@); \
 # Resolves to shell code to create $(3) from $(2) and $(4) using
 # $(bin.c-pp).
 #
-# $1 = build name
+# $1 = build name/logtag
 # $2 = Input file(s)
 # $3 = Output file
 # $4 = optional $(bin.c-pp) flags
@@ -517,7 +517,7 @@ WASM_CUSTOM_INSTANTIATE = 1
 # -D... flags which should be included in all invocations should be
 # appended to $(b.c-pp.target.flags).
 bin.c-pp = ./c-pp
-$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
+$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
        $(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
                -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \
                -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \
@@ -1054,7 +1054,7 @@ cflags.wasmfs = -DSQLITE_ENABLE_WASMFS
 bin.mkwb = ./mkwasmbuilds
 ifneq (1,$(MAKING_CLEAN))
 $(bin.mkwb): $(bin.mkwb).c $(MAKEFILE)
-       $(CC) -g -std=c99 -o $@ $< -DWASM_CUSTOM_INSTANTIATE=$(WASM_CUSTOM_INSTANTIATE)
+       $(CC) -O0 -g -std=c99 -o $@ $< -DWASM_CUSTOM_INSTANTIATE=$(WASM_CUSTOM_INSTANTIATE)
 
 .wasmbuilds.make: $(bin.mkwb)
        @rm -f $@
index a0c8c5677bb7e12fa2dea725a86446be23165cf8..d87d47ee47437f770db1482eb5655bf579eb0f51 100644 (file)
 #define CMPP_DEFAULT_DELIM "##"
 #endif
 
+#ifndef CMPP_ATSIGN
+#define CMPP_ATSIGN (unsigned char)'@'
+#endif
+
 #if 1
 #  define CMPP_NORETURN __attribute__((noreturn))
 #else
@@ -105,6 +109,11 @@ static void * cmpp_realloc(void * p, unsigned n);
 static void * cmpp_malloc(unsigned n);
 #endif
 
+static void check__oom2(void const *p, char const *zFile, int line){
+  if(!p) fatal("Alloc failed at %s:%d", zFile, line);
+}
+#define check__oom(P) check__oom2((P), __FILE__, __LINE__)
+
 /*
 ** If p is stdin or stderr then this is a no-op, else it is a
 ** proxy for fclose(). This is a no-op if p is NULL.
@@ -154,12 +163,10 @@ static int db_step(sqlite3_stmt *pStmt);
 ** Proxy for sqlite3_bind_int() which fails fatally on error.
 */
 static void db_bind_int(sqlite3_stmt *pStmt, int col, int val);
-#if 0
 /*
 ** Proxy for sqlite3_bind_null() which fails fatally on error.
 */
 static void db_bind_null(sqlite3_stmt *pStmt, int col);
-#endif
 /*
 ** Proxy for sqlite3_bind_text() which fails fatally on error.
 */
@@ -189,7 +196,32 @@ static void db_define_add(const char * zKey);
 ** Returns true if the given key is already in the `#define` list,
 ** else false. Fails fatally on db error.
 */
-static int db_define_has(const char * zName);
+//static
+int db_define_has(const char * zName);
+
+/*
+** Returns true if the given key is already in the `#define` list, and
+** it has a truthy value (is not empty and not equal to '0'), else
+** false. Fails fatally on db error.
+**
+** nName is the length of zName, or <0 to use strlen() to figure
+** it out.
+*/
+static int db_define_get_bool(const char * zName, int nName);
+
+/*
+** Searches for a define where (k GLOB zName). If one is found, a copy
+** of it is assigned to *zVal (the caller must eventually db_free()
+** it)), *nVal (if nVal is not NULL) is assigned its strlen, and
+** returns non-0. If no match is found, 0 is returned and neither
+** *zVal nor *nVal are modified. If more than one result matches, a
+** fatal error is triggered.
+**
+** It is legal for *zVal to be NULL (and *nVal to be 0) if it returns
+** non-0. That just means that the key was defined with no value part.
+*/
+static int db_define_get(const char * zName, int nName, char **zVal, unsigned int *nVal);
+
 /*
 ** Removes the given `#define` macro name from the list of
 ** macros. Fails fatally on error.
@@ -229,6 +261,23 @@ static void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...);
 */
 static void cmpp_process_file(const char * zName);
 
+/*
+ ** If the first nKey bytes of zKey contain a chEq character then:
+ **
+ ** - Assigns *nVal to the strlen() of the part after that (may be 0).
+ ** - If zEq is not NULL, it is set to the position of the chEq.
+ ** - Returns the part one byte after that chEq.
+ **
+ ** Else returns NULL and does not modify *len or *zEq.
+ **
+ ** If nKey is negative then strlen() is used to calculate it.
+ */
+static char const * cmpp_val_part(char const *zKey,
+                                  int nKey,
+                                  char chEq,
+                                  unsigned * nVal,
+                                  char const **zEq);
+
 /*
 ** Returns the number newline characters between the given starting
 ** point and inclusive ending point. Results are undefined if zFrom is
@@ -260,6 +309,11 @@ static void FileWrapper_close(FileWrapper * p);
 static void FileWrapper_open(FileWrapper * p, const char * zName, const char *zMode);
 /* Proxy for FILE_slurp(). */
 static void FileWrapper_slurp(FileWrapper * p);
+/*
+** If p->zContent ends in \n or \r\n, that part is replaced with 0 and
+** p->nContent is adjusted. Returns true if it chomps, else false.
+*/
+int FileWrapper_chomp(FileWrapper * p);
 
 /*
 ** Outputs a printf()-formatted message to stderr.
@@ -270,39 +324,22 @@ static void g_stderr(char const *zFmt, ...);
 */
 static void g_stderrv(char const *zFmt, va_list);
 #define g_debug(lvl,pfexpr)                                          \
-  if(lvl<=g.doDebug) g_stderr("%s @ %s:%d: ",g.zArgv0,__FILE__,__LINE__); \
-  if(lvl<=g.doDebug) g_stderr pfexpr
-
-void fatalv(char const *zFmt, va_list va){
-  if(zFmt && *zFmt){
-    vfprintf(stderr, zFmt, va);
-  }
-  fputc('\n', stderr);
-  fflush(stdout);
-  fflush(stderr);
-  exit(1);
-}
-
-void fatal(char const *zFmt, ...){
-  va_list va;
-  va_start(va, zFmt);
-  fatalv(zFmt, va);
-  va_end(va);
-}
+  if(lvl<=g.flags.doDebug) g_stderr("%s @ %s():%d: ",g.zArgv0,__func__,__LINE__); \
+  if(lvl<=g.flags.doDebug) g_stderr pfexpr
 
 void cmpp_free(void *p){
-  free(p);
+  sqlite3_free(p);
 }
 
 void * cmpp_realloc(void * p, unsigned n){
-  void * const rc = realloc(p, n);
+  void * const rc = sqlite3_realloc(p, n);
   if(!rc) fatal("realloc(P,%u) failed", n);
   return rc;
 }
 
 #if 0
 void * cmpp_malloc(unsigned n){
-  void * const rc = malloc(n);
+  void * const rc = sqlite3_alloc(n);
   if(!rc) fatal("malloc(%u) failed", n);
   return rc;
 }
@@ -369,6 +406,17 @@ void FileWrapper_slurp(FileWrapper * p){
   FILE_slurp(p->pFile, &p->zContent, &p->nContent);
 }
 
+int FileWrapper_chomp(FileWrapper * p){
+  if( p->nContent && '\n'==p->zContent[p->nContent-1] ){
+    p->zContent[--p->nContent] = 0;
+    if( p->nContent && '\r'==p->zContent[p->nContent-1] ){
+      p->zContent[--p->nContent] = 0;
+    }
+    return 1;
+  }
+  return 0;
+}
+
 unsigned count_lines(unsigned char const * zFrom, unsigned char const *zTo){
   unsigned ln = 0;
   unsigned char const *zPos = zFrom;
@@ -529,28 +577,67 @@ static void CmppLevel_pop(CmppTokenizer * const t);
 */
 static CmppLevel * CmppLevel_get(CmppTokenizer * const t);
 
+#define CMPPLEVEL_GET
+/*
+** Policies for how to handle undefined @tokens@ when performing
+** content filtering.
+*/
+enum AtPolicy {
+  AT_invalid = -1,
+  /** Turn off @foo@ parsing. */
+  AT_OFF = 0,
+  /** Retain undefined @foo@ - emit it as-is. */
+  AT_RETAIN,
+  /** Elide undefined @foo@. */
+  AT_ELIDE,
+  /** Error for undefined @foo@. */
+  AT_ERROR,
+  AT_DEFAULT = AT_ERROR
+};
+typedef enum AtPolicy AtPolicy;
+
+static AtPolicy AtPolicy_fromStr(char const *z){
+  if( 0==strcmp(z, "retain") ) return AT_RETAIN;
+  if( 0==strcmp(z, "elide") ) return AT_ELIDE;
+  if( 0==strcmp(z, "error") ) return AT_ERROR;
+  if( 0==strcmp(z, "off") ) return AT_OFF;
+  return AT_invalid;
+}
+
 /*
-** Global app state singleton. */
+** Global app state singleton.
+*/
 static struct Global {
   /* main()'s argv[0]. */
   const char * zArgv0;
-  /*
-  ** Bytes of the keyword delimiter/prefix. Owned
-  ** elsewhere.
-  */
-  const char * zDelim;
-  /* Byte length of this->zDelim. */
-  unsigned short nDelim;
-  /* If true, enables certain debugging output. */
-  int doDebug;
   /* App's db instance. */
   sqlite3 * db;
+  /* Current tokenizer (for error reporting purposes). */
+  CmppTokenizer const * tok;
   /* Output channel. */
   FileWrapper out;
+  struct {
+    /*
+    ** Bytes of the keyword delimiter/prefix. Owned
+    ** elsewhere.
+    */
+    const char * z;
+    /* Byte length of this->zDelim. */
+    unsigned short n;
+    /*
+    ** The @token@ delimiter.
+    **
+    ** Potential TODO is replace this with a pair of opener/closer
+    ** strings, e.g. "{{" and "}}".
+    */
+    const unsigned char chAt;
+  } delim;
   struct {
     sqlite3_stmt * defIns;
     sqlite3_stmt * defDel;
     sqlite3_stmt * defHas;
+    sqlite3_stmt * defGet;
+    sqlite3_stmt * defGetBool;
     sqlite3_stmt * inclIns;
     sqlite3_stmt * inclDel;
     sqlite3_stmt * inclHas;
@@ -561,17 +648,29 @@ static struct Global {
     FILE * pFile;
     int expandSql;
   } sqlTrace;
+  struct {
+    AtPolicy atPolicy;
+    /* If true, enables certain debugging output. */
+    char doDebug;
+    /* If true, chomp() files read via -Fx=file. */
+    char chompF;
+  } flags;
 } g = {
   .zArgv0 = "?",
-  .zDelim = CMPP_DEFAULT_DELIM,
-  .nDelim = (unsigned short) sizeof(CMPP_DEFAULT_DELIM)-1,
-  .doDebug = 0,
   .db = 0,
+  .tok = 0,
   .out = FileWrapper_empty_m,
+  .delim = {
+    .z = CMPP_DEFAULT_DELIM,
+    .n = (unsigned short) sizeof(CMPP_DEFAULT_DELIM)-1,
+    .chAt = '@'
+  },
   .stmt = {
     .defIns =   0,
     .defDel = 0,
     .defHas = 0,
+    .defGet = 0,
+    .defGetBool = 0,
     .inclIns =   0,
     .inclDel =   0,
     .inclHas =   0,
@@ -581,6 +680,11 @@ static struct Global {
   .sqlTrace = {
     .pFile = 0,
     .expandSql = 0
+  },
+  .flags = {
+    .atPolicy = AT_OFF,
+    .doDebug = 0,
+    .chompF = 0
   }
 };
 
@@ -599,7 +703,6 @@ void g_outf(char const *zFmt, ...){
 }
 #endif
 
-#if 0
 /* Outputs n bytes from z to c-pp's global output channel. */
 static void g_out(void const *z, unsigned int n);
 void g_out(void const *z, unsigned int n){
@@ -608,7 +711,6 @@ void g_out(void const *z, unsigned int n){
     fatal("fwrite() output failed with errno #%d", err);
   }
 }
-#endif
 
 void g_stderrv(char const *zFmt, va_list va){
   vfprintf(stderr, zFmt, va);
@@ -621,15 +723,13 @@ void g_stderr(char const *zFmt, ...){
   va_end(va);
 }
 
+/*
+** Emits n bytes of z if CT_skip(t) is false.
+*/
 void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){
   g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
   g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
-  if(!CT_skip(t)){
-    if(1!=fwrite(z, n, 1, g.out.pFile)){
-      int const err = errno;
-      fatal("fwrite() output failed with errno #%d", err);
-    }
-  }
+  if(!CT_skip(t)) g_out(z, n);
 }
 
 void CmppLevel_push(CmppTokenizer * const t){
@@ -637,7 +737,7 @@ void CmppLevel_push(CmppTokenizer * const t){
   CmppLevel * p;
   if(t->level.ndx+1 == (unsigned)CmppLevel_Max){
     fatal("%sif nesting level is too deep. Max=%d\n",
-          g.zDelim, CmppLevel_Max);
+          g.delim.z, CmppLevel_Max);
   }
   pPrev = &CT_level(t);
   g_debug(3,("push from tokenizer level=%u flags=%04x\n", t->level.ndx, pPrev->flags));
@@ -671,7 +771,8 @@ CmppLevel * CmppLevel_get(CmppTokenizer * const t){
 
 void db_affirm_rc(int rc, const char * zMsg){
   if(rc){
-    fatal("Db error #%d %s: %s", rc, zMsg, sqlite3_errmsg(g.db));
+    fatal("Db error #%d %s: %s", rc, zMsg,
+          sqlite3_errmsg(g.db));
   }
 }
 
@@ -722,23 +823,23 @@ void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...){
 }
 
 void db_bind_int(sqlite3_stmt *pStmt, int col, int val){
-  int const rc = sqlite3_bind_int(pStmt, col, val);
-  db_affirm_rc(rc,"from db_bind_int()");
+  db_affirm_rc(sqlite3_bind_int(pStmt, col, val),
+               "from db_bind_int()");
 }
 
-#if 0
 void db_bind_null(sqlite3_stmt *pStmt, int col){
-  int const rc = sqlite3_bind_null(pStmt, col);
-  db_affirm_rc(rc,"from db_bind_null()");
+  db_affirm_rc(sqlite3_bind_null(pStmt, col),
+               "from db_bind_null()");
 }
-#endif
 
 void db_bind_textn(sqlite3_stmt *pStmt, int col,
                    const char * zStr, int n){
-  int const rc = zStr
+  db_affirm_rc(
+    (zStr && n)
     ? sqlite3_bind_text(pStmt, col, zStr, n, SQLITE_TRANSIENT)
-    : sqlite3_bind_null(pStmt, col);
-  db_affirm_rc(rc,"from db_bind_textn()");
+    : sqlite3_bind_null(pStmt, col),
+    "from db_bind_textn()"
+  );
 }
 
 void db_bind_text(sqlite3_stmt *pStmt, int col,
@@ -767,28 +868,98 @@ void db_free(void *m){
   sqlite3_free(m);
 }
 
-void db_define_add(const char * zKey){
-  int rc;
+static sqlite3_stmt * db__prep_add(void){
   if(!g.stmt.defIns){
     db_prepare(&g.stmt.defIns,
-               "INSERT OR REPLACE INTO def(k) VALUES(?)");
+               "INSERT OR REPLACE INTO def(k,v) VALUES(?,?)");
+  }
+  return g.stmt.defIns;
+}
+
+void db_define_add(const char * zKey){
+  int rc;
+  char const * zEq = 0;
+  unsigned nVal = 0;
+  char const * zVal = cmpp_val_part(zKey, -1, '=', &nVal, &zEq);
+  sqlite3_stmt * const q = db__prep_add();
+  //g_stderr("zKey=%s\nzVal=%s\nzEq=%s\n", zKey, zVal, zEq);
+  if( zEq ){
+    db_bind_textn(q, 1, zKey, (zEq-zKey));
+  }else{
+    db_bind_text(q, 1, zKey);
   }
-  db_bind_text(g.stmt.defIns, 1, zKey);
-  rc = db_step(g.stmt.defIns);
+  if( zEq ){
+    if( zVal && nVal ){
+      db_bind_text(q, 2, zVal);
+    }else{
+      db_bind_null(q, 2);
+    }
+  }else{
+    db_bind_int(q, 2, 1);
+  }
+  rc = db_step(q);
   if(SQLITE_DONE != rc){
     db_affirm_rc(rc, "Stepping INSERT on def");
   }
-  g_debug(2,("define: %s\n",zKey));
-  sqlite3_reset(g.stmt.defIns);
+  g_debug(2,("define: %s%s%s\n",
+             zKey,
+             zVal ? " with value " : "",
+             zVal ? zVal : ""));
+  sqlite3_reset(q);
+}
+
+static void db_define_add_file(const char * zKey){
+  int rc;
+  char const * zEq = 0;
+  unsigned nVal = 0;
+  char const * zVal = cmpp_val_part(zKey, -1, '=', &nVal, &zEq);
+  if( !zVal || !nVal ){
+    fatal("Invalid filename: %s", zKey);
+  }
+  sqlite3_stmt * q = 0;
+  FileWrapper fw = FileWrapper_empty;
+  FileWrapper_open(&fw, zVal, "r");
+  FileWrapper_slurp(&fw);
+  q = db__prep_add();
+  //g_stderr("zKey=%s\nzVal=%s\nzEq=%s\n", zKey, zVal, zEq);
+  db_bind_textn(q, 1, zKey, (zEq-zKey));
+  if( g.flags.chompF ){
+    FileWrapper_chomp(&fw);
+  }
+  if( fw.nContent ){
+    db_affirm_rc(
+      sqlite3_bind_text(q, 2,
+                        (char const *)fw.zContent,
+                        (int)fw.nContent, sqlite3_free),
+      "binding file content");
+    fw.zContent = 0 /* transfered ownership */;
+    fw.nContent = 0;
+  }else{
+    db_affirm_rc( sqlite3_bind_null(q, 2),
+                  "binding empty file content");
+  }
+  FileWrapper_close(&fw);
+  rc = db_step(q);
+  if(SQLITE_DONE != rc){
+    db_affirm_rc(rc, "stepping INSERT on def");
+  }
+  g_debug(2,("define: %s%s%s\n",
+             zKey,
+             zVal ? " with value " : "",
+             zVal ? zVal : ""));
+  sqlite3_clear_bindings(q);
+  sqlite3_reset(q);
 }
 
 int db_define_has(const char * zName){
   int rc;
-  if(!g.stmt.defHas){
-    db_prepare(&g.stmt.defHas, "SELECT 1 FROM def WHERE k=?");
+  sqlite3_stmt * q = g.stmt.defHas;
+  if(!q){
+    db_prepare(&q, "SELECT 1 FROM def WHERE k GLOB ?");
+    g.stmt.defHas = q;
   }
-  db_bind_text(g.stmt.defHas, 1, zName);
-  rc = db_step(g.stmt.defHas);
+  db_bind_text(q, 1, zName);
+  rc = db_step(q);
   if(SQLITE_ROW == rc){
     rc = 1;
   }else{
@@ -796,28 +967,84 @@ int db_define_has(const char * zName){
     rc = 0;
   }
   g_debug(1,("defined [%s] ?= %d\n",zName, rc));
-  sqlite3_clear_bindings(g.stmt.defHas);
-  sqlite3_reset(g.stmt.defHas);
+  sqlite3_clear_bindings(q);
+  sqlite3_reset(q);
+  return rc;
+}
+
+int db_define_get_bool(const char * zName, int nName){
+  sqlite3_stmt * q = g.stmt.defGetBool;
+  int rc = 0;
+  if(!q){
+    db_prepare(
+      &q,
+      "SELECT 1 FROM def WHERE k = ?1"
+      " AND v IS NOT NULL"
+      " AND '0'!=v AND ''!=v"
+    );
+    g.stmt.defGetBool = q;
+  }
+  if( nName<0 ) nName=(int)strlen(zName);
+  db_bind_textn(q, 1, zName, nName);
+  rc = db_step(q);
+  if(SQLITE_ROW == rc){
+    if( SQLITE_ROW==sqlite3_step(q) ){
+      fatal("Key is ambiguous: %s", zName);
+    }
+    rc = 1;
+  }else{
+    assert(SQLITE_DONE==rc);
+    rc = 0;
+  }
+  sqlite3_clear_bindings(q);
+  sqlite3_reset(q);
   return rc;
 }
 
+int db_define_get(const char * zName, int nName,
+                  char **zVal, unsigned int *nVal){
+  sqlite3_stmt * q = g.stmt.defGet;
+  int rc = 0;
+  int n = 0;
+  if(!q){
+    db_prepare(&q, "SELECT k,v FROM def WHERE k GLOB ?");
+    g.stmt.defGet = q;
+  }
+  if( nName<0 ) nName=(int)strlen(zName);
+  db_bind_textn(q, 1, zName, nName);
+  rc = db_step(q);
+  if(SQLITE_ROW == rc){
+    const unsigned char * z = sqlite3_column_text(q, 1);
+    n = sqlite3_column_bytes(q,1);
+    if( nVal ) *nVal = (unsigned)n;
+    *zVal = n ? sqlite3_mprintf("%.*s", n, z) : 0;
+    if( n && z ) check__oom(*zVal);
+    if( SQLITE_ROW==sqlite3_step(q) ){
+      db_free(*zVal);
+      *zVal = 0;
+      fatal("Key is ambiguous: %.*s\n",
+            nName, zName);
+    }
+    rc = 1;
+  }else{
+    assert(SQLITE_DONE==rc);
+    rc = 0;
+  }
+  g_debug(1,("define [%.*s] ?= %d %.*s\n",
+             nName, zName, rc,
+             *zVal ? n : 0,
+             *zVal ? *zVal : "<NULL>"));
+  sqlite3_clear_bindings(q);
+  sqlite3_reset(q);
+  return rc;
+}
 
 void db_define_rm(const char * zKey){
   int rc;
   int n = 0;
-  //const char *zPos = zKey;
-#if 0
-  if( !zKey ){
-    if( g.db ){
-      sqlite3_exec(g.db, "DELETE FROM def", 0, 0, 0);
-    }
-    return;
-  }
-#endif
   if(!g.stmt.defDel){
     db_prepare(&g.stmt.defDel, "DELETE FROM def WHERE k GLOB ?");
   }
-  //for( ; *zPos && '='!=*zPos; ++n, ++zPos) {}
   db_bind_text(g.stmt.defDel, 1, zKey);
   rc = db_step(g.stmt.defDel);
   if(SQLITE_DONE != rc){
@@ -933,7 +1160,8 @@ void db_include_dir_add(const char * zDir){
 
 static void cmpp_atexit(void){
 #define FINI(M) if(g.stmt.M) sqlite3_finalize(g.stmt.M)
-  FINI(defIns); FINI(defDel); FINI(defHas);
+  FINI(defIns); FINI(defDel);
+  FINI(defHas); FINI(defGet); FINI(defGetBool);
   FINI(inclIns); FINI(inclDel); FINI(inclHas);
   FINI(inclPathAdd); FINI(inclSearch);
 #undef FINI
@@ -966,50 +1194,48 @@ static int cmpp__db_sq3TraceV2(unsigned t,void*c,void*p,void*x){
   switch(t){
     case SQLITE_TRACE_STMT:{
       FILE * const fp = g.sqlTrace.pFile;
-      char const * zSql = (char const *)x;
-      char * zExp = g.sqlTrace.expandSql
-        ? sqlite3_expanded_sql((sqlite3_stmt*)p)
-        : 0;
-      assert( fp );
-      fprintf(fp, "SQL TRACE #%u: %s\n",
-              ++counter, zExp ? zExp : zSql);
-      sqlite3_free(zExp);
+      if( fp ){
+        char const * zSql = (char const *)x;
+        char * zExp = g.sqlTrace.expandSql
+          ? sqlite3_expanded_sql((sqlite3_stmt*)p)
+          : 0;
+        fprintf(fp, "SQL TRACE #%u: %s\n",
+                ++counter, zExp ? zExp : zSql);
+        sqlite3_free(zExp);
+      }
       break;
     }
   }
   return 0;
 }
 
-
 /* Initialize g.db, failing fatally on error. */
 static void cmpp_initdb(void){
   int rc;
   char * zErr = 0;
   const char * zSchema =
     "CREATE TABLE def("
-      "k TEXT PRIMARY KEY NOT NULL"
-    /*"v INTEGER DEFAULT 1"*/
-    ") WITHOUT ROWID;"
     /* ^^^ defines */
+      "k TEXT PRIMARY KEY NOT NULL,"
+      "v TEXT DEFAULT NULL"
+    ") WITHOUT ROWID;"
     "CREATE TABLE incl("
+    /* ^^^ files currently being included */
       "file TEXT PRIMARY KEY NOT NULL,"
       "srcFile TEXT DEFAULT NULL,"
       "srcLine INTEGER DEFAULT 0"
     ") WITHOUT ROWID;"
-    /* ^^^ files currently being included */
     "CREATE TABLE inclpath("
+    /* ^^^ include path */
       "seq INTEGER UNIQUE ON CONFLICT IGNORE, "
       "dir TEXT PRIMARY KEY NOT NULL ON CONFLICT IGNORE"
-    ")"
-    /* ^^^ include path */
+    ");"
     ;
   assert(0==g.db);
   if(g.db) return;
   rc = sqlite3_open_v2(":memory:", &g.db, SQLITE_OPEN_READWRITE, 0);
   if(rc) fatal("Error opening :memory: db.");
-  if( g.sqlTrace.pFile ){
-    sqlite3_trace_v2(g.db, SQLITE_TRACE_STMT, cmpp__db_sq3TraceV2, 0);
-  }
+  sqlite3_trace_v2(g.db, SQLITE_TRACE_STMT, cmpp__db_sq3TraceV2, 0);
   rc = sqlite3_exec(g.db, zSchema, 0, 0, &zErr);
   if(rc) fatal("Error initializing database: %s", zErr);
   rc = sqlite3_create_function(g.db, "fileExists", 1,
@@ -1020,8 +1246,8 @@ static void cmpp_initdb(void){
 
 /*
 ** For position zPos, which must be in the half-open range
-** [zBegin,zEnd), returns g.nDelim if it is at the start of a line and
-** starts with g.zDelim, else returns 0.
+** [zBegin,zEnd), returns g.delim.n if it is at the start of a line and
+** starts with g.delim.z, else returns 0.
 */
 static unsigned short cmpp_is_delim(unsigned char const *zBegin,
                                     unsigned char const *zEnd,
@@ -1031,15 +1257,110 @@ static unsigned short cmpp_is_delim(unsigned char const *zBegin,
   assert(zPos>=zBegin);
   if(zPos>zBegin &&
      ('\n'!=*(zPos - 1)
-      || ((unsigned)(zEnd - zPos) <= g.nDelim))){
+      || ((unsigned)(zEnd - zPos) <= g.delim.n))){
     return 0;
-  }else if(0==memcmp(zPos, g.zDelim, g.nDelim)){
-    return g.nDelim;
+  }else if(0==memcmp(zPos, g.delim.z, g.delim.n)){
+    return g.delim.n;
   }else{
     return 0;
   }
 }
 
+static char const * cmpp_val_part(char const *zKey,
+                                  int nKey,
+                                  char chEq,
+                                  unsigned * len,
+                                  char const **zEq){
+  const char *zPos = zKey;
+  if( nKey<0 ) nKey = (int)strlen(zKey);
+  const char * const zEnd = zPos + nKey;
+  for( ; *zPos && zPos<zEnd ; ++zPos) {
+    if( chEq==*zPos ){
+      if( zEq ) *zEq = zPos;
+      ++zPos;
+      *len = (unsigned)(zEnd - zPos);
+      return zPos;
+    }
+  }
+  return 0;
+}
+
+static void cmpp_t_out_expand(CmppTokenizer * const t,
+                              unsigned char const * zFrom,
+                              unsigned int n){
+  unsigned char const *zLeft = zFrom;
+  unsigned char const * const zEnd = zFrom + n;
+  unsigned char const *z = AT_OFF==g.flags.atPolicy ? zEnd : zLeft;
+  unsigned char const chEol = (unsigned char)'\n';
+  int state = 0 /* 0==looking for opening @
+                ** 1==looking for closing @ */;
+#define tflush \
+  if(zLeft<z){ cmpp_t_out(t, zLeft, (z-zLeft)); } zLeft = z
+  for( ; z<zEnd; ++z ){
+    zLeft = z;
+    for( ;z<zEnd; ++z ){
+      if( chEol==*z ){
+        state = 0;
+        ++z /*ensure that we flush the EOL now*/;
+        tflush;
+        --z/*And make sure that zLeft does the right thing*/;
+        break;
+      }
+      if( g.delim.chAt==*z ){
+        if( 0==state ){
+          tflush;
+          state = 1;
+        }else{ /* process chAt...chAt */
+          char *zVal = 0;
+          unsigned int nVal = 0;
+          assert( 1==state );
+          assert( g.delim.chAt==*zLeft );
+          assert( zLeft<z );
+          if( z==zLeft+1 ){
+            tflush;
+          }else{
+            char const *zKey = (char const*)zLeft+1;
+            int const nKey = (z-zLeft-1);
+            if( db_define_get(zKey, nKey, &zVal, &nVal) ){
+              if( nVal ){
+                cmpp_t_out(t, (unsigned char const*)zVal, nVal);
+              }else{
+                /* Elide it */
+              }
+              zLeft = z+1/*skip closing g.delim.chAt*/;
+              db_free(zVal);
+            }else{
+              assert( !zVal );
+              /* No match. Emit it as-is. */
+              switch( g.flags.atPolicy ){
+                case AT_RETAIN:
+                  tflush;
+                  break;
+                case AT_ERROR:
+                  fatal("Undefined key: %c%.*s%c",
+                        g.delim.chAt, nKey, zKey, g.delim.chAt );
+                  break;
+                case AT_ELIDE:
+                  zLeft = z+1;
+                  break;
+                case AT_invalid:
+                case AT_OFF:
+                  fatal("Unhandled g.flags.atPolicy #%d!",
+                        g.flags.atPolicy);
+                  break;
+              }
+            }
+            state = 0;
+          }
+        }/* process chAt...chAt */
+      }/*g.delim.chAt*/
+    }/*per-line loop*/
+  }/*outer loop*/
+  tflush;
+#undef tflush
+  return;
+}
+
 /*
 ** Scans t to the next keyword line, emitting all input before that
 ** which is _not_ a keyword line unless it's elided due to being
@@ -1066,9 +1387,10 @@ static int cmpp_next_keyword_line(CmppTokenizer * const t){
   }
   if(z>zStart){
     /* We passed up content */
-    cmpp_t_out(t, zStart, (unsigned)(z - zStart));
+    //cmpp_t_out(t, zStart, (unsigned)(z - zStart));
+    cmpp_t_out_expand(t, zStart, (unsigned)(z - zStart));
   }
-  assert(isDelim==0 || isDelim==g.nDelim);
+  assert(isDelim==0 || isDelim==g.delim.n);
   tok->lineNo = t->lineNo += count_lines(zStart, z);
   if(isDelim){
     /* Handle backslash-escaped newlines */
@@ -1108,8 +1430,8 @@ static int cmpp_next_keyword_line(CmppTokenizer * const t){
 
     assert(TT_Line==tok->ttype);
     if((unsigned)sizeof(t->args.lineBuf) < tokLen + 1){
-      fatal("Keyword line is unreasonably long: %.*s",
-            tokLen, tok->zBegin);
+      fatal("Keyword line #%u is unreasonably long: %.*s",
+            tok->lineNo, tokLen, tok->zBegin);
     }else if(!tokLen){
       fatal("Line #%u has no keyword after delimiter", tok->lineNo);
     }
@@ -1157,7 +1479,7 @@ static int cmpp_next_keyword_line(CmppTokenizer * const t){
     for( ++zz ; *zz && isspace(*zz); ++zz ){}
     if(t->args.pKw->bTokenize){
       for( ; *zz; prevChar = *zz, ++zz ){
-        /* Split string into word-shaped tokens. 
+        /* Split string into word-shaped tokens.
         ** TODO ?= quoted strings, for the sake of the
         ** #error keyword. */
         if(isspace(*zz)){
@@ -1177,7 +1499,7 @@ static int cmpp_next_keyword_line(CmppTokenizer * const t){
       if(*zz) t->args.argv[argc++] = zz;
     }
     tok->ttype = t->args.pKw->ttype;
-    if(g.doDebug>1){
+    if(g.flags.doDebug>1){
       for(i = 0; i < argc; ++i){
         g_debug(0,("line %u arg #%d=%s\n",
                    tok->lineNo, i,
@@ -1246,7 +1568,7 @@ static void cmpp_kwd_define(CmppKeyword const * pKw, CmppTokenizer *t){
 
 /* Impl. for #if, #ifnot, #elif, #elifnot. */
 static void cmpp_kwd_if(CmppKeyword const * pKw, CmppTokenizer *t){
-  int buul;
+  int buul = 0;
   CmppParseState tmpState = TS_Start;
   if(t->args.argc!=2){
     cmpp_kwd__misuse(pKw, t, "Expecting exactly 1 argument");
@@ -1271,7 +1593,25 @@ static void cmpp_kwd_if(CmppKeyword const * pKw, CmppTokenizer *t){
       cmpp_kwd__misuse(pKw, t, "Unexpected keyword token type");
       break;
   }
-  buul = db_define_has((char const *)t->args.argv[1]);
+  char const * const zKey = (char const *)t->args.argv[1];
+  char const * zEq = 0;
+  unsigned nValPart = 0;
+  char const * zValPart = cmpp_val_part(zKey, -1, '=', &nValPart, &zEq);
+  if( zValPart ){
+    unsigned nVal = 0;
+    char * zVal = 0;
+    buul = db_define_get(zKey, (zEq-zKey), &zVal, &nVal);
+    if( nVal ){
+      /* FIXME? do this with a query */
+      g_debug(1,("if get-define %.*s=%.*s zValPart=%s\n",
+                 (zEq-zKey), zKey,
+                 nVal, zVal, zValPart));
+      buul = 0==sqlite3_strglob(zValPart,zVal);
+    }
+    db_free(zVal);
+  }else{
+    buul = db_define_get_bool(zKey, -1);
+  }
   if(TT_IfNot==pKw->ttype || TT_ElifNot==pKw->ttype) buul = !buul;
   if(buul){
     CT_pstate(t) = tmpState = TS_IfPassed;
@@ -1302,7 +1642,7 @@ static void cmpp_kwd_if(CmppKeyword const * pKw, CmppTokenizer *t){
       cmpp_kwd__err_prefix(pKw, t, NULL);
       fatal("Input ended inside an unterminated %sif "
             "opened at [%s] line %u",
-            g.zDelim, t->zName, lvlToken.lineNo);
+            g.delim.z, t->zName, lvlToken.lineNo);
     }
   }
   return;
@@ -1398,8 +1738,16 @@ static void cmpp_kwd_pragma(CmppKeyword const * pKw, CmppTokenizer *t){
       g_stderr("\t%.*s\n", n, z);
     }
     db_finalize(q);
+  }else if(M("@")){
+    g.flags.atPolicy = AT_RETAIN;
+  }else if(M("no-@")){
+    g.flags.atPolicy = AT_OFF;
+  }else if(M("chomp-F")){
+    g.flags.chompF = 1;
+  }else if(M("no-chomp-F")){
+    g.flags.chompF = 0;
   }else{
-    cmpp_kwd__misuse(pKw, t, "Unknown pragma");
+    cmpp_kwd__misuse(pKw, t, "Unknown pragma: %s", zArg);
   }
 #undef M
 }
@@ -1415,7 +1763,7 @@ static void cmpp_kwd_stderr(CmppKeyword const * pKw, CmppTokenizer *t){
     }else{
       g_stderr("%s:%u: (no %.*s%s argument)\n",
                t->zName, t->token.lineNo,
-               g.nDelim, g.zDelim, pKw->zName);
+               g.delim.n, g.delim.z, pKw->zName);
     }
   }
 }
@@ -1469,7 +1817,9 @@ void cmpp_process_keyword(CmppTokenizer * const t){
 
 void cmpp_process_file(const char * zName){
   FileWrapper fw = FileWrapper_empty;
+  CmppTokenizer const * const oldTok = g.tok;
   CmppTokenizer ct = CmppTokenizer_empty;
+  g.tok = &ct;
   FileWrapper_open(&fw, zName, "r");
   FileWrapper_slurp(&fw);
   g_debug(1,("Read %u byte(s) from [%s]\n", fw.nContent, fw.zName));
@@ -1487,6 +1837,34 @@ void cmpp_process_file(const char * zName){
     fatal("Input ended inside an unterminated nested construct"
           "opened at [%s] line %u", zName, lv->token.lineNo);
   }
+  g.tok = oldTok;
+}
+
+
+void fatalv(char const *zFmt, va_list va){
+  fflush(stdout);
+  fputc('\n', stderr);
+  if( g.tok ){
+    fprintf(stderr,"%s: @%s:%d: ",
+            g.zArgv0,
+            (g.tok->zName && 0==strcmp("-",g.tok->zName))
+            ? "<stdin>"
+            : g.tok->zName,
+            g.tok->lineNo);
+  }
+  if(zFmt && *zFmt){
+    vfprintf(stderr, zFmt, va);
+  }
+  fputc('\n', stderr);
+  fflush(stderr);
+  exit(1);
+}
+
+void fatal(char const *zFmt, ...){
+  va_list va;
+  va_start(va, zFmt);
+  fatalv(zFmt, va);
+  va_end(va);
 }
 
 #undef CT_level
@@ -1501,35 +1879,84 @@ static void usage(int isErr){
   fprintf(fOut,
           "Flags and filenames may be in any order and "
           "they are processed in that order.\n"
-          "\nFlags:\n\n");
-
-#define arg(F,D) fprintf(fOut,"  %s\n      %s\n",F, D)
-  arg("-o|--outfile FILE","Send output to FILE (default=- (stdout)). "
-      "    Because arguments are processed in order, this should "
-      "    normally be given before -f.");
+          "\nFlags:\n");
+#define GAP "     "
+#define arg(F,D) fprintf(fOut,"\n  %s\n" GAP "%s\n",F, D)
+  arg("-o|--outfile FILE","Send output to FILE (default=- (stdout)).\n"
+      GAP "Because arguments are processed in order, this should\n"
+      GAP "normally be given before -f.");
   arg("-f|--file FILE","Read input from FILE (default=- (stdin)).\n"
-      "    All non-flag arguments are assumed to be the input files.");
-  arg("-DXYZ","Define XYZ to true");
-  arg("-UXYZ","Undefine all matching glob XYZ");
-  arg("-IXYZ","Add dir XYZ to include path");
+      "     All non-flag arguments are assumed to be the input files.");
+  arg("-DXYZ[=value]","Define XYZ to the given value (default=1).");
+  arg("-UXYZ","Undefine all defines matching glob XYZ.");
+  arg("-IXYZ","Add dir XYZ to the " CMPP_DEFAULT_DELIM "include path.");
+  arg("-FXYZ=filename",
+      "Define XYZ to the raw contents of the given file.\n"
+      GAP "The file is not processed as by " CMPP_DEFAULT_DELIM"include\n"
+      GAP "Maybe it should be. Or maybe we need a new flag for that.");
   arg("-d|--delimiter VALUE", "Set keyword delimiter to VALUE "
-      "(default=" CMPP_DEFAULT_DELIM ")");
-  arg("--sql-trace", "Send a trace of all SQL to stderr");
-  arg("--sql-trace-x", "Like --sql-trace but expand the SQL");
+      "(default=" CMPP_DEFAULT_DELIM ").");
+  arg("--@-policy retain|elide|error|off",
+      "Specifies how to handle @tokens@ (default=off).\n"
+      GAP "off    = do not look for @tokens@\n"
+      GAP "retain = parse @tokens@ and retain any undefined ones\n"
+      GAP "elide  = parse @tokens@ and elide any undefined ones\n"
+      GAP "error  = parse @tokens@ and error for any undefined ones"
+  );
+  arg("-@", "Equivalent to --@-policy=error.");
+  arg("-no-@", "Equivalent to --@-policy=off (the default).");
+  arg("--sql-trace", "Send a trace of all SQL to stderr.");
+  arg("--sql-trace-x",
+      "Like --sql-trace but expand all bound values in the SQL.");
+  arg("--no-sql-trace", "Disable SQL tracing (default).");
+  arg("--chomp-F", "One trailing newline is trimmed from files "
+      "read via -FXYZ=filename.");
+  arg("--no-chomp-F", "Disable --chomp-F (default).");
 #undef arg
-  fputs("",fOut);
+#undef GAP
+  fputs("\n",fOut);
+}
+
+static void get_flag_val(int argc, char const * const * argv, int * ndx,
+                    char const **zVal){
+  char const * zEq = strchr(argv[*ndx], '=');
+  if( zEq ){
+    *zVal = zEq+1;
+    return;
+  }
+  if(*ndx+1>=argc){
+    fatal("Missing value for flag '%s'", argv[*ndx]);
+  }
+  *zVal = argv[++*ndx];
+}
+
+static int arg_is_flag( char const *zFlag, char const *zArg,
+                        char const **zValIfEqX ){
+  *zValIfEqX = 0;
+  if( 0==strcmp(zFlag, zArg) ) return 1;
+  char const * z = strchr(zArg,'=');
+  if( z && z>zArg ){
+    /* compare the part before the '=' */
+    if( 0==strncmp(zFlag, zArg, z-zArg) ){
+      *zValIfEqX = z+1;
+      return 1;
+    }
+  }
+  return 0;
 }
 
 int main(int argc, char const * const * argv){
   int rc = 0;
   int inclCount = 0;
   int nFile = 0;
-#define M(X) (0==strcmp(X,zArg))
+  int ndxTrace = 0;
+  int expandMode = 0;
+  char const * zVal = 0;
+#define ARGVAL if( !zVal ) get_flag_val(argc, argv, &i, &zVal)
+#define M(X) arg_is_flag(X, zArg, &zVal)
 #define ISFLAG(X) else if(M(X))
 #define ISFLAG2(X,Y) else if(M(X) || M(Y))
-#define ARGVAL \
-  if(i+1>=argc) fatal("Missing value for flag '%s'", zArg);  \
-  zArg = argv[++i]
+#define NOVAL if( zVal ) fatal("Unexpected value for %s", zArg)
 
   g.zArgv0 = argv[0];
 #define DOIT if(doIt)
@@ -1544,14 +1971,31 @@ int main(int argc, char const * const * argv){
     */
     DOIT{
       atexit(cmpp_atexit);
+      if( 1==ndxTrace ){
+        /* Ensure that we start with tracing in the early stage if
+           --sql-trace is the first arg, in order to log schema
+           setup. */
+        g.sqlTrace.pFile = stderr;
+        g.sqlTrace.expandSql = expandMode;
+      }
       cmpp_initdb();
     }
     for(int i = 1; i < argc; ++i){
+      int negate = 0;
       char const * zArg = argv[i];
+      //g_stderr("i=%d zArg=%s\n", i, zArg);
+      zVal = 0;
       while('-'==*zArg) ++zArg;
       if(zArg==argv[i]/*not a flag*/){
+        zVal = zArg;
         goto do_infile;
-      }ISFLAG2("?","help"){
+      }
+      if( 0==strncmp(zArg,"no-",3) ){
+        zArg += 3;
+        negate = 1;
+      }
+      ISFLAG2("?","help"){
+        NOVAL;
         usage(0);
         goto end;
       }else if('D'==*zArg){
@@ -1560,6 +2004,12 @@ int main(int argc, char const * const * argv){
         DOIT {
           db_define_add(zArg);
         }
+      }else if('F'==*zArg){
+        ++zArg;
+        if(!*zArg) fatal("Missing key for -F");
+        DOIT {
+          db_define_add_file(zArg);
+        }
       }else if('U'==*zArg){
         ++zArg;
         if(!*zArg) fatal("Missing key for -U");
@@ -1577,7 +2027,7 @@ int main(int argc, char const * const * argv){
       ISFLAG2("o","outfile"){
         ARGVAL;
         DOIT {
-          FileWrapper_open(&g.out, zArg, "w");
+          FileWrapper_open(&g.out, zVal, "w");
         }
       }
       ISFLAG2("f","file"){
@@ -1590,34 +2040,63 @@ int main(int argc, char const * const * argv){
             db_include_dir_add(".");
             ++inclCount;
           }
-          cmpp_process_file(zArg);
+          cmpp_process_file(zVal);
         }
       }
-      ISFLAG2("d","delimiter"){
-        ARGVAL;
-        if( !doIt ){
-          g.zDelim = zArg;
-          g.nDelim = (unsigned short)strlen(zArg);
-          if(!g.nDelim) fatal("Keyword delimiter may not be empty.");
+      ISFLAG("@"){
+        NOVAL;
+        DOIT {
+          assert( AT_DEFAULT!=AT_OFF );
+          g.flags.atPolicy = negate ? AT_OFF : AT_DEFAULT;
         }
       }
-      ISFLAG("debug"){
+      ISFLAG("@-policy"){
+        AtPolicy aup;
+        ARGVAL;
+        aup = AtPolicy_fromStr(zVal);
+        if( AT_invalid==aup ){
+          fatal("Invalid --@-policy. Try one of retain|elide|error|off.");
+        }
         DOIT {
-          ++g.doDebug;
+          g.flags.atPolicy = aup;
         }
       }
+      ISFLAG("debug"){
+        NOVAL;
+        g.flags.doDebug += negate ? -1 : 1;
+      }
       ISFLAG("sql-trace"){
-        if( !doIt ){
-          /* Needs to be set before the start of the second pass, when
-             the db is inited. */
-          g.sqlTrace.pFile = stderr;
-          g.sqlTrace.expandSql = 0;
+        NOVAL;
+        /* Needs to be set before the start of the second pass, when
+           the db is inited. */
+        g.sqlTrace.expandSql = 0;
+        DOIT {
+          g.sqlTrace.pFile = negate ? (FILE*)0 : stderr;
+        }else if( !ndxTrace && !negate ){
+          ndxTrace = i;
+          expandMode = 0;
         }
       }
       ISFLAG("sql-trace-x"){
+        NOVAL;
+        g.sqlTrace.expandSql = 1;
+        DOIT {
+          g.sqlTrace.pFile = negate ? (FILE*)0 : stderr;
+        }else if( !ndxTrace && !negate ){
+          ndxTrace = i;
+          expandMode = 1;
+        }
+      }
+      ISFLAG("chomp-F"){
+        NOVAL;
+        DOIT g.flags.chompF = !negate;
+      }
+      ISFLAG2("d","delimiter"){
+        ARGVAL;
         if( !doIt ){
-          g.sqlTrace.pFile = stderr;
-          g.sqlTrace.expandSql = 1;
+          g.delim.z = zVal;
+          g.delim.n = (unsigned short)strlen(zVal);
+          if(!g.delim.n) fatal("Keyword delimiter may not be empty.");
         }
       }
       else{
index e360f869e580b8c9ce310efa7d83ffb563c3bf75..add4bb8f8d485a90f63933ea781792510aab1286 100644 (file)
@@ -571,6 +571,14 @@ static void mk_prologue(void){
 #define C_PP_D_CUSTOM_INSTANTIATE
 #endif
 
+static char const * BuildDef_jsext(const BuildDef * pB){
+  return (F_ESM & pB->flags) ? ".mjs" : ".js";
+}
+
+static char const * BuildDef_basename(const BuildDef * pB){
+  return pB->zBaseName ? pB->zBaseName : oBuildDefs.vanilla.zBaseName;
+}
+
 /*
 ** Emits makefile code for setting up values for the --pre-js=FILE,
 ** --post-js=FILE, and --extern-post-js=FILE emcc flags, as well as
@@ -581,8 +589,10 @@ static void mk_prologue(void){
 ** pB may be NULL.
 */
 static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
-/* Very common printf() args combo. */
+  char const * const zBaseName = pB
+    ? BuildDef_basename(pB) : 0;
 
+  assert( zBuildName );
   pf("%s# Begin --pre/--post flags for %s\n", zBanner, zBuildName);
 
   ps("# --pre-js=...");
@@ -653,12 +663,24 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
   ps("\n# --extern-post-js=...");
   pf("extern-post-js.%s.js = $(dir.tmp)/extern-post-js.%s.js\n",
      zBuildName, zBuildName);
-  pf("$(eval $(call b.c-pp.target,"
-     "%s,"
-     "$(extern-post-js.in.js),"
-     "$(extern-post-js.%s.js),"
-     "$(c-pp.D.%s)))\n",
-     zBuildName, zBuildName, zBuildName);
+  if( 0!=WASM_CUSTOM_INSTANTIATE && zBaseName ){
+    pf("$(eval $(call b.c-pp.target,"
+       "%s,"
+       "$(extern-post-js.in.js),"
+       "$(extern-post-js.%s.js),"
+       "$(c-pp.D.%s) --@-policy=error -Dsqlite3.wasm=%s.wasm"
+       "))",
+       zBuildName, zBuildName, zBuildName,
+       zBaseName);
+  }else{
+    pf("$(eval $(call b.c-pp.target,"
+       "%s,"
+       "$(extern-post-js.in.js),"
+       "$(extern-post-js.%s.js),"
+       "$(c-pp.D.%s)"
+       "))",
+       zBuildName, zBuildName, zBuildName);
+  }
 
   ps("\n# --pre/post misc...");
   /* Combined flags for use with emcc... */
@@ -679,14 +701,6 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
   pf("# End --pre/--post flags for %s%s", zBuildName, zBanner);
 }
 
-static char const * BuildDef_jsext(const BuildDef * pB){
-  return (F_ESM & pB->flags) ? ".mjs" : ".js";
-}
-
-static char const * BuildDef_basename(const BuildDef * pB){
-  return pB->zBaseName ? pB->zBaseName : oBuildDefs.vanilla.zBaseName;
-}
-
 static void emit_compile_start(char const *zBuildName){
   pf("\t@$(call b.mkdir@);"
      " $(call b.echo,%s,$(emo.compile) building ...)\n",
@@ -706,14 +720,10 @@ static void emit_logtag(char const *zBuildName){
 }
 
 /**
-   Emit rules for sqlite3-api.${zBuildName}.js.  zCmppD is optional
-   flags for $(bin.c-pp).
+   Emit rules for sqlite3-api.${zBuildName}.js.
 */
-static void emit_api_js(char const *zBuildName,
-                        char const *zCmppD){
-  pf("c-pp.D.%s = %s\n"
-     "sqlite3-api.%s.js = $(dir.tmp)/sqlite3-api.%s.js\n",
-     zBuildName, zCmppD ? zCmppD: "",
+static void emit_api_js(char const *zBuildName){
+  pf("sqlite3-api.%s.js = $(dir.tmp)/sqlite3-api.%s.js\n",
      zBuildName, zBuildName);
   pf("$(eval $(call b.c-pp.target,"
      "%s,"
@@ -763,22 +773,22 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
   pf("out.%s.base ?= $(dir.dout.%s)/%s\n",
      zBuildName, zBuildName, zBaseName);
 
-  if( pB->zDeps ){
-    pf("deps.%s += %s\n", zBuildName, pB->zDeps);
+  pf("c-pp.D.%s ?= %s\n", zBuildName, pB->zCmppD ? pB->zCmppD : "");
+  if( pB->flags & F_64BIT ){
+    pf("c-pp.D.%s += $(c-pp.D.64bit)\n", zBuildName);
   }
 
-  pf("c-pp.D.%s ?= %s\n", zBuildName, pB->zCmppD ? pB->zCmppD : "");
   pf("emcc.environment.%s ?= %s\n", zBuildName,
      pB->zEnv ? pB->zEnv : oBuildDefs.vanilla.zEnv);
   if( pB->zEmccExtra ){
     pf("emcc.flags.%s = %s\n", zBuildName, pB->zEmccExtra);
   }
 
-  emit_api_js(zBuildName, pB->zCmppD);
-  if( pB->flags & F_64BIT ){
-    pf("c-pp.D.%s +=  $(c-pp.D.64bit)\n", zBuildName);
+  if( pB->zDeps ){
+    pf("deps.%s += %s\n", zBuildName, pB->zDeps);
   }
 
+  emit_api_js(zBuildName);
   mk_pre_post(zBuildName, pB);
 
   { /* build it... */
@@ -845,13 +855,6 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
 
       pf("\t@$(call b.do.wasm-opt,%s)\n", zBuildName);
       pf("\t@$(call b.strip-js-emcc-bindings,$(logtag.%s))\n", zBuildName);
-      { /* Replace @sqlite3.wasm@ with the proper wasm file name. */
-        pf("\t@echo '"
-           "$(logtag.%s) $(emo.disk) s/@sqlite.wasm@/%s.wasm/g"
-           "'; "
-           "sed -i -e 's/@sqlite3.wasm@/%s.wasm/g' $@ || exit\n",
-           zBuildName, pB->zBaseName, pB->zBaseName);
-      }
 
       if( CP_JS & pB->flags ){
         /*
@@ -907,12 +910,13 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){
 
   if( CP_JS & pB->flags ){
     pf("$(dir.dout)/%s%s: $(out.%s.js)\n",
-       pB->zBaseName, zJsExt, zBuildName
+       zBaseName, zJsExt, zBuildName
     );
   }
+
   if( CP_WASM & pB->flags ){
     pf("$(dir.dout)/%s.wasm: $(out.%s.wasm)\n",
-       pB->zBaseName, zBuildName
+       zBaseName, zBuildName
     );
   }
 
@@ -966,7 +970,7 @@ static void mk_fiddle(void){
        zBuildName, zBuildName,
        zBuildName, zBuildName);
 
-    emit_api_js(zBuildName, 0);
+    emit_api_js(zBuildName);
     mk_pre_post(zBuildName, 0);
 
     {/* emcc */
index 9d9fc3ec10ddd18f7a3d7d2ca73770e39e6fc776..a93995084138a7db00e86b191a2f5ca6f43a2063 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sand\sedit\ssome\scomments.
-D 2025-09-27T00:07:25.718
+C Teach\sc-pp\show\sto\sreplace\sconfigure-script-like\s@tokens@,\sgiving\sus\sa\smuch\ssimpler\sway\sto\sget\sthe\sproper\sWASM\sfile\sname\sinjected\sinto\seach\sJS\sbuild.
+D 2025-09-27T11:38:35.546
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -578,7 +578,7 @@ F ext/session/sqlite3session.c b3de195ce668cace9b324599bf6255a70290cbfb5451e826e
 F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
 F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb
 F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile 47535171454c7448c116b4a51b7c820a90985d5c2484ca708afc36453d3385ba
+F ext/wasm/GNUmakefile a0b4f179bbaa295171bb00eb8ae20a28c634e47bedfe9339ac3ed0e351b7931a
 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
 F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7
 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -610,7 +610,7 @@ F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72
 F ext/wasm/api/sqlite3-wasm.c ff2dc011e17b06186b8b35e408626d7ace69a362b92c197a34d78bef25c7105a
 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 8fb6adfbae6270344f43f2652e63780df3f86521755bde8f92cf6b809ba7891d
 F ext/wasm/api/sqlite3-worker1.c-pp.js 69483df1df2d0988e708390f7b1feda769c16e9e9efd4683557f8e7197099cc0
-F ext/wasm/c-pp.c 4a7d3d34e7e5d2804031750a54a12f7d30731362b249eab8d746622a2a86ac1b
+F ext/wasm/c-pp.c 3c84267ad9c9018f8eb0c83952b1b37eac08e0c614d6771fba5cf7640641525b
 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
 F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
@@ -634,7 +634,7 @@ F ext/wasm/index.html 1b06cef70db4b2d5c0af1f9e6e32b27c1ca298cde97365a887926d501f
 F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d
 F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
 F ext/wasm/mkdist.sh 29f8a37a7aba41fa5df8e89b1fab02b83b35c43473c5cf808584872e022514b8 x
-F ext/wasm/mkwasmbuilds.c d86a3e178c4b17d3a430fd9579de3eb4f6575514237f22a03f5b83b077f36ed2
+F ext/wasm/mkwasmbuilds.c b29e041d7ac096897ce1e75abff2e8b2608a17b05a02fba7c06ad58da49fa577
 F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
@@ -2169,8 +2169,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P dced5a7c434b83553ede533f71e3133450795c12fc67acd1a55fdedfa8fed76c
-R a20298bbdf5568b5399dd36cf0a7d2aa
+P 1fa7e32d264f8329a8c9b0b5b469f1fc7ccadee86696d65e05df7fa3868af158
+R 3a56e0912785d2ab6d25423374f2119c
 U stephan
-Z 5680c7c50a9cb69997608b0e12b44048
+Z 11190564f62030b343ceea51d93a998a
 # Remove this line to create a well-formed Fossil manifest.
index 4ff5d88f7a2759a902b0d2afdcfc5d8694961d07..88c32983fb7e34f46424ad1bee62feb02aad6f75 100644 (file)
@@ -1 +1 @@
-1fa7e32d264f8329a8c9b0b5b469f1fc7ccadee86696d65e05df7fa3868af158
+ffd5c8eaa89250a043b573c3eb66693dfec087a5b5eef184ae6d7bfbcf61235a