]> git.draconx.ca Git - cdecl99.git/blob - src/gperf-wordwrap.awk
Release 1.3.
[cdecl99.git] / src / gperf-wordwrap.awk
1 #!/bin/awk -f
2 #
3 # Copyright © 2023 Nick Bowler
4 #
5 # Hackjob to replace gperf's generated string table with a custom function.
6 #
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
12 # by the user.
13 #
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.
18 #
19 # To work, the following gperf options are assumed:
20 #
21 #   %struct-type
22 #   %null-strings
23 #
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.
26 #
27 # The user must supply a function with the following signature in the gperf file:
28 #
29 #   const char *wordlist_func(const struct tag *);
30 #
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
34 # entry.
35 #
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}.
40
41 BEGIN {
42   wl_tag = wl_name = "";
43   in_wordlist = 0;
44   linecount = 0;
45 }
46
47 NF == 1 && $1 == "};" {
48   in_wordlist = 0;
49 }
50
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)");
55 }
56
57 in_wordlist && $1 ~ /^[^#]/ {
58   # Convert empty wordlist entries to {0}.
59   gsub(/[{][(]char\*[)]0[}]/, "{0}");
60
61   # Remove string portion of populated entry initializers.
62   gsub(/\\"/, "\1");
63   sub(/"[^"]*",? */, "");
64   gsub("\1", "\\\"");
65 }
66
67 # Locate the wordlist array definition, which is identified by a magic
68 # name ending in "_wrapped"
69 $NF == "=" && $(NF-1) ~ /._wrapped\[\]$/ {
70   wl_tag = $(NF-2);
71   wl_name = $(NF-1);
72   sub(/_[^_]*$/, "", wl_name);
73
74   in_wordlist = 1;
75   dump_lines();
76 }
77
78 !wl_name {
79   # Buffer lines until we know the structure and wordlist names
80   lines[linecount++] = $0;
81   next;
82 }
83
84 { print; }
85
86 END { dump_lines(); }
87
88 function dump_lines(i, flag) {
89   flag = 0;
90   for (i = 0; i < linecount; i++) {
91     if (wl_name && !(flag > 0 || lines[i] ~ /^\//)) {
92       print "/* Postprocessed by gperf-wordwrap.awk */";
93       flag = 1;
94     }
95
96     if (flag == 1 && (lines[i] ~ "struct  *" wl_tag " *{")) {
97       print "static const char *" wl_name "_func(const struct " wl_tag " *);"
98       flag = 2;
99     }
100
101     print lines[i];
102     delete lines[i];
103   }
104   linecount = 0;
105 }