]> git.draconx.ca Git - dxcommon.git/blobdiff - scripts/bake-config.awk
Add a script to embed config.h into installed headers.
[dxcommon.git] / scripts / bake-config.awk
diff --git a/scripts/bake-config.awk b/scripts/bake-config.awk
new file mode 100755 (executable)
index 0000000..56e2151
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/awk -f
+#
+# Copyright © 2023 Nick Bowler
+#
+# Usage: bake-config.awk config.h some_header.h
+#
+# Looks for #define and #undef lines in config.h to identify configuration
+# macros, then looks for uses of those macros in some_header.h and substitutes
+# them accordingly.  The result is a header file that does not directly depend
+# on config.h, which can be installed normally.
+#
+# Presently, two kinds of substitions are made.
+#
+# - For a #define in config.h, any occurrence of that macro is substituted with
+#   its replacement text.
+#
+# - For an #undef in config.h, any occurrence of that macro in an #if or #elif
+#   directive is replaced with a literal 0.
+#
+# Almost no attempt is made to understand C syntax so the replacement is very
+# simplistic, and won't work well in many cases.  Inspect the output!
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+BEGIN {
+  filenum = 0;
+  idclass = "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0-9_]";
+}
+
+FNR == 1 { filenum++; }
+filenum == 1 && $1 == "#define" && $2 !~ /[(]/ {
+  key = $2;
+  $1 = $2 = "";
+  sub(/^ */, "", $0);
+  config[key] = $0 " /* " key " */";
+}
+
+# Autoconf comments out #undef lines in config.h, so we're looking for
+#    /* #undef FOO */
+filenum == 1 && $2 == "#undef" {
+  undef[$3] = 0 " /* " $3 " */";
+}
+
+filenum == 2 {
+  CHANGED = 0;
+  tok = $0;
+
+  # Mark identifier boundaries to avoid replacing substrings.  Use ` as
+  # it is not valid in C code (outside of string/character literals).
+  gsub(idclass"+", "`&`", tok);
+
+  # Replace all occurrences of configuration macros normally.
+  tok = do_replace(tok, config);
+
+  # Replace explicitly undefined configuration macros in #if/#elif
+  if ($0 ~ /^[ \t]*#[ \t]*(el)?if[ \t]/)
+    tok = do_replace(tok, undef);
+
+  if (CHANGED) {
+    gsub(/`/, "", tok);
+    print tok;
+  } else {
+    print $0;
+  }
+}
+
+function do_replace(s, config, result, t)
+{
+  while (match(s, "`" idclass "+`")) {
+    t = substr(s, RSTART+1, RLENGTH-2);
+    if (t in config) {
+      result = result substr(s, 1, RSTART - 1) config[t];
+      CHANGED = 1;
+    } else {
+      result = result substr(s, 1, RSTART + RLENGTH - 1);
+    }
+
+    s = substr(s, RSTART + RLENGTH);
+  }
+
+  return result s;
+}