diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-24 17:24:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-24 17:24:14 -0400 |
commit | 6e936d3e9a45a4307e7f4a29ee9829e7a0464af1 (patch) | |
tree | 555f9d89779e6a675b38d9703f278ecf0579531c /scripts | |
parent | a68aa1cc6f3203b8a332683ebde67a00f39eec43 (diff) | |
parent | 5cc8d246d0ebbdf827d4bb7c3de175377d244d73 (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.include | 93 | ||||
-rw-r--r-- | scripts/Makefile | 5 | ||||
-rw-r--r-- | scripts/Makefile.build | 5 | ||||
-rw-r--r-- | scripts/Makefile.headersinst | 2 | ||||
-rw-r--r-- | scripts/Makefile.host | 20 | ||||
-rw-r--r-- | scripts/Makefile.modpost | 13 | ||||
-rw-r--r-- | scripts/kconfig/Makefile | 1 | ||||
-rw-r--r-- | scripts/kconfig/confdata.c | 8 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 42 | ||||
-rwxr-xr-x | scripts/package/mkspec | 4 | ||||
-rw-r--r-- | scripts/unifdef.c | 1005 |
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 := | |||
8 | space := $(empty) $(empty) | 8 | space := $(empty) $(empty) |
9 | 9 | ||
10 | ### | 10 | ### |
11 | # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o | ||
12 | dot-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 |
13 | depfile = $(subst $(comma),_,$(@D)/.$(@F).d) | 17 | depfile = $(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))) | |||
119 | ifneq ($(KBUILD_NOCMDDEP),1) | 123 | ifneq ($(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 |
122 | arg-check = $(strip $(filter-out $(1), $(2)) $(filter-out $(2), $(1)) ) | 126 | arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ |
127 | $(filter-out $(cmd_$@), $(cmd_$(1))) ) | ||
123 | endif | 128 | endif |
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 |
126 | echo-cmd = $(if $($(quiet)cmd_$(1)), \ | 131 | echo-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 | ||
129 | make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) | 138 | make-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 | 142 | any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) |
143 | |||
144 | # Execute command if command has changed or prerequisitei(s) are updated | ||
134 | # | 145 | # |
135 | if_changed = $(if $(strip $(filter-out $(PHONY),$?) \ | 146 | if_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 |
143 | if_changed_dep = $(if $(strip $(filter-out $(PHONY),$?) \ | 153 | if_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) |
155 | if_changed_rule = $(if $(strip $(filter-out $(PHONY),$?) \ | 163 | if_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 | ||
186 | ifeq ($(KBUILD_VERBOSE),2) | ||
187 | why = \ | ||
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 | |||
204 | echo-why = $(call escsq, $(strip $(why))) | ||
205 | endif | ||
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 | ||
16 | always := $(hostprogs-y) | 16 | always := $(hostprogs-y) |
17 | 17 | ||
18 | # The following hostprogs-y programs are only build on demand | ||
19 | hostprogs-y += unifdef | ||
20 | |||
18 | subdir-$(CONFIG_MODVERSIONS) += genksyms | 21 | subdir-$(CONFIG_MODVERSIONS) += genksyms |
19 | subdir-$(CONFIG_MODULES) += mod | 22 | subdir-y += mod |
20 | 23 | ||
21 | # Let clean descend into subdirs | 24 | # Let clean descend into subdirs |
22 | subdir- += basic kconfig package | 25 | subdir- += 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 |
197 | endef | 198 | endef |
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 | ||
10 | UNIFDEF := unifdef -U__KERNEL__ | 10 | UNIFDEF := 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 |
13 | HDRSED := sed -e "s/ inline / __inline__ /g" \ | 13 | HDRSED := 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 | ||
36 | host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f)))) | ||
37 | host-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 |
42 | host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) | 37 | host-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 |
66 | host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs)))) | 61 | host-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 | ||
65 | host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f)))) | ||
66 | # directory of .o files from prog-objs notation | ||
67 | host-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 | ||
71 | host-objdirs += $(foreach f,$(host-cxxmulti), \ | ||
72 | $(foreach m,$($(f)-cxxobjs), \ | ||
73 | $(if $(dir $(m)),$(dir $(m))))) | ||
74 | |||
75 | host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs)))) | ||
76 | |||
77 | |||
68 | __hostprogs := $(addprefix $(obj)/,$(__hostprogs)) | 78 | __hostprogs := $(addprefix $(obj)/,$(__hostprogs)) |
69 | host-csingle := $(addprefix $(obj)/,$(host-csingle)) | 79 | host-csingle := $(addprefix $(obj)/,$(host-csingle)) |
70 | host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) | 80 | host-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 |
54 | quiet_cmd_modpost = MODPOST | 54 | quiet_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 | ||
63 | PHONY += __modpost | 64 | PHONY += __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 | ||
68 | quiet_cmd_kernel-mod = MODPOST $@ | ||
69 | cmd_kernel-mod = $(cmd_modpost) | ||
70 | |||
71 | vmlinux: 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; | |||
23 | static int all_versions = 0; | 23 | static int all_versions = 0; |
24 | /* If we are modposting external module set to 1 */ | 24 | /* If we are modposting external module set to 1 */ |
25 | static int external_module = 0; | 25 | static int external_module = 0; |
26 | /* Only warn about unresolved symbols */ | ||
27 | static int warn_unresolved = 0; | ||
26 | /* How a symbol is exported */ | 28 | /* How a symbol is exported */ |
27 | enum export { | 29 | enum 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 | **/ |
584 | static int secref_whitelist(const char *tosec, const char *fromsec, | 586 | static 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 | **/ |
1190 | static void add_versions(struct buffer *b, struct module *mod) | 1201 | static 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 | ||
1230 | static void add_depends(struct buffer *b, struct module *mod, | 1246 | static 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 | ||
64 | echo "%install" | 64 | echo "%install" |
65 | echo "%ifarch ia64" | 65 | echo "%ifarch ia64" |
66 | echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules' | 66 | echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules' |
67 | echo "%else" | 67 | echo "%else" |
68 | echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules' | 68 | echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules' |
69 | echo "%endif" | 69 | echo "%endif" |
70 | 70 | ||
71 | echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install' | 71 | echo '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 | ||
38 | static 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 | |||
75 | size_t strlcpy(char *dst, const char *src, size_t siz); | ||
76 | |||
77 | /* types of input lines: */ | ||
78 | typedef 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 | |||
96 | static 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 */ | ||
107 | typedef 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 | |||
121 | static 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 */ | ||
129 | typedef 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 | |||
139 | static char const * const comment_name[] = { | ||
140 | "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING" | ||
141 | }; | ||
142 | |||
143 | /* state of preprocessor line parser */ | ||
144 | typedef 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 | |||
150 | static 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 | |||
171 | static bool complement; /* -c: do the complement */ | ||
172 | static bool debugging; /* -d: debugging reports */ | ||
173 | static bool iocccok; /* -e: fewer IOCCC errors */ | ||
174 | static bool killconsts; /* -k: eval constant #ifs */ | ||
175 | static bool lnblank; /* -l: blank deleted lines */ | ||
176 | static bool lnnum; /* -n: add #line directives */ | ||
177 | static bool symlist; /* -s: output symbol list */ | ||
178 | static bool text; /* -t: this is a text file */ | ||
179 | |||
180 | static const char *symname[MAXSYMS]; /* symbol name */ | ||
181 | static const char *value[MAXSYMS]; /* -Dsym=value */ | ||
182 | static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */ | ||
183 | static int nsyms; /* number of symbols */ | ||
184 | |||
185 | static FILE *input; /* input file pointer */ | ||
186 | static const char *filename; /* input file name */ | ||
187 | static int linenum; /* current line number */ | ||
188 | |||
189 | static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ | ||
190 | static char *keyword; /* used for editing #elif's */ | ||
191 | |||
192 | static Comment_state incomment; /* comment parser state */ | ||
193 | static Line_state linestate; /* #if line parser state */ | ||
194 | static Ifstate ifstate[MAXDEPTH]; /* #if processor state */ | ||
195 | static bool ignoring[MAXDEPTH]; /* ignore comments state */ | ||
196 | static int stifline[MAXDEPTH]; /* start of current #if */ | ||
197 | static int depth; /* current #if nesting */ | ||
198 | static int delcount; /* count of deleted lines */ | ||
199 | static bool keepthis; /* don't delete constant #if */ | ||
200 | |||
201 | static int exitstat; /* program exit status */ | ||
202 | |||
203 | static void addsym(bool, bool, char *); | ||
204 | static void debug(const char *, ...); | ||
205 | static void done(void); | ||
206 | static void error(const char *); | ||
207 | static int findsym(const char *); | ||
208 | static void flushline(bool); | ||
209 | static Linetype getline(void); | ||
210 | static Linetype ifeval(const char **); | ||
211 | static void ignoreoff(void); | ||
212 | static void ignoreon(void); | ||
213 | static void keywordedit(const char *); | ||
214 | static void nest(void); | ||
215 | static void process(void); | ||
216 | static const char *skipcomment(const char *); | ||
217 | static const char *skipsym(const char *); | ||
218 | static void state(Ifstate); | ||
219 | static int strlcmp(const char *, const char *, size_t); | ||
220 | static void unnest(void); | ||
221 | static void usage(void); | ||
222 | |||
223 | #define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_') | ||
224 | |||
225 | /* | ||
226 | * The main program. | ||
227 | */ | ||
228 | int | ||
229 | main(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 | |||
302 | static void | ||
303 | usage(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 | */ | ||
339 | typedef void state_fn(void); | ||
340 | |||
341 | /* report an error */ | ||
342 | static void Eelif (void) { error("Inappropriate #elif"); } | ||
343 | static void Eelse (void) { error("Inappropriate #else"); } | ||
344 | static void Eendif(void) { error("Inappropriate #endif"); } | ||
345 | static void Eeof (void) { error("Premature EOF"); } | ||
346 | static void Eioccc(void) { error("Obfuscated preprocessor control line"); } | ||
347 | /* plain line handling */ | ||
348 | static void print (void) { flushline(true); } | ||
349 | static void drop (void) { flushline(false); } | ||
350 | /* output lacks group's start line */ | ||
351 | static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); } | ||
352 | static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); } | ||
353 | static void Selse (void) { drop(); state(IS_TRUE_ELSE); } | ||
354 | /* print/pass this block */ | ||
355 | static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); } | ||
356 | static void Pelse (void) { print(); state(IS_PASS_ELSE); } | ||
357 | static void Pendif(void) { print(); unnest(); } | ||
358 | /* discard this block */ | ||
359 | static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); } | ||
360 | static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); } | ||
361 | static void Delse (void) { drop(); state(IS_FALSE_ELSE); } | ||
362 | static void Dendif(void) { drop(); unnest(); } | ||
363 | /* first line of group */ | ||
364 | static void Fdrop (void) { nest(); Dfalse(); } | ||
365 | static void Fpass (void) { nest(); Pelif(); } | ||
366 | static void Ftrue (void) { nest(); Strue(); } | ||
367 | static void Ffalse(void) { nest(); Sfalse(); } | ||
368 | /* variable pedantry for obfuscated lines */ | ||
369 | static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); } | ||
370 | static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); } | ||
371 | static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); } | ||
372 | /* ignore comments in this block */ | ||
373 | static void Idrop (void) { Fdrop(); ignoreon(); } | ||
374 | static void Itrue (void) { Ftrue(); ignoreon(); } | ||
375 | static void Ifalse(void) { Ffalse(); ignoreon(); } | ||
376 | /* edit this line */ | ||
377 | static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); } | ||
378 | static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); } | ||
379 | static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); } | ||
380 | static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); } | ||
381 | |||
382 | static 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 | */ | ||
431 | static void | ||
432 | done(void) | ||
433 | { | ||
434 | if (incomment) | ||
435 | error("EOF in comment"); | ||
436 | exit(exitstat); | ||
437 | } | ||
438 | static void | ||
439 | ignoreoff(void) | ||
440 | { | ||
441 | if (depth == 0) | ||
442 | abort(); /* bug */ | ||
443 | ignoring[depth] = ignoring[depth-1]; | ||
444 | } | ||
445 | static void | ||
446 | ignoreon(void) | ||
447 | { | ||
448 | ignoring[depth] = true; | ||
449 | } | ||
450 | static void | ||
451 | keywordedit(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 | } | ||
463 | static void | ||
464 | nest(void) | ||
465 | { | ||
466 | depth += 1; | ||
467 | if (depth >= MAXDEPTH) | ||
468 | error("Too many levels of nesting"); | ||
469 | stifline[depth] = linenum; | ||
470 | } | ||
471 | static void | ||
472 | unnest(void) | ||
473 | { | ||
474 | if (depth == 0) | ||
475 | abort(); /* bug */ | ||
476 | depth -= 1; | ||
477 | } | ||
478 | static void | ||
479 | state(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 | */ | ||
487 | static void | ||
488 | flushline(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 | */ | ||
508 | static void | ||
509 | process(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 | */ | ||
528 | static Linetype | ||
529 | getline(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 | */ | ||
616 | static int op_lt(int a, int b) { return (a < b); } | ||
617 | static int op_gt(int a, int b) { return (a > b); } | ||
618 | static int op_le(int a, int b) { return (a <= b); } | ||
619 | static int op_ge(int a, int b) { return (a >= b); } | ||
620 | static int op_eq(int a, int b) { return (a == b); } | ||
621 | static int op_ne(int a, int b) { return (a != b); } | ||
622 | static int op_or(int a, int b) { return (a || b); } | ||
623 | static 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 | */ | ||
635 | struct ops; | ||
636 | |||
637 | typedef Linetype eval_fn(const struct ops *, int *, const char **); | ||
638 | |||
639 | static 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 | */ | ||
648 | static 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 | */ | ||
670 | static Linetype | ||
671 | eval_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 | */ | ||
738 | static Linetype | ||
739 | eval_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 | */ | ||
773 | static Linetype | ||
774 | ifeval(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 | */ | ||
793 | static const char * | ||
794 | skipcomment(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 | */ | ||
897 | static const char * | ||
898 | skipsym(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 | */ | ||
909 | static int | ||
910 | findsym(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 | */ | ||
936 | static void | ||
937 | addsym(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 | */ | ||
970 | static int | ||
971 | strlcmp(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 | */ | ||
984 | static void | ||
985 | debug(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 | |||
996 | static void | ||
997 | error(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 | } | ||