]> git.draconx.ca Git - dxcommon.git/commitdiff
Add a helper macro to use the new gen-options packed format.
authorNick Bowler <nbowler@draconx.ca>
Sun, 8 Jan 2023 05:32:22 +0000 (00:32 -0500)
committerNick Bowler <nbowler@draconx.ca>
Sun, 8 Jan 2023 19:45:51 +0000 (14:45 -0500)
Abstract some of the boilerplate into a new macro.  The gen-options.awk
is augmented to also give the packed format width as a power of two
(8/16/32/64).  Other than that we can use all the existing definitions
to make this common code in a new "xtra.h" header file.

scripts/gen-options.awk
src/xtra.h [new file with mode: 0644]

index a93c47cf95e576d5a723c6101d7d315a13461f49..80adcb44177a3fb91f79b0868e4e2b07dd4ca812 100755 (executable)
@@ -82,7 +82,9 @@
 #
 #   * the object-like macro LOPT_PACK_BITS expands to an integer constant
 #     expression, suitable for use in #if directives, that specifies the
-#     minimum number of bits required by the encoding.
+#     minimum number of bits required by the encoding.  LOPT_PACK_BITS2
+#     is the same, but rounded up to the next power of two greater than
+#     or equal to 8.
 #
 #   * the object-like macro LOPTS_PACKED_INITIALIZER expands to a
 #     comma-separated sequence of integer constant expressions, suitable
@@ -358,17 +360,18 @@ END {
 # Currently, this only works if none of the options use action specifications
 # (as these would require encoding user-specified pointer expressions and
 # arbitrary int values).
-function output_packed_macros(i, tmp, accum, max)
+function output_packed_macros(i, tmp, accum, max, totalbits)
 {
-  print "\n#define LOPT_PACK_BITS (LOPT_SC_BITS + LOPT_HA_BITS + LOPT_LS_BITS)";
+  print "";
 
   # determine number of bits to encode offsets in SOPT_STRING
   max = length(sopt_string);
-  accum = 0;
+  totalbits = accum = 0;
   for (i = 1; i <= max; i *= 2) {
     accum++;
   }
   print "#define LOPT_SC_BITS " accum;
+  totalbits += accum;
 
   # determine number of bits to encode has_arg values
   max = 0;
@@ -377,7 +380,9 @@ function output_packed_macros(i, tmp, accum, max)
     if (tmp > max)
       max = tmp;
   }
-  print "#define LOPT_HA_BITS " (max > 1 ? 2 : max > 0 ? 1 : 0);
+  accum = (max > 1 ? 2 : max > 0 ? 1 : 0);
+  print "#define LOPT_HA_BITS " accum;
+  totalbits += accum;
 
   # determine number of bits to encode offsets in lopt_strings
   max = 0;
@@ -391,6 +396,12 @@ function output_packed_macros(i, tmp, accum, max)
     accum++;
   }
   print "#define LOPT_LS_BITS " accum;
+  totalbits += accum;
+
+  print "#define LOPT_PACK_BITS " totalbits;
+  for (i = 8; i < totalbits; i *= 2)
+    ;
+  print "#define LOPT_PACK_BITS2 " i;
 
   # Now emit the packed initializer macro
   print "\n#define LOPTS_PACKED_INITIALIZER \\";
diff --git a/src/xtra.h b/src/xtra.h
new file mode 100644 (file)
index 0000000..4de8df5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2023 Nick Bowler
+ *
+ * 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.
+ */
+
+#ifndef DX_XTRA_H_
+#define DX_XTRA_H_
+
+#define XTRA_PASTE(a, b) a ## b
+#define XTRA_PASTE2(a, b) XTRA_PASTE(a, b)
+
+#define XTRA_ARRAYSIZE(a) (sizeof (a) / sizeof (a)[0])
+
+/*
+ * This macro may be used to simplify construction of a 'struct option'
+ * array from the packed format produced by gen-options.awk.
+ *
+ * Expanding this in a function will
+ *
+ *   (1) declare a constant array with static storage duration that
+ *       contains the packed representation, and
+ *   (2) declare an array of struct option of suitable length, with
+ *       the given name, and
+ *   (3) emit code to fill the struct option array from the packed
+ *       representation.
+ *
+ * The uint_leastXX_t typedefs must be in scope in order to use this macro.
+ */
+#define XTRA_PACKED_LOPTS(name) \
+       static const XTRA_PASTE2(uint_least, XTRA_PASTE2(LOPT_PACK_BITS2, _t)) \
+               name##_packed[] = { LOPTS_PACKED_INITIALIZER }; \
+       struct option name[XTRA_ARRAYSIZE(name##_packed) + 1] = {0}; \
+       do { \
+               unsigned i; \
+               for (i = 0; i < XTRA_ARRAYSIZE(name##_packed); i++) \
+                       LOPT_UNPACK(name[i], name##_packed[i]); \
+       } while (0)
+
+#endif