DX_COPYRIGHT: Fix stripping of leading/trailing newlines.
[dxcommon.git] / scripts / import-gnu-getopt.awk
blob8266f84d2fe2bae9ef6ab76fd9f6f6c23a5a89bf
1 #!/bin/awk -f
3 # Patcher script to import getopt.c from Gnulib in order to remove
4 # bits and make it directly usable as a fallback getopt_long(_only)
5 # implementation in programs.
7 # Copyright © 2024 Nick Bowler
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
22 # Exercising section 3 of the LGPLv2.1 to the modified library:
24 # You may opt to apply the terms of the ordinary GNU General Public
25 # License instead of this License to a given copy of the Library. To
26 # do this, you must alter all the notices that refer to this License,
27 # so that they refer to the ordinary GNU General Public License, version 2,
28 # instead of this License. (If a newer version than version 2 of the
29 # ordinary GNU General Public License has appeared, then you can specify
30 # that version instead if you wish.) Do not make any other change in
31 # these notices.
33 # "GNU Lesser General Public License" -> "GNU General Public License"
34 sub(/Lesser General/, "General");
36 # "version 2.1 of the License" -> "version 3 of the License"
37 sub(/version 2[.]1/, "version 3");
40 # Remove all conditionally compiled blocks
41 BEGIN { cond_depth = 0; }
42 /^#[\t ]*if/ { cond_depth++; }
43 /^#[\t ]*endif/ { cond_depth--; next; }
44 cond_depth > 0 { next; }
46 # Replace references to getopt_data with direct variable names
47 { gsub(/d->__/, ""); gsub(/d->opt/, "opt"); }
49 # Rename stuff out of the implementation-reserved namespace
50 { gsub(/_getopt_internal_r/, "gnu_getopt"); }
51 { gsub(/_getopt_initialize/, "initialize"); }
53 # Remove comment and macro about removed plain "getopt"
54 /LSB-compliant getopt/ { while (!/[*][/]/) getline; next; }
55 /^#[\t ]*define +GETOPT_ENTRY/ { while (/\\$/) getline; next; }
57 # Avoid further touches to block comments
58 BEGIN { first_comment = in_comment = 0; }
59 /^[\t ]*[/][*]/ { in_comment = 1; }
60 in_comment == 1 {
61 if (/[*][/]/) {
62 if (first_comment == 0) first_comment = 1;
63 in_comment = 0;
66 print deferred_blank (last_line = $0);
67 deferred_blank = "";
68 next;
71 # Add our stuff right after the copyright notice
72 first_comment == 1 {
73 first_comment = -1;
75 date_cmd="date +%Y-%m-%d";
76 date_cmd | getline date;
77 close(date_cmd);
79 print "\n/*";
80 print " * This file has been modified from its original version,";
81 if (date) date = " on " date;
82 print " * postprocessed by import-gnu-getopt.awk" date;
83 print " */";
85 if (!test_mode) {
86 print "\n#if HAVE_CONFIG_H";
87 print "#\tinclude <config.h>";
88 print "#endif\n";
90 print "#include <stdio.h>";
91 print "#include <stdlib.h>";
92 print "#include <string.h>";
93 print "#include \"gnu_getopt.h\"\n";
95 print "#if ENABLE_NLS"
96 print "#\tinclude <libintl.h>"
97 print "#else"
98 print "#\tdefine gettext(x) (x)";
99 print "#endif";
103 # Remove all includes from the input.
104 /^#[\t ]*include/ { next; }
106 # Remove linter nonsense
107 { gsub(/_GL_UNUSED */, ""); }
109 # Remove alloca
110 { gsub(/(__libc_use_alloca|alloca) *[(][^)]*[)]/, "0"); }
112 # Convert _() to a direct gettext call
113 { gsub(/_[(]"/, "gettext(\""); }
115 # Remove stdio locking
116 /f(un)?lockfile/ { next; }
118 # Replace global getopt_data struct with separate global variables ...
119 /^static.*getopt_data/ {
120 $0 = "static int first_nonopt, last_nonopt;\n" \
121 "static char *nextchar;\n" \
122 "static unsigned char ordering, initialized;\n" \
123 "enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };";
126 # ... and remove parameter declarations of it everywhere ...
127 { sub(/, *struct +_getopt_data *[*] *d/, ""); }
128 /^[\t ]*struct +_getopt_data *[*] *d,/ {
129 sub(/struct +_getopt_data *[*] *d, */, "");
132 # ... and remove it from function calls
133 { gsub(/, *d *,/, ","); gsub(/, *d *[)]/, ")"); }
135 # Also remove posixly_correct parameter from functions
137 sub(/, *int +posixly_correct *[)]/, ")");
138 sub(/int +posixly_correct *[)]/, "int unused)");
139 gsub(/posixly_correct/, "0");
142 # Remove _getopt_internal function completely
143 BEGIN { func_delete = 0; func_block = 0; func_tmp = ""; }
144 /^int$/ { func_tmp = $0; next; }
145 func_tmp != "" {
146 if ($1 == "_getopt_internal") {
147 func_delete = 1;
148 } else {
149 $0 = func_tmp ORS $0;
151 func_tmp = "";
154 func_delete != 0 {
155 if ((func_block += gsub(/{/, "{")) > 0) {
156 if ((func_block -= gsub(/}/, "}")) == 0) {
157 func_delete = 0;
160 $0 = "";
163 # For the tests, move optind/opterr assignments into do_getopt_long_(only), as
164 # all callers explicitly set these to 1 and 0, respectivly, prior to the call.
165 # In addition to reducing the complexity of the test program, this also works
166 # around a code generation bug in old versions of MIPSpro C.
167 BEGIN { in_wrapper = 0; in_test = 0; }
168 /^do_getopt_long/ { in_wrapper = 1; }
169 in_wrapper && /{/ {
170 $0 = $0 "\n optind = 1, opterr = 0;";
171 in_wrapper = 0;
174 # Drop no longer needed optind/opterr assignments
175 in_test && (/optind *= *1/ || /opterr *= *0/) { next; }
176 /^test_getopt/ { in_test = 1; }
177 in_test && /^}/ { in_test = 0; }
179 # Consolidate redundant declarations in the test functions
180 in_test == 2 && /char *[*]argv\[/ { next; }
181 in_test == 2 && /int *c;/ { next; }
182 in_test == 1 && /{/ {
183 $0 = $0 "\n const char *argv[20];\n int c;";
184 in_test = 2;
187 # Remove consecutive blank lines which may be generated by the above
188 BEGIN { last_line = ""; deferred_blank = ""; }
190 empty = sub(/^[\f\t ]*$/, "")
192 if (!empty && deferred_blank) {
193 print (deferred_blank = "");
196 if (!empty || last_line != "") {
197 if ($0 == "") {
198 deferred_blank = ORS;
199 } else {
200 print $0;
204 last_line = $0;