-
Notifications
You must be signed in to change notification settings - Fork 0
/
mkpro.SH
226 lines (213 loc) · 5.64 KB
/
mkpro.SH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
case $CONFIG in
'') . ./config.sh ;;
esac
echo "Extracting mkpro (with variable substitutions)"
$spitshell >mkpro <<!GROK!THIS!
#!$perlpath
#
# mkpro - make prototypes, appending them to the .h and .ih files
#
chdir "$src";
!GROK!THIS!
$spitshell >>mkpro <<'!NO!SUBS!'
$dont_line="/* DON'T EDIT BELOW THIS LINE OR YOUR CHANGES WILL BE LOST! */\n";
$changes = 0;
# We're looking for the following limited format:
#
# void
# function(arg1, arg2)
# char* arg1;
# int (*arg2) _((void));
# {
#
# Once we find the '{' on a line by itself, we scan backward, parsing
# the arguments until we find the function line, at which point we snag
# the return value and check for a preceding #if line.
#
# Public prototypes for foo.c are written to foo.h, while the private
# (i.e. static) ones are written to foo.ih. When updating the files,
# we generate foo.nh and foo.nih and discard any file that is not
# different from the original. If a file is different, the original
# is moved into the directory "sanity", and the new file renamed.
foreach $file (<*.c>) {
next if $file eq 'ndir.c' || $file eq 'parsedate.c';
next unless $file =~ s/\.c$//;
open(IN_C, "$file.c") || die "Can't open $file.c for input: $!\n";
# Copy everything in foo.h up to the "DON'T EDIT" line to foo.nh
if (!open(IN, "$file.h")) {
#print STDERR "Can't open $file.h -- skipping $file.c.\n";
next;
}
open(OUT_H, ">$file.nh") || die "Can't open $file.nh for output: $!\n";
while (<IN>) {
last if /DON'T EDIT BELOW/;
print OUT_H $_;
}
print OUT_H $dont_line . "\n";
close IN;
# Copy everything in foo.ih up to the "DON'T EDIT" line to foo.nih
open(OUT_I, ">$file.nih") || die "Can't open $file.nih for output: $!\n";
if (open(IN, "$file.ih")) {
while (<IN>) {
last if /DON'T EDIT BELOW/;
print OUT_I $_;
}
close IN;
$need_I = 1;
$new_I = '';
} else {
# If foo.ih doesn't yet exist, create a foo.nih anyway
print OUT_I "/* $file.ih\n */\n\n";
$need_I = 0;
$new_I = ' **NEW**';
}
print OUT_I $dont_line . "\n";
$cond_H = 'none';
$cond_I = 'none';
while (<IN_C>) {
# Limit the lines stack to 20 entries
shift @lines if $#lines >= 20;
push(@lines, $_);
next unless /^{\s*$/;
pop @lines;
undef @args;
undef $func;
# The default is to use the .h file unless we see a "static"
$out = OUT_H;
$cond = $cond_H;
while ($_ = pop @lines) {
s|\s*/\*.*\*/||; # trim any comment
if (/^(\S*).*;/) {
# A line with ';' is an argument
$arg = $1;
# Discard "register" prefix
if ($arg eq "register") {
/^register\s*(\S*)\s/;
$arg = $1;
}
# If the arg line has _((...)), remember that bit as well.
if (/(_\(\(.*\)\))/) {
$arg .= "(*) $1";
push(@args,$arg);
}
else {
# Append an extra '*' for arg[]
$arg .= '*' if /]/;
push(@args,$arg);
# We allow only one duplicate, e.g. int arg1, arg2
if (/,/) {
push(@args,$arg);
}
}
} elsif (/^(.*)\(/) {
# A line with '(' but without ';' is the function name.
$func = $1;
} elsif (/,/) {
# Any remaining line with a comma is a continuation-line
# of the function's arg-list, e.g. " arg8,arg9,arg10)"
} else {
chop;
$ret = $_;
if (/^static\s/) {
# A static function goes in .ih, not .h
$out = OUT_I;
$cond = $cond_I;
$need_I = 1;
}
# Pop the previous line (and another if empty)
$_ = pop @lines;
$_ = pop @lines if /^$/;
if (/^\#\s*if([^\/]*)/) {
# Remember conditional preceding function
$newcond = $1;
$newcond =~ s/\s*$//;
} elsif (/^\#\s*else/) {
# Discard a function after an #else -- it's a duplicate
last;
} else {
# No conditional -- turn it off
$newcond = 'none';
}
# Output conditional, but only if it's different.
if ($cond ne $newcond) {
# Out with the old...
if ($cond ne 'none') {
print $out "#endif\n";
}
# In with the new...
if ($newcond ne 'none') {
print $out "#if$newcond\n";
}
}
# At last, output the actual prototype.
print $out "$ret $func _((";
if ($_ = pop @args) {
print $out $_;
while ($_ = pop @args) {
print $out ",$_";
}
} else {
print $out "void";
}
# Some special processing for non-returning "finalize"
if ($func eq "finalize") {
print $out "))
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR >= 5)
__attribute__((noreturn))
#endif
;\n";
} else {
print $out "));\n";
}
# Remember the conditional state of the current .h|.ih file.
if ($ret =~ /^static\s/) {
$cond_I = $newcond;
} else {
$cond_H = $newcond;
}
last;
}
}
}
close IN_C;
# Close any dangling conditionals
if ($cond_H ne 'none') {
print OUT_H "#endif\n";
}
close OUT_H;
if ($cond_I ne 'none') {
print OUT_I "#endif\n";
}
close OUT_I;
# Check for any differences and update if changed.
if (system "diff $file.h $file.nh >/dev/null") {
print "Updating $file.h\n";
mkdir("sanity",0755) unless -d "sanity";
rename("$file.h","sanity/$file.h");
rename("$file.nh","$file.h");
$changes++;
} else {
unlink "$file.nh";
}
# The .ih file is a little different, in that it might not be needed.
if ($need_I) {
if ($new_I ne '') {
system "touch $file.ih";
}
if (system "diff $file.ih $file.nih >/dev/null") {
print "Updating $file.ih$new_I\n";
mkdir("sanity",0755) unless -d "sanity";
rename("$file.ih","sanity/$file.ih");
rename("$file.nih","$file.ih");
$changes++;
} else {
unlink "$file.nih";
}
} else {
unlink "$file.nih";
}
}
print "No changes to prototypes.\n" if !$changes;
!NO!SUBS!
$eunicefix mkpro
chmod 755 mkpro