3 # Copyright © 2023 Nick Bowler
5 # Hackjob to replace gperf's generated string table with a custom function.
7 # Sometimes it is not desired to use a gperf-generated string table, as this
8 # can be quite large and is mostly wasted space if we have some other means
9 # of creating strings. This script replaces the "wordlist" initializer with
10 # one that does not include any strings, and replaces the reference to the
11 # ".name" member of the wordlist with a function call which can be supplied
14 # This transformation only occurs if the %define word-array-name is used to
15 # define an identifier that ends in _wrapped. If this option is not used,
16 # no modifications are made to the gperf output, so that this script can be
17 # used in generic build recipes and selectively enabled/disabled.
19 # To work, the following gperf options are assumed:
24 # Do not use %pic. Since this script removes all keyword strings from the
25 # table initializer it is not required to avoid relocations in PIC code.
27 # The user must supply a function with the following signature in the gperf file:
29 # const char *wordlist_func(const struct tag *);
31 # where "wordlist" is the same identifier provided to word-array-name, without
32 # the _wrapped suffix, and "tag" is the identifier used for the gperf struct-type
33 # declaration. This function returns the string corresponding to a given table
36 # The structure declaration should not include the first "name" member which is
37 # ordinarily required. All struct members for nonempty table entries are set
38 # exactly as specified in the gperf input, without the keyword name. All empty
39 # table entries are initialized with {0}.
42 wl_tag = wl_name = "";
47 NF == 1 && $1 == "};" {
51 !in_wordlist && wl_name {
52 # Convert wordlist "name" member references to function call.
53 re = wl_name "_wrapped\\[key\\]\\.name";
54 gsub(re, wl_name "_func(" wl_name "_wrapped+key)");
57 in_wordlist && $1 ~ /^[^#]/ {
58 # Convert empty wordlist entries to {0}.
59 gsub(/[{][(]char\*[)]0[}]/, "{0}");
61 # Remove string portion of populated entry initializers.
63 sub(/"[^"]*",? */, "");
67 # Locate the wordlist array definition, which is identified by a magic
68 # name ending in "_wrapped"
69 $NF == "=" && $(NF-1) ~ /._wrapped\[\]$/ {
72 sub(/_[^_]*$/, "", wl_name);
79 # Buffer lines until we know the structure and wordlist names
80 lines[linecount++] = $0;
88 function dump_lines(i, flag) {
90 for (i = 0; i < linecount; i++) {
91 if (wl_name && !(flag > 0 || lines[i] ~ /^\//)) {
92 print "/* Postprocessed by gperf-wordwrap.awk */";
96 if (flag == 1 && (lines[i] ~ "struct *" wl_tag " *{")) {
97 print "static const char *" wl_name "_func(const struct " wl_tag " *);"