aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-09-24 17:24:14 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-24 17:24:14 -0400
commit6e936d3e9a45a4307e7f4a29ee9829e7a0464af1 (patch)
tree555f9d89779e6a675b38d9703f278ecf0579531c /scripts
parenta68aa1cc6f3203b8a332683ebde67a00f39eec43 (diff)
parent5cc8d246d0ebbdf827d4bb7c3de175377d244d73 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild
* git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild: (28 commits) kbuild: add distclean info to 'make help' and more details for 'clean' dontdiff: add utsrelease.h kbuild: fix "mkdir -p" usage in scripts/package/mkspec kbuild: correct and clarify versioning info in Makefile kbuild: fixup Documentation/kbuild/modules.txt kbuild: Extend kbuild/defconfig tags support to exuberant ctags kbuild: fix for some typos in Documentation/makefiles.txt kbuild: clarify "make C=" build option Documentaion: update Documentation/Changes with minimum versions kbuild: update help in top level Makefile kbuild: fail kernel compilation in case of unresolved module symbols kbuild: remove debug left-over from Makefile.host kbuild: create output directory for hostprogs with O=.. build kbuild: add missing return statement in modpost.c:secref_whitelist() kbuild: preperly align SYSMAP output kbuild: make -rR is now default kbuild: make V=2 tell why a target is rebuild kbuild: modpost on vmlinux regardless of CONFIG_MODULES kbuild: ignore references from ".pci_fixup" to ".init.text" kbuild: linguistic fixes for Documentation/kbuild/makefiles.txt ...
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Kbuild.include93
-rw-r--r--scripts/Makefile5
-rw-r--r--scripts/Makefile.build5
-rw-r--r--scripts/Makefile.headersinst2
-rw-r--r--scripts/Makefile.host20
-rw-r--r--scripts/Makefile.modpost13
-rw-r--r--scripts/kconfig/Makefile1
-rw-r--r--scripts/kconfig/confdata.c8
-rw-r--r--scripts/mod/modpost.c42
-rwxr-xr-xscripts/package/mkspec4
-rw-r--r--scripts/unifdef.c1005
11 files changed, 1149 insertions, 49 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index bb19c1561f1e..3d523899fdc0 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -8,9 +8,13 @@ empty :=
8space := $(empty) $(empty) 8space := $(empty) $(empty)
9 9
10### 10###
11# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
12dot-target = $(dir $@).$(notdir $@)
13
14###
11# The temporary file to save gcc -MD generated dependencies must not 15# The temporary file to save gcc -MD generated dependencies must not
12# contain a comma 16# contain a comma
13depfile = $(subst $(comma),_,$(@D)/.$(@F).d) 17depfile = $(subst $(comma),_,$(dot-target).d)
14 18
15### 19###
16# filename of target with directory and extension stripped 20# filename of target with directory and extension stripped
@@ -119,40 +123,83 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
119ifneq ($(KBUILD_NOCMDDEP),1) 123ifneq ($(KBUILD_NOCMDDEP),1)
120# Check if both arguments has same arguments. Result in empty string if equal 124# Check if both arguments has same arguments. Result in empty string if equal
121# User may override this check using make KBUILD_NOCMDDEP=1 125# User may override this check using make KBUILD_NOCMDDEP=1
122arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) ) 126arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
127 $(filter-out $(cmd_$@), $(cmd_$(1))) )
123endif 128endif
124 129
125# echo command. Short version is $(quiet) equals quiet, otherwise full command 130# echo command. Short version is $(quiet) equals quiet, otherwise full command
126echo-cmd = $(if $($(quiet)cmd_$(1)), \ 131echo-cmd = $(if $($(quiet)cmd_$(1)), \
127 echo ' $(call escsq,$($(quiet)cmd_$(1)))';) 132 echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
128 133
134# >'< substitution is for echo to work,
135# >$< substitution to preserve $ when reloading .cmd file
136# note: when using inline perl scripts [perl -e '...$$t=1;...']
137# in $(cmd_xxx) double $$ your perl vars
129make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) 138make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
130 139
131# function to only execute the passed command if necessary 140# Find any prerequisites that is newer than target or that does not exist.
132# >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file 141# PHONY targets skipped in both cases.
133# note: when using inline perl scripts [perl -e '...$$t=1;...'] in $(cmd_xxx) double $$ your perl vars 142any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
143
144# Execute command if command has changed or prerequisitei(s) are updated
134# 145#
135if_changed = $(if $(strip $(filter-out $(PHONY),$?) \ 146if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
136 $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \ 147 @set -e; \
137 @set -e; \ 148 $(echo-cmd) $(cmd_$(1)); \
138 $(echo-cmd) $(cmd_$(1)); \ 149 echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
139 echo 'cmd_$@ := $(make-cmd)' > $(@D)/.$(@F).cmd)
140 150
141# execute the command and also postprocess generated .d dependencies 151# execute the command and also postprocess generated .d dependencies
142# file 152# file
143if_changed_dep = $(if $(strip $(filter-out $(PHONY),$?) \ 153if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
144 $(filter-out FORCE $(wildcard $^),$^) \ 154 @set -e; \
145 $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \ 155 $(echo-cmd) $(cmd_$(1)); \
146 @set -e; \ 156 scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
147 $(echo-cmd) $(cmd_$(1)); \ 157 rm -f $(depfile); \
148 scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(@D)/.$(@F).tmp; \ 158 mv -f $(dot-target).tmp $(dot-target).cmd)
149 rm -f $(depfile); \
150 mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
151 159
152# Usage: $(call if_changed_rule,foo) 160# Usage: $(call if_changed_rule,foo)
153# will check if $(cmd_foo) changed, or any of the prequisites changed, 161# will check if $(cmd_foo) changed, or any of the prequisites changed,
154# and if so will execute $(rule_foo) 162# and if so will execute $(rule_foo)
155if_changed_rule = $(if $(strip $(filter-out $(PHONY),$?) \ 163if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
156 $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\ 164 @set -e; \
157 @set -e; \ 165 $(rule_$(1)))
158 $(rule_$(1))) 166
167###
168# why - tell why a a target got build
169# enabled by make V=2
170# Output (listed in the order they are checked):
171# (1) - due to target is PHONY
172# (2) - due to target missing
173# (3) - due to: file1.h file2.h
174# (4) - due to command line change
175# (5) - due to missing .cmd file
176# (6) - due to target not in $(targets)
177# (1) PHONY targets are always build
178# (2) No target, so we better build it
179# (3) Prerequisite is newer than target
180# (4) The command line stored in the file named dir/.target.cmd
181# differed from actual command line. This happens when compiler
182# options changes
183# (5) No dir/.target.cmd file (used to store command line)
184# (6) No dir/.target.cmd file and target not listed in $(targets)
185# This is a good hint that there is a bug in the kbuild file
186ifeq ($(KBUILD_VERBOSE),2)
187why = \
188 $(if $(filter $@, $(PHONY)),- due to target is PHONY, \
189 $(if $(wildcard $@), \
190 $(if $(strip $(any-prereq)),- due to: $(any-prereq), \
191 $(if $(arg-check), \
192 $(if $(cmd_$@),- due to command line change, \
193 $(if $(filter $@, $(targets)), \
194 - due to missing .cmd file, \
195 - due to $(notdir $@) not in $$(targets) \
196 ) \
197 ) \
198 ) \
199 ), \
200 - due to target missing \
201 ) \
202 )
203
204echo-why = $(call escsq, $(strip $(why)))
205endif
diff --git a/scripts/Makefile b/scripts/Makefile
index 6f6b48f39f0a..ea41de8fb7f5 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,8 +15,11 @@ hostprogs-$(CONFIG_IKCONFIG) += bin2c
15 15
16always := $(hostprogs-y) 16always := $(hostprogs-y)
17 17
18# The following hostprogs-y programs are only build on demand
19hostprogs-y += unifdef
20
18subdir-$(CONFIG_MODVERSIONS) += genksyms 21subdir-$(CONFIG_MODVERSIONS) += genksyms
19subdir-$(CONFIG_MODULES) += mod 22subdir-y += mod
20 23
21# Let clean descend into subdirs 24# Let clean descend into subdirs
22subdir- += basic kconfig package 25subdir- += basic kconfig package
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 3cb445cc7432..e2ad2dccccdb 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -191,9 +191,10 @@ define rule_cc_o_c
191 $(call echo-cmd,checksrc) $(cmd_checksrc) \ 191 $(call echo-cmd,checksrc) $(cmd_checksrc) \
192 $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ 192 $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
193 $(cmd_modversions) \ 193 $(cmd_modversions) \
194 scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > $(@D)/.$(@F).tmp; \ 194 scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
195 $(dot-target).tmp; \
195 rm -f $(depfile); \ 196 rm -f $(depfile); \
196 mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd 197 mv -f $(dot-target).tmp $(dot-target).cmd
197endef 198endef
198 199
199# Built-in and composite module parts 200# Built-in and composite module parts
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index 12e1daf875c8..8c02d2df4278 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -7,7 +7,7 @@
7# 7#
8# ========================================================================== 8# ==========================================================================
9 9
10UNIFDEF := unifdef -U__KERNEL__ 10UNIFDEF := scripts/unifdef -U__KERNEL__
11 11
12# Eliminate the contents of (and inclusions of) compiler.h 12# Eliminate the contents of (and inclusions of) compiler.h
13HDRSED := sed -e "s/ inline / __inline__ /g" \ 13HDRSED := sed -e "s/ inline / __inline__ /g" \
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 060f4c563a5c..575afbe5e370 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -32,11 +32,6 @@
32 32
33__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) 33__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
34 34
35# hostprogs-y := tools/build may have been specified. Retreive directory
36host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
37host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
38
39
40# C code 35# C code
41# Executables compiled from a single .c file 36# Executables compiled from a single .c file
42host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) 37host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
@@ -65,6 +60,21 @@ host-cobjs := $(filter-out %.so,$(host-cobjs))
65#Object (.o) files used by the shared libaries 60#Object (.o) files used by the shared libaries
66host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs)))) 61host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
67 62
63# output directory for programs/.o files
64# hostprogs-y := tools/build may have been specified. Retreive directory
65host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
66# directory of .o files from prog-objs notation
67host-objdirs += $(foreach f,$(host-cmulti), \
68 $(foreach m,$($(f)-objs), \
69 $(if $(dir $(m)),$(dir $(m)))))
70# directory of .o files from prog-cxxobjs notation
71host-objdirs += $(foreach f,$(host-cxxmulti), \
72 $(foreach m,$($(f)-cxxobjs), \
73 $(if $(dir $(m)),$(dir $(m)))))
74
75host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
76
77
68__hostprogs := $(addprefix $(obj)/,$(__hostprogs)) 78__hostprogs := $(addprefix $(obj)/,$(__hostprogs))
69host-csingle := $(addprefix $(obj)/,$(host-csingle)) 79host-csingle := $(addprefix $(obj)/,$(host-csingle))
70host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) 80host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 0a64688c2b5d..4b2721ca97da 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -51,19 +51,26 @@ _modpost: $(modules)
51 51
52# Step 2), invoke modpost 52# Step 2), invoke modpost
53# Includes step 3,4 53# Includes step 3,4
54quiet_cmd_modpost = MODPOST 54quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
55 cmd_modpost = scripts/mod/modpost \ 55 cmd_modpost = scripts/mod/modpost \
56 $(if $(CONFIG_MODVERSIONS),-m) \ 56 $(if $(CONFIG_MODVERSIONS),-m) \
57 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ 57 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
58 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ 58 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
59 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ 59 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
60 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ 60 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
61 $(filter-out FORCE,$^) 61 $(if $(KBUILD_EXTMOD),-w) \
62 $(wildcard vmlinux) $(filter-out FORCE,$^)
62 63
63PHONY += __modpost 64PHONY += __modpost
64__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE 65__modpost: $(modules:.ko=.o) FORCE
65 $(call cmd,modpost) 66 $(call cmd,modpost)
66 67
68quiet_cmd_kernel-mod = MODPOST $@
69 cmd_kernel-mod = $(cmd_modpost)
70
71vmlinux: FORCE
72 $(call cmd,kernel-mod)
73
67# Declare generated files as targets for modpost 74# Declare generated files as targets for modpost
68$(symverfile): __modpost ; 75$(symverfile): __modpost ;
69$(modules:.ko=.mod.c): __modpost ; 76$(modules:.ko=.mod.c): __modpost ;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index e6499db4c8cc..a90d3cc76bfa 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -74,6 +74,7 @@ help:
74 @echo ' xconfig - Update current config utilising a QT based front-end' 74 @echo ' xconfig - Update current config utilising a QT based front-end'
75 @echo ' gconfig - Update current config utilising a GTK based front-end' 75 @echo ' gconfig - Update current config utilising a GTK based front-end'
76 @echo ' oldconfig - Update current config utilising a provided .config as base' 76 @echo ' oldconfig - Update current config utilising a provided .config as base'
77 @echo ' silentoldconfig - Same as oldconfig, but quietly'
77 @echo ' randconfig - New config with random answer to all options' 78 @echo ' randconfig - New config with random answer to all options'
78 @echo ' defconfig - New config with default answer to all options' 79 @echo ' defconfig - New config with default answer to all options'
79 @echo ' allmodconfig - New config selecting modules when possible' 80 @echo ' allmodconfig - New config selecting modules when possible'
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index a69d8acbf274..69f96b398c22 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -193,8 +193,11 @@ load:
193 continue; 193 continue;
194 *p++ = 0; 194 *p++ = 0;
195 p2 = strchr(p, '\n'); 195 p2 = strchr(p, '\n');
196 if (p2) 196 if (p2) {
197 *p2 = 0; 197 *p2-- = 0;
198 if (*p2 == '\r')
199 *p2 = 0;
200 }
198 if (def == S_DEF_USER) { 201 if (def == S_DEF_USER) {
199 sym = sym_find(line + 7); 202 sym = sym_find(line + 7);
200 if (!sym) { 203 if (!sym) {
@@ -266,6 +269,7 @@ load:
266 ; 269 ;
267 } 270 }
268 break; 271 break;
272 case '\r':
269 case '\n': 273 case '\n':
270 break; 274 break;
271 default: 275 default:
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index dfde0e87a765..41277963f47a 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -23,6 +23,8 @@ int have_vmlinux = 0;
23static int all_versions = 0; 23static int all_versions = 0;
24/* If we are modposting external module set to 1 */ 24/* If we are modposting external module set to 1 */
25static int external_module = 0; 25static int external_module = 0;
26/* Only warn about unresolved symbols */
27static int warn_unresolved = 0;
26/* How a symbol is exported */ 28/* How a symbol is exported */
27enum export { 29enum export {
28 export_plain, export_unused, export_gpl, 30 export_plain, export_unused, export_gpl,
@@ -581,8 +583,8 @@ static int strrcmp(const char *s, const char *sub)
581 * fromsec = .data 583 * fromsec = .data
582 * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one 584 * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
583 **/ 585 **/
584static int secref_whitelist(const char *tosec, const char *fromsec, 586static int secref_whitelist(const char *modname, const char *tosec,
585 const char *atsym) 587 const char *fromsec, const char *atsym)
586{ 588{
587 int f1 = 1, f2 = 1; 589 int f1 = 1, f2 = 1;
588 const char **s; 590 const char **s;
@@ -618,8 +620,16 @@ static int secref_whitelist(const char *tosec, const char *fromsec,
618 for (s = pat2sym; *s; s++) 620 for (s = pat2sym; *s; s++)
619 if (strrcmp(atsym, *s) == 0) 621 if (strrcmp(atsym, *s) == 0)
620 f1 = 1; 622 f1 = 1;
623 if (f1 && f2)
624 return 1;
621 625
622 return f1 && f2; 626 /* Whitelist all references from .pci_fixup section if vmlinux */
627 if (is_vmlinux(modname)) {
628 if ((strcmp(fromsec, ".pci_fixup") == 0) &&
629 (strcmp(tosec, ".init.text") == 0))
630 return 1;
631 }
632 return 0;
623} 633}
624 634
625/** 635/**
@@ -726,7 +736,8 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
726 736
727 /* check whitelist - we may ignore it */ 737 /* check whitelist - we may ignore it */
728 if (before && 738 if (before &&
729 secref_whitelist(secname, fromsec, elf->strtab + before->st_name)) 739 secref_whitelist(modname, secname, fromsec,
740 elf->strtab + before->st_name))
730 return; 741 return;
731 742
732 if (before && after) { 743 if (before && after) {
@@ -1187,16 +1198,19 @@ static void add_header(struct buffer *b, struct module *mod)
1187/** 1198/**
1188 * Record CRCs for unresolved symbols 1199 * Record CRCs for unresolved symbols
1189 **/ 1200 **/
1190static void add_versions(struct buffer *b, struct module *mod) 1201static int add_versions(struct buffer *b, struct module *mod)
1191{ 1202{
1192 struct symbol *s, *exp; 1203 struct symbol *s, *exp;
1204 int err = 0;
1193 1205
1194 for (s = mod->unres; s; s = s->next) { 1206 for (s = mod->unres; s; s = s->next) {
1195 exp = find_symbol(s->name); 1207 exp = find_symbol(s->name);
1196 if (!exp || exp->module == mod) { 1208 if (!exp || exp->module == mod) {
1197 if (have_vmlinux && !s->weak) 1209 if (have_vmlinux && !s->weak) {
1198 warn("\"%s\" [%s.ko] undefined!\n", 1210 warn("\"%s\" [%s.ko] undefined!\n",
1199 s->name, mod->name); 1211 s->name, mod->name);
1212 err = warn_unresolved ? 0 : 1;
1213 }
1200 continue; 1214 continue;
1201 } 1215 }
1202 s->module = exp->module; 1216 s->module = exp->module;
@@ -1205,7 +1219,7 @@ static void add_versions(struct buffer *b, struct module *mod)
1205 } 1219 }
1206 1220
1207 if (!modversions) 1221 if (!modversions)
1208 return; 1222 return err;
1209 1223
1210 buf_printf(b, "\n"); 1224 buf_printf(b, "\n");
1211 buf_printf(b, "static const struct modversion_info ____versions[]\n"); 1225 buf_printf(b, "static const struct modversion_info ____versions[]\n");
@@ -1225,6 +1239,8 @@ static void add_versions(struct buffer *b, struct module *mod)
1225 } 1239 }
1226 1240
1227 buf_printf(b, "};\n"); 1241 buf_printf(b, "};\n");
1242
1243 return err;
1228} 1244}
1229 1245
1230static void add_depends(struct buffer *b, struct module *mod, 1246static void add_depends(struct buffer *b, struct module *mod,
@@ -1402,8 +1418,9 @@ int main(int argc, char **argv)
1402 char *kernel_read = NULL, *module_read = NULL; 1418 char *kernel_read = NULL, *module_read = NULL;
1403 char *dump_write = NULL; 1419 char *dump_write = NULL;
1404 int opt; 1420 int opt;
1421 int err;
1405 1422
1406 while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) { 1423 while ((opt = getopt(argc, argv, "i:I:mo:aw")) != -1) {
1407 switch(opt) { 1424 switch(opt) {
1408 case 'i': 1425 case 'i':
1409 kernel_read = optarg; 1426 kernel_read = optarg;
@@ -1421,6 +1438,9 @@ int main(int argc, char **argv)
1421 case 'a': 1438 case 'a':
1422 all_versions = 1; 1439 all_versions = 1;
1423 break; 1440 break;
1441 case 'w':
1442 warn_unresolved = 1;
1443 break;
1424 default: 1444 default:
1425 exit(1); 1445 exit(1);
1426 } 1446 }
@@ -1441,6 +1461,8 @@ int main(int argc, char **argv)
1441 check_exports(mod); 1461 check_exports(mod);
1442 } 1462 }
1443 1463
1464 err = 0;
1465
1444 for (mod = modules; mod; mod = mod->next) { 1466 for (mod = modules; mod; mod = mod->next) {
1445 if (mod->skip) 1467 if (mod->skip)
1446 continue; 1468 continue;
@@ -1448,7 +1470,7 @@ int main(int argc, char **argv)
1448 buf.pos = 0; 1470 buf.pos = 0;
1449 1471
1450 add_header(&buf, mod); 1472 add_header(&buf, mod);
1451 add_versions(&buf, mod); 1473 err |= add_versions(&buf, mod);
1452 add_depends(&buf, mod, modules); 1474 add_depends(&buf, mod, modules);
1453 add_moddevtable(&buf, mod); 1475 add_moddevtable(&buf, mod);
1454 add_srcversion(&buf, mod); 1476 add_srcversion(&buf, mod);
@@ -1460,5 +1482,5 @@ int main(int argc, char **argv)
1460 if (dump_write) 1482 if (dump_write)
1461 write_dump(dump_write); 1483 write_dump(dump_write);
1462 1484
1463 return 0; 1485 return err;
1464} 1486}
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index df892841b118..ffd61fe0c1ad 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -63,9 +63,9 @@ fi
63 63
64echo "%install" 64echo "%install"
65echo "%ifarch ia64" 65echo "%ifarch ia64"
66echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules' 66echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
67echo "%else" 67echo "%else"
68echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules' 68echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
69echo "%endif" 69echo "%endif"
70 70
71echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install' 71echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install'
diff --git a/scripts/unifdef.c b/scripts/unifdef.c
new file mode 100644
index 000000000000..552025e72acb
--- /dev/null
+++ b/scripts/unifdef.c
@@ -0,0 +1,1005 @@
1/*
2 * Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>. All rights reserved.
3 *
4 * This code is derived from software contributed to Berkeley by Dave Yost.
5 * It was rewritten to support ANSI C by Tony Finch. The original version of
6 * unifdef carried the following copyright notice. None of its code remains
7 * in this version (though some of the names remain).
8 *
9 * Copyright (c) 1985, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35
36#ifndef lint
37#if 0
38static const char copyright[] =
39"@(#) Copyright (c) 1985, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
41#endif
42#ifdef __IDSTRING
43__IDSTRING(Berkeley, "@(#)unifdef.c 8.1 (Berkeley) 6/6/93");
44__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $");
45__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.171 2005/03/08 12:38:48 fanf2 Exp $");
46#endif
47#endif /* not lint */
48#ifdef __FBSDID
49__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05/21 09:55:09 ru Exp $");
50#endif
51
52/*
53 * unifdef - remove ifdef'ed lines
54 *
55 * Wishlist:
56 * provide an option which will append the name of the
57 * appropriate symbol after #else's and #endif's
58 * provide an option which will check symbols after
59 * #else's and #endif's to see that they match their
60 * corresponding #ifdef or #ifndef
61 *
62 * The first two items above require better buffer handling, which would
63 * also make it possible to handle all "dodgy" directives correctly.
64 */
65
66#include <ctype.h>
67#include <err.h>
68#include <stdarg.h>
69#include <stdbool.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74
75size_t strlcpy(char *dst, const char *src, size_t siz);
76
77/* types of input lines: */
78typedef enum {
79 LT_TRUEI, /* a true #if with ignore flag */
80 LT_FALSEI, /* a false #if with ignore flag */
81 LT_IF, /* an unknown #if */
82 LT_TRUE, /* a true #if */
83 LT_FALSE, /* a false #if */
84 LT_ELIF, /* an unknown #elif */
85 LT_ELTRUE, /* a true #elif */
86 LT_ELFALSE, /* a false #elif */
87 LT_ELSE, /* #else */
88 LT_ENDIF, /* #endif */
89 LT_DODGY, /* flag: directive is not on one line */
90 LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
91 LT_PLAIN, /* ordinary line */
92 LT_EOF, /* end of file */
93 LT_COUNT
94} Linetype;
95
96static char const * const linetype_name[] = {
97 "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
98 "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
99 "DODGY TRUEI", "DODGY FALSEI",
100 "DODGY IF", "DODGY TRUE", "DODGY FALSE",
101 "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
102 "DODGY ELSE", "DODGY ENDIF",
103 "PLAIN", "EOF"
104};
105
106/* state of #if processing */
107typedef enum {
108 IS_OUTSIDE,
109 IS_FALSE_PREFIX, /* false #if followed by false #elifs */
110 IS_TRUE_PREFIX, /* first non-false #(el)if is true */
111 IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */
112 IS_FALSE_MIDDLE, /* a false #elif after a pass state */
113 IS_TRUE_MIDDLE, /* a true #elif after a pass state */
114 IS_PASS_ELSE, /* an else after a pass state */
115 IS_FALSE_ELSE, /* an else after a true state */
116 IS_TRUE_ELSE, /* an else after only false states */
117 IS_FALSE_TRAILER, /* #elifs after a true are false */
118 IS_COUNT
119} Ifstate;
120
121static char const * const ifstate_name[] = {
122 "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
123 "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
124 "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
125 "FALSE_TRAILER"
126};
127
128/* state of comment parser */
129typedef enum {
130 NO_COMMENT = false, /* outside a comment */
131 C_COMMENT, /* in a comment like this one */
132 CXX_COMMENT, /* between // and end of line */
133 STARTING_COMMENT, /* just after slash-backslash-newline */
134 FINISHING_COMMENT, /* star-backslash-newline in a C comment */
135 CHAR_LITERAL, /* inside '' */
136 STRING_LITERAL /* inside "" */
137} Comment_state;
138
139static char const * const comment_name[] = {
140 "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
141};
142
143/* state of preprocessor line parser */
144typedef enum {
145 LS_START, /* only space and comments on this line */
146 LS_HASH, /* only space, comments, and a hash */
147 LS_DIRTY /* this line can't be a preprocessor line */
148} Line_state;
149
150static char const * const linestate_name[] = {
151 "START", "HASH", "DIRTY"
152};
153
154/*
155 * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
156 */
157#define MAXDEPTH 64 /* maximum #if nesting */
158#define MAXLINE 4096 /* maximum length of line */
159#define MAXSYMS 4096 /* maximum number of symbols */
160
161/*
162 * Sometimes when editing a keyword the replacement text is longer, so
163 * we leave some space at the end of the tline buffer to accommodate this.
164 */
165#define EDITSLOP 10
166
167/*
168 * Globals.
169 */
170
171static bool complement; /* -c: do the complement */
172static bool debugging; /* -d: debugging reports */
173static bool iocccok; /* -e: fewer IOCCC errors */
174static bool killconsts; /* -k: eval constant #ifs */
175static bool lnblank; /* -l: blank deleted lines */
176static bool lnnum; /* -n: add #line directives */
177static bool symlist; /* -s: output symbol list */
178static bool text; /* -t: this is a text file */
179
180static const char *symname[MAXSYMS]; /* symbol name */
181static const char *value[MAXSYMS]; /* -Dsym=value */
182static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */
183static int nsyms; /* number of symbols */
184
185static FILE *input; /* input file pointer */
186static const char *filename; /* input file name */
187static int linenum; /* current line number */
188
189static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
190static char *keyword; /* used for editing #elif's */
191
192static Comment_state incomment; /* comment parser state */
193static Line_state linestate; /* #if line parser state */
194static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
195static bool ignoring[MAXDEPTH]; /* ignore comments state */
196static int stifline[MAXDEPTH]; /* start of current #if */
197static int depth; /* current #if nesting */
198static int delcount; /* count of deleted lines */
199static bool keepthis; /* don't delete constant #if */
200
201static int exitstat; /* program exit status */
202
203static void addsym(bool, bool, char *);
204static void debug(const char *, ...);
205static void done(void);
206static void error(const char *);
207static int findsym(const char *);
208static void flushline(bool);
209static Linetype getline(void);
210static Linetype ifeval(const char **);
211static void ignoreoff(void);
212static void ignoreon(void);
213static void keywordedit(const char *);
214static void nest(void);
215static void process(void);
216static const char *skipcomment(const char *);
217static const char *skipsym(const char *);
218static void state(Ifstate);
219static int strlcmp(const char *, const char *, size_t);
220static void unnest(void);
221static void usage(void);
222
223#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
224
225/*
226 * The main program.
227 */
228int
229main(int argc, char *argv[])
230{
231 int opt;
232
233 while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
234 switch (opt) {
235 case 'i': /* treat stuff controlled by these symbols as text */
236 /*
237 * For strict backwards-compatibility the U or D
238 * should be immediately after the -i but it doesn't
239 * matter much if we relax that requirement.
240 */
241 opt = *optarg++;
242 if (opt == 'D')
243 addsym(true, true, optarg);
244 else if (opt == 'U')
245 addsym(true, false, optarg);
246 else
247 usage();
248 break;
249 case 'D': /* define a symbol */
250 addsym(false, true, optarg);
251 break;
252 case 'U': /* undef a symbol */
253 addsym(false, false, optarg);
254 break;
255 case 'I':
256 /* no-op for compatibility with cpp */
257 break;
258 case 'c': /* treat -D as -U and vice versa */
259 complement = true;
260 break;
261 case 'd':
262 debugging = true;
263 break;
264 case 'e': /* fewer errors from dodgy lines */
265 iocccok = true;
266 break;
267 case 'k': /* process constant #ifs */
268 killconsts = true;
269 break;
270 case 'l': /* blank deleted lines instead of omitting them */
271 lnblank = true;
272 break;
273 case 'n': /* add #line directive after deleted lines */
274 lnnum = true;
275 break;
276 case 's': /* only output list of symbols that control #ifs */
277 symlist = true;
278 break;
279 case 't': /* don't parse C comments */
280 text = true;
281 break;
282 default:
283 usage();
284 }
285 argc -= optind;
286 argv += optind;
287 if (argc > 1) {
288 errx(2, "can only do one file");
289 } else if (argc == 1 && strcmp(*argv, "-") != 0) {
290 filename = *argv;
291 input = fopen(filename, "r");
292 if (input == NULL)
293 err(2, "can't open %s", filename);
294 } else {
295 filename = "[stdin]";
296 input = stdin;
297 }
298 process();
299 abort(); /* bug */
300}
301
302static void
303usage(void)
304{
305 fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
306 " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
307 exit(2);
308}
309
310/*
311 * A state transition function alters the global #if processing state
312 * in a particular way. The table below is indexed by the current
313 * processing state and the type of the current line.
314 *
315 * Nesting is handled by keeping a stack of states; some transition
316 * functions increase or decrease the depth. They also maintain the
317 * ignore state on a stack. In some complicated cases they have to
318 * alter the preprocessor directive, as follows.
319 *
320 * When we have processed a group that starts off with a known-false
321 * #if/#elif sequence (which has therefore been deleted) followed by a
322 * #elif that we don't understand and therefore must keep, we edit the
323 * latter into a #if to keep the nesting correct.
324 *
325 * When we find a true #elif in a group, the following block will
326 * always be kept and the rest of the sequence after the next #elif or
327 * #else will be discarded. We edit the #elif into a #else and the
328 * following directive to #endif since this has the desired behaviour.
329 *
330 * "Dodgy" directives are split across multiple lines, the most common
331 * example being a multi-line comment hanging off the right of the
332 * directive. We can handle them correctly only if there is no change
333 * from printing to dropping (or vice versa) caused by that directive.
334 * If the directive is the first of a group we have a choice between
335 * failing with an error, or passing it through unchanged instead of
336 * evaluating it. The latter is not the default to avoid questions from
337 * users about unifdef unexpectedly leaving behind preprocessor directives.
338 */
339typedef void state_fn(void);
340
341/* report an error */
342static void Eelif (void) { error("Inappropriate #elif"); }
343static void Eelse (void) { error("Inappropriate #else"); }
344static void Eendif(void) { error("Inappropriate #endif"); }
345static void Eeof (void) { error("Premature EOF"); }
346static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
347/* plain line handling */
348static void print (void) { flushline(true); }
349static void drop (void) { flushline(false); }
350/* output lacks group's start line */
351static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
352static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
353static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
354/* print/pass this block */
355static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
356static void Pelse (void) { print(); state(IS_PASS_ELSE); }
357static void Pendif(void) { print(); unnest(); }
358/* discard this block */
359static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
360static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
361static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
362static void Dendif(void) { drop(); unnest(); }
363/* first line of group */
364static void Fdrop (void) { nest(); Dfalse(); }
365static void Fpass (void) { nest(); Pelif(); }
366static void Ftrue (void) { nest(); Strue(); }
367static void Ffalse(void) { nest(); Sfalse(); }
368/* variable pedantry for obfuscated lines */
369static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
370static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); }
371static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
372/* ignore comments in this block */
373static void Idrop (void) { Fdrop(); ignoreon(); }
374static void Itrue (void) { Ftrue(); ignoreon(); }
375static void Ifalse(void) { Ffalse(); ignoreon(); }
376/* edit this line */
377static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
378static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); }
379static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
380static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
381
382static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
383/* IS_OUTSIDE */
384{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
385 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
386 print, done },
387/* IS_FALSE_PREFIX */
388{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
389 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
390 drop, Eeof },
391/* IS_TRUE_PREFIX */
392{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
393 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
394 print, Eeof },
395/* IS_PASS_MIDDLE */
396{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
397 Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
398 print, Eeof },
399/* IS_FALSE_MIDDLE */
400{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
401 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
402 drop, Eeof },
403/* IS_TRUE_MIDDLE */
404{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
405 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
406 print, Eeof },
407/* IS_PASS_ELSE */
408{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
409 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
410 print, Eeof },
411/* IS_FALSE_ELSE */
412{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
413 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
414 drop, Eeof },
415/* IS_TRUE_ELSE */
416{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
417 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
418 print, Eeof },
419/* IS_FALSE_TRAILER */
420{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
421 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
422 drop, Eeof }
423/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
424 TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
425 PLAIN EOF */
426};
427
428/*
429 * State machine utility functions
430 */
431static void
432done(void)
433{
434 if (incomment)
435 error("EOF in comment");
436 exit(exitstat);
437}
438static void
439ignoreoff(void)
440{
441 if (depth == 0)
442 abort(); /* bug */
443 ignoring[depth] = ignoring[depth-1];
444}
445static void
446ignoreon(void)
447{
448 ignoring[depth] = true;
449}
450static void
451keywordedit(const char *replacement)
452{
453 size_t size = tline + sizeof(tline) - keyword;
454 char *dst = keyword;
455 const char *src = replacement;
456 if (size != 0) {
457 while ((--size != 0) && (*src != '\0'))
458 *dst++ = *src++;
459 *dst = '\0';
460 }
461 print();
462}
463static void
464nest(void)
465{
466 depth += 1;
467 if (depth >= MAXDEPTH)
468 error("Too many levels of nesting");
469 stifline[depth] = linenum;
470}
471static void
472unnest(void)
473{
474 if (depth == 0)
475 abort(); /* bug */
476 depth -= 1;
477}
478static void
479state(Ifstate is)
480{
481 ifstate[depth] = is;
482}
483
484/*
485 * Write a line to the output or not, according to command line options.
486 */
487static void
488flushline(bool keep)
489{
490 if (symlist)
491 return;
492 if (keep ^ complement) {
493 if (lnnum && delcount > 0)
494 printf("#line %d\n", linenum);
495 fputs(tline, stdout);
496 delcount = 0;
497 } else {
498 if (lnblank)
499 putc('\n', stdout);
500 exitstat = 1;
501 delcount += 1;
502 }
503}
504
505/*
506 * The driver for the state machine.
507 */
508static void
509process(void)
510{
511 Linetype lineval;
512
513 for (;;) {
514 linenum++;
515 lineval = getline();
516 trans_table[ifstate[depth]][lineval]();
517 debug("process %s -> %s depth %d",
518 linetype_name[lineval],
519 ifstate_name[ifstate[depth]], depth);
520 }
521}
522
523/*
524 * Parse a line and determine its type. We keep the preprocessor line
525 * parser state between calls in the global variable linestate, with
526 * help from skipcomment().
527 */
528static Linetype
529getline(void)
530{
531 const char *cp;
532 int cursym;
533 int kwlen;
534 Linetype retval;
535 Comment_state wascomment;
536
537 if (fgets(tline, MAXLINE, input) == NULL)
538 return (LT_EOF);
539 retval = LT_PLAIN;
540 wascomment = incomment;
541 cp = skipcomment(tline);
542 if (linestate == LS_START) {
543 if (*cp == '#') {
544 linestate = LS_HASH;
545 cp = skipcomment(cp + 1);
546 } else if (*cp != '\0')
547 linestate = LS_DIRTY;
548 }
549 if (!incomment && linestate == LS_HASH) {
550 keyword = tline + (cp - tline);
551 cp = skipsym(cp);
552 kwlen = cp - keyword;
553 /* no way can we deal with a continuation inside a keyword */
554 if (strncmp(cp, "\\\n", 2) == 0)
555 Eioccc();
556 if (strlcmp("ifdef", keyword, kwlen) == 0 ||
557 strlcmp("ifndef", keyword, kwlen) == 0) {
558 cp = skipcomment(cp);
559 if ((cursym = findsym(cp)) < 0)
560 retval = LT_IF;
561 else {
562 retval = (keyword[2] == 'n')
563 ? LT_FALSE : LT_TRUE;
564 if (value[cursym] == NULL)
565 retval = (retval == LT_TRUE)
566 ? LT_FALSE : LT_TRUE;
567 if (ignore[cursym])
568 retval = (retval == LT_TRUE)
569 ? LT_TRUEI : LT_FALSEI;
570 }
571 cp = skipsym(cp);
572 } else if (strlcmp("if", keyword, kwlen) == 0)
573 retval = ifeval(&cp);
574 else if (strlcmp("elif", keyword, kwlen) == 0)
575 retval = ifeval(&cp) - LT_IF + LT_ELIF;
576 else if (strlcmp("else", keyword, kwlen) == 0)
577 retval = LT_ELSE;
578 else if (strlcmp("endif", keyword, kwlen) == 0)
579 retval = LT_ENDIF;
580 else {
581 linestate = LS_DIRTY;
582 retval = LT_PLAIN;
583 }
584 cp = skipcomment(cp);
585 if (*cp != '\0') {
586 linestate = LS_DIRTY;
587 if (retval == LT_TRUE || retval == LT_FALSE ||
588 retval == LT_TRUEI || retval == LT_FALSEI)
589 retval = LT_IF;
590 if (retval == LT_ELTRUE || retval == LT_ELFALSE)
591 retval = LT_ELIF;
592 }
593 if (retval != LT_PLAIN && (wascomment || incomment)) {
594 retval += LT_DODGY;
595 if (incomment)
596 linestate = LS_DIRTY;
597 }
598 /* skipcomment should have changed the state */
599 if (linestate == LS_HASH)
600 abort(); /* bug */
601 }
602 if (linestate == LS_DIRTY) {
603 while (*cp != '\0')
604 cp = skipcomment(cp + 1);
605 }
606 debug("parser %s comment %s line",
607 comment_name[incomment], linestate_name[linestate]);
608 return (retval);
609}
610
611/*
612 * These are the binary operators that are supported by the expression
613 * evaluator. Note that if support for division is added then we also
614 * need short-circuiting booleans because of divide-by-zero.
615 */
616static int op_lt(int a, int b) { return (a < b); }
617static int op_gt(int a, int b) { return (a > b); }
618static int op_le(int a, int b) { return (a <= b); }
619static int op_ge(int a, int b) { return (a >= b); }
620static int op_eq(int a, int b) { return (a == b); }
621static int op_ne(int a, int b) { return (a != b); }
622static int op_or(int a, int b) { return (a || b); }
623static int op_and(int a, int b) { return (a && b); }
624
625/*
626 * An evaluation function takes three arguments, as follows: (1) a pointer to
627 * an element of the precedence table which lists the operators at the current
628 * level of precedence; (2) a pointer to an integer which will receive the
629 * value of the expression; and (3) a pointer to a char* that points to the
630 * expression to be evaluated and that is updated to the end of the expression
631 * when evaluation is complete. The function returns LT_FALSE if the value of
632 * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the
633 * expression could not be evaluated.
634 */
635struct ops;
636
637typedef Linetype eval_fn(const struct ops *, int *, const char **);
638
639static eval_fn eval_table, eval_unary;
640
641/*
642 * The precedence table. Expressions involving binary operators are evaluated
643 * in a table-driven way by eval_table. When it evaluates a subexpression it
644 * calls the inner function with its first argument pointing to the next
645 * element of the table. Innermost expressions have special non-table-driven
646 * handling.
647 */
648static const struct ops {
649 eval_fn *inner;
650 struct op {
651 const char *str;
652 int (*fn)(int, int);
653 } op[5];
654} eval_ops[] = {
655 { eval_table, { { "||", op_or } } },
656 { eval_table, { { "&&", op_and } } },
657 { eval_table, { { "==", op_eq },
658 { "!=", op_ne } } },
659 { eval_unary, { { "<=", op_le },
660 { ">=", op_ge },
661 { "<", op_lt },
662 { ">", op_gt } } }
663};
664
665/*
666 * Function for evaluating the innermost parts of expressions,
667 * viz. !expr (expr) defined(symbol) symbol number
668 * We reset the keepthis flag when we find a non-constant subexpression.
669 */
670static Linetype
671eval_unary(const struct ops *ops, int *valp, const char **cpp)
672{
673 const char *cp;
674 char *ep;
675 int sym;
676
677 cp = skipcomment(*cpp);
678 if (*cp == '!') {
679 debug("eval%d !", ops - eval_ops);
680 cp++;
681 if (eval_unary(ops, valp, &cp) == LT_IF)
682 return (LT_IF);
683 *valp = !*valp;
684 } else if (*cp == '(') {
685 cp++;
686 debug("eval%d (", ops - eval_ops);
687 if (eval_table(eval_ops, valp, &cp) == LT_IF)
688 return (LT_IF);
689 cp = skipcomment(cp);
690 if (*cp++ != ')')
691 return (LT_IF);
692 } else if (isdigit((unsigned char)*cp)) {
693 debug("eval%d number", ops - eval_ops);
694 *valp = strtol(cp, &ep, 0);
695 cp = skipsym(cp);
696 } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
697 cp = skipcomment(cp+7);
698 debug("eval%d defined", ops - eval_ops);
699 if (*cp++ != '(')
700 return (LT_IF);
701 cp = skipcomment(cp);
702 sym = findsym(cp);
703 if (sym < 0)
704 return (LT_IF);
705 *valp = (value[sym] != NULL);
706 cp = skipsym(cp);
707 cp = skipcomment(cp);
708 if (*cp++ != ')')
709 return (LT_IF);
710 keepthis = false;
711 } else if (!endsym(*cp)) {
712 debug("eval%d symbol", ops - eval_ops);
713 sym = findsym(cp);
714 if (sym < 0)
715 return (LT_IF);
716 if (value[sym] == NULL)
717 *valp = 0;
718 else {
719 *valp = strtol(value[sym], &ep, 0);
720 if (*ep != '\0' || ep == value[sym])
721 return (LT_IF);
722 }
723 cp = skipsym(cp);
724 keepthis = false;
725 } else {
726 debug("eval%d bad expr", ops - eval_ops);
727 return (LT_IF);
728 }
729
730 *cpp = cp;
731 debug("eval%d = %d", ops - eval_ops, *valp);
732 return (*valp ? LT_TRUE : LT_FALSE);
733}
734
735/*
736 * Table-driven evaluation of binary operators.
737 */
738static Linetype
739eval_table(const struct ops *ops, int *valp, const char **cpp)
740{
741 const struct op *op;
742 const char *cp;
743 int val;
744
745 debug("eval%d", ops - eval_ops);
746 cp = *cpp;
747 if (ops->inner(ops+1, valp, &cp) == LT_IF)
748 return (LT_IF);
749 for (;;) {
750 cp = skipcomment(cp);
751 for (op = ops->op; op->str != NULL; op++)
752 if (strncmp(cp, op->str, strlen(op->str)) == 0)
753 break;
754 if (op->str == NULL)
755 break;
756 cp += strlen(op->str);
757 debug("eval%d %s", ops - eval_ops, op->str);
758 if (ops->inner(ops+1, &val, &cp) == LT_IF)
759 return (LT_IF);
760 *valp = op->fn(*valp, val);
761 }
762
763 *cpp = cp;
764 debug("eval%d = %d", ops - eval_ops, *valp);
765 return (*valp ? LT_TRUE : LT_FALSE);
766}
767
768/*
769 * Evaluate the expression on a #if or #elif line. If we can work out
770 * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
771 * return just a generic LT_IF.
772 */
773static Linetype
774ifeval(const char **cpp)
775{
776 int ret;
777 int val;
778
779 debug("eval %s", *cpp);
780 keepthis = killconsts ? false : true;
781 ret = eval_table(eval_ops, &val, cpp);
782 debug("eval = %d", val);
783 return (keepthis ? LT_IF : ret);
784}
785
786/*
787 * Skip over comments, strings, and character literals and stop at the
788 * next character position that is not whitespace. Between calls we keep
789 * the comment state in the global variable incomment, and we also adjust
790 * the global variable linestate when we see a newline.
791 * XXX: doesn't cope with the buffer splitting inside a state transition.
792 */
793static const char *
794skipcomment(const char *cp)
795{
796 if (text || ignoring[depth]) {
797 for (; isspace((unsigned char)*cp); cp++)
798 if (*cp == '\n')
799 linestate = LS_START;
800 return (cp);
801 }
802 while (*cp != '\0')
803 /* don't reset to LS_START after a line continuation */
804 if (strncmp(cp, "\\\n", 2) == 0)
805 cp += 2;
806 else switch (incomment) {
807 case NO_COMMENT:
808 if (strncmp(cp, "/\\\n", 3) == 0) {
809 incomment = STARTING_COMMENT;
810 cp += 3;
811 } else if (strncmp(cp, "/*", 2) == 0) {
812 incomment = C_COMMENT;
813 cp += 2;
814 } else if (strncmp(cp, "//", 2) == 0) {
815 incomment = CXX_COMMENT;
816 cp += 2;
817 } else if (strncmp(cp, "\'", 1) == 0) {
818 incomment = CHAR_LITERAL;
819 linestate = LS_DIRTY;
820 cp += 1;
821 } else if (strncmp(cp, "\"", 1) == 0) {
822 incomment = STRING_LITERAL;
823 linestate = LS_DIRTY;
824 cp += 1;
825 } else if (strncmp(cp, "\n", 1) == 0) {
826 linestate = LS_START;
827 cp += 1;
828 } else if (strchr(" \t", *cp) != NULL) {
829 cp += 1;
830 } else
831 return (cp);
832 continue;
833 case CXX_COMMENT:
834 if (strncmp(cp, "\n", 1) == 0) {
835 incomment = NO_COMMENT;
836 linestate = LS_START;
837 }
838 cp += 1;
839 continue;
840 case CHAR_LITERAL:
841 case STRING_LITERAL:
842 if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
843 (incomment == STRING_LITERAL && cp[0] == '\"')) {
844 incomment = NO_COMMENT;
845 cp += 1;
846 } else if (cp[0] == '\\') {
847 if (cp[1] == '\0')
848 cp += 1;
849 else
850 cp += 2;
851 } else if (strncmp(cp, "\n", 1) == 0) {
852 if (incomment == CHAR_LITERAL)
853 error("unterminated char literal");
854 else
855 error("unterminated string literal");
856 } else
857 cp += 1;
858 continue;
859 case C_COMMENT:
860 if (strncmp(cp, "*\\\n", 3) == 0) {
861 incomment = FINISHING_COMMENT;
862 cp += 3;
863 } else if (strncmp(cp, "*/", 2) == 0) {
864 incomment = NO_COMMENT;
865 cp += 2;
866 } else
867 cp += 1;
868 continue;
869 case STARTING_COMMENT:
870 if (*cp == '*') {
871 incomment = C_COMMENT;
872 cp += 1;
873 } else if (*cp == '/') {
874 incomment = CXX_COMMENT;
875 cp += 1;
876 } else {
877 incomment = NO_COMMENT;
878 linestate = LS_DIRTY;
879 }
880 continue;
881 case FINISHING_COMMENT:
882 if (*cp == '/') {
883 incomment = NO_COMMENT;
884 cp += 1;
885 } else
886 incomment = C_COMMENT;
887 continue;
888 default:
889 abort(); /* bug */
890 }
891 return (cp);
892}
893
894/*
895 * Skip over an identifier.
896 */
897static const char *
898skipsym(const char *cp)
899{
900 while (!endsym(*cp))
901 ++cp;
902 return (cp);
903}
904
905/*
906 * Look for the symbol in the symbol table. If is is found, we return
907 * the symbol table index, else we return -1.
908 */
909static int
910findsym(const char *str)
911{
912 const char *cp;
913 int symind;
914
915 cp = skipsym(str);
916 if (cp == str)
917 return (-1);
918 if (symlist) {
919 printf("%.*s\n", (int)(cp-str), str);
920 /* we don't care about the value of the symbol */
921 return (0);
922 }
923 for (symind = 0; symind < nsyms; ++symind) {
924 if (strlcmp(symname[symind], str, cp-str) == 0) {
925 debug("findsym %s %s", symname[symind],
926 value[symind] ? value[symind] : "");
927 return (symind);
928 }
929 }
930 return (-1);
931}
932
933/*
934 * Add a symbol to the symbol table.
935 */
936static void
937addsym(bool ignorethis, bool definethis, char *sym)
938{
939 int symind;
940 char *val;
941
942 symind = findsym(sym);
943 if (symind < 0) {
944 if (nsyms >= MAXSYMS)
945 errx(2, "too many symbols");
946 symind = nsyms++;
947 }
948 symname[symind] = sym;
949 ignore[symind] = ignorethis;
950 val = sym + (skipsym(sym) - sym);
951 if (definethis) {
952 if (*val == '=') {
953 value[symind] = val+1;
954 *val = '\0';
955 } else if (*val == '\0')
956 value[symind] = "";
957 else
958 usage();
959 } else {
960 if (*val != '\0')
961 usage();
962 value[symind] = NULL;
963 }
964}
965
966/*
967 * Compare s with n characters of t.
968 * The same as strncmp() except that it checks that s[n] == '\0'.
969 */
970static int
971strlcmp(const char *s, const char *t, size_t n)
972{
973 while (n-- && *t != '\0')
974 if (*s != *t)
975 return ((unsigned char)*s - (unsigned char)*t);
976 else
977 ++s, ++t;
978 return ((unsigned char)*s);
979}
980
981/*
982 * Diagnostics.
983 */
984static void
985debug(const char *msg, ...)
986{
987 va_list ap;
988
989 if (debugging) {
990 va_start(ap, msg);
991 vwarnx(msg, ap);
992 va_end(ap);
993 }
994}
995
996static void
997error(const char *msg)
998{
999 if (depth == 0)
1000 warnx("%s: %d: %s", filename, linenum, msg);
1001 else
1002 warnx("%s: %d: %s (#if line %d depth %d)",
1003 filename, linenum, msg, stifline[depth], depth);
1004 errx(2, "output may be truncated");
1005}