diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-15 01:41:27 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-15 01:41:27 -0400 |
| commit | c362495586e8a3a6487a318fcd82eaf15ffe2142 (patch) | |
| tree | 86f7b195d36ba198f24f86be327f21a8d24ec248 /scripts | |
| parent | b70936d9ffbf0f45f4fa13a03122f015f13ecdb0 (diff) | |
| parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) | |
Merge 3.7-rc1 into tty-linus
This syncs up the tty-linus branch to the latest in Linus's tree to get all of
the UAPI stuff needed for the next set of patches to merge.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'scripts')
33 files changed, 2749 insertions, 171 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 65f362d931b5..fb070fa1038f 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore | |||
| @@ -10,3 +10,4 @@ ihex2fw | |||
| 10 | recordmcount | 10 | recordmcount |
| 11 | docproc | 11 | docproc |
| 12 | sortextable | 12 | sortextable |
| 13 | asn1_compiler | ||
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 6a3ee981931d..978416dd31ca 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include | |||
| @@ -98,24 +98,24 @@ try-run = $(shell set -e; \ | |||
| 98 | # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) | 98 | # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) |
| 99 | 99 | ||
| 100 | as-option = $(call try-run,\ | 100 | as-option = $(call try-run,\ |
| 101 | $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) | 101 | $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) |
| 102 | 102 | ||
| 103 | # as-instr | 103 | # as-instr |
| 104 | # Usage: cflags-y += $(call as-instr,instr,option1,option2) | 104 | # Usage: cflags-y += $(call as-instr,instr,option1,option2) |
| 105 | 105 | ||
| 106 | as-instr = $(call try-run,\ | 106 | as-instr = $(call try-run,\ |
| 107 | printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) | 107 | printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) |
| 108 | 108 | ||
| 109 | # cc-option | 109 | # cc-option |
| 110 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) | 110 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) |
| 111 | 111 | ||
| 112 | cc-option = $(call try-run,\ | 112 | cc-option = $(call try-run,\ |
| 113 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) | 113 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) |
| 114 | 114 | ||
| 115 | # cc-option-yn | 115 | # cc-option-yn |
| 116 | # Usage: flag := $(call cc-option-yn,-march=winchip-c6) | 116 | # Usage: flag := $(call cc-option-yn,-march=winchip-c6) |
| 117 | cc-option-yn = $(call try-run,\ | 117 | cc-option-yn = $(call try-run,\ |
| 118 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) | 118 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) |
| 119 | 119 | ||
| 120 | # cc-option-align | 120 | # cc-option-align |
| 121 | # Prefix align with either -falign or -malign | 121 | # Prefix align with either -falign or -malign |
| @@ -125,7 +125,7 @@ cc-option-align = $(subst -functions=0,,\ | |||
| 125 | # cc-disable-warning | 125 | # cc-disable-warning |
| 126 | # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) | 126 | # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) |
| 127 | cc-disable-warning = $(call try-run,\ | 127 | cc-disable-warning = $(call try-run,\ |
| 128 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) | 128 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) |
| 129 | 129 | ||
| 130 | # cc-version | 130 | # cc-version |
| 131 | # Usage gcc-ver := $(call cc-version) | 131 | # Usage gcc-ver := $(call cc-version) |
| @@ -143,7 +143,7 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) | |||
| 143 | # cc-ldoption | 143 | # cc-ldoption |
| 144 | # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) | 144 | # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) |
| 145 | cc-ldoption = $(call try-run,\ | 145 | cc-ldoption = $(call try-run,\ |
| 146 | $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) | 146 | $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) |
| 147 | 147 | ||
| 148 | # ld-option | 148 | # ld-option |
| 149 | # Usage: LDFLAGS += $(call ld-option, -X) | 149 | # Usage: LDFLAGS += $(call ld-option, -X) |
| @@ -209,7 +209,7 @@ endif | |||
| 209 | # >$< substitution to preserve $ when reloading .cmd file | 209 | # >$< substitution to preserve $ when reloading .cmd file |
| 210 | # note: when using inline perl scripts [perl -e '...$$t=1;...'] | 210 | # note: when using inline perl scripts [perl -e '...$$t=1;...'] |
| 211 | # in $(cmd_xxx) double $$ your perl vars | 211 | # in $(cmd_xxx) double $$ your perl vars |
| 212 | make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) | 212 | make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))) |
| 213 | 213 | ||
| 214 | # Find any prerequisites that is newer than target or that does not exist. | 214 | # Find any prerequisites that is newer than target or that does not exist. |
| 215 | # PHONY targets skipped in both cases. | 215 | # PHONY targets skipped in both cases. |
diff --git a/scripts/Makefile b/scripts/Makefile index a55b0067758a..01e7adb838d9 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
| @@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash | |||
| 16 | hostprogs-$(CONFIG_IKCONFIG) += bin2c | 16 | hostprogs-$(CONFIG_IKCONFIG) += bin2c |
| 17 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 17 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
| 18 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 18 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
| 19 | hostprogs-$(CONFIG_ASN1) += asn1_compiler | ||
| 19 | 20 | ||
| 20 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | 21 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include |
| 22 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | ||
| 21 | 23 | ||
| 22 | always := $(hostprogs-y) $(hostprogs-m) | 24 | always := $(hostprogs-y) $(hostprogs-m) |
| 23 | 25 | ||
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index ff1720d28d0c..0e801c3cdaf8 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
| @@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@ | |||
| 354 | $(obj)/%.lds: $(src)/%.lds.S FORCE | 354 | $(obj)/%.lds: $(src)/%.lds.S FORCE |
| 355 | $(call if_changed_dep,cpp_lds_S) | 355 | $(call if_changed_dep,cpp_lds_S) |
| 356 | 356 | ||
| 357 | # ASN.1 grammar | ||
| 358 | # --------------------------------------------------------------------------- | ||
| 359 | quiet_cmd_asn1_compiler = ASN.1 $@ | ||
| 360 | cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ | ||
| 361 | $(subst .h,.c,$@) $(subst .c,.h,$@) | ||
| 362 | |||
| 363 | .PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h | ||
| 364 | |||
| 365 | $(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler | ||
| 366 | $(call cmd,asn1_compiler) | ||
| 367 | |||
| 357 | # Build the compiled-in targets | 368 | # Build the compiled-in targets |
| 358 | # --------------------------------------------------------------------------- | 369 | # --------------------------------------------------------------------------- |
| 359 | 370 | ||
diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst index 4d908d16c035..c3f69ae275d1 100644 --- a/scripts/Makefile.fwinst +++ b/scripts/Makefile.fwinst | |||
| @@ -27,7 +27,7 @@ endif | |||
| 27 | installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw)) | 27 | installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw)) |
| 28 | 28 | ||
| 29 | installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all)) | 29 | installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all)) |
| 30 | installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/./ | 30 | installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/. |
| 31 | 31 | ||
| 32 | # Workaround for make < 3.81, where .SECONDEXPANSION doesn't work. | 32 | # Workaround for make < 3.81, where .SECONDEXPANSION doesn't work. |
| 33 | PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs | 33 | PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs |
| @@ -42,7 +42,7 @@ quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@) | |||
| 42 | $(installed-fw-dirs): | 42 | $(installed-fw-dirs): |
| 43 | $(call cmd,mkdir) | 43 | $(call cmd,mkdir) |
| 44 | 44 | ||
| 45 | $(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %) | 45 | $(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $$(dir $(INSTALL_FW_PATH)/%) |
| 46 | $(call cmd,install) | 46 | $(call cmd,install) |
| 47 | 47 | ||
| 48 | PHONY += __fw_install __fw_modinst FORCE | 48 | PHONY += __fw_install __fw_modinst FORCE |
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index efa5d940e632..3d13d3a3edfe 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst | |||
| @@ -9,7 +9,7 @@ include scripts/Kbuild.include | |||
| 9 | 9 | ||
| 10 | # | 10 | # |
| 11 | 11 | ||
| 12 | __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) | 12 | __modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) |
| 13 | modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) | 13 | modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) |
| 14 | 14 | ||
| 15 | PHONY += $(modules) | 15 | PHONY += $(modules) |
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 08dce14f2dc8..002089141df4 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost | |||
| @@ -14,7 +14,8 @@ | |||
| 14 | # 3) create one <module>.mod.c file pr. module | 14 | # 3) create one <module>.mod.c file pr. module |
| 15 | # 4) create one Module.symvers file with CRC for all exported symbols | 15 | # 4) create one Module.symvers file with CRC for all exported symbols |
| 16 | # 5) compile all <module>.mod.c files | 16 | # 5) compile all <module>.mod.c files |
| 17 | # 6) final link of the module to a <module.ko> file | 17 | # 6) final link of the module to a <module.ko> (or <module.unsigned>) file |
| 18 | # 7) signs the modules to a <module.ko> file | ||
| 18 | 19 | ||
| 19 | # Step 3 is used to place certain information in the module's ELF | 20 | # Step 3 is used to place certain information in the module's ELF |
| 20 | # section, including information such as: | 21 | # section, including information such as: |
| @@ -32,6 +33,8 @@ | |||
| 32 | # Step 4 is solely used to allow module versioning in external modules, | 33 | # Step 4 is solely used to allow module versioning in external modules, |
| 33 | # where the CRC of each module is retrieved from the Module.symvers file. | 34 | # where the CRC of each module is retrieved from the Module.symvers file. |
| 34 | 35 | ||
| 36 | # Step 7 is dependent on CONFIG_MODULE_SIG being enabled. | ||
| 37 | |||
| 35 | # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined | 38 | # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined |
| 36 | # symbols in the final module linking stage | 39 | # symbols in the final module linking stage |
| 37 | # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. | 40 | # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. |
| @@ -60,7 +63,7 @@ kernelsymfile := $(objtree)/Module.symvers | |||
| 60 | modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers | 63 | modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers |
| 61 | 64 | ||
| 62 | # Step 1), find all modules listed in $(MODVERDIR)/ | 65 | # Step 1), find all modules listed in $(MODVERDIR)/ |
| 63 | __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) | 66 | __modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) |
| 64 | modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) | 67 | modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) |
| 65 | 68 | ||
| 66 | # Stop after building .o files if NOFINAL is set. Makes compile tests quicker | 69 | # Stop after building .o files if NOFINAL is set. Makes compile tests quicker |
| @@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE | |||
| 116 | targets += $(modules:.ko=.mod.o) | 119 | targets += $(modules:.ko=.mod.o) |
| 117 | 120 | ||
| 118 | # Step 6), final link of the modules | 121 | # Step 6), final link of the modules |
| 122 | ifneq ($(CONFIG_MODULE_SIG),y) | ||
| 119 | quiet_cmd_ld_ko_o = LD [M] $@ | 123 | quiet_cmd_ld_ko_o = LD [M] $@ |
| 120 | cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ | 124 | cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ |
| 121 | $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ | 125 | $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ |
| @@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE | |||
| 125 | $(call if_changed,ld_ko_o) | 129 | $(call if_changed,ld_ko_o) |
| 126 | 130 | ||
| 127 | targets += $(modules) | 131 | targets += $(modules) |
| 132 | else | ||
| 133 | quiet_cmd_ld_ko_unsigned_o = LD [M] $@ | ||
| 134 | cmd_ld_ko_unsigned_o = \ | ||
| 135 | $(LD) -r $(LDFLAGS) \ | ||
| 136 | $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ | ||
| 137 | -o $@ $(filter-out FORCE,$^) \ | ||
| 138 | $(if $(AFTER_LINK),; $(AFTER_LINK)) | ||
| 139 | |||
| 140 | $(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE | ||
| 141 | $(call if_changed,ld_ko_unsigned_o) | ||
| 142 | |||
| 143 | targets += $(modules:.ko=.ko.unsigned) | ||
| 144 | |||
| 145 | # Step 7), sign the modules | ||
| 146 | MODSECKEY = ./signing_key.priv | ||
| 147 | MODPUBKEY = ./signing_key.x509 | ||
| 148 | |||
| 149 | ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) | ||
| 150 | ifeq ($(KBUILD_SRC),) | ||
| 151 | # no O= is being used | ||
| 152 | SCRIPTS_DIR := scripts | ||
| 153 | else | ||
| 154 | SCRIPTS_DIR := $(KBUILD_SRC)/scripts | ||
| 155 | endif | ||
| 156 | SIGN_MODULES := 1 | ||
| 157 | else | ||
| 158 | SIGN_MODULES := 0 | ||
| 159 | endif | ||
| 160 | |||
| 161 | # only sign if it's an in-tree module | ||
| 162 | ifneq ($(KBUILD_EXTMOD),) | ||
| 163 | SIGN_MODULES := 0 | ||
| 164 | endif | ||
| 128 | 165 | ||
| 166 | # We strip the module as best we can - note that using both strip and eu-strip | ||
| 167 | # results in a smaller module than using either alone. | ||
| 168 | EU_STRIP = $(shell which eu-strip || echo true) | ||
| 169 | |||
| 170 | quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@ | ||
| 171 | cmd_sign_ko_stripped_ko_unsigned = \ | ||
| 172 | cp $< $@ && \ | ||
| 173 | strip -x -g $@ && \ | ||
| 174 | $(EU_STRIP) $@ | ||
| 175 | |||
| 176 | ifeq ($(SIGN_MODULES),1) | ||
| 177 | |||
| 178 | quiet_cmd_genkeyid = GENKEYID $@ | ||
| 179 | cmd_genkeyid = \ | ||
| 180 | perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid | ||
| 181 | |||
| 182 | %.signer %.keyid: % | ||
| 183 | $(call if_changed,genkeyid) | ||
| 184 | |||
| 185 | KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid | ||
| 186 | quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@ | ||
| 187 | cmd_sign_ko_ko_stripped = \ | ||
| 188 | sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@ | ||
| 189 | else | ||
| 190 | KEYRING_DEP := | ||
| 191 | quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ | ||
| 192 | cmd_sign_ko_ko_unsigned = \ | ||
| 193 | cp $< $@ | ||
| 194 | endif | ||
| 195 | |||
| 196 | $(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE | ||
| 197 | $(call if_changed,sign_ko_ko_stripped) | ||
| 198 | |||
| 199 | $(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE | ||
| 200 | $(call if_changed,sign_ko_stripped_ko_unsigned) | ||
| 201 | |||
| 202 | targets += $(modules) | ||
| 203 | endif | ||
| 129 | 204 | ||
| 130 | # Add FORCE to the prequisites of a target to force it to be always rebuilt. | 205 | # Add FORCE to the prequisites of a target to force it to be always rebuilt. |
| 131 | # --------------------------------------------------------------------------- | 206 | # --------------------------------------------------------------------------- |
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c new file mode 100644 index 000000000000..db0e5cd34c70 --- /dev/null +++ b/scripts/asn1_compiler.c | |||
| @@ -0,0 +1,1545 @@ | |||
| 1 | /* Simplified ASN.1 notation parser | ||
| 2 | * | ||
| 3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdarg.h> | ||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <stdint.h> | ||
| 16 | #include <string.h> | ||
| 17 | #include <ctype.h> | ||
| 18 | #include <unistd.h> | ||
| 19 | #include <fcntl.h> | ||
| 20 | #include <sys/stat.h> | ||
| 21 | #include <linux/asn1_ber_bytecode.h> | ||
| 22 | |||
| 23 | enum token_type { | ||
| 24 | DIRECTIVE_ABSENT, | ||
| 25 | DIRECTIVE_ALL, | ||
| 26 | DIRECTIVE_ANY, | ||
| 27 | DIRECTIVE_APPLICATION, | ||
| 28 | DIRECTIVE_AUTOMATIC, | ||
| 29 | DIRECTIVE_BEGIN, | ||
| 30 | DIRECTIVE_BIT, | ||
| 31 | DIRECTIVE_BMPString, | ||
| 32 | DIRECTIVE_BOOLEAN, | ||
| 33 | DIRECTIVE_BY, | ||
| 34 | DIRECTIVE_CHARACTER, | ||
| 35 | DIRECTIVE_CHOICE, | ||
| 36 | DIRECTIVE_CLASS, | ||
| 37 | DIRECTIVE_COMPONENT, | ||
| 38 | DIRECTIVE_COMPONENTS, | ||
| 39 | DIRECTIVE_CONSTRAINED, | ||
| 40 | DIRECTIVE_CONTAINING, | ||
| 41 | DIRECTIVE_DEFAULT, | ||
| 42 | DIRECTIVE_DEFINED, | ||
| 43 | DIRECTIVE_DEFINITIONS, | ||
| 44 | DIRECTIVE_EMBEDDED, | ||
| 45 | DIRECTIVE_ENCODED, | ||
| 46 | DIRECTIVE_ENCODING_CONTROL, | ||
| 47 | DIRECTIVE_END, | ||
| 48 | DIRECTIVE_ENUMERATED, | ||
| 49 | DIRECTIVE_EXCEPT, | ||
| 50 | DIRECTIVE_EXPLICIT, | ||
| 51 | DIRECTIVE_EXPORTS, | ||
| 52 | DIRECTIVE_EXTENSIBILITY, | ||
| 53 | DIRECTIVE_EXTERNAL, | ||
| 54 | DIRECTIVE_FALSE, | ||
| 55 | DIRECTIVE_FROM, | ||
| 56 | DIRECTIVE_GeneralString, | ||
| 57 | DIRECTIVE_GeneralizedTime, | ||
| 58 | DIRECTIVE_GraphicString, | ||
| 59 | DIRECTIVE_IA5String, | ||
| 60 | DIRECTIVE_IDENTIFIER, | ||
| 61 | DIRECTIVE_IMPLICIT, | ||
| 62 | DIRECTIVE_IMPLIED, | ||
| 63 | DIRECTIVE_IMPORTS, | ||
| 64 | DIRECTIVE_INCLUDES, | ||
| 65 | DIRECTIVE_INSTANCE, | ||
| 66 | DIRECTIVE_INSTRUCTIONS, | ||
| 67 | DIRECTIVE_INTEGER, | ||
| 68 | DIRECTIVE_INTERSECTION, | ||
| 69 | DIRECTIVE_ISO646String, | ||
| 70 | DIRECTIVE_MAX, | ||
| 71 | DIRECTIVE_MIN, | ||
| 72 | DIRECTIVE_MINUS_INFINITY, | ||
| 73 | DIRECTIVE_NULL, | ||
| 74 | DIRECTIVE_NumericString, | ||
| 75 | DIRECTIVE_OBJECT, | ||
| 76 | DIRECTIVE_OCTET, | ||
| 77 | DIRECTIVE_OF, | ||
| 78 | DIRECTIVE_OPTIONAL, | ||
| 79 | DIRECTIVE_ObjectDescriptor, | ||
| 80 | DIRECTIVE_PATTERN, | ||
| 81 | DIRECTIVE_PDV, | ||
| 82 | DIRECTIVE_PLUS_INFINITY, | ||
| 83 | DIRECTIVE_PRESENT, | ||
| 84 | DIRECTIVE_PRIVATE, | ||
| 85 | DIRECTIVE_PrintableString, | ||
| 86 | DIRECTIVE_REAL, | ||
| 87 | DIRECTIVE_RELATIVE_OID, | ||
| 88 | DIRECTIVE_SEQUENCE, | ||
| 89 | DIRECTIVE_SET, | ||
| 90 | DIRECTIVE_SIZE, | ||
| 91 | DIRECTIVE_STRING, | ||
| 92 | DIRECTIVE_SYNTAX, | ||
| 93 | DIRECTIVE_T61String, | ||
| 94 | DIRECTIVE_TAGS, | ||
| 95 | DIRECTIVE_TRUE, | ||
| 96 | DIRECTIVE_TeletexString, | ||
| 97 | DIRECTIVE_UNION, | ||
| 98 | DIRECTIVE_UNIQUE, | ||
| 99 | DIRECTIVE_UNIVERSAL, | ||
| 100 | DIRECTIVE_UTCTime, | ||
| 101 | DIRECTIVE_UTF8String, | ||
| 102 | DIRECTIVE_UniversalString, | ||
| 103 | DIRECTIVE_VideotexString, | ||
| 104 | DIRECTIVE_VisibleString, | ||
| 105 | DIRECTIVE_WITH, | ||
| 106 | NR__DIRECTIVES, | ||
| 107 | TOKEN_ASSIGNMENT = NR__DIRECTIVES, | ||
| 108 | TOKEN_OPEN_CURLY, | ||
| 109 | TOKEN_CLOSE_CURLY, | ||
| 110 | TOKEN_OPEN_SQUARE, | ||
| 111 | TOKEN_CLOSE_SQUARE, | ||
| 112 | TOKEN_OPEN_ACTION, | ||
| 113 | TOKEN_CLOSE_ACTION, | ||
| 114 | TOKEN_COMMA, | ||
| 115 | TOKEN_NUMBER, | ||
| 116 | TOKEN_TYPE_NAME, | ||
| 117 | TOKEN_ELEMENT_NAME, | ||
| 118 | NR__TOKENS | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const unsigned char token_to_tag[NR__TOKENS] = { | ||
| 122 | /* EOC goes first */ | ||
| 123 | [DIRECTIVE_BOOLEAN] = ASN1_BOOL, | ||
| 124 | [DIRECTIVE_INTEGER] = ASN1_INT, | ||
| 125 | [DIRECTIVE_BIT] = ASN1_BTS, | ||
| 126 | [DIRECTIVE_OCTET] = ASN1_OTS, | ||
| 127 | [DIRECTIVE_NULL] = ASN1_NULL, | ||
| 128 | [DIRECTIVE_OBJECT] = ASN1_OID, | ||
| 129 | [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, | ||
| 130 | [DIRECTIVE_EXTERNAL] = ASN1_EXT, | ||
| 131 | [DIRECTIVE_REAL] = ASN1_REAL, | ||
| 132 | [DIRECTIVE_ENUMERATED] = ASN1_ENUM, | ||
| 133 | [DIRECTIVE_EMBEDDED] = 0, | ||
| 134 | [DIRECTIVE_UTF8String] = ASN1_UTF8STR, | ||
| 135 | [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, | ||
| 136 | /* 14 */ | ||
| 137 | /* 15 */ | ||
| 138 | [DIRECTIVE_SEQUENCE] = ASN1_SEQ, | ||
| 139 | [DIRECTIVE_SET] = ASN1_SET, | ||
| 140 | [DIRECTIVE_NumericString] = ASN1_NUMSTR, | ||
| 141 | [DIRECTIVE_PrintableString] = ASN1_PRNSTR, | ||
| 142 | [DIRECTIVE_T61String] = ASN1_TEXSTR, | ||
| 143 | [DIRECTIVE_TeletexString] = ASN1_TEXSTR, | ||
| 144 | [DIRECTIVE_VideotexString] = ASN1_VIDSTR, | ||
| 145 | [DIRECTIVE_IA5String] = ASN1_IA5STR, | ||
| 146 | [DIRECTIVE_UTCTime] = ASN1_UNITIM, | ||
| 147 | [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, | ||
| 148 | [DIRECTIVE_GraphicString] = ASN1_GRASTR, | ||
| 149 | [DIRECTIVE_VisibleString] = ASN1_VISSTR, | ||
| 150 | [DIRECTIVE_GeneralString] = ASN1_GENSTR, | ||
| 151 | [DIRECTIVE_UniversalString] = ASN1_UNITIM, | ||
| 152 | [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, | ||
| 153 | [DIRECTIVE_BMPString] = ASN1_BMPSTR, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static const char asn1_classes[4][5] = { | ||
| 157 | [ASN1_UNIV] = "UNIV", | ||
| 158 | [ASN1_APPL] = "APPL", | ||
| 159 | [ASN1_CONT] = "CONT", | ||
| 160 | [ASN1_PRIV] = "PRIV" | ||
| 161 | }; | ||
| 162 | |||
| 163 | static const char asn1_methods[2][5] = { | ||
| 164 | [ASN1_UNIV] = "PRIM", | ||
| 165 | [ASN1_APPL] = "CONS" | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const char *const asn1_universal_tags[32] = { | ||
| 169 | "EOC", | ||
| 170 | "BOOL", | ||
| 171 | "INT", | ||
| 172 | "BTS", | ||
| 173 | "OTS", | ||
| 174 | "NULL", | ||
| 175 | "OID", | ||
| 176 | "ODE", | ||
| 177 | "EXT", | ||
| 178 | "REAL", | ||
| 179 | "ENUM", | ||
| 180 | "EPDV", | ||
| 181 | "UTF8STR", | ||
| 182 | "RELOID", | ||
| 183 | NULL, /* 14 */ | ||
| 184 | NULL, /* 15 */ | ||
| 185 | "SEQ", | ||
| 186 | "SET", | ||
| 187 | "NUMSTR", | ||
| 188 | "PRNSTR", | ||
| 189 | "TEXSTR", | ||
| 190 | "VIDSTR", | ||
| 191 | "IA5STR", | ||
| 192 | "UNITIM", | ||
| 193 | "GENTIM", | ||
| 194 | "GRASTR", | ||
| 195 | "VISSTR", | ||
| 196 | "GENSTR", | ||
| 197 | "UNISTR", | ||
| 198 | "CHRSTR", | ||
| 199 | "BMPSTR", | ||
| 200 | NULL /* 31 */ | ||
| 201 | }; | ||
| 202 | |||
| 203 | static const char *filename; | ||
| 204 | static const char *grammar_name; | ||
| 205 | static const char *outputname; | ||
| 206 | static const char *headername; | ||
| 207 | |||
| 208 | static const char *const directives[NR__DIRECTIVES] = { | ||
| 209 | #define _(X) [DIRECTIVE_##X] = #X | ||
| 210 | _(ABSENT), | ||
| 211 | _(ALL), | ||
| 212 | _(ANY), | ||
| 213 | _(APPLICATION), | ||
| 214 | _(AUTOMATIC), | ||
| 215 | _(BEGIN), | ||
| 216 | _(BIT), | ||
| 217 | _(BMPString), | ||
| 218 | _(BOOLEAN), | ||
| 219 | _(BY), | ||
| 220 | _(CHARACTER), | ||
| 221 | _(CHOICE), | ||
| 222 | _(CLASS), | ||
| 223 | _(COMPONENT), | ||
| 224 | _(COMPONENTS), | ||
| 225 | _(CONSTRAINED), | ||
| 226 | _(CONTAINING), | ||
| 227 | _(DEFAULT), | ||
| 228 | _(DEFINED), | ||
| 229 | _(DEFINITIONS), | ||
| 230 | _(EMBEDDED), | ||
| 231 | _(ENCODED), | ||
| 232 | [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", | ||
| 233 | _(END), | ||
| 234 | _(ENUMERATED), | ||
| 235 | _(EXCEPT), | ||
| 236 | _(EXPLICIT), | ||
| 237 | _(EXPORTS), | ||
| 238 | _(EXTENSIBILITY), | ||
| 239 | _(EXTERNAL), | ||
| 240 | _(FALSE), | ||
| 241 | _(FROM), | ||
| 242 | _(GeneralString), | ||
| 243 | _(GeneralizedTime), | ||
| 244 | _(GraphicString), | ||
| 245 | _(IA5String), | ||
| 246 | _(IDENTIFIER), | ||
| 247 | _(IMPLICIT), | ||
| 248 | _(IMPLIED), | ||
| 249 | _(IMPORTS), | ||
| 250 | _(INCLUDES), | ||
| 251 | _(INSTANCE), | ||
| 252 | _(INSTRUCTIONS), | ||
| 253 | _(INTEGER), | ||
| 254 | _(INTERSECTION), | ||
| 255 | _(ISO646String), | ||
| 256 | _(MAX), | ||
| 257 | _(MIN), | ||
| 258 | [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", | ||
| 259 | [DIRECTIVE_NULL] = "NULL", | ||
| 260 | _(NumericString), | ||
| 261 | _(OBJECT), | ||
| 262 | _(OCTET), | ||
| 263 | _(OF), | ||
| 264 | _(OPTIONAL), | ||
| 265 | _(ObjectDescriptor), | ||
| 266 | _(PATTERN), | ||
| 267 | _(PDV), | ||
| 268 | [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", | ||
| 269 | _(PRESENT), | ||
| 270 | _(PRIVATE), | ||
| 271 | _(PrintableString), | ||
| 272 | _(REAL), | ||
| 273 | [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", | ||
| 274 | _(SEQUENCE), | ||
| 275 | _(SET), | ||
| 276 | _(SIZE), | ||
| 277 | _(STRING), | ||
| 278 | _(SYNTAX), | ||
| 279 | _(T61String), | ||
| 280 | _(TAGS), | ||
| 281 | _(TRUE), | ||
| 282 | _(TeletexString), | ||
| 283 | _(UNION), | ||
| 284 | _(UNIQUE), | ||
| 285 | _(UNIVERSAL), | ||
| 286 | _(UTCTime), | ||
| 287 | _(UTF8String), | ||
| 288 | _(UniversalString), | ||
| 289 | _(VideotexString), | ||
| 290 | _(VisibleString), | ||
| 291 | _(WITH) | ||
| 292 | }; | ||
| 293 | |||
| 294 | struct action { | ||
| 295 | struct action *next; | ||
| 296 | unsigned char index; | ||
| 297 | char name[]; | ||
| 298 | }; | ||
| 299 | |||
| 300 | static struct action *action_list; | ||
| 301 | static unsigned nr_actions; | ||
| 302 | |||
| 303 | struct token { | ||
| 304 | unsigned short line; | ||
| 305 | enum token_type token_type : 8; | ||
| 306 | unsigned char size; | ||
| 307 | struct action *action; | ||
| 308 | const char *value; | ||
| 309 | struct type *type; | ||
| 310 | }; | ||
| 311 | |||
| 312 | static struct token *token_list; | ||
| 313 | static unsigned nr_tokens; | ||
| 314 | |||
| 315 | static int directive_compare(const void *_key, const void *_pdir) | ||
| 316 | { | ||
| 317 | const struct token *token = _key; | ||
| 318 | const char *const *pdir = _pdir, *dir = *pdir; | ||
| 319 | size_t dlen, clen; | ||
| 320 | int val; | ||
| 321 | |||
| 322 | dlen = strlen(dir); | ||
| 323 | clen = (dlen < token->size) ? dlen : token->size; | ||
| 324 | |||
| 325 | //printf("cmp(%*.*s,%s) = ", | ||
| 326 | // (int)token->size, (int)token->size, token->value, | ||
| 327 | // dir); | ||
| 328 | |||
| 329 | val = memcmp(token->value, dir, clen); | ||
| 330 | if (val != 0) { | ||
| 331 | //printf("%d [cmp]\n", val); | ||
| 332 | return val; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (dlen == token->size) { | ||
| 336 | //printf("0\n"); | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | //printf("%d\n", (int)dlen - (int)token->size); | ||
| 340 | return dlen - token->size; /* shorter -> negative */ | ||
| 341 | } | ||
| 342 | |||
| 343 | /* | ||
| 344 | * Tokenise an ASN.1 grammar | ||
| 345 | */ | ||
| 346 | static void tokenise(char *buffer, char *end) | ||
| 347 | { | ||
| 348 | struct token *tokens; | ||
| 349 | char *line, *nl, *p, *q; | ||
| 350 | unsigned tix, lineno; | ||
| 351 | |||
| 352 | /* Assume we're going to have half as many tokens as we have | ||
| 353 | * characters | ||
| 354 | */ | ||
| 355 | token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); | ||
| 356 | if (!tokens) { | ||
| 357 | perror(NULL); | ||
| 358 | exit(1); | ||
| 359 | } | ||
| 360 | tix = 0; | ||
| 361 | |||
| 362 | lineno = 0; | ||
| 363 | while (buffer < end) { | ||
| 364 | /* First of all, break out a line */ | ||
| 365 | lineno++; | ||
| 366 | line = buffer; | ||
| 367 | nl = memchr(line, '\n', end - buffer); | ||
| 368 | if (!nl) { | ||
| 369 | buffer = nl = end; | ||
| 370 | } else { | ||
| 371 | buffer = nl + 1; | ||
| 372 | *nl = '\0'; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Remove "--" comments */ | ||
| 376 | p = line; | ||
| 377 | next_comment: | ||
| 378 | while ((p = memchr(p, '-', nl - p))) { | ||
| 379 | if (p[1] == '-') { | ||
| 380 | /* Found a comment; see if there's a terminator */ | ||
| 381 | q = p + 2; | ||
| 382 | while ((q = memchr(q, '-', nl - q))) { | ||
| 383 | if (q[1] == '-') { | ||
| 384 | /* There is - excise the comment */ | ||
| 385 | q += 2; | ||
| 386 | memmove(p, q, nl - q); | ||
| 387 | goto next_comment; | ||
| 388 | } | ||
| 389 | q++; | ||
| 390 | } | ||
| 391 | *p = '\0'; | ||
| 392 | nl = p; | ||
| 393 | break; | ||
| 394 | } else { | ||
| 395 | p++; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | p = line; | ||
| 400 | while (p < nl) { | ||
| 401 | /* Skip white space */ | ||
| 402 | while (p < nl && isspace(*p)) | ||
| 403 | *(p++) = 0; | ||
| 404 | if (p >= nl) | ||
| 405 | break; | ||
| 406 | |||
| 407 | tokens[tix].line = lineno; | ||
| 408 | tokens[tix].value = p; | ||
| 409 | |||
| 410 | /* Handle string tokens */ | ||
| 411 | if (isalpha(*p)) { | ||
| 412 | const char **dir; | ||
| 413 | |||
| 414 | /* Can be a directive, type name or element | ||
| 415 | * name. Find the end of the name. | ||
| 416 | */ | ||
| 417 | q = p + 1; | ||
| 418 | while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) | ||
| 419 | q++; | ||
| 420 | tokens[tix].size = q - p; | ||
| 421 | p = q; | ||
| 422 | |||
| 423 | /* If it begins with a lowercase letter then | ||
| 424 | * it's an element name | ||
| 425 | */ | ||
| 426 | if (islower(tokens[tix].value[0])) { | ||
| 427 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; | ||
| 428 | continue; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* Otherwise we need to search the directive | ||
| 432 | * table | ||
| 433 | */ | ||
| 434 | dir = bsearch(&tokens[tix], directives, | ||
| 435 | sizeof(directives) / sizeof(directives[1]), | ||
| 436 | sizeof(directives[1]), | ||
| 437 | directive_compare); | ||
| 438 | if (dir) { | ||
| 439 | tokens[tix++].token_type = dir - directives; | ||
| 440 | continue; | ||
| 441 | } | ||
| 442 | |||
| 443 | tokens[tix++].token_type = TOKEN_TYPE_NAME; | ||
| 444 | continue; | ||
| 445 | } | ||
| 446 | |||
| 447 | /* Handle numbers */ | ||
| 448 | if (isdigit(*p)) { | ||
| 449 | /* Find the end of the number */ | ||
| 450 | q = p + 1; | ||
| 451 | while (q < nl && (isdigit(*q))) | ||
| 452 | q++; | ||
| 453 | tokens[tix].size = q - p; | ||
| 454 | p = q; | ||
| 455 | tokens[tix++].token_type = TOKEN_NUMBER; | ||
| 456 | continue; | ||
| 457 | } | ||
| 458 | |||
| 459 | if (nl - p >= 3) { | ||
| 460 | if (memcmp(p, "::=", 3) == 0) { | ||
| 461 | p += 3; | ||
| 462 | tokens[tix].size = 3; | ||
| 463 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; | ||
| 464 | continue; | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | if (nl - p >= 2) { | ||
| 469 | if (memcmp(p, "({", 2) == 0) { | ||
| 470 | p += 2; | ||
| 471 | tokens[tix].size = 2; | ||
| 472 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; | ||
| 473 | continue; | ||
| 474 | } | ||
| 475 | if (memcmp(p, "})", 2) == 0) { | ||
| 476 | p += 2; | ||
| 477 | tokens[tix].size = 2; | ||
| 478 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; | ||
| 479 | continue; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | if (nl - p >= 1) { | ||
| 484 | tokens[tix].size = 1; | ||
| 485 | switch (*p) { | ||
| 486 | case '{': | ||
| 487 | p += 1; | ||
| 488 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; | ||
| 489 | continue; | ||
| 490 | case '}': | ||
| 491 | p += 1; | ||
| 492 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; | ||
| 493 | continue; | ||
| 494 | case '[': | ||
| 495 | p += 1; | ||
| 496 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; | ||
| 497 | continue; | ||
| 498 | case ']': | ||
| 499 | p += 1; | ||
| 500 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; | ||
| 501 | continue; | ||
| 502 | case ',': | ||
| 503 | p += 1; | ||
| 504 | tokens[tix++].token_type = TOKEN_COMMA; | ||
| 505 | continue; | ||
| 506 | default: | ||
| 507 | break; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", | ||
| 512 | filename, lineno, *p); | ||
| 513 | exit(1); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | nr_tokens = tix; | ||
| 518 | printf("Extracted %u tokens\n", nr_tokens); | ||
| 519 | |||
| 520 | #if 0 | ||
| 521 | { | ||
| 522 | int n; | ||
| 523 | for (n = 0; n < nr_tokens; n++) | ||
| 524 | printf("Token %3u: '%*.*s'\n", | ||
| 525 | n, | ||
| 526 | (int)token_list[n].size, (int)token_list[n].size, | ||
| 527 | token_list[n].value); | ||
| 528 | } | ||
| 529 | #endif | ||
| 530 | } | ||
| 531 | |||
| 532 | static void build_type_list(void); | ||
| 533 | static void parse(void); | ||
| 534 | static void render(FILE *out, FILE *hdr); | ||
| 535 | |||
| 536 | /* | ||
| 537 | * | ||
| 538 | */ | ||
| 539 | int main(int argc, char **argv) | ||
| 540 | { | ||
| 541 | struct stat st; | ||
| 542 | ssize_t readlen; | ||
| 543 | FILE *out, *hdr; | ||
| 544 | char *buffer, *p; | ||
| 545 | int fd; | ||
| 546 | |||
| 547 | if (argc != 4) { | ||
| 548 | fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", | ||
| 549 | argv[0]); | ||
| 550 | exit(2); | ||
| 551 | } | ||
| 552 | |||
| 553 | filename = argv[1]; | ||
| 554 | outputname = argv[2]; | ||
| 555 | headername = argv[3]; | ||
| 556 | |||
| 557 | fd = open(filename, O_RDONLY); | ||
| 558 | if (fd < 0) { | ||
| 559 | perror(filename); | ||
| 560 | exit(1); | ||
| 561 | } | ||
| 562 | |||
| 563 | if (fstat(fd, &st) < 0) { | ||
| 564 | perror(filename); | ||
| 565 | exit(1); | ||
| 566 | } | ||
| 567 | |||
| 568 | if (!(buffer = malloc(st.st_size + 1))) { | ||
| 569 | perror(NULL); | ||
| 570 | exit(1); | ||
| 571 | } | ||
| 572 | |||
| 573 | if ((readlen = read(fd, buffer, st.st_size)) < 0) { | ||
| 574 | perror(filename); | ||
| 575 | exit(1); | ||
| 576 | } | ||
| 577 | |||
| 578 | if (close(fd) < 0) { | ||
| 579 | perror(filename); | ||
| 580 | exit(1); | ||
| 581 | } | ||
| 582 | |||
| 583 | if (readlen != st.st_size) { | ||
| 584 | fprintf(stderr, "%s: Short read\n", filename); | ||
| 585 | exit(1); | ||
| 586 | } | ||
| 587 | |||
| 588 | p = strrchr(argv[1], '/'); | ||
| 589 | p = p ? p + 1 : argv[1]; | ||
| 590 | grammar_name = strdup(p); | ||
| 591 | if (!p) { | ||
| 592 | perror(NULL); | ||
| 593 | exit(1); | ||
| 594 | } | ||
| 595 | p = strchr(grammar_name, '.'); | ||
| 596 | if (p) | ||
| 597 | *p = '\0'; | ||
| 598 | |||
| 599 | buffer[readlen] = 0; | ||
| 600 | tokenise(buffer, buffer + readlen); | ||
| 601 | build_type_list(); | ||
| 602 | parse(); | ||
| 603 | |||
| 604 | out = fopen(outputname, "w"); | ||
| 605 | if (!out) { | ||
| 606 | perror(outputname); | ||
| 607 | exit(1); | ||
| 608 | } | ||
| 609 | |||
| 610 | hdr = fopen(headername, "w"); | ||
| 611 | if (!out) { | ||
| 612 | perror(headername); | ||
| 613 | exit(1); | ||
| 614 | } | ||
| 615 | |||
| 616 | render(out, hdr); | ||
| 617 | |||
| 618 | if (fclose(out) < 0) { | ||
| 619 | perror(outputname); | ||
| 620 | exit(1); | ||
| 621 | } | ||
| 622 | |||
| 623 | if (fclose(hdr) < 0) { | ||
| 624 | perror(headername); | ||
| 625 | exit(1); | ||
| 626 | } | ||
| 627 | |||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | enum compound { | ||
| 632 | NOT_COMPOUND, | ||
| 633 | SET, | ||
| 634 | SET_OF, | ||
| 635 | SEQUENCE, | ||
| 636 | SEQUENCE_OF, | ||
| 637 | CHOICE, | ||
| 638 | ANY, | ||
| 639 | TYPE_REF, | ||
| 640 | TAG_OVERRIDE | ||
| 641 | }; | ||
| 642 | |||
| 643 | struct element { | ||
| 644 | struct type *type_def; | ||
| 645 | struct token *name; | ||
| 646 | struct token *type; | ||
| 647 | struct action *action; | ||
| 648 | struct element *children; | ||
| 649 | struct element *next; | ||
| 650 | struct element *render_next; | ||
| 651 | struct element *list_next; | ||
| 652 | uint8_t n_elements; | ||
| 653 | enum compound compound : 8; | ||
| 654 | enum asn1_class class : 8; | ||
| 655 | enum asn1_method method : 8; | ||
| 656 | uint8_t tag; | ||
| 657 | unsigned entry_index; | ||
| 658 | unsigned flags; | ||
| 659 | #define ELEMENT_IMPLICIT 0x0001 | ||
| 660 | #define ELEMENT_EXPLICIT 0x0002 | ||
| 661 | #define ELEMENT_MARKED 0x0004 | ||
| 662 | #define ELEMENT_RENDERED 0x0008 | ||
| 663 | #define ELEMENT_SKIPPABLE 0x0010 | ||
| 664 | #define ELEMENT_CONDITIONAL 0x0020 | ||
| 665 | }; | ||
| 666 | |||
| 667 | struct type { | ||
| 668 | struct token *name; | ||
| 669 | struct token *def; | ||
| 670 | struct element *element; | ||
| 671 | unsigned ref_count; | ||
| 672 | unsigned flags; | ||
| 673 | #define TYPE_STOP_MARKER 0x0001 | ||
| 674 | #define TYPE_BEGIN 0x0002 | ||
| 675 | }; | ||
| 676 | |||
| 677 | static struct type *type_list; | ||
| 678 | static struct type **type_index; | ||
| 679 | static unsigned nr_types; | ||
| 680 | |||
| 681 | static int type_index_compare(const void *_a, const void *_b) | ||
| 682 | { | ||
| 683 | const struct type *const *a = _a, *const *b = _b; | ||
| 684 | |||
| 685 | if ((*a)->name->size != (*b)->name->size) | ||
| 686 | return (*a)->name->size - (*b)->name->size; | ||
| 687 | else | ||
| 688 | return memcmp((*a)->name->value, (*b)->name->value, | ||
| 689 | (*a)->name->size); | ||
| 690 | } | ||
| 691 | |||
| 692 | static int type_finder(const void *_key, const void *_ti) | ||
| 693 | { | ||
| 694 | const struct token *token = _key; | ||
| 695 | const struct type *const *ti = _ti; | ||
| 696 | const struct type *type = *ti; | ||
| 697 | |||
| 698 | if (token->size != type->name->size) | ||
| 699 | return token->size - type->name->size; | ||
| 700 | else | ||
| 701 | return memcmp(token->value, type->name->value, | ||
| 702 | token->size); | ||
| 703 | } | ||
| 704 | |||
| 705 | /* | ||
| 706 | * Build up a list of types and a sorted index to that list. | ||
| 707 | */ | ||
| 708 | static void build_type_list(void) | ||
| 709 | { | ||
| 710 | struct type *types; | ||
| 711 | unsigned nr, t, n; | ||
| 712 | |||
| 713 | nr = 0; | ||
| 714 | for (n = 0; n < nr_tokens - 1; n++) | ||
| 715 | if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && | ||
| 716 | token_list[n + 1].token_type == TOKEN_ASSIGNMENT) | ||
| 717 | nr++; | ||
| 718 | |||
| 719 | if (nr == 0) { | ||
| 720 | fprintf(stderr, "%s: No defined types\n", filename); | ||
| 721 | exit(1); | ||
| 722 | } | ||
| 723 | |||
| 724 | nr_types = nr; | ||
| 725 | types = type_list = calloc(nr + 1, sizeof(type_list[0])); | ||
| 726 | if (!type_list) { | ||
| 727 | perror(NULL); | ||
| 728 | exit(1); | ||
| 729 | } | ||
| 730 | type_index = calloc(nr, sizeof(type_index[0])); | ||
| 731 | if (!type_index) { | ||
| 732 | perror(NULL); | ||
| 733 | exit(1); | ||
| 734 | } | ||
| 735 | |||
| 736 | t = 0; | ||
| 737 | types[t].flags |= TYPE_BEGIN; | ||
| 738 | for (n = 0; n < nr_tokens - 1; n++) { | ||
| 739 | if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && | ||
| 740 | token_list[n + 1].token_type == TOKEN_ASSIGNMENT) { | ||
| 741 | types[t].name = &token_list[n]; | ||
| 742 | type_index[t] = &types[t]; | ||
| 743 | t++; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | types[t].name = &token_list[n + 1]; | ||
| 747 | types[t].flags |= TYPE_STOP_MARKER; | ||
| 748 | |||
| 749 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); | ||
| 750 | |||
| 751 | printf("Extracted %u types\n", nr_types); | ||
| 752 | #if 0 | ||
| 753 | for (n = 0; n < nr_types; n++) { | ||
| 754 | struct type *type = type_index[n]; | ||
| 755 | printf("- %*.*s\n", | ||
| 756 | (int)type->name->size, | ||
| 757 | (int)type->name->size, | ||
| 758 | type->name->value); | ||
| 759 | } | ||
| 760 | #endif | ||
| 761 | } | ||
| 762 | |||
| 763 | static struct element *parse_type(struct token **_cursor, struct token *stop, | ||
| 764 | struct token *name); | ||
| 765 | |||
| 766 | /* | ||
| 767 | * Parse the token stream | ||
| 768 | */ | ||
| 769 | static void parse(void) | ||
| 770 | { | ||
| 771 | struct token *cursor; | ||
| 772 | struct type *type; | ||
| 773 | |||
| 774 | /* Parse one type definition statement at a time */ | ||
| 775 | type = type_list; | ||
| 776 | do { | ||
| 777 | cursor = type->name; | ||
| 778 | |||
| 779 | if (cursor[0].token_type != TOKEN_TYPE_NAME || | ||
| 780 | cursor[1].token_type != TOKEN_ASSIGNMENT) | ||
| 781 | abort(); | ||
| 782 | cursor += 2; | ||
| 783 | |||
| 784 | type->element = parse_type(&cursor, type[1].name, NULL); | ||
| 785 | type->element->type_def = type; | ||
| 786 | |||
| 787 | if (cursor != type[1].name) { | ||
| 788 | fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", | ||
| 789 | filename, cursor->line, | ||
| 790 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 791 | exit(1); | ||
| 792 | } | ||
| 793 | |||
| 794 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); | ||
| 795 | |||
| 796 | printf("Extracted %u actions\n", nr_actions); | ||
| 797 | } | ||
| 798 | |||
| 799 | static struct element *element_list; | ||
| 800 | |||
| 801 | static struct element *alloc_elem(struct token *type) | ||
| 802 | { | ||
| 803 | struct element *e = calloc(1, sizeof(*e)); | ||
| 804 | if (!e) { | ||
| 805 | perror(NULL); | ||
| 806 | exit(1); | ||
| 807 | } | ||
| 808 | e->list_next = element_list; | ||
| 809 | element_list = e; | ||
| 810 | return e; | ||
| 811 | } | ||
| 812 | |||
| 813 | static struct element *parse_compound(struct token **_cursor, struct token *end, | ||
| 814 | int alternates); | ||
| 815 | |||
| 816 | /* | ||
| 817 | * Parse one type definition statement | ||
| 818 | */ | ||
| 819 | static struct element *parse_type(struct token **_cursor, struct token *end, | ||
| 820 | struct token *name) | ||
| 821 | { | ||
| 822 | struct element *top, *element; | ||
| 823 | struct action *action, **ppaction; | ||
| 824 | struct token *cursor = *_cursor; | ||
| 825 | struct type **ref; | ||
| 826 | char *p; | ||
| 827 | int labelled = 0, implicit = 0; | ||
| 828 | |||
| 829 | top = element = alloc_elem(cursor); | ||
| 830 | element->class = ASN1_UNIV; | ||
| 831 | element->method = ASN1_PRIM; | ||
| 832 | element->tag = token_to_tag[cursor->token_type]; | ||
| 833 | element->name = name; | ||
| 834 | |||
| 835 | /* Extract the tag value if one given */ | ||
| 836 | if (cursor->token_type == TOKEN_OPEN_SQUARE) { | ||
| 837 | cursor++; | ||
| 838 | if (cursor >= end) | ||
| 839 | goto overrun_error; | ||
| 840 | switch (cursor->token_type) { | ||
| 841 | case DIRECTIVE_UNIVERSAL: | ||
| 842 | element->class = ASN1_UNIV; | ||
| 843 | cursor++; | ||
| 844 | break; | ||
| 845 | case DIRECTIVE_APPLICATION: | ||
| 846 | element->class = ASN1_APPL; | ||
| 847 | cursor++; | ||
| 848 | break; | ||
| 849 | case TOKEN_NUMBER: | ||
| 850 | element->class = ASN1_CONT; | ||
| 851 | break; | ||
| 852 | case DIRECTIVE_PRIVATE: | ||
| 853 | element->class = ASN1_PRIV; | ||
| 854 | cursor++; | ||
| 855 | break; | ||
| 856 | default: | ||
| 857 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", | ||
| 858 | filename, cursor->line, | ||
| 859 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 860 | exit(1); | ||
| 861 | } | ||
| 862 | |||
| 863 | if (cursor >= end) | ||
| 864 | goto overrun_error; | ||
| 865 | if (cursor->token_type != TOKEN_NUMBER) { | ||
| 866 | fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", | ||
| 867 | filename, cursor->line, | ||
| 868 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 869 | exit(1); | ||
| 870 | } | ||
| 871 | |||
| 872 | element->tag &= ~0x1f; | ||
| 873 | element->tag |= strtoul(cursor->value, &p, 10); | ||
| 874 | if (p - cursor->value != cursor->size) | ||
| 875 | abort(); | ||
| 876 | cursor++; | ||
| 877 | |||
| 878 | if (cursor >= end) | ||
| 879 | goto overrun_error; | ||
| 880 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { | ||
| 881 | fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", | ||
| 882 | filename, cursor->line, | ||
| 883 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 884 | exit(1); | ||
| 885 | } | ||
| 886 | cursor++; | ||
| 887 | if (cursor >= end) | ||
| 888 | goto overrun_error; | ||
| 889 | labelled = 1; | ||
| 890 | } | ||
| 891 | |||
| 892 | /* Handle implicit and explicit markers */ | ||
| 893 | if (cursor->token_type == DIRECTIVE_IMPLICIT) { | ||
| 894 | element->flags |= ELEMENT_IMPLICIT; | ||
| 895 | implicit = 1; | ||
| 896 | cursor++; | ||
| 897 | if (cursor >= end) | ||
| 898 | goto overrun_error; | ||
| 899 | } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { | ||
| 900 | element->flags |= ELEMENT_EXPLICIT; | ||
| 901 | cursor++; | ||
| 902 | if (cursor >= end) | ||
| 903 | goto overrun_error; | ||
| 904 | } | ||
| 905 | |||
| 906 | if (labelled) { | ||
| 907 | if (!implicit) | ||
| 908 | element->method |= ASN1_CONS; | ||
| 909 | element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; | ||
| 910 | element->children = alloc_elem(cursor); | ||
| 911 | element = element->children; | ||
| 912 | element->class = ASN1_UNIV; | ||
| 913 | element->method = ASN1_PRIM; | ||
| 914 | element->tag = token_to_tag[cursor->token_type]; | ||
| 915 | element->name = name; | ||
| 916 | } | ||
| 917 | |||
| 918 | /* Extract the type we're expecting here */ | ||
| 919 | element->type = cursor; | ||
| 920 | switch (cursor->token_type) { | ||
| 921 | case DIRECTIVE_ANY: | ||
| 922 | element->compound = ANY; | ||
| 923 | cursor++; | ||
| 924 | break; | ||
| 925 | |||
| 926 | case DIRECTIVE_NULL: | ||
| 927 | case DIRECTIVE_BOOLEAN: | ||
| 928 | case DIRECTIVE_ENUMERATED: | ||
| 929 | case DIRECTIVE_INTEGER: | ||
| 930 | element->compound = NOT_COMPOUND; | ||
| 931 | cursor++; | ||
| 932 | break; | ||
| 933 | |||
| 934 | case DIRECTIVE_EXTERNAL: | ||
| 935 | element->method = ASN1_CONS; | ||
| 936 | |||
| 937 | case DIRECTIVE_BMPString: | ||
| 938 | case DIRECTIVE_GeneralString: | ||
| 939 | case DIRECTIVE_GraphicString: | ||
| 940 | case DIRECTIVE_IA5String: | ||
| 941 | case DIRECTIVE_ISO646String: | ||
| 942 | case DIRECTIVE_NumericString: | ||
| 943 | case DIRECTIVE_PrintableString: | ||
| 944 | case DIRECTIVE_T61String: | ||
| 945 | case DIRECTIVE_TeletexString: | ||
| 946 | case DIRECTIVE_UniversalString: | ||
| 947 | case DIRECTIVE_UTF8String: | ||
| 948 | case DIRECTIVE_VideotexString: | ||
| 949 | case DIRECTIVE_VisibleString: | ||
| 950 | case DIRECTIVE_ObjectDescriptor: | ||
| 951 | case DIRECTIVE_GeneralizedTime: | ||
| 952 | case DIRECTIVE_UTCTime: | ||
| 953 | element->compound = NOT_COMPOUND; | ||
| 954 | cursor++; | ||
| 955 | break; | ||
| 956 | |||
| 957 | case DIRECTIVE_BIT: | ||
| 958 | case DIRECTIVE_OCTET: | ||
| 959 | element->compound = NOT_COMPOUND; | ||
| 960 | cursor++; | ||
| 961 | if (cursor >= end) | ||
| 962 | goto overrun_error; | ||
| 963 | if (cursor->token_type != DIRECTIVE_STRING) | ||
| 964 | goto parse_error; | ||
| 965 | cursor++; | ||
| 966 | break; | ||
| 967 | |||
| 968 | case DIRECTIVE_OBJECT: | ||
| 969 | element->compound = NOT_COMPOUND; | ||
| 970 | cursor++; | ||
| 971 | if (cursor >= end) | ||
| 972 | goto overrun_error; | ||
| 973 | if (cursor->token_type != DIRECTIVE_IDENTIFIER) | ||
| 974 | goto parse_error; | ||
| 975 | cursor++; | ||
| 976 | break; | ||
| 977 | |||
| 978 | case TOKEN_TYPE_NAME: | ||
| 979 | element->compound = TYPE_REF; | ||
| 980 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), | ||
| 981 | type_finder); | ||
| 982 | if (!ref) { | ||
| 983 | fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", | ||
| 984 | filename, cursor->line, | ||
| 985 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 986 | exit(1); | ||
| 987 | } | ||
| 988 | cursor->type = *ref; | ||
| 989 | (*ref)->ref_count++; | ||
| 990 | cursor++; | ||
| 991 | break; | ||
| 992 | |||
| 993 | case DIRECTIVE_CHOICE: | ||
| 994 | element->compound = CHOICE; | ||
| 995 | cursor++; | ||
| 996 | element->children = parse_compound(&cursor, end, 1); | ||
| 997 | break; | ||
| 998 | |||
| 999 | case DIRECTIVE_SEQUENCE: | ||
| 1000 | element->compound = SEQUENCE; | ||
| 1001 | element->method = ASN1_CONS; | ||
| 1002 | cursor++; | ||
| 1003 | if (cursor >= end) | ||
| 1004 | goto overrun_error; | ||
| 1005 | if (cursor->token_type == DIRECTIVE_OF) { | ||
| 1006 | element->compound = SEQUENCE_OF; | ||
| 1007 | cursor++; | ||
| 1008 | if (cursor >= end) | ||
| 1009 | goto overrun_error; | ||
| 1010 | element->children = parse_type(&cursor, end, NULL); | ||
| 1011 | } else { | ||
| 1012 | element->children = parse_compound(&cursor, end, 0); | ||
| 1013 | } | ||
| 1014 | break; | ||
| 1015 | |||
| 1016 | case DIRECTIVE_SET: | ||
| 1017 | element->compound = SET; | ||
| 1018 | element->method = ASN1_CONS; | ||
| 1019 | cursor++; | ||
| 1020 | if (cursor >= end) | ||
| 1021 | goto overrun_error; | ||
| 1022 | if (cursor->token_type == DIRECTIVE_OF) { | ||
| 1023 | element->compound = SET_OF; | ||
| 1024 | cursor++; | ||
| 1025 | if (cursor >= end) | ||
| 1026 | goto parse_error; | ||
| 1027 | element->children = parse_type(&cursor, end, NULL); | ||
| 1028 | } else { | ||
| 1029 | element->children = parse_compound(&cursor, end, 1); | ||
| 1030 | } | ||
| 1031 | break; | ||
| 1032 | |||
| 1033 | default: | ||
| 1034 | fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", | ||
| 1035 | filename, cursor->line, | ||
| 1036 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1037 | exit(1); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | /* Handle elements that are optional */ | ||
| 1041 | if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || | ||
| 1042 | cursor->token_type == DIRECTIVE_DEFAULT) | ||
| 1043 | ) { | ||
| 1044 | cursor++; | ||
| 1045 | top->flags |= ELEMENT_SKIPPABLE; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { | ||
| 1049 | cursor++; | ||
| 1050 | if (cursor >= end) | ||
| 1051 | goto overrun_error; | ||
| 1052 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { | ||
| 1053 | fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", | ||
| 1054 | filename, cursor->line, | ||
| 1055 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1056 | exit(1); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | action = malloc(sizeof(struct action) + cursor->size + 1); | ||
| 1060 | if (!action) { | ||
| 1061 | perror(NULL); | ||
| 1062 | exit(1); | ||
| 1063 | } | ||
| 1064 | action->index = 0; | ||
| 1065 | memcpy(action->name, cursor->value, cursor->size); | ||
| 1066 | action->name[cursor->size] = 0; | ||
| 1067 | |||
| 1068 | for (ppaction = &action_list; | ||
| 1069 | *ppaction; | ||
| 1070 | ppaction = &(*ppaction)->next | ||
| 1071 | ) { | ||
| 1072 | int cmp = strcmp(action->name, (*ppaction)->name); | ||
| 1073 | if (cmp == 0) { | ||
| 1074 | free(action); | ||
| 1075 | action = *ppaction; | ||
| 1076 | goto found; | ||
| 1077 | } | ||
| 1078 | if (cmp < 0) { | ||
| 1079 | action->next = *ppaction; | ||
| 1080 | *ppaction = action; | ||
| 1081 | nr_actions++; | ||
| 1082 | goto found; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | action->next = NULL; | ||
| 1086 | *ppaction = action; | ||
| 1087 | nr_actions++; | ||
| 1088 | found: | ||
| 1089 | |||
| 1090 | element->action = action; | ||
| 1091 | cursor->action = action; | ||
| 1092 | cursor++; | ||
| 1093 | if (cursor >= end) | ||
| 1094 | goto overrun_error; | ||
| 1095 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { | ||
| 1096 | fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", | ||
| 1097 | filename, cursor->line, | ||
| 1098 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1099 | exit(1); | ||
| 1100 | } | ||
| 1101 | cursor++; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | *_cursor = cursor; | ||
| 1105 | return top; | ||
| 1106 | |||
| 1107 | parse_error: | ||
| 1108 | fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", | ||
| 1109 | filename, cursor->line, | ||
| 1110 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1111 | exit(1); | ||
| 1112 | |||
| 1113 | overrun_error: | ||
| 1114 | fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); | ||
| 1115 | exit(1); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | /* | ||
| 1119 | * Parse a compound type list | ||
| 1120 | */ | ||
| 1121 | static struct element *parse_compound(struct token **_cursor, struct token *end, | ||
| 1122 | int alternates) | ||
| 1123 | { | ||
| 1124 | struct element *children, **child_p = &children, *element; | ||
| 1125 | struct token *cursor = *_cursor, *name; | ||
| 1126 | |||
| 1127 | if (cursor->token_type != TOKEN_OPEN_CURLY) { | ||
| 1128 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", | ||
| 1129 | filename, cursor->line, | ||
| 1130 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1131 | exit(1); | ||
| 1132 | } | ||
| 1133 | cursor++; | ||
| 1134 | if (cursor >= end) | ||
| 1135 | goto overrun_error; | ||
| 1136 | |||
| 1137 | if (cursor->token_type == TOKEN_OPEN_CURLY) { | ||
| 1138 | fprintf(stderr, "%s:%d: Empty compound\n", | ||
| 1139 | filename, cursor->line); | ||
| 1140 | exit(1); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | for (;;) { | ||
| 1144 | name = NULL; | ||
| 1145 | if (cursor->token_type == TOKEN_ELEMENT_NAME) { | ||
| 1146 | name = cursor; | ||
| 1147 | cursor++; | ||
| 1148 | if (cursor >= end) | ||
| 1149 | goto overrun_error; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | element = parse_type(&cursor, end, name); | ||
| 1153 | if (alternates) | ||
| 1154 | element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; | ||
| 1155 | |||
| 1156 | *child_p = element; | ||
| 1157 | child_p = &element->next; | ||
| 1158 | |||
| 1159 | if (cursor >= end) | ||
| 1160 | goto overrun_error; | ||
| 1161 | if (cursor->token_type != TOKEN_COMMA) | ||
| 1162 | break; | ||
| 1163 | cursor++; | ||
| 1164 | if (cursor >= end) | ||
| 1165 | goto overrun_error; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | children->flags &= ~ELEMENT_CONDITIONAL; | ||
| 1169 | |||
| 1170 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { | ||
| 1171 | fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", | ||
| 1172 | filename, cursor->line, | ||
| 1173 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1174 | exit(1); | ||
| 1175 | } | ||
| 1176 | cursor++; | ||
| 1177 | |||
| 1178 | *_cursor = cursor; | ||
| 1179 | return children; | ||
| 1180 | |||
| 1181 | overrun_error: | ||
| 1182 | fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); | ||
| 1183 | exit(1); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | static void render_element(FILE *out, struct element *e, struct element *tag); | ||
| 1187 | static void render_out_of_line_list(FILE *out); | ||
| 1188 | |||
| 1189 | static int nr_entries; | ||
| 1190 | static int render_depth = 1; | ||
| 1191 | static struct element *render_list, **render_list_p = &render_list; | ||
| 1192 | |||
| 1193 | __attribute__((format(printf, 2, 3))) | ||
| 1194 | static void render_opcode(FILE *out, const char *fmt, ...) | ||
| 1195 | { | ||
| 1196 | va_list va; | ||
| 1197 | |||
| 1198 | if (out) { | ||
| 1199 | fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); | ||
| 1200 | va_start(va, fmt); | ||
| 1201 | vfprintf(out, fmt, va); | ||
| 1202 | va_end(va); | ||
| 1203 | } | ||
| 1204 | nr_entries++; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | __attribute__((format(printf, 2, 3))) | ||
| 1208 | static void render_more(FILE *out, const char *fmt, ...) | ||
| 1209 | { | ||
| 1210 | va_list va; | ||
| 1211 | |||
| 1212 | if (out) { | ||
| 1213 | va_start(va, fmt); | ||
| 1214 | vfprintf(out, fmt, va); | ||
| 1215 | va_end(va); | ||
| 1216 | } | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | /* | ||
| 1220 | * Render the grammar into a state machine definition. | ||
| 1221 | */ | ||
| 1222 | static void render(FILE *out, FILE *hdr) | ||
| 1223 | { | ||
| 1224 | struct element *e; | ||
| 1225 | struct action *action; | ||
| 1226 | struct type *root; | ||
| 1227 | int index; | ||
| 1228 | |||
| 1229 | fprintf(hdr, "/*\n"); | ||
| 1230 | fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n"); | ||
| 1231 | fprintf(hdr, " *\n"); | ||
| 1232 | fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name); | ||
| 1233 | fprintf(hdr, " */\n"); | ||
| 1234 | fprintf(hdr, "#include <linux/asn1_decoder.h>\n"); | ||
| 1235 | fprintf(hdr, "\n"); | ||
| 1236 | fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); | ||
| 1237 | if (ferror(hdr)) { | ||
| 1238 | perror(headername); | ||
| 1239 | exit(1); | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | fprintf(out, "/*\n"); | ||
| 1243 | fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n"); | ||
| 1244 | fprintf(out, " *\n"); | ||
| 1245 | fprintf(out, " * ASN.1 parser for %s\n", grammar_name); | ||
| 1246 | fprintf(out, " */\n"); | ||
| 1247 | fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n"); | ||
| 1248 | fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); | ||
| 1249 | fprintf(out, "\n"); | ||
| 1250 | if (ferror(out)) { | ||
| 1251 | perror(outputname); | ||
| 1252 | exit(1); | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /* Tabulate the action functions we might have to call */ | ||
| 1256 | fprintf(hdr, "\n"); | ||
| 1257 | index = 0; | ||
| 1258 | for (action = action_list; action; action = action->next) { | ||
| 1259 | action->index = index++; | ||
| 1260 | fprintf(hdr, | ||
| 1261 | "extern int %s(void *, size_t, unsigned char," | ||
| 1262 | " const void *, size_t);\n", | ||
| 1263 | action->name); | ||
| 1264 | } | ||
| 1265 | fprintf(hdr, "\n"); | ||
| 1266 | |||
| 1267 | fprintf(out, "enum %s_actions {\n", grammar_name); | ||
| 1268 | for (action = action_list; action; action = action->next) | ||
| 1269 | fprintf(out, "\tACT_%s = %u,\n", | ||
| 1270 | action->name, action->index); | ||
| 1271 | fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); | ||
| 1272 | fprintf(out, "};\n"); | ||
| 1273 | |||
| 1274 | fprintf(out, "\n"); | ||
| 1275 | fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", | ||
| 1276 | grammar_name, grammar_name); | ||
| 1277 | for (action = action_list; action; action = action->next) | ||
| 1278 | fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); | ||
| 1279 | fprintf(out, "};\n"); | ||
| 1280 | |||
| 1281 | if (ferror(out)) { | ||
| 1282 | perror(outputname); | ||
| 1283 | exit(1); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | /* We do two passes - the first one calculates all the offsets */ | ||
| 1287 | printf("Pass 1\n"); | ||
| 1288 | nr_entries = 0; | ||
| 1289 | root = &type_list[0]; | ||
| 1290 | render_element(NULL, root->element, NULL); | ||
| 1291 | render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); | ||
| 1292 | render_out_of_line_list(NULL); | ||
| 1293 | |||
| 1294 | for (e = element_list; e; e = e->list_next) | ||
| 1295 | e->flags &= ~ELEMENT_RENDERED; | ||
| 1296 | |||
| 1297 | /* And then we actually render */ | ||
| 1298 | printf("Pass 2\n"); | ||
| 1299 | fprintf(out, "\n"); | ||
| 1300 | fprintf(out, "static const unsigned char %s_machine[] = {\n", | ||
| 1301 | grammar_name); | ||
| 1302 | |||
| 1303 | nr_entries = 0; | ||
| 1304 | root = &type_list[0]; | ||
| 1305 | render_element(out, root->element, NULL); | ||
| 1306 | render_opcode(out, "ASN1_OP_COMPLETE,\n"); | ||
| 1307 | render_out_of_line_list(out); | ||
| 1308 | |||
| 1309 | fprintf(out, "};\n"); | ||
| 1310 | |||
| 1311 | fprintf(out, "\n"); | ||
| 1312 | fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); | ||
| 1313 | fprintf(out, "\t.machine = %s_machine,\n", grammar_name); | ||
| 1314 | fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); | ||
| 1315 | fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); | ||
| 1316 | fprintf(out, "};\n"); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /* | ||
| 1320 | * Render the out-of-line elements | ||
| 1321 | */ | ||
| 1322 | static void render_out_of_line_list(FILE *out) | ||
| 1323 | { | ||
| 1324 | struct element *e, *ce; | ||
| 1325 | const char *act; | ||
| 1326 | int entry; | ||
| 1327 | |||
| 1328 | while ((e = render_list)) { | ||
| 1329 | render_list = e->render_next; | ||
| 1330 | if (!render_list) | ||
| 1331 | render_list_p = &render_list; | ||
| 1332 | |||
| 1333 | render_more(out, "\n"); | ||
| 1334 | e->entry_index = entry = nr_entries; | ||
| 1335 | render_depth++; | ||
| 1336 | for (ce = e->children; ce; ce = ce->next) | ||
| 1337 | render_element(out, ce, NULL); | ||
| 1338 | render_depth--; | ||
| 1339 | |||
| 1340 | act = e->action ? "_ACT" : ""; | ||
| 1341 | switch (e->compound) { | ||
| 1342 | case SEQUENCE: | ||
| 1343 | render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); | ||
| 1344 | break; | ||
| 1345 | case SEQUENCE_OF: | ||
| 1346 | render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); | ||
| 1347 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
| 1348 | break; | ||
| 1349 | case SET: | ||
| 1350 | render_opcode(out, "ASN1_OP_END_SET%s,\n", act); | ||
| 1351 | break; | ||
| 1352 | case SET_OF: | ||
| 1353 | render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); | ||
| 1354 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
| 1355 | break; | ||
| 1356 | } | ||
| 1357 | if (e->action) | ||
| 1358 | render_opcode(out, "_action(ACT_%s),\n", | ||
| 1359 | e->action->name); | ||
| 1360 | render_opcode(out, "ASN1_OP_RETURN,\n"); | ||
| 1361 | } | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | /* | ||
| 1365 | * Render an element. | ||
| 1366 | */ | ||
| 1367 | static void render_element(FILE *out, struct element *e, struct element *tag) | ||
| 1368 | { | ||
| 1369 | struct element *ec; | ||
| 1370 | const char *cond, *act; | ||
| 1371 | int entry, skippable = 0, outofline = 0; | ||
| 1372 | |||
| 1373 | if (e->flags & ELEMENT_SKIPPABLE || | ||
| 1374 | (tag && tag->flags & ELEMENT_SKIPPABLE)) | ||
| 1375 | skippable = 1; | ||
| 1376 | |||
| 1377 | if ((e->type_def && e->type_def->ref_count > 1) || | ||
| 1378 | skippable) | ||
| 1379 | outofline = 1; | ||
| 1380 | |||
| 1381 | if (e->type_def && out) { | ||
| 1382 | render_more(out, "\t// %*.*s\n", | ||
| 1383 | (int)e->type_def->name->size, (int)e->type_def->name->size, | ||
| 1384 | e->type_def->name->value); | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | /* Render the operation */ | ||
| 1388 | cond = (e->flags & ELEMENT_CONDITIONAL || | ||
| 1389 | (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; | ||
| 1390 | act = e->action ? "_ACT" : ""; | ||
| 1391 | switch (e->compound) { | ||
| 1392 | case ANY: | ||
| 1393 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); | ||
| 1394 | if (e->name) | ||
| 1395 | render_more(out, "\t\t// %*.*s", | ||
| 1396 | (int)e->name->size, (int)e->name->size, | ||
| 1397 | e->name->value); | ||
| 1398 | render_more(out, "\n"); | ||
| 1399 | goto dont_render_tag; | ||
| 1400 | |||
| 1401 | case TAG_OVERRIDE: | ||
| 1402 | render_element(out, e->children, e); | ||
| 1403 | return; | ||
| 1404 | |||
| 1405 | case SEQUENCE: | ||
| 1406 | case SEQUENCE_OF: | ||
| 1407 | case SET: | ||
| 1408 | case SET_OF: | ||
| 1409 | render_opcode(out, "ASN1_OP_%sMATCH%s%s,", | ||
| 1410 | cond, | ||
| 1411 | outofline ? "_JUMP" : "", | ||
| 1412 | skippable ? "_OR_SKIP" : ""); | ||
| 1413 | break; | ||
| 1414 | |||
| 1415 | case CHOICE: | ||
| 1416 | goto dont_render_tag; | ||
| 1417 | |||
| 1418 | case TYPE_REF: | ||
| 1419 | if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) | ||
| 1420 | goto dont_render_tag; | ||
| 1421 | default: | ||
| 1422 | render_opcode(out, "ASN1_OP_%sMATCH%s%s,", | ||
| 1423 | cond, act, | ||
| 1424 | skippable ? "_OR_SKIP" : ""); | ||
| 1425 | break; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | if (e->name) | ||
| 1429 | render_more(out, "\t\t// %*.*s", | ||
| 1430 | (int)e->name->size, (int)e->name->size, | ||
| 1431 | e->name->value); | ||
| 1432 | render_more(out, "\n"); | ||
| 1433 | |||
| 1434 | /* Render the tag */ | ||
| 1435 | if (!tag) | ||
| 1436 | tag = e; | ||
| 1437 | if (tag->class == ASN1_UNIV && | ||
| 1438 | tag->tag != 14 && | ||
| 1439 | tag->tag != 15 && | ||
| 1440 | tag->tag != 31) | ||
| 1441 | render_opcode(out, "_tag(%s, %s, %s),\n", | ||
| 1442 | asn1_classes[tag->class], | ||
| 1443 | asn1_methods[tag->method | e->method], | ||
| 1444 | asn1_universal_tags[tag->tag]); | ||
| 1445 | else | ||
| 1446 | render_opcode(out, "_tagn(%s, %s, %2u),\n", | ||
| 1447 | asn1_classes[tag->class], | ||
| 1448 | asn1_methods[tag->method | e->method], | ||
| 1449 | tag->tag); | ||
| 1450 | tag = NULL; | ||
| 1451 | dont_render_tag: | ||
| 1452 | |||
| 1453 | /* Deal with compound types */ | ||
| 1454 | switch (e->compound) { | ||
| 1455 | case TYPE_REF: | ||
| 1456 | render_element(out, e->type->type->element, tag); | ||
| 1457 | if (e->action) | ||
| 1458 | render_opcode(out, "ASN1_OP_ACT,\n"); | ||
| 1459 | break; | ||
| 1460 | |||
| 1461 | case SEQUENCE: | ||
| 1462 | if (outofline) { | ||
| 1463 | /* Render out-of-line for multiple use or | ||
| 1464 | * skipability */ | ||
| 1465 | render_opcode(out, "_jump_target(%u),", e->entry_index); | ||
| 1466 | if (e->type_def && e->type_def->name) | ||
| 1467 | render_more(out, "\t\t// --> %*.*s", | ||
| 1468 | (int)e->type_def->name->size, | ||
| 1469 | (int)e->type_def->name->size, | ||
| 1470 | e->type_def->name->value); | ||
| 1471 | render_more(out, "\n"); | ||
| 1472 | if (!(e->flags & ELEMENT_RENDERED)) { | ||
| 1473 | e->flags |= ELEMENT_RENDERED; | ||
| 1474 | *render_list_p = e; | ||
| 1475 | render_list_p = &e->render_next; | ||
| 1476 | } | ||
| 1477 | return; | ||
| 1478 | } else { | ||
| 1479 | /* Render inline for single use */ | ||
| 1480 | render_depth++; | ||
| 1481 | for (ec = e->children; ec; ec = ec->next) | ||
| 1482 | render_element(out, ec, NULL); | ||
| 1483 | render_depth--; | ||
| 1484 | render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); | ||
| 1485 | } | ||
| 1486 | break; | ||
| 1487 | |||
| 1488 | case SEQUENCE_OF: | ||
| 1489 | case SET_OF: | ||
| 1490 | if (outofline) { | ||
| 1491 | /* Render out-of-line for multiple use or | ||
| 1492 | * skipability */ | ||
| 1493 | render_opcode(out, "_jump_target(%u),", e->entry_index); | ||
| 1494 | if (e->type_def && e->type_def->name) | ||
| 1495 | render_more(out, "\t\t// --> %*.*s", | ||
| 1496 | (int)e->type_def->name->size, | ||
| 1497 | (int)e->type_def->name->size, | ||
| 1498 | e->type_def->name->value); | ||
| 1499 | render_more(out, "\n"); | ||
| 1500 | if (!(e->flags & ELEMENT_RENDERED)) { | ||
| 1501 | e->flags |= ELEMENT_RENDERED; | ||
| 1502 | *render_list_p = e; | ||
| 1503 | render_list_p = &e->render_next; | ||
| 1504 | } | ||
| 1505 | return; | ||
| 1506 | } else { | ||
| 1507 | /* Render inline for single use */ | ||
| 1508 | entry = nr_entries; | ||
| 1509 | render_depth++; | ||
| 1510 | render_element(out, e->children, NULL); | ||
| 1511 | render_depth--; | ||
| 1512 | if (e->compound == SEQUENCE_OF) | ||
| 1513 | render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); | ||
| 1514 | else | ||
| 1515 | render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); | ||
| 1516 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
| 1517 | } | ||
| 1518 | break; | ||
| 1519 | |||
| 1520 | case SET: | ||
| 1521 | /* I can't think of a nice way to do SET support without having | ||
| 1522 | * a stack of bitmasks to make sure no element is repeated. | ||
| 1523 | * The bitmask has also to be checked that no non-optional | ||
| 1524 | * elements are left out whilst not preventing optional | ||
| 1525 | * elements from being left out. | ||
| 1526 | */ | ||
| 1527 | fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); | ||
| 1528 | exit(1); | ||
| 1529 | |||
| 1530 | case CHOICE: | ||
| 1531 | for (ec = e->children; ec; ec = ec->next) | ||
| 1532 | render_element(out, ec, NULL); | ||
| 1533 | if (!skippable) | ||
| 1534 | render_opcode(out, "ASN1_OP_COND_FAIL,\n"); | ||
| 1535 | if (e->action) | ||
| 1536 | render_opcode(out, "ASN1_OP_ACT,\n"); | ||
| 1537 | break; | ||
| 1538 | |||
| 1539 | default: | ||
| 1540 | break; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | if (e->action) | ||
| 1544 | render_opcode(out, "_action(ACT_%s),\n", e->action->name); | ||
| 1545 | } | ||
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ca05ba217f5f..21a9f5de0a21 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl | |||
| @@ -421,7 +421,7 @@ sub top_of_kernel_tree { | |||
| 421 | } | 421 | } |
| 422 | } | 422 | } |
| 423 | return 1; | 423 | return 1; |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | sub parse_email { | 426 | sub parse_email { |
| 427 | my ($formatted_email) = @_; | 427 | my ($formatted_email) = @_; |
| @@ -1386,6 +1386,8 @@ sub process { | |||
| 1386 | my $in_header_lines = 1; | 1386 | my $in_header_lines = 1; |
| 1387 | my $in_commit_log = 0; #Scanning lines before patch | 1387 | my $in_commit_log = 0; #Scanning lines before patch |
| 1388 | 1388 | ||
| 1389 | my $non_utf8_charset = 0; | ||
| 1390 | |||
| 1389 | our @report = (); | 1391 | our @report = (); |
| 1390 | our $cnt_lines = 0; | 1392 | our $cnt_lines = 0; |
| 1391 | our $cnt_error = 0; | 1393 | our $cnt_error = 0; |
| @@ -1686,10 +1688,17 @@ sub process { | |||
| 1686 | $in_commit_log = 1; | 1688 | $in_commit_log = 1; |
| 1687 | } | 1689 | } |
| 1688 | 1690 | ||
| 1689 | # Still not yet in a patch, check for any UTF-8 | 1691 | # Check if there is UTF-8 in a commit log when a mail header has explicitly |
| 1690 | if ($in_commit_log && $realfile =~ /^$/ && | 1692 | # declined it, i.e defined some charset where it is missing. |
| 1693 | if ($in_header_lines && | ||
| 1694 | $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && | ||
| 1695 | $1 !~ /utf-8/i) { | ||
| 1696 | $non_utf8_charset = 1; | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && | ||
| 1691 | $rawline =~ /$NON_ASCII_UTF8/) { | 1700 | $rawline =~ /$NON_ASCII_UTF8/) { |
| 1692 | CHK("UTF8_BEFORE_PATCH", | 1701 | WARN("UTF8_BEFORE_PATCH", |
| 1693 | "8-bit UTF-8 used in possible commit log\n" . $herecurr); | 1702 | "8-bit UTF-8 used in possible commit log\n" . $herecurr); |
| 1694 | } | 1703 | } |
| 1695 | 1704 | ||
| @@ -1873,6 +1882,20 @@ sub process { | |||
| 1873 | "No space is necessary after a cast\n" . $hereprev); | 1882 | "No space is necessary after a cast\n" . $hereprev); |
| 1874 | } | 1883 | } |
| 1875 | 1884 | ||
| 1885 | if ($realfile =~ m@^(drivers/net/|net/)@ && | ||
| 1886 | $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ && | ||
| 1887 | $prevrawline =~ /^\+[ \t]*$/) { | ||
| 1888 | WARN("NETWORKING_BLOCK_COMMENT_STYLE", | ||
| 1889 | "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); | ||
| 1890 | } | ||
| 1891 | |||
| 1892 | if ($realfile =~ m@^(drivers/net/|net/)@ && | ||
| 1893 | $rawline !~ m@^\+[ \t]*(\/\*|\*\/)@ && | ||
| 1894 | $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { | ||
| 1895 | WARN("NETWORKING_BLOCK_COMMENT_STYLE", | ||
| 1896 | "networking block comments put the trailing */ on a separate line\n" . $herecurr); | ||
| 1897 | } | ||
| 1898 | |||
| 1876 | # check for spaces at the beginning of a line. | 1899 | # check for spaces at the beginning of a line. |
| 1877 | # Exceptions: | 1900 | # Exceptions: |
| 1878 | # 1) within comments | 1901 | # 1) within comments |
| @@ -2390,8 +2413,10 @@ sub process { | |||
| 2390 | my $orig = $1; | 2413 | my $orig = $1; |
| 2391 | my $level = lc($orig); | 2414 | my $level = lc($orig); |
| 2392 | $level = "warn" if ($level eq "warning"); | 2415 | $level = "warn" if ($level eq "warning"); |
| 2416 | my $level2 = $level; | ||
| 2417 | $level2 = "dbg" if ($level eq "debug"); | ||
| 2393 | WARN("PREFER_PR_LEVEL", | 2418 | WARN("PREFER_PR_LEVEL", |
| 2394 | "Prefer pr_$level(... to printk(KERN_$1, ...\n" . $herecurr); | 2419 | "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); |
| 2395 | } | 2420 | } |
| 2396 | 2421 | ||
| 2397 | if ($line =~ /\bpr_warning\s*\(/) { | 2422 | if ($line =~ /\bpr_warning\s*\(/) { |
| @@ -2947,7 +2972,7 @@ sub process { | |||
| 2947 | my $exceptions = qr{ | 2972 | my $exceptions = qr{ |
| 2948 | $Declare| | 2973 | $Declare| |
| 2949 | module_param_named| | 2974 | module_param_named| |
| 2950 | MODULE_PARAM_DESC| | 2975 | MODULE_PARM_DESC| |
| 2951 | DECLARE_PER_CPU| | 2976 | DECLARE_PER_CPU| |
| 2952 | DEFINE_PER_CPU| | 2977 | DEFINE_PER_CPU| |
| 2953 | __typeof__\(| | 2978 | __typeof__\(| |
diff --git a/scripts/coccicheck b/scripts/coccicheck index 823e972149e5..1a49d1c7ecfe 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck | |||
| @@ -95,6 +95,9 @@ coccinelle () { | |||
| 95 | $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \ | 95 | $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \ |
| 96 | $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ | 96 | $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ |
| 97 | $SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1 | 97 | $SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1 |
| 98 | elif [ "$MODE" = "rep+ctxt" ] ; then | ||
| 99 | $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff && \ | ||
| 100 | $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 | ||
| 98 | else | 101 | else |
| 99 | $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 | 102 | $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 |
| 100 | fi | 103 | fi |
diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci index cbfd08c7d8c7..15f076fdecbe 100644 --- a/scripts/coccinelle/api/ptr_ret.cocci +++ b/scripts/coccinelle/api/ptr_ret.cocci | |||
| @@ -30,6 +30,13 @@ expression ptr; | |||
| 30 | - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; | 30 | - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; |
| 31 | + return PTR_RET(ptr); | 31 | + return PTR_RET(ptr); |
| 32 | 32 | ||
| 33 | @depends on patch@ | ||
| 34 | expression ptr; | ||
| 35 | @@ | ||
| 36 | |||
| 37 | - (IS_ERR(ptr) ? PTR_ERR(ptr) : 0) | ||
| 38 | + PTR_RET(ptr) | ||
| 39 | |||
| 33 | @r1 depends on !patch@ | 40 | @r1 depends on !patch@ |
| 34 | expression ptr; | 41 | expression ptr; |
| 35 | position p1; | 42 | position p1; |
| @@ -44,6 +51,13 @@ position p2; | |||
| 44 | 51 | ||
| 45 | * if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; | 52 | * if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; |
| 46 | 53 | ||
| 54 | @r3 depends on !patch@ | ||
| 55 | expression ptr; | ||
| 56 | position p3; | ||
| 57 | @@ | ||
| 58 | |||
| 59 | * IS_ERR@p3(ptr) ? PTR_ERR(ptr) : 0 | ||
| 60 | |||
| 47 | @script:python depends on org@ | 61 | @script:python depends on org@ |
| 48 | p << r1.p1; | 62 | p << r1.p1; |
| 49 | @@ | 63 | @@ |
| @@ -57,6 +71,12 @@ p << r2.p2; | |||
| 57 | 71 | ||
| 58 | coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") | 72 | coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") |
| 59 | 73 | ||
| 74 | @script:python depends on org@ | ||
| 75 | p << r3.p3; | ||
| 76 | @@ | ||
| 77 | |||
| 78 | coccilib.org.print_todo(p[0], "WARNING: PTR_RET can be used") | ||
| 79 | |||
| 60 | @script:python depends on report@ | 80 | @script:python depends on report@ |
| 61 | p << r1.p1; | 81 | p << r1.p1; |
| 62 | @@ | 82 | @@ |
| @@ -68,3 +88,9 @@ p << r2.p2; | |||
| 68 | @@ | 88 | @@ |
| 69 | 89 | ||
| 70 | coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") | 90 | coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") |
| 91 | |||
| 92 | @script:python depends on report@ | ||
| 93 | p << r3.p3; | ||
| 94 | @@ | ||
| 95 | |||
| 96 | coccilib.report.print_report(p[0], "WARNING: PTR_RET can be used") | ||
diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci new file mode 100644 index 000000000000..e8dd8a6b28a2 --- /dev/null +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /// PTR_ERR should access the value just tested by IS_ERR | ||
| 2 | //# There can be false positives in the patch case, where it is the call | ||
| 3 | //# IS_ERR that is wrong. | ||
| 4 | /// | ||
| 5 | // Confidence: High | ||
| 6 | // Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2. | ||
| 7 | // Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2. | ||
| 8 | // URL: http://coccinelle.lip6.fr/ | ||
| 9 | // Comments: | ||
| 10 | // Options: -no_includes -include_headers | ||
| 11 | |||
| 12 | virtual patch | ||
| 13 | virtual context | ||
| 14 | virtual org | ||
| 15 | virtual report | ||
| 16 | |||
| 17 | @depends on patch@ | ||
| 18 | expression e,e1; | ||
| 19 | @@ | ||
| 20 | |||
| 21 | ( | ||
| 22 | if (IS_ERR(e)) { ... PTR_ERR(e) ... } | ||
| 23 | | | ||
| 24 | if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } | ||
| 25 | | | ||
| 26 | if (IS_ERR(e)) | ||
| 27 | { ... | ||
| 28 | PTR_ERR( | ||
| 29 | - e1 | ||
| 30 | + e | ||
| 31 | ) | ||
| 32 | ... } | ||
| 33 | ) | ||
| 34 | |||
| 35 | @r depends on !patch@ | ||
| 36 | expression e,e1; | ||
| 37 | position p1,p2; | ||
| 38 | @@ | ||
| 39 | |||
| 40 | ( | ||
| 41 | if (IS_ERR(e)) { ... PTR_ERR(e) ... } | ||
| 42 | | | ||
| 43 | if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } | ||
| 44 | | | ||
| 45 | *if (IS_ERR@p1(e)) | ||
| 46 | { ... | ||
| 47 | * PTR_ERR@p2(e1) | ||
| 48 | ... } | ||
| 49 | ) | ||
| 50 | |||
| 51 | @script:python depends on org@ | ||
| 52 | p1 << r.p1; | ||
| 53 | p2 << r.p2; | ||
| 54 | @@ | ||
| 55 | |||
| 56 | cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1) | ||
| 57 | cocci.print_secs("PTR_ERR",p2) | ||
| 58 | |||
| 59 | @script:python depends on report@ | ||
| 60 | p1 << r.p1; | ||
| 61 | p2 << r.p2; | ||
| 62 | @@ | ||
| 63 | |||
| 64 | msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line) | ||
| 65 | coccilib.report.print_report(p1[0],msg) | ||
diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index debecb5561c4..7f2126df91f2 100644 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh | |||
| @@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then | |||
| 22 | exit 1 | 22 | exit 1 |
| 23 | fi | 23 | fi |
| 24 | 24 | ||
| 25 | MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) | 25 | MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) |
| 26 | MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) | 26 | MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) |
| 27 | if [ "x$with_patchlevel" != "x" ] ; then | 27 | if [ "x$with_patchlevel" != "x" ] ; then |
| 28 | PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) | 28 | PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) |
| 29 | printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL | 29 | printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL |
| 30 | else | 30 | else |
| 31 | printf "%02d%02d\\n" $MAJOR $MINOR | 31 | printf "%02d%02d\\n" $MAJOR $MINOR |
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh index 29493dc4528d..12dbd0b11ea4 100644 --- a/scripts/gcc-x86_32-has-stack-protector.sh +++ b/scripts/gcc-x86_32-has-stack-protector.sh | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | 2 | ||
| 3 | echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" | 3 | echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" |
| 4 | if [ "$?" -eq "0" ] ; then | 4 | if [ "$?" -eq "0" ] ; then |
| 5 | echo y | 5 | echo y |
| 6 | else | 6 | else |
diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh index afaec618b395..973e8c141567 100644 --- a/scripts/gcc-x86_64-has-stack-protector.sh +++ b/scripts/gcc-x86_64-has-stack-protector.sh | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | 2 | ||
| 3 | echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" | 3 | echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" |
| 4 | if [ "$?" -eq "0" ] ; then | 4 | if [ "$?" -eq "0" ] ; then |
| 5 | echo y | 5 | echo y |
| 6 | else | 6 | else |
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 77d53999ffb9..3091794e9354 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile | |||
| @@ -76,11 +76,17 @@ PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig | |||
| 76 | allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf | 76 | allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf |
| 77 | $< --$@ $(Kconfig) | 77 | $< --$@ $(Kconfig) |
| 78 | 78 | ||
| 79 | PHONY += listnewconfig oldnoconfig savedefconfig defconfig | 79 | PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig |
| 80 | 80 | ||
| 81 | listnewconfig oldnoconfig: $(obj)/conf | 81 | listnewconfig olddefconfig: $(obj)/conf |
| 82 | $< --$@ $(Kconfig) | 82 | $< --$@ $(Kconfig) |
| 83 | 83 | ||
| 84 | # oldnoconfig is an alias of olddefconfig, because people already are dependent | ||
| 85 | # on its behavior(sets new symbols to their default value but not 'n') with the | ||
| 86 | # counter-intuitive name. | ||
| 87 | oldnoconfig: $(obj)/conf | ||
| 88 | $< --olddefconfig $(Kconfig) | ||
| 89 | |||
| 84 | savedefconfig: $(obj)/conf | 90 | savedefconfig: $(obj)/conf |
| 85 | $< --$@=defconfig $(Kconfig) | 91 | $< --$@=defconfig $(Kconfig) |
| 86 | 92 | ||
| @@ -114,7 +120,7 @@ help: | |||
| 114 | @echo ' alldefconfig - New config with all symbols set to default' | 120 | @echo ' alldefconfig - New config with all symbols set to default' |
| 115 | @echo ' randconfig - New config with random answer to all options' | 121 | @echo ' randconfig - New config with random answer to all options' |
| 116 | @echo ' listnewconfig - List new options' | 122 | @echo ' listnewconfig - List new options' |
| 117 | @echo ' oldnoconfig - Same as silentoldconfig but sets new symbols to their default value' | 123 | @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' |
| 118 | 124 | ||
| 119 | # lxdialog stuff | 125 | # lxdialog stuff |
| 120 | check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh | 126 | check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh |
diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh index fa59cbf9d62c..854d9c7c675c 100755 --- a/scripts/kconfig/check.sh +++ b/scripts/kconfig/check.sh | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | # Needed for systems without gettext | 2 | # Needed for systems without gettext |
| 3 | $* -xc -o /dev/null - > /dev/null 2>&1 << EOF | 3 | $* -x c -o /dev/null - > /dev/null 2>&1 << EOF |
| 4 | #include <libintl.h> | 4 | #include <libintl.h> |
| 5 | int main() | 5 | int main() |
| 6 | { | 6 | { |
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 0dc4a2c779b1..4da3b4adfad2 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c | |||
| @@ -32,7 +32,7 @@ enum input_mode { | |||
| 32 | defconfig, | 32 | defconfig, |
| 33 | savedefconfig, | 33 | savedefconfig, |
| 34 | listnewconfig, | 34 | listnewconfig, |
| 35 | oldnoconfig, | 35 | olddefconfig, |
| 36 | } input_mode = oldaskconfig; | 36 | } input_mode = oldaskconfig; |
| 37 | 37 | ||
| 38 | static int indent = 1; | 38 | static int indent = 1; |
| @@ -365,7 +365,7 @@ static void conf(struct menu *menu) | |||
| 365 | case P_MENU: | 365 | case P_MENU: |
| 366 | if ((input_mode == silentoldconfig || | 366 | if ((input_mode == silentoldconfig || |
| 367 | input_mode == listnewconfig || | 367 | input_mode == listnewconfig || |
| 368 | input_mode == oldnoconfig) && | 368 | input_mode == olddefconfig) && |
| 369 | rootEntry != menu) { | 369 | rootEntry != menu) { |
| 370 | check_conf(menu); | 370 | check_conf(menu); |
| 371 | return; | 371 | return; |
| @@ -429,7 +429,7 @@ static void check_conf(struct menu *menu) | |||
| 429 | if (sym->name && !sym_is_choice_value(sym)) { | 429 | if (sym->name && !sym_is_choice_value(sym)) { |
| 430 | printf("%s%s\n", CONFIG_, sym->name); | 430 | printf("%s%s\n", CONFIG_, sym->name); |
| 431 | } | 431 | } |
| 432 | } else if (input_mode != oldnoconfig) { | 432 | } else if (input_mode != olddefconfig) { |
| 433 | if (!conf_cnt++) | 433 | if (!conf_cnt++) |
| 434 | printf(_("*\n* Restart config...\n*\n")); | 434 | printf(_("*\n* Restart config...\n*\n")); |
| 435 | rootEntry = menu_get_parent_menu(menu); | 435 | rootEntry = menu_get_parent_menu(menu); |
| @@ -454,7 +454,13 @@ static struct option long_opts[] = { | |||
| 454 | {"alldefconfig", no_argument, NULL, alldefconfig}, | 454 | {"alldefconfig", no_argument, NULL, alldefconfig}, |
| 455 | {"randconfig", no_argument, NULL, randconfig}, | 455 | {"randconfig", no_argument, NULL, randconfig}, |
| 456 | {"listnewconfig", no_argument, NULL, listnewconfig}, | 456 | {"listnewconfig", no_argument, NULL, listnewconfig}, |
| 457 | {"oldnoconfig", no_argument, NULL, oldnoconfig}, | 457 | {"olddefconfig", no_argument, NULL, olddefconfig}, |
| 458 | /* | ||
| 459 | * oldnoconfig is an alias of olddefconfig, because people already | ||
| 460 | * are dependent on its behavior(sets new symbols to their default | ||
| 461 | * value but not 'n') with the counter-intuitive name. | ||
| 462 | */ | ||
| 463 | {"oldnoconfig", no_argument, NULL, olddefconfig}, | ||
| 458 | {NULL, 0, NULL, 0} | 464 | {NULL, 0, NULL, 0} |
| 459 | }; | 465 | }; |
| 460 | 466 | ||
| @@ -467,7 +473,8 @@ static void conf_usage(const char *progname) | |||
| 467 | printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); | 473 | printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); |
| 468 | printf(" --oldconfig Update a configuration using a provided .config as base\n"); | 474 | printf(" --oldconfig Update a configuration using a provided .config as base\n"); |
| 469 | printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); | 475 | printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); |
| 470 | printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n"); | 476 | printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); |
| 477 | printf(" --oldnoconfig An alias of olddefconfig\n"); | ||
| 471 | printf(" --defconfig <file> New config with default defined in <file>\n"); | 478 | printf(" --defconfig <file> New config with default defined in <file>\n"); |
| 472 | printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); | 479 | printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); |
| 473 | printf(" --allnoconfig New config where all options are answered with no\n"); | 480 | printf(" --allnoconfig New config where all options are answered with no\n"); |
| @@ -520,7 +527,7 @@ int main(int ac, char **av) | |||
| 520 | case allmodconfig: | 527 | case allmodconfig: |
| 521 | case alldefconfig: | 528 | case alldefconfig: |
| 522 | case listnewconfig: | 529 | case listnewconfig: |
| 523 | case oldnoconfig: | 530 | case olddefconfig: |
| 524 | break; | 531 | break; |
| 525 | case '?': | 532 | case '?': |
| 526 | conf_usage(progname); | 533 | conf_usage(progname); |
| @@ -565,7 +572,7 @@ int main(int ac, char **av) | |||
| 565 | case oldaskconfig: | 572 | case oldaskconfig: |
| 566 | case oldconfig: | 573 | case oldconfig: |
| 567 | case listnewconfig: | 574 | case listnewconfig: |
| 568 | case oldnoconfig: | 575 | case olddefconfig: |
| 569 | conf_read(NULL); | 576 | conf_read(NULL); |
| 570 | break; | 577 | break; |
| 571 | case allnoconfig: | 578 | case allnoconfig: |
| @@ -645,7 +652,7 @@ int main(int ac, char **av) | |||
| 645 | /* fall through */ | 652 | /* fall through */ |
| 646 | case oldconfig: | 653 | case oldconfig: |
| 647 | case listnewconfig: | 654 | case listnewconfig: |
| 648 | case oldnoconfig: | 655 | case olddefconfig: |
| 649 | case silentoldconfig: | 656 | case silentoldconfig: |
| 650 | /* Update until a loop caused no more changes */ | 657 | /* Update until a loop caused no more changes */ |
| 651 | do { | 658 | do { |
| @@ -653,7 +660,7 @@ int main(int ac, char **av) | |||
| 653 | check_conf(&rootmenu); | 660 | check_conf(&rootmenu); |
| 654 | } while (conf_cnt && | 661 | } while (conf_cnt && |
| 655 | (input_mode != listnewconfig && | 662 | (input_mode != listnewconfig && |
| 656 | input_mode != oldnoconfig)); | 663 | input_mode != olddefconfig)); |
| 657 | break; | 664 | break; |
| 658 | } | 665 | } |
| 659 | 666 | ||
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index d4ecce8bc3a6..bd2e09895553 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h | |||
| @@ -12,6 +12,7 @@ extern "C" { | |||
| 12 | 12 | ||
| 13 | #include <assert.h> | 13 | #include <assert.h> |
| 14 | #include <stdio.h> | 14 | #include <stdio.h> |
| 15 | #include <sys/queue.h> | ||
| 15 | #ifndef __cplusplus | 16 | #ifndef __cplusplus |
| 16 | #include <stdbool.h> | 17 | #include <stdbool.h> |
| 17 | #endif | 18 | #endif |
| @@ -173,6 +174,16 @@ struct menu { | |||
| 173 | #define MENU_CHANGED 0x0001 | 174 | #define MENU_CHANGED 0x0001 |
| 174 | #define MENU_ROOT 0x0002 | 175 | #define MENU_ROOT 0x0002 |
| 175 | 176 | ||
| 177 | struct jump_key { | ||
| 178 | CIRCLEQ_ENTRY(jump_key) entries; | ||
| 179 | size_t offset; | ||
| 180 | struct menu *target; | ||
| 181 | int index; | ||
| 182 | }; | ||
| 183 | CIRCLEQ_HEAD(jk_head, jump_key); | ||
| 184 | |||
| 185 | #define JUMP_NB 9 | ||
| 186 | |||
| 176 | extern struct file *file_list; | 187 | extern struct file *file_list; |
| 177 | extern struct file *current_file; | 188 | extern struct file *current_file; |
| 178 | struct file *lookup_file(const char *name); | 189 | struct file *lookup_file(const char *name); |
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 47fe9c340f9a..1d1c08537f1e 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h | |||
| @@ -21,8 +21,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); | |||
| 21 | P(menu_get_parent_menu,struct menu *,(struct menu *menu)); | 21 | P(menu_get_parent_menu,struct menu *,(struct menu *menu)); |
| 22 | P(menu_has_help,bool,(struct menu *menu)); | 22 | P(menu_has_help,bool,(struct menu *menu)); |
| 23 | P(menu_get_help,const char *,(struct menu *menu)); | 23 | P(menu_get_help,const char *,(struct menu *menu)); |
| 24 | P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); | 24 | P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head |
| 25 | P(get_relations_str, struct gstr, (struct symbol **sym_arr)); | 25 | *head)); |
| 26 | P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head | ||
| 27 | *head)); | ||
| 26 | P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); | 28 | P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); |
| 27 | 29 | ||
| 28 | /* symbol.c */ | 30 | /* symbol.c */ |
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index e3b12c010417..c8e8a7154753 100644 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh | |||
| @@ -38,7 +38,7 @@ trap "rm -f $tmp" 0 1 2 3 15 | |||
| 38 | 38 | ||
| 39 | # Check if we can link to ncurses | 39 | # Check if we can link to ncurses |
| 40 | check() { | 40 | check() { |
| 41 | $cc -xc - -o $tmp 2>/dev/null <<'EOF' | 41 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' |
| 42 | #include CURSES_LOC | 42 | #include CURSES_LOC |
| 43 | main() {} | 43 | main() {} |
| 44 | EOF | 44 | EOF |
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index b5211fce0d94..ee17a5264d5b 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h | |||
| @@ -144,6 +144,7 @@ struct dialog_info { | |||
| 144 | */ | 144 | */ |
| 145 | extern struct dialog_info dlg; | 145 | extern struct dialog_info dlg; |
| 146 | extern char dialog_input_result[]; | 146 | extern char dialog_input_result[]; |
| 147 | extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ | ||
| 147 | 148 | ||
| 148 | /* | 149 | /* |
| 149 | * Function prototypes | 150 | * Function prototypes |
| @@ -209,7 +210,13 @@ int first_alpha(const char *string, const char *exempt); | |||
| 209 | int dialog_yesno(const char *title, const char *prompt, int height, int width); | 210 | int dialog_yesno(const char *title, const char *prompt, int height, int width); |
| 210 | int dialog_msgbox(const char *title, const char *prompt, int height, | 211 | int dialog_msgbox(const char *title, const char *prompt, int height, |
| 211 | int width, int pause); | 212 | int width, int pause); |
| 212 | int dialog_textbox(const char *title, const char *file, int height, int width); | 213 | |
| 214 | |||
| 215 | typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void | ||
| 216 | *_data); | ||
| 217 | int dialog_textbox(const char *title, char *tbuf, int initial_height, | ||
| 218 | int initial_width, int *keys, int *_vscroll, int *_hscroll, | ||
| 219 | update_text_fn update_text, void *data); | ||
| 213 | int dialog_menu(const char *title, const char *prompt, | 220 | int dialog_menu(const char *title, const char *prompt, |
| 214 | const void *selected, int *s_scroll); | 221 | const void *selected, int *s_scroll); |
| 215 | int dialog_checklist(const char *title, const char *prompt, int height, | 222 | int dialog_checklist(const char *title, const char *prompt, int height, |
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 4e5de60a0c0d..a48bb93e0907 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c | |||
| @@ -22,23 +22,25 @@ | |||
| 22 | #include "dialog.h" | 22 | #include "dialog.h" |
| 23 | 23 | ||
| 24 | static void back_lines(int n); | 24 | static void back_lines(int n); |
| 25 | static void print_page(WINDOW * win, int height, int width); | 25 | static void print_page(WINDOW *win, int height, int width, update_text_fn |
| 26 | static void print_line(WINDOW * win, int row, int width); | 26 | update_text, void *data); |
| 27 | static void print_line(WINDOW *win, int row, int width); | ||
| 27 | static char *get_line(void); | 28 | static char *get_line(void); |
| 28 | static void print_position(WINDOW * win); | 29 | static void print_position(WINDOW * win); |
| 29 | 30 | ||
| 30 | static int hscroll; | 31 | static int hscroll; |
| 31 | static int begin_reached, end_reached, page_length; | 32 | static int begin_reached, end_reached, page_length; |
| 32 | static const char *buf; | 33 | static char *buf; |
| 33 | static const char *page; | 34 | static char *page; |
| 34 | 35 | ||
| 35 | /* | 36 | /* |
| 36 | * refresh window content | 37 | * refresh window content |
| 37 | */ | 38 | */ |
| 38 | static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, | 39 | static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, |
| 39 | int cur_y, int cur_x) | 40 | int cur_y, int cur_x, update_text_fn update_text, |
| 41 | void *data) | ||
| 40 | { | 42 | { |
| 41 | print_page(box, boxh, boxw); | 43 | print_page(box, boxh, boxw, update_text, data); |
| 42 | print_position(dialog); | 44 | print_position(dialog); |
| 43 | wmove(dialog, cur_y, cur_x); /* Restore cursor position */ | 45 | wmove(dialog, cur_y, cur_x); /* Restore cursor position */ |
| 44 | wrefresh(dialog); | 46 | wrefresh(dialog); |
| @@ -47,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, | |||
| 47 | 49 | ||
| 48 | /* | 50 | /* |
| 49 | * Display text from a file in a dialog box. | 51 | * Display text from a file in a dialog box. |
| 52 | * | ||
| 53 | * keys is a null-terminated array | ||
| 54 | * update_text() may not add or remove any '\n' or '\0' in tbuf | ||
| 50 | */ | 55 | */ |
| 51 | int dialog_textbox(const char *title, const char *tbuf, | 56 | int dialog_textbox(const char *title, char *tbuf, int initial_height, |
| 52 | int initial_height, int initial_width) | 57 | int initial_width, int *keys, int *_vscroll, int *_hscroll, |
| 58 | update_text_fn update_text, void *data) | ||
| 53 | { | 59 | { |
| 54 | int i, x, y, cur_x, cur_y, key = 0; | 60 | int i, x, y, cur_x, cur_y, key = 0; |
| 55 | int height, width, boxh, boxw; | 61 | int height, width, boxh, boxw; |
| 56 | int passed_end; | ||
| 57 | WINDOW *dialog, *box; | 62 | WINDOW *dialog, *box; |
| 63 | bool done = false; | ||
| 58 | 64 | ||
| 59 | begin_reached = 1; | 65 | begin_reached = 1; |
| 60 | end_reached = 0; | 66 | end_reached = 0; |
| @@ -63,6 +69,15 @@ int dialog_textbox(const char *title, const char *tbuf, | |||
| 63 | buf = tbuf; | 69 | buf = tbuf; |
| 64 | page = buf; /* page is pointer to start of page to be displayed */ | 70 | page = buf; /* page is pointer to start of page to be displayed */ |
| 65 | 71 | ||
| 72 | if (_vscroll && *_vscroll) { | ||
| 73 | begin_reached = 0; | ||
| 74 | |||
| 75 | for (i = 0; i < *_vscroll; i++) | ||
| 76 | get_line(); | ||
| 77 | } | ||
| 78 | if (_hscroll) | ||
| 79 | hscroll = *_hscroll; | ||
| 80 | |||
| 66 | do_resize: | 81 | do_resize: |
| 67 | getmaxyx(stdscr, height, width); | 82 | getmaxyx(stdscr, height, width); |
| 68 | if (height < 8 || width < 8) | 83 | if (height < 8 || width < 8) |
| @@ -120,9 +135,10 @@ do_resize: | |||
| 120 | 135 | ||
| 121 | /* Print first page of text */ | 136 | /* Print first page of text */ |
| 122 | attr_clear(box, boxh, boxw, dlg.dialog.atr); | 137 | attr_clear(box, boxh, boxw, dlg.dialog.atr); |
| 123 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); | 138 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, |
| 139 | data); | ||
| 124 | 140 | ||
| 125 | while ((key != KEY_ESC) && (key != '\n')) { | 141 | while (!done) { |
| 126 | key = wgetch(dialog); | 142 | key = wgetch(dialog); |
| 127 | switch (key) { | 143 | switch (key) { |
| 128 | case 'E': /* Exit */ | 144 | case 'E': /* Exit */ |
| @@ -130,16 +146,17 @@ do_resize: | |||
| 130 | case 'X': | 146 | case 'X': |
| 131 | case 'x': | 147 | case 'x': |
| 132 | case 'q': | 148 | case 'q': |
| 133 | delwin(box); | 149 | case '\n': |
| 134 | delwin(dialog); | 150 | done = true; |
| 135 | return 0; | 151 | break; |
| 136 | case 'g': /* First page */ | 152 | case 'g': /* First page */ |
| 137 | case KEY_HOME: | 153 | case KEY_HOME: |
| 138 | if (!begin_reached) { | 154 | if (!begin_reached) { |
| 139 | begin_reached = 1; | 155 | begin_reached = 1; |
| 140 | page = buf; | 156 | page = buf; |
| 141 | refresh_text_box(dialog, box, boxh, boxw, | 157 | refresh_text_box(dialog, box, boxh, boxw, |
| 142 | cur_y, cur_x); | 158 | cur_y, cur_x, update_text, |
| 159 | data); | ||
| 143 | } | 160 | } |
| 144 | break; | 161 | break; |
| 145 | case 'G': /* Last page */ | 162 | case 'G': /* Last page */ |
| @@ -149,45 +166,18 @@ do_resize: | |||
| 149 | /* point to last char in buf */ | 166 | /* point to last char in buf */ |
| 150 | page = buf + strlen(buf); | 167 | page = buf + strlen(buf); |
| 151 | back_lines(boxh); | 168 | back_lines(boxh); |
| 152 | refresh_text_box(dialog, box, boxh, boxw, | 169 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 153 | cur_y, cur_x); | 170 | cur_x, update_text, data); |
| 154 | break; | 171 | break; |
| 155 | case 'K': /* Previous line */ | 172 | case 'K': /* Previous line */ |
| 156 | case 'k': | 173 | case 'k': |
| 157 | case KEY_UP: | 174 | case KEY_UP: |
| 158 | if (!begin_reached) { | 175 | if (begin_reached) |
| 159 | back_lines(page_length + 1); | 176 | break; |
| 160 | |||
| 161 | /* We don't call print_page() here but use | ||
| 162 | * scrolling to ensure faster screen update. | ||
| 163 | * However, 'end_reached' and 'page_length' | ||
| 164 | * should still be updated, and 'page' should | ||
| 165 | * point to start of next page. This is done | ||
| 166 | * by calling get_line() in the following | ||
| 167 | * 'for' loop. */ | ||
| 168 | scrollok(box, TRUE); | ||
| 169 | wscrl(box, -1); /* Scroll box region down one line */ | ||
| 170 | scrollok(box, FALSE); | ||
| 171 | page_length = 0; | ||
| 172 | passed_end = 0; | ||
| 173 | for (i = 0; i < boxh; i++) { | ||
| 174 | if (!i) { | ||
| 175 | /* print first line of page */ | ||
| 176 | print_line(box, 0, boxw); | ||
| 177 | wnoutrefresh(box); | ||
| 178 | } else | ||
| 179 | /* Called to update 'end_reached' and 'page' */ | ||
| 180 | get_line(); | ||
| 181 | if (!passed_end) | ||
| 182 | page_length++; | ||
| 183 | if (end_reached && !passed_end) | ||
| 184 | passed_end = 1; | ||
| 185 | } | ||
| 186 | 177 | ||
| 187 | print_position(dialog); | 178 | back_lines(page_length + 1); |
| 188 | wmove(dialog, cur_y, cur_x); /* Restore cursor position */ | 179 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 189 | wrefresh(dialog); | 180 | cur_x, update_text, data); |
| 190 | } | ||
| 191 | break; | 181 | break; |
| 192 | case 'B': /* Previous page */ | 182 | case 'B': /* Previous page */ |
| 193 | case 'b': | 183 | case 'b': |
| @@ -196,23 +186,18 @@ do_resize: | |||
| 196 | if (begin_reached) | 186 | if (begin_reached) |
| 197 | break; | 187 | break; |
| 198 | back_lines(page_length + boxh); | 188 | back_lines(page_length + boxh); |
| 199 | refresh_text_box(dialog, box, boxh, boxw, | 189 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 200 | cur_y, cur_x); | 190 | cur_x, update_text, data); |
| 201 | break; | 191 | break; |
| 202 | case 'J': /* Next line */ | 192 | case 'J': /* Next line */ |
| 203 | case 'j': | 193 | case 'j': |
| 204 | case KEY_DOWN: | 194 | case KEY_DOWN: |
| 205 | if (!end_reached) { | 195 | if (end_reached) |
| 206 | begin_reached = 0; | 196 | break; |
| 207 | scrollok(box, TRUE); | 197 | |
| 208 | scroll(box); /* Scroll box region up one line */ | 198 | back_lines(page_length - 1); |
| 209 | scrollok(box, FALSE); | 199 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 210 | print_line(box, boxh - 1, boxw); | 200 | cur_x, update_text, data); |
| 211 | wnoutrefresh(box); | ||
| 212 | print_position(dialog); | ||
| 213 | wmove(dialog, cur_y, cur_x); /* Restore cursor position */ | ||
| 214 | wrefresh(dialog); | ||
| 215 | } | ||
| 216 | break; | 201 | break; |
| 217 | case KEY_NPAGE: /* Next page */ | 202 | case KEY_NPAGE: /* Next page */ |
| 218 | case ' ': | 203 | case ' ': |
| @@ -221,8 +206,8 @@ do_resize: | |||
| 221 | break; | 206 | break; |
| 222 | 207 | ||
| 223 | begin_reached = 0; | 208 | begin_reached = 0; |
| 224 | refresh_text_box(dialog, box, boxh, boxw, | 209 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 225 | cur_y, cur_x); | 210 | cur_x, update_text, data); |
| 226 | break; | 211 | break; |
| 227 | case '0': /* Beginning of line */ | 212 | case '0': /* Beginning of line */ |
| 228 | case 'H': /* Scroll left */ | 213 | case 'H': /* Scroll left */ |
| @@ -237,8 +222,8 @@ do_resize: | |||
| 237 | hscroll--; | 222 | hscroll--; |
| 238 | /* Reprint current page to scroll horizontally */ | 223 | /* Reprint current page to scroll horizontally */ |
| 239 | back_lines(page_length); | 224 | back_lines(page_length); |
| 240 | refresh_text_box(dialog, box, boxh, boxw, | 225 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 241 | cur_y, cur_x); | 226 | cur_x, update_text, data); |
| 242 | break; | 227 | break; |
| 243 | case 'L': /* Scroll right */ | 228 | case 'L': /* Scroll right */ |
| 244 | case 'l': | 229 | case 'l': |
| @@ -248,11 +233,12 @@ do_resize: | |||
| 248 | hscroll++; | 233 | hscroll++; |
| 249 | /* Reprint current page to scroll horizontally */ | 234 | /* Reprint current page to scroll horizontally */ |
| 250 | back_lines(page_length); | 235 | back_lines(page_length); |
| 251 | refresh_text_box(dialog, box, boxh, boxw, | 236 | refresh_text_box(dialog, box, boxh, boxw, cur_y, |
| 252 | cur_y, cur_x); | 237 | cur_x, update_text, data); |
| 253 | break; | 238 | break; |
| 254 | case KEY_ESC: | 239 | case KEY_ESC: |
| 255 | key = on_key_esc(dialog); | 240 | if (on_key_esc(dialog) == KEY_ESC) |
| 241 | done = true; | ||
| 256 | break; | 242 | break; |
| 257 | case KEY_RESIZE: | 243 | case KEY_RESIZE: |
| 258 | back_lines(height); | 244 | back_lines(height); |
| @@ -260,11 +246,31 @@ do_resize: | |||
| 260 | delwin(dialog); | 246 | delwin(dialog); |
| 261 | on_key_resize(); | 247 | on_key_resize(); |
| 262 | goto do_resize; | 248 | goto do_resize; |
| 249 | default: | ||
| 250 | for (i = 0; keys[i]; i++) { | ||
| 251 | if (key == keys[i]) { | ||
| 252 | done = true; | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 263 | } | 256 | } |
| 264 | } | 257 | } |
| 265 | delwin(box); | 258 | delwin(box); |
| 266 | delwin(dialog); | 259 | delwin(dialog); |
| 267 | return key; /* ESC pressed */ | 260 | if (_vscroll) { |
| 261 | const char *s; | ||
| 262 | |||
| 263 | s = buf; | ||
| 264 | *_vscroll = 0; | ||
| 265 | back_lines(page_length); | ||
| 266 | while (s < page && (s = strchr(s, '\n'))) { | ||
| 267 | (*_vscroll)++; | ||
| 268 | s++; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | if (_hscroll) | ||
| 272 | *_hscroll = hscroll; | ||
| 273 | return key; | ||
| 268 | } | 274 | } |
| 269 | 275 | ||
| 270 | /* | 276 | /* |
| @@ -301,12 +307,23 @@ static void back_lines(int n) | |||
| 301 | } | 307 | } |
| 302 | 308 | ||
| 303 | /* | 309 | /* |
| 304 | * Print a new page of text. Called by dialog_textbox(). | 310 | * Print a new page of text. |
| 305 | */ | 311 | */ |
| 306 | static void print_page(WINDOW * win, int height, int width) | 312 | static void print_page(WINDOW *win, int height, int width, update_text_fn |
| 313 | update_text, void *data) | ||
| 307 | { | 314 | { |
| 308 | int i, passed_end = 0; | 315 | int i, passed_end = 0; |
| 309 | 316 | ||
| 317 | if (update_text) { | ||
| 318 | char *end; | ||
| 319 | |||
| 320 | for (i = 0; i < height; i++) | ||
| 321 | get_line(); | ||
| 322 | end = page; | ||
| 323 | back_lines(height); | ||
| 324 | update_text(buf, page - buf, end - buf, data); | ||
| 325 | } | ||
| 326 | |||
| 310 | page_length = 0; | 327 | page_length = 0; |
| 311 | for (i = 0; i < height; i++) { | 328 | for (i = 0; i < height; i++) { |
| 312 | print_line(win, i, width); | 329 | print_line(win, i, width); |
| @@ -319,7 +336,7 @@ static void print_page(WINDOW * win, int height, int width) | |||
| 319 | } | 336 | } |
| 320 | 337 | ||
| 321 | /* | 338 | /* |
| 322 | * Print a new line of text. Called by dialog_textbox() and print_page(). | 339 | * Print a new line of text. |
| 323 | */ | 340 | */ |
| 324 | static void print_line(WINDOW * win, int row, int width) | 341 | static void print_line(WINDOW * win, int row, int width) |
| 325 | { | 342 | { |
| @@ -357,10 +374,8 @@ static char *get_line(void) | |||
| 357 | end_reached = 0; | 374 | end_reached = 0; |
| 358 | while (*page != '\n') { | 375 | while (*page != '\n') { |
| 359 | if (*page == '\0') { | 376 | if (*page == '\0') { |
| 360 | if (!end_reached) { | 377 | end_reached = 1; |
| 361 | end_reached = 1; | 378 | break; |
| 362 | break; | ||
| 363 | } | ||
| 364 | } else if (i < MAX_LEN) | 379 | } else if (i < MAX_LEN) |
| 365 | line[i++] = *(page++); | 380 | line[i++] = *(page++); |
| 366 | else { | 381 | else { |
| @@ -373,7 +388,7 @@ static char *get_line(void) | |||
| 373 | if (i <= MAX_LEN) | 388 | if (i <= MAX_LEN) |
| 374 | line[i] = '\0'; | 389 | line[i] = '\0'; |
| 375 | if (!end_reached) | 390 | if (!end_reached) |
| 376 | page++; /* move pass '\n' */ | 391 | page++; /* move past '\n' */ |
| 377 | 392 | ||
| 378 | return line; | 393 | return line; |
| 379 | } | 394 | } |
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index f2375ad7ebc9..109d53117d22 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c | |||
| @@ -23,6 +23,9 @@ | |||
| 23 | 23 | ||
| 24 | #include "dialog.h" | 24 | #include "dialog.h" |
| 25 | 25 | ||
| 26 | /* Needed in signal handler in mconf.c */ | ||
| 27 | int saved_x, saved_y; | ||
| 28 | |||
| 26 | struct dialog_info dlg; | 29 | struct dialog_info dlg; |
| 27 | 30 | ||
| 28 | static void set_mono_theme(void) | 31 | static void set_mono_theme(void) |
| @@ -273,6 +276,10 @@ int init_dialog(const char *backtitle) | |||
| 273 | int height, width; | 276 | int height, width; |
| 274 | 277 | ||
| 275 | initscr(); /* Init curses */ | 278 | initscr(); /* Init curses */ |
| 279 | |||
| 280 | /* Get current cursor position for signal handler in mconf.c */ | ||
| 281 | getyx(stdscr, saved_y, saved_x); | ||
| 282 | |||
| 276 | getmaxyx(stdscr, height, width); | 283 | getmaxyx(stdscr, height, width); |
| 277 | if (height < 19 || width < 80) { | 284 | if (height < 19 || width < 80) { |
| 278 | endwin(); | 285 | endwin(); |
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index f584a281bb4c..48f67448af7b 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c | |||
| @@ -236,16 +236,19 @@ search_help[] = N_( | |||
| 236 | "Result:\n" | 236 | "Result:\n" |
| 237 | "-----------------------------------------------------------------\n" | 237 | "-----------------------------------------------------------------\n" |
| 238 | "Symbol: FOO [=m]\n" | 238 | "Symbol: FOO [=m]\n" |
| 239 | "Type : tristate\n" | ||
| 239 | "Prompt: Foo bus is used to drive the bar HW\n" | 240 | "Prompt: Foo bus is used to drive the bar HW\n" |
| 240 | "Defined at drivers/pci/Kconfig:47\n" | 241 | " Defined at drivers/pci/Kconfig:47\n" |
| 241 | "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" | 242 | " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" |
| 242 | "Location:\n" | 243 | " Location:\n" |
| 243 | " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" | 244 | " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" |
| 244 | " -> PCI support (PCI [=y])\n" | 245 | " -> PCI support (PCI [=y])\n" |
| 245 | " -> PCI access mode (<choice> [=y])\n" | 246 | "(1) -> PCI access mode (<choice> [=y])\n" |
| 246 | "Selects: LIBCRC32\n" | 247 | " Selects: LIBCRC32\n" |
| 247 | "Selected by: BAR\n" | 248 | " Selected by: BAR\n" |
| 248 | "-----------------------------------------------------------------\n" | 249 | "-----------------------------------------------------------------\n" |
| 250 | "o The line 'Type:' shows the type of the configuration option for\n" | ||
| 251 | " this symbol (boolean, tristate, string, ...)\n" | ||
| 249 | "o The line 'Prompt:' shows the text used in the menu structure for\n" | 252 | "o The line 'Prompt:' shows the text used in the menu structure for\n" |
| 250 | " this symbol\n" | 253 | " this symbol\n" |
| 251 | "o The 'Defined at' line tell at what file / line number the symbol\n" | 254 | "o The 'Defined at' line tell at what file / line number the symbol\n" |
| @@ -254,8 +257,12 @@ search_help[] = N_( | |||
| 254 | " this symbol to be visible in the menu (selectable)\n" | 257 | " this symbol to be visible in the menu (selectable)\n" |
| 255 | "o The 'Location:' lines tell where in the menu structure this symbol\n" | 258 | "o The 'Location:' lines tell where in the menu structure this symbol\n" |
| 256 | " is located\n" | 259 | " is located\n" |
| 257 | " A location followed by a [=y] indicate that this is a selectable\n" | 260 | " A location followed by a [=y] indicates that this is a\n" |
| 258 | " menu item - and current value is displayed inside brackets.\n" | 261 | " selectable menu item - and the current value is displayed inside\n" |
| 262 | " brackets.\n" | ||
| 263 | " Press the key in the (#) prefix to jump directly to that\n" | ||
| 264 | " location. You will be returned to the current search results\n" | ||
| 265 | " after exiting this new menu.\n" | ||
| 259 | "o The 'Selects:' line tell what symbol will be automatically\n" | 266 | "o The 'Selects:' line tell what symbol will be automatically\n" |
| 260 | " selected if this symbol is selected (y or m)\n" | 267 | " selected if this symbol is selected (y or m)\n" |
| 261 | "o The 'Selected by' line tell what symbol has selected this symbol\n" | 268 | "o The 'Selected by' line tell what symbol has selected this symbol\n" |
| @@ -273,13 +280,15 @@ static struct menu *current_menu; | |||
| 273 | static int child_count; | 280 | static int child_count; |
| 274 | static int single_menu_mode; | 281 | static int single_menu_mode; |
| 275 | static int show_all_options; | 282 | static int show_all_options; |
| 276 | static int saved_x, saved_y; | ||
| 277 | 283 | ||
| 278 | static void conf(struct menu *menu); | 284 | static void conf(struct menu *menu, struct menu *active_menu); |
| 279 | static void conf_choice(struct menu *menu); | 285 | static void conf_choice(struct menu *menu); |
| 280 | static void conf_string(struct menu *menu); | 286 | static void conf_string(struct menu *menu); |
| 281 | static void conf_load(void); | 287 | static void conf_load(void); |
| 282 | static void conf_save(void); | 288 | static void conf_save(void); |
| 289 | static int show_textbox_ext(const char *title, char *text, int r, int c, | ||
| 290 | int *keys, int *vscroll, int *hscroll, | ||
| 291 | update_text_fn update_text, void *data); | ||
| 283 | static void show_textbox(const char *title, const char *text, int r, int c); | 292 | static void show_textbox(const char *title, const char *text, int r, int c); |
| 284 | static void show_helptext(const char *title, const char *text); | 293 | static void show_helptext(const char *title, const char *text); |
| 285 | static void show_help(struct menu *menu); | 294 | static void show_help(struct menu *menu); |
| @@ -302,12 +311,47 @@ static void set_config_filename(const char *config_filename) | |||
| 302 | } | 311 | } |
| 303 | 312 | ||
| 304 | 313 | ||
| 314 | struct search_data { | ||
| 315 | struct jk_head *head; | ||
| 316 | struct menu **targets; | ||
| 317 | int *keys; | ||
| 318 | }; | ||
| 319 | |||
| 320 | static void update_text(char *buf, size_t start, size_t end, void *_data) | ||
| 321 | { | ||
| 322 | struct search_data *data = _data; | ||
| 323 | struct jump_key *pos; | ||
| 324 | int k = 0; | ||
| 325 | |||
| 326 | CIRCLEQ_FOREACH(pos, data->head, entries) { | ||
| 327 | if (pos->offset >= start && pos->offset < end) { | ||
| 328 | char header[4]; | ||
| 329 | |||
| 330 | if (k < JUMP_NB) { | ||
| 331 | int key = '0' + (pos->index % JUMP_NB) + 1; | ||
| 332 | |||
| 333 | sprintf(header, "(%c)", key); | ||
| 334 | data->keys[k] = key; | ||
| 335 | data->targets[k] = pos->target; | ||
| 336 | k++; | ||
| 337 | } else { | ||
| 338 | sprintf(header, " "); | ||
| 339 | } | ||
| 340 | |||
| 341 | memcpy(buf + pos->offset, header, sizeof(header) - 1); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | data->keys[k] = 0; | ||
| 345 | } | ||
| 346 | |||
| 305 | static void search_conf(void) | 347 | static void search_conf(void) |
| 306 | { | 348 | { |
| 307 | struct symbol **sym_arr; | 349 | struct symbol **sym_arr; |
| 308 | struct gstr res; | 350 | struct gstr res; |
| 309 | char *dialog_input; | 351 | char *dialog_input; |
| 310 | int dres; | 352 | int dres, vscroll = 0, hscroll = 0; |
| 353 | bool again; | ||
| 354 | |||
| 311 | again: | 355 | again: |
| 312 | dialog_clear(); | 356 | dialog_clear(); |
| 313 | dres = dialog_inputbox(_("Search Configuration Parameter"), | 357 | dres = dialog_inputbox(_("Search Configuration Parameter"), |
| @@ -330,10 +374,30 @@ again: | |||
| 330 | dialog_input += strlen(CONFIG_); | 374 | dialog_input += strlen(CONFIG_); |
| 331 | 375 | ||
| 332 | sym_arr = sym_re_search(dialog_input); | 376 | sym_arr = sym_re_search(dialog_input); |
| 333 | res = get_relations_str(sym_arr); | 377 | do { |
| 378 | struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head); | ||
| 379 | struct menu *targets[JUMP_NB]; | ||
| 380 | int keys[JUMP_NB + 1], i; | ||
| 381 | struct search_data data = { | ||
| 382 | .head = &head, | ||
| 383 | .targets = targets, | ||
| 384 | .keys = keys, | ||
| 385 | }; | ||
| 386 | |||
| 387 | res = get_relations_str(sym_arr, &head); | ||
| 388 | dres = show_textbox_ext(_("Search Results"), (char *) | ||
| 389 | str_get(&res), 0, 0, keys, &vscroll, | ||
| 390 | &hscroll, &update_text, (void *) | ||
| 391 | &data); | ||
| 392 | again = false; | ||
| 393 | for (i = 0; i < JUMP_NB && keys[i]; i++) | ||
| 394 | if (dres == keys[i]) { | ||
| 395 | conf(targets[i]->parent, targets[i]); | ||
| 396 | again = true; | ||
| 397 | } | ||
| 398 | str_free(&res); | ||
| 399 | } while (again); | ||
| 334 | free(sym_arr); | 400 | free(sym_arr); |
| 335 | show_textbox(_("Search Results"), str_get(&res), 0, 0); | ||
| 336 | str_free(&res); | ||
| 337 | } | 401 | } |
| 338 | 402 | ||
| 339 | static void build_conf(struct menu *menu) | 403 | static void build_conf(struct menu *menu) |
| @@ -514,12 +578,11 @@ conf_childs: | |||
| 514 | indent -= doint; | 578 | indent -= doint; |
| 515 | } | 579 | } |
| 516 | 580 | ||
| 517 | static void conf(struct menu *menu) | 581 | static void conf(struct menu *menu, struct menu *active_menu) |
| 518 | { | 582 | { |
| 519 | struct menu *submenu; | 583 | struct menu *submenu; |
| 520 | const char *prompt = menu_get_prompt(menu); | 584 | const char *prompt = menu_get_prompt(menu); |
| 521 | struct symbol *sym; | 585 | struct symbol *sym; |
| 522 | struct menu *active_menu = NULL; | ||
| 523 | int res; | 586 | int res; |
| 524 | int s_scroll = 0; | 587 | int s_scroll = 0; |
| 525 | 588 | ||
| @@ -562,13 +625,13 @@ static void conf(struct menu *menu) | |||
| 562 | if (single_menu_mode) | 625 | if (single_menu_mode) |
| 563 | submenu->data = (void *) (long) !submenu->data; | 626 | submenu->data = (void *) (long) !submenu->data; |
| 564 | else | 627 | else |
| 565 | conf(submenu); | 628 | conf(submenu, NULL); |
| 566 | break; | 629 | break; |
| 567 | case 't': | 630 | case 't': |
| 568 | if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) | 631 | if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) |
| 569 | conf_choice(submenu); | 632 | conf_choice(submenu); |
| 570 | else if (submenu->prompt->type == P_MENU) | 633 | else if (submenu->prompt->type == P_MENU) |
| 571 | conf(submenu); | 634 | conf(submenu, NULL); |
| 572 | break; | 635 | break; |
| 573 | case 's': | 636 | case 's': |
| 574 | conf_string(submenu); | 637 | conf_string(submenu); |
| @@ -607,7 +670,7 @@ static void conf(struct menu *menu) | |||
| 607 | if (item_is_tag('t')) | 670 | if (item_is_tag('t')) |
| 608 | sym_toggle_tristate_value(sym); | 671 | sym_toggle_tristate_value(sym); |
| 609 | else if (item_is_tag('m')) | 672 | else if (item_is_tag('m')) |
| 610 | conf(submenu); | 673 | conf(submenu, NULL); |
| 611 | break; | 674 | break; |
| 612 | case 7: | 675 | case 7: |
| 613 | search_conf(); | 676 | search_conf(); |
| @@ -619,10 +682,19 @@ static void conf(struct menu *menu) | |||
| 619 | } | 682 | } |
| 620 | } | 683 | } |
| 621 | 684 | ||
| 622 | static void show_textbox(const char *title, const char *text, int r, int c) | 685 | static int show_textbox_ext(const char *title, char *text, int r, int c, int |
| 686 | *keys, int *vscroll, int *hscroll, update_text_fn | ||
| 687 | update_text, void *data) | ||
| 623 | { | 688 | { |
| 624 | dialog_clear(); | 689 | dialog_clear(); |
| 625 | dialog_textbox(title, text, r, c); | 690 | return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, |
| 691 | update_text, data); | ||
| 692 | } | ||
| 693 | |||
| 694 | static void show_textbox(const char *title, const char *text, int r, int c) | ||
| 695 | { | ||
| 696 | show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, | ||
| 697 | NULL, NULL); | ||
| 626 | } | 698 | } |
| 627 | 699 | ||
| 628 | static void show_helptext(const char *title, const char *text) | 700 | static void show_helptext(const char *title, const char *text) |
| @@ -862,9 +934,6 @@ int main(int ac, char **av) | |||
| 862 | single_menu_mode = 1; | 934 | single_menu_mode = 1; |
| 863 | } | 935 | } |
| 864 | 936 | ||
| 865 | initscr(); | ||
| 866 | |||
| 867 | getyx(stdscr, saved_y, saved_x); | ||
| 868 | if (init_dialog(NULL)) { | 937 | if (init_dialog(NULL)) { |
| 869 | fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); | 938 | fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); |
| 870 | fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); | 939 | fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); |
| @@ -873,7 +942,7 @@ int main(int ac, char **av) | |||
| 873 | 942 | ||
| 874 | set_config_filename(conf_get_configname()); | 943 | set_config_filename(conf_get_configname()); |
| 875 | do { | 944 | do { |
| 876 | conf(&rootmenu); | 945 | conf(&rootmenu, NULL); |
| 877 | res = handle_exit(); | 946 | res = handle_exit(); |
| 878 | } while (res == KEY_ESC); | 947 | } while (res == KEY_ESC); |
| 879 | 948 | ||
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 8c2a97e60faf..a3cade659f89 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c | |||
| @@ -507,10 +507,12 @@ const char *menu_get_help(struct menu *menu) | |||
| 507 | return ""; | 507 | return ""; |
| 508 | } | 508 | } |
| 509 | 509 | ||
| 510 | static void get_prompt_str(struct gstr *r, struct property *prop) | 510 | static void get_prompt_str(struct gstr *r, struct property *prop, |
| 511 | struct jk_head *head) | ||
| 511 | { | 512 | { |
| 512 | int i, j; | 513 | int i, j; |
| 513 | struct menu *submenu[8], *menu; | 514 | struct menu *submenu[8], *menu, *location = NULL; |
| 515 | struct jump_key *jump; | ||
| 514 | 516 | ||
| 515 | str_printf(r, _("Prompt: %s\n"), _(prop->text)); | 517 | str_printf(r, _("Prompt: %s\n"), _(prop->text)); |
| 516 | str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, | 518 | str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, |
| @@ -521,13 +523,43 @@ static void get_prompt_str(struct gstr *r, struct property *prop) | |||
| 521 | str_append(r, "\n"); | 523 | str_append(r, "\n"); |
| 522 | } | 524 | } |
| 523 | menu = prop->menu->parent; | 525 | menu = prop->menu->parent; |
| 524 | for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) | 526 | for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { |
| 527 | bool accessible = menu_is_visible(menu); | ||
| 528 | |||
| 525 | submenu[i++] = menu; | 529 | submenu[i++] = menu; |
| 530 | if (location == NULL && accessible) | ||
| 531 | location = menu; | ||
| 532 | } | ||
| 533 | if (head && location) { | ||
| 534 | jump = malloc(sizeof(struct jump_key)); | ||
| 535 | |||
| 536 | if (menu_is_visible(prop->menu)) { | ||
| 537 | /* | ||
| 538 | * There is not enough room to put the hint at the | ||
| 539 | * beginning of the "Prompt" line. Put the hint on the | ||
| 540 | * last "Location" line even when it would belong on | ||
| 541 | * the former. | ||
| 542 | */ | ||
| 543 | jump->target = prop->menu; | ||
| 544 | } else | ||
| 545 | jump->target = location; | ||
| 546 | |||
| 547 | if (CIRCLEQ_EMPTY(head)) | ||
| 548 | jump->index = 0; | ||
| 549 | else | ||
| 550 | jump->index = CIRCLEQ_LAST(head)->index + 1; | ||
| 551 | |||
| 552 | CIRCLEQ_INSERT_TAIL(head, jump, entries); | ||
| 553 | } | ||
| 554 | |||
| 526 | if (i > 0) { | 555 | if (i > 0) { |
| 527 | str_printf(r, _(" Location:\n")); | 556 | str_printf(r, _(" Location:\n")); |
| 528 | for (j = 4; --i >= 0; j += 2) { | 557 | for (j = 4; --i >= 0; j += 2) { |
| 529 | menu = submenu[i]; | 558 | menu = submenu[i]; |
| 530 | str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); | 559 | if (head && location && menu == location) |
| 560 | jump->offset = r->len - 1; | ||
| 561 | str_printf(r, "%*c-> %s", j, ' ', | ||
| 562 | _(menu_get_prompt(menu))); | ||
| 531 | if (menu->sym) { | 563 | if (menu->sym) { |
| 532 | str_printf(r, " (%s [=%s])", menu->sym->name ? | 564 | str_printf(r, " (%s [=%s])", menu->sym->name ? |
| 533 | menu->sym->name : _("<choice>"), | 565 | menu->sym->name : _("<choice>"), |
| @@ -538,7 +570,10 @@ static void get_prompt_str(struct gstr *r, struct property *prop) | |||
| 538 | } | 570 | } |
| 539 | } | 571 | } |
| 540 | 572 | ||
| 541 | void get_symbol_str(struct gstr *r, struct symbol *sym) | 573 | /* |
| 574 | * head is optional and may be NULL | ||
| 575 | */ | ||
| 576 | void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head) | ||
| 542 | { | 577 | { |
| 543 | bool hit; | 578 | bool hit; |
| 544 | struct property *prop; | 579 | struct property *prop; |
| @@ -557,7 +592,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) | |||
| 557 | } | 592 | } |
| 558 | } | 593 | } |
| 559 | for_all_prompts(sym, prop) | 594 | for_all_prompts(sym, prop) |
| 560 | get_prompt_str(r, prop); | 595 | get_prompt_str(r, prop, head); |
| 561 | hit = false; | 596 | hit = false; |
| 562 | for_all_properties(sym, prop, P_SELECT) { | 597 | for_all_properties(sym, prop, P_SELECT) { |
| 563 | if (!hit) { | 598 | if (!hit) { |
| @@ -577,14 +612,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) | |||
| 577 | str_append(r, "\n\n"); | 612 | str_append(r, "\n\n"); |
| 578 | } | 613 | } |
| 579 | 614 | ||
| 580 | struct gstr get_relations_str(struct symbol **sym_arr) | 615 | struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head) |
| 581 | { | 616 | { |
| 582 | struct symbol *sym; | 617 | struct symbol *sym; |
| 583 | struct gstr res = str_new(); | 618 | struct gstr res = str_new(); |
| 584 | int i; | 619 | int i; |
| 585 | 620 | ||
| 586 | for (i = 0; sym_arr && (sym = sym_arr[i]); i++) | 621 | for (i = 0; sym_arr && (sym = sym_arr[i]); i++) |
| 587 | get_symbol_str(&res, sym); | 622 | get_symbol_str(&res, sym, head); |
| 588 | if (!i) | 623 | if (!i) |
| 589 | str_append(&res, _("No matches found.\n")); | 624 | str_append(&res, _("No matches found.\n")); |
| 590 | return res; | 625 | return res; |
| @@ -603,5 +638,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) | |||
| 603 | } | 638 | } |
| 604 | str_printf(help, "%s\n", _(help_text)); | 639 | str_printf(help, "%s\n", _(help_text)); |
| 605 | if (sym) | 640 | if (sym) |
| 606 | get_symbol_str(help, sym); | 641 | get_symbol_str(help, sym, NULL); |
| 607 | } | 642 | } |
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 1704a8562a5d..87d4b15da951 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c | |||
| @@ -721,7 +721,7 @@ again: | |||
| 721 | dialog_input += strlen(CONFIG_); | 721 | dialog_input += strlen(CONFIG_); |
| 722 | 722 | ||
| 723 | sym_arr = sym_re_search(dialog_input); | 723 | sym_arr = sym_re_search(dialog_input); |
| 724 | res = get_relations_str(sym_arr); | 724 | res = get_relations_str(sym_arr, NULL); |
| 725 | free(sym_arr); | 725 | free(sym_arr); |
| 726 | show_scroll_win(main_window, | 726 | show_scroll_win(main_window, |
| 727 | _("Search Results"), str_get(&res)); | 727 | _("Search Results"), str_get(&res)); |
diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8fd107a3fac4..46e7aff80d1a 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc | |||
| @@ -6,6 +6,7 @@ use strict; | |||
| 6 | ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## | 6 | ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## |
| 7 | ## Copyright (C) 2001 Simon Huggins ## | 7 | ## Copyright (C) 2001 Simon Huggins ## |
| 8 | ## Copyright (C) 2005-2012 Randy Dunlap ## | 8 | ## Copyright (C) 2005-2012 Randy Dunlap ## |
| 9 | ## Copyright (C) 2012 Dan Luedtke ## | ||
| 9 | ## ## | 10 | ## ## |
| 10 | ## #define enhancements by Armin Kuster <akuster@mvista.com> ## | 11 | ## #define enhancements by Armin Kuster <akuster@mvista.com> ## |
| 11 | ## Copyright (c) 2000 MontaVista Software, Inc. ## | 12 | ## Copyright (c) 2000 MontaVista Software, Inc. ## |
| @@ -35,6 +36,8 @@ use strict; | |||
| 35 | # Small fixes (like spaces vs. \s in regex) | 36 | # Small fixes (like spaces vs. \s in regex) |
| 36 | # -- Tim Jansen <tim@tjansen.de> | 37 | # -- Tim Jansen <tim@tjansen.de> |
| 37 | 38 | ||
| 39 | # 25/07/2012 - Added support for HTML5 | ||
| 40 | # -- Dan Luedtke <mail@danrl.de> | ||
| 38 | 41 | ||
| 39 | # | 42 | # |
| 40 | # This will read a 'c' file and scan for embedded comments in the | 43 | # This will read a 'c' file and scan for embedded comments in the |
| @@ -44,12 +47,16 @@ use strict; | |||
| 44 | # Note: This only supports 'c'. | 47 | # Note: This only supports 'c'. |
| 45 | 48 | ||
| 46 | # usage: | 49 | # usage: |
| 47 | # kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] | 50 | # kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] |
| 48 | # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile | 51 | # [ -no-doc-sections ] |
| 52 | # [ -function funcname [ -function funcname ...] ] | ||
| 53 | # c file(s)s > outputfile | ||
| 49 | # or | 54 | # or |
| 50 | # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile | 55 | # [ -nofunction funcname [ -function funcname ...] ] |
| 56 | # c file(s)s > outputfile | ||
| 51 | # | 57 | # |
| 52 | # Set output format using one of -docbook -html -text or -man. Default is man. | 58 | # Set output format using one of -docbook -html -html5 -text or -man. |
| 59 | # Default is man. | ||
| 53 | # The -list format is for internal use by docproc. | 60 | # The -list format is for internal use by docproc. |
| 54 | # | 61 | # |
| 55 | # -no-doc-sections | 62 | # -no-doc-sections |
| @@ -182,6 +189,14 @@ my $local_lt = "\\\\\\\\lt:"; | |||
| 182 | my $local_gt = "\\\\\\\\gt:"; | 189 | my $local_gt = "\\\\\\\\gt:"; |
| 183 | my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" | 190 | my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" |
| 184 | 191 | ||
| 192 | # html version 5 | ||
| 193 | my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>", | ||
| 194 | $type_func, "<span class=\"func\">\$1</span>", | ||
| 195 | $type_struct_xml, "<span class=\"struct\">\$1</span>", | ||
| 196 | $type_env, "<span class=\"env\">\$1</span>", | ||
| 197 | $type_param, "<span class=\"param\">\$1</span>" ); | ||
| 198 | my $blankline_html5 = $local_lt . "br /" . $local_gt; | ||
| 199 | |||
| 185 | # XML, docbook format | 200 | # XML, docbook format |
| 186 | my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", | 201 | my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", |
| 187 | $type_constant, "<constant>\$1</constant>", | 202 | $type_constant, "<constant>\$1</constant>", |
| @@ -230,6 +245,7 @@ my $dohighlight = ""; | |||
| 230 | 245 | ||
| 231 | my $verbose = 0; | 246 | my $verbose = 0; |
| 232 | my $output_mode = "man"; | 247 | my $output_mode = "man"; |
| 248 | my $output_preformatted = 0; | ||
| 233 | my $no_doc_sections = 0; | 249 | my $no_doc_sections = 0; |
| 234 | my %highlights = %highlights_man; | 250 | my %highlights = %highlights_man; |
| 235 | my $blankline = $blankline_man; | 251 | my $blankline = $blankline_man; |
| @@ -280,9 +296,10 @@ my $doc_special = "\@\%\$\&"; | |||
| 280 | my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. | 296 | my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. |
| 281 | my $doc_end = '\*/'; | 297 | my $doc_end = '\*/'; |
| 282 | my $doc_com = '\s*\*\s*'; | 298 | my $doc_com = '\s*\*\s*'; |
| 299 | my $doc_com_body = '\s*\* ?'; | ||
| 283 | my $doc_decl = $doc_com . '(\w+)'; | 300 | my $doc_decl = $doc_com . '(\w+)'; |
| 284 | my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; | 301 | my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; |
| 285 | my $doc_content = $doc_com . '(.*)'; | 302 | my $doc_content = $doc_com_body . '(.*)'; |
| 286 | my $doc_block = $doc_com . 'DOC:\s*(.*)?'; | 303 | my $doc_block = $doc_com . 'DOC:\s*(.*)?'; |
| 287 | 304 | ||
| 288 | my %constants; | 305 | my %constants; |
| @@ -309,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { | |||
| 309 | $output_mode = "html"; | 326 | $output_mode = "html"; |
| 310 | %highlights = %highlights_html; | 327 | %highlights = %highlights_html; |
| 311 | $blankline = $blankline_html; | 328 | $blankline = $blankline_html; |
| 329 | } elsif ($cmd eq "-html5") { | ||
| 330 | $output_mode = "html5"; | ||
| 331 | %highlights = %highlights_html5; | ||
| 332 | $blankline = $blankline_html5; | ||
| 312 | } elsif ($cmd eq "-man") { | 333 | } elsif ($cmd eq "-man") { |
| 313 | $output_mode = "man"; | 334 | $output_mode = "man"; |
| 314 | %highlights = %highlights_man; | 335 | %highlights = %highlights_man; |
| @@ -351,10 +372,11 @@ while ($ARGV[0] =~ m/^-(.*)/) { | |||
| 351 | # continue execution near EOF; | 372 | # continue execution near EOF; |
| 352 | 373 | ||
| 353 | sub usage { | 374 | sub usage { |
| 354 | print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; | 375 | print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; |
| 355 | print " [ -no-doc-sections ]\n"; | 376 | print " [ -no-doc-sections ]\n"; |
| 356 | print " [ -function funcname [ -function funcname ...] ]\n"; | 377 | print " [ -function funcname [ -function funcname ...] ]\n"; |
| 357 | print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; | 378 | print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; |
| 379 | print " [ -v ]\n"; | ||
| 358 | print " c source file(s) > outputfile\n"; | 380 | print " c source file(s) > outputfile\n"; |
| 359 | print " -v : verbose output, more warnings & other info listed\n"; | 381 | print " -v : verbose output, more warnings & other info listed\n"; |
| 360 | exit 1; | 382 | exit 1; |
| @@ -448,7 +470,8 @@ sub output_highlight { | |||
| 448 | # confess "output_highlight got called with no args?\n"; | 470 | # confess "output_highlight got called with no args?\n"; |
| 449 | # } | 471 | # } |
| 450 | 472 | ||
| 451 | if ($output_mode eq "html" || $output_mode eq "xml") { | 473 | if ($output_mode eq "html" || $output_mode eq "html5" || |
| 474 | $output_mode eq "xml") { | ||
| 452 | $contents = local_unescape($contents); | 475 | $contents = local_unescape($contents); |
| 453 | # convert data read & converted thru xml_escape() into &xyz; format: | 476 | # convert data read & converted thru xml_escape() into &xyz; format: |
| 454 | $contents =~ s/\\\\\\/\&/g; | 477 | $contents =~ s/\\\\\\/\&/g; |
| @@ -458,9 +481,19 @@ sub output_highlight { | |||
| 458 | die $@ if $@; | 481 | die $@ if $@; |
| 459 | # print STDERR "contents af:$contents\n"; | 482 | # print STDERR "contents af:$contents\n"; |
| 460 | 483 | ||
| 484 | # strip whitespaces when generating html5 | ||
| 485 | if ($output_mode eq "html5") { | ||
| 486 | $contents =~ s/^\s+//; | ||
| 487 | $contents =~ s/\s+$//; | ||
| 488 | } | ||
| 461 | foreach $line (split "\n", $contents) { | 489 | foreach $line (split "\n", $contents) { |
| 490 | if (! $output_preformatted) { | ||
| 491 | $line =~ s/^\s*//; | ||
| 492 | } | ||
| 462 | if ($line eq ""){ | 493 | if ($line eq ""){ |
| 463 | print $lineprefix, local_unescape($blankline); | 494 | if (! $output_preformatted) { |
| 495 | print $lineprefix, local_unescape($blankline); | ||
| 496 | } | ||
| 464 | } else { | 497 | } else { |
| 465 | $line =~ s/\\\\\\/\&/g; | 498 | $line =~ s/\\\\\\/\&/g; |
| 466 | if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { | 499 | if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { |
| @@ -473,7 +506,7 @@ sub output_highlight { | |||
| 473 | } | 506 | } |
| 474 | } | 507 | } |
| 475 | 508 | ||
| 476 | #output sections in html | 509 | # output sections in html |
| 477 | sub output_section_html(%) { | 510 | sub output_section_html(%) { |
| 478 | my %args = %{$_[0]}; | 511 | my %args = %{$_[0]}; |
| 479 | my $section; | 512 | my $section; |
| @@ -633,6 +666,239 @@ sub output_blockhead_html(%) { | |||
| 633 | print "<hr>\n"; | 666 | print "<hr>\n"; |
| 634 | } | 667 | } |
| 635 | 668 | ||
| 669 | # output sections in html5 | ||
| 670 | sub output_section_html5(%) { | ||
| 671 | my %args = %{$_[0]}; | ||
| 672 | my $section; | ||
| 673 | |||
| 674 | foreach $section (@{$args{'sectionlist'}}) { | ||
| 675 | print "<section>\n"; | ||
| 676 | print "<h1>$section</h1>\n"; | ||
| 677 | print "<p>\n"; | ||
| 678 | output_highlight($args{'sections'}{$section}); | ||
| 679 | print "</p>\n"; | ||
| 680 | print "</section>\n"; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | # output enum in html5 | ||
| 685 | sub output_enum_html5(%) { | ||
| 686 | my %args = %{$_[0]}; | ||
| 687 | my ($parameter); | ||
| 688 | my $count; | ||
| 689 | my $html5id; | ||
| 690 | |||
| 691 | $html5id = $args{'enum'}; | ||
| 692 | $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; | ||
| 693 | print "<article class=\"enum\" id=\"enum:". $html5id . "\">"; | ||
| 694 | print "<h1>enum " . $args{'enum'} . "</h1>\n"; | ||
| 695 | print "<ol class=\"code\">\n"; | ||
| 696 | print "<li>"; | ||
| 697 | print "<span class=\"keyword\">enum</span> "; | ||
| 698 | print "<span class=\"identifier\">" . $args{'enum'} . "</span> {"; | ||
| 699 | print "</li>\n"; | ||
| 700 | $count = 0; | ||
| 701 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 702 | print "<li class=\"indent\">"; | ||
| 703 | print "<span class=\"param\">" . $parameter . "</span>"; | ||
| 704 | if ($count != $#{$args{'parameterlist'}}) { | ||
| 705 | $count++; | ||
| 706 | print ","; | ||
| 707 | } | ||
| 708 | print "</li>\n"; | ||
| 709 | } | ||
| 710 | print "<li>};</li>\n"; | ||
| 711 | print "</ol>\n"; | ||
| 712 | |||
| 713 | print "<section>\n"; | ||
| 714 | print "<h1>Constants</h1>\n"; | ||
| 715 | print "<dl>\n"; | ||
| 716 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 717 | print "<dt>" . $parameter . "</dt>\n"; | ||
| 718 | print "<dd>"; | ||
| 719 | output_highlight($args{'parameterdescs'}{$parameter}); | ||
| 720 | print "</dd>\n"; | ||
| 721 | } | ||
| 722 | print "</dl>\n"; | ||
| 723 | print "</section>\n"; | ||
| 724 | output_section_html5(@_); | ||
| 725 | print "</article>\n"; | ||
| 726 | } | ||
| 727 | |||
| 728 | # output typedef in html5 | ||
| 729 | sub output_typedef_html5(%) { | ||
| 730 | my %args = %{$_[0]}; | ||
| 731 | my ($parameter); | ||
| 732 | my $count; | ||
| 733 | my $html5id; | ||
| 734 | |||
| 735 | $html5id = $args{'typedef'}; | ||
| 736 | $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; | ||
| 737 | print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n"; | ||
| 738 | print "<h1>typedef " . $args{'typedef'} . "</h1>\n"; | ||
| 739 | |||
| 740 | print "<ol class=\"code\">\n"; | ||
| 741 | print "<li>"; | ||
| 742 | print "<span class=\"keyword\">typedef</span> "; | ||
| 743 | print "<span class=\"identifier\">" . $args{'typedef'} . "</span>"; | ||
| 744 | print "</li>\n"; | ||
| 745 | print "</ol>\n"; | ||
| 746 | output_section_html5(@_); | ||
| 747 | print "</article>\n"; | ||
| 748 | } | ||
| 749 | |||
| 750 | # output struct in html5 | ||
| 751 | sub output_struct_html5(%) { | ||
| 752 | my %args = %{$_[0]}; | ||
| 753 | my ($parameter); | ||
| 754 | my $html5id; | ||
| 755 | |||
| 756 | $html5id = $args{'struct'}; | ||
| 757 | $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; | ||
| 758 | print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n"; | ||
| 759 | print "<hgroup>\n"; | ||
| 760 | print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>"; | ||
| 761 | print "<h2>". $args{'purpose'} . "</h2>\n"; | ||
| 762 | print "</hgroup>\n"; | ||
| 763 | print "<ol class=\"code\">\n"; | ||
| 764 | print "<li>"; | ||
| 765 | print "<span class=\"type\">" . $args{'type'} . "</span> "; | ||
| 766 | print "<span class=\"identifier\">" . $args{'struct'} . "</span> {"; | ||
| 767 | print "</li>\n"; | ||
| 768 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 769 | print "<li class=\"indent\">"; | ||
| 770 | if ($parameter =~ /^#/) { | ||
| 771 | print "<span class=\"param\">" . $parameter ."</span>\n"; | ||
| 772 | print "</li>\n"; | ||
| 773 | next; | ||
| 774 | } | ||
| 775 | my $parameter_name = $parameter; | ||
| 776 | $parameter_name =~ s/\[.*//; | ||
| 777 | |||
| 778 | ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; | ||
| 779 | $type = $args{'parametertypes'}{$parameter}; | ||
| 780 | if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { | ||
| 781 | # pointer-to-function | ||
| 782 | print "<span class=\"type\">$1</span> "; | ||
| 783 | print "<span class=\"param\">$parameter</span>"; | ||
| 784 | print "<span class=\"type\">)</span> "; | ||
| 785 | print "(<span class=\"args\">$2</span>);"; | ||
| 786 | } elsif ($type =~ m/^(.*?)\s*(:.*)/) { | ||
| 787 | # bitfield | ||
| 788 | print "<span class=\"type\">$1</span> "; | ||
| 789 | print "<span class=\"param\">$parameter</span>"; | ||
| 790 | print "<span class=\"bits\">$2</span>;"; | ||
| 791 | } else { | ||
| 792 | print "<span class=\"type\">$type</span> "; | ||
| 793 | print "<span class=\"param\">$parameter</span>;"; | ||
| 794 | } | ||
| 795 | print "</li>\n"; | ||
| 796 | } | ||
| 797 | print "<li>};</li>\n"; | ||
| 798 | print "</ol>\n"; | ||
| 799 | |||
| 800 | print "<section>\n"; | ||
| 801 | print "<h1>Members</h1>\n"; | ||
| 802 | print "<dl>\n"; | ||
| 803 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 804 | ($parameter =~ /^#/) && next; | ||
| 805 | |||
| 806 | my $parameter_name = $parameter; | ||
| 807 | $parameter_name =~ s/\[.*//; | ||
| 808 | |||
| 809 | ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; | ||
| 810 | print "<dt>" . $parameter . "</dt>\n"; | ||
| 811 | print "<dd>"; | ||
| 812 | output_highlight($args{'parameterdescs'}{$parameter_name}); | ||
| 813 | print "</dd>\n"; | ||
| 814 | } | ||
| 815 | print "</dl>\n"; | ||
| 816 | print "</section>\n"; | ||
| 817 | output_section_html5(@_); | ||
| 818 | print "</article>\n"; | ||
| 819 | } | ||
| 820 | |||
| 821 | # output function in html5 | ||
| 822 | sub output_function_html5(%) { | ||
| 823 | my %args = %{$_[0]}; | ||
| 824 | my ($parameter, $section); | ||
| 825 | my $count; | ||
| 826 | my $html5id; | ||
| 827 | |||
| 828 | $html5id = $args{'function'}; | ||
| 829 | $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; | ||
| 830 | print "<article class=\"function\" id=\"func:". $html5id . "\">\n"; | ||
| 831 | print "<hgroup>\n"; | ||
| 832 | print "<h1>" . $args{'function'} . "</h1>"; | ||
| 833 | print "<h2>" . $args{'purpose'} . "</h2>\n"; | ||
| 834 | print "</hgroup>\n"; | ||
| 835 | print "<ol class=\"code\">\n"; | ||
| 836 | print "<li>"; | ||
| 837 | print "<span class=\"type\">" . $args{'functiontype'} . "</span> "; | ||
| 838 | print "<span class=\"identifier\">" . $args{'function'} . "</span> ("; | ||
| 839 | print "</li>"; | ||
| 840 | $count = 0; | ||
| 841 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 842 | print "<li class=\"indent\">"; | ||
| 843 | $type = $args{'parametertypes'}{$parameter}; | ||
| 844 | if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { | ||
| 845 | # pointer-to-function | ||
| 846 | print "<span class=\"type\">$1</span> "; | ||
| 847 | print "<span class=\"param\">$parameter</span>"; | ||
| 848 | print "<span class=\"type\">)</span> "; | ||
| 849 | print "(<span class=\"args\">$2</span>)"; | ||
| 850 | } else { | ||
| 851 | print "<span class=\"type\">$type</span> "; | ||
| 852 | print "<span class=\"param\">$parameter</span>"; | ||
| 853 | } | ||
| 854 | if ($count != $#{$args{'parameterlist'}}) { | ||
| 855 | $count++; | ||
| 856 | print ","; | ||
| 857 | } | ||
| 858 | print "</li>\n"; | ||
| 859 | } | ||
| 860 | print "<li>)</li>\n"; | ||
| 861 | print "</ol>\n"; | ||
| 862 | |||
| 863 | print "<section>\n"; | ||
| 864 | print "<h1>Arguments</h1>\n"; | ||
| 865 | print "<p>\n"; | ||
| 866 | print "<dl>\n"; | ||
| 867 | foreach $parameter (@{$args{'parameterlist'}}) { | ||
| 868 | my $parameter_name = $parameter; | ||
| 869 | $parameter_name =~ s/\[.*//; | ||
| 870 | |||
| 871 | ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; | ||
| 872 | print "<dt>" . $parameter . "</dt>\n"; | ||
| 873 | print "<dd>"; | ||
| 874 | output_highlight($args{'parameterdescs'}{$parameter_name}); | ||
| 875 | print "</dd>\n"; | ||
| 876 | } | ||
| 877 | print "</dl>\n"; | ||
| 878 | print "</section>\n"; | ||
| 879 | output_section_html5(@_); | ||
| 880 | print "</article>\n"; | ||
| 881 | } | ||
| 882 | |||
| 883 | # output DOC: block header in html5 | ||
| 884 | sub output_blockhead_html5(%) { | ||
| 885 | my %args = %{$_[0]}; | ||
| 886 | my ($parameter, $section); | ||
| 887 | my $count; | ||
| 888 | my $html5id; | ||
| 889 | |||
| 890 | foreach $section (@{$args{'sectionlist'}}) { | ||
| 891 | $html5id = $section; | ||
| 892 | $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; | ||
| 893 | print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n"; | ||
| 894 | print "<h1>$section</h1>\n"; | ||
| 895 | print "<p>\n"; | ||
| 896 | output_highlight($args{'sections'}{$section}); | ||
| 897 | print "</p>\n"; | ||
| 898 | } | ||
| 899 | print "</article>\n"; | ||
| 900 | } | ||
| 901 | |||
| 636 | sub output_section_xml(%) { | 902 | sub output_section_xml(%) { |
| 637 | my %args = %{$_[0]}; | 903 | my %args = %{$_[0]}; |
| 638 | my $section; | 904 | my $section; |
| @@ -643,10 +909,12 @@ sub output_section_xml(%) { | |||
| 643 | print "<title>$section</title>\n"; | 909 | print "<title>$section</title>\n"; |
| 644 | if ($section =~ m/EXAMPLE/i) { | 910 | if ($section =~ m/EXAMPLE/i) { |
| 645 | print "<informalexample><programlisting>\n"; | 911 | print "<informalexample><programlisting>\n"; |
| 912 | $output_preformatted = 1; | ||
| 646 | } else { | 913 | } else { |
| 647 | print "<para>\n"; | 914 | print "<para>\n"; |
| 648 | } | 915 | } |
| 649 | output_highlight($args{'sections'}{$section}); | 916 | output_highlight($args{'sections'}{$section}); |
| 917 | $output_preformatted = 0; | ||
| 650 | if ($section =~ m/EXAMPLE/i) { | 918 | if ($section =~ m/EXAMPLE/i) { |
| 651 | print "</programlisting></informalexample>\n"; | 919 | print "</programlisting></informalexample>\n"; |
| 652 | } else { | 920 | } else { |
| @@ -949,10 +1217,12 @@ sub output_blockhead_xml(%) { | |||
| 949 | } | 1217 | } |
| 950 | if ($section =~ m/EXAMPLE/i) { | 1218 | if ($section =~ m/EXAMPLE/i) { |
| 951 | print "<example><para>\n"; | 1219 | print "<example><para>\n"; |
| 1220 | $output_preformatted = 1; | ||
| 952 | } else { | 1221 | } else { |
| 953 | print "<para>\n"; | 1222 | print "<para>\n"; |
| 954 | } | 1223 | } |
| 955 | output_highlight($args{'sections'}{$section}); | 1224 | output_highlight($args{'sections'}{$section}); |
| 1225 | $output_preformatted = 0; | ||
| 956 | if ($section =~ m/EXAMPLE/i) { | 1226 | if ($section =~ m/EXAMPLE/i) { |
| 957 | print "</para></example>\n"; | 1227 | print "</para></example>\n"; |
| 958 | } else { | 1228 | } else { |
| @@ -1028,10 +1298,12 @@ sub output_function_gnome { | |||
| 1028 | print "<simplesect>\n <title>$section</title>\n"; | 1298 | print "<simplesect>\n <title>$section</title>\n"; |
| 1029 | if ($section =~ m/EXAMPLE/i) { | 1299 | if ($section =~ m/EXAMPLE/i) { |
| 1030 | print "<example><programlisting>\n"; | 1300 | print "<example><programlisting>\n"; |
| 1301 | $output_preformatted = 1; | ||
| 1031 | } else { | 1302 | } else { |
| 1032 | } | 1303 | } |
| 1033 | print "<para>\n"; | 1304 | print "<para>\n"; |
| 1034 | output_highlight($args{'sections'}{$section}); | 1305 | output_highlight($args{'sections'}{$section}); |
| 1306 | $output_preformatted = 0; | ||
| 1035 | print "</para>\n"; | 1307 | print "</para>\n"; |
| 1036 | if ($section =~ m/EXAMPLE/i) { | 1308 | if ($section =~ m/EXAMPLE/i) { |
| 1037 | print "</programlisting></example>\n"; | 1309 | print "</programlisting></example>\n"; |
| @@ -2046,6 +2318,9 @@ sub process_file($) { | |||
| 2046 | 2318 | ||
| 2047 | $section_counter = 0; | 2319 | $section_counter = 0; |
| 2048 | while (<IN>) { | 2320 | while (<IN>) { |
| 2321 | while (s/\\\s*$//) { | ||
| 2322 | $_ .= <IN>; | ||
| 2323 | } | ||
| 2049 | if ($state == 0) { | 2324 | if ($state == 0) { |
| 2050 | if (/$doc_start/o) { | 2325 | if (/$doc_start/o) { |
| 2051 | $state = 1; # next line is always the function name | 2326 | $state = 1; # next line is always the function name |
| @@ -2073,7 +2348,7 @@ sub process_file($) { | |||
| 2073 | $descr= $1; | 2348 | $descr= $1; |
| 2074 | $descr =~ s/^\s*//; | 2349 | $descr =~ s/^\s*//; |
| 2075 | $descr =~ s/\s*$//; | 2350 | $descr =~ s/\s*$//; |
| 2076 | $descr =~ s/\s+/ /; | 2351 | $descr =~ s/\s+/ /g; |
| 2077 | $declaration_purpose = xml_escape($descr); | 2352 | $declaration_purpose = xml_escape($descr); |
| 2078 | $in_purpose = 1; | 2353 | $in_purpose = 1; |
| 2079 | } else { | 2354 | } else { |
| @@ -2165,6 +2440,7 @@ sub process_file($) { | |||
| 2165 | # Continued declaration purpose | 2440 | # Continued declaration purpose |
| 2166 | chomp($declaration_purpose); | 2441 | chomp($declaration_purpose); |
| 2167 | $declaration_purpose .= " " . xml_escape($1); | 2442 | $declaration_purpose .= " " . xml_escape($1); |
| 2443 | $declaration_purpose =~ s/\s+/ /g; | ||
| 2168 | } else { | 2444 | } else { |
| 2169 | $contents .= $1 . "\n"; | 2445 | $contents .= $1 . "\n"; |
| 2170 | } | 2446 | } |
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 68e9f5ed0a6f..0d93856a03f4 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
| @@ -821,12 +821,15 @@ static const char *section_white_list[] = | |||
| 821 | ".debug*", | 821 | ".debug*", |
| 822 | ".zdebug*", /* Compressed debug sections. */ | 822 | ".zdebug*", /* Compressed debug sections. */ |
| 823 | ".GCC-command-line", /* mn10300 */ | 823 | ".GCC-command-line", /* mn10300 */ |
| 824 | ".GCC.command.line", /* record-gcc-switches, non mn10300 */ | ||
| 824 | ".mdebug*", /* alpha, score, mips etc. */ | 825 | ".mdebug*", /* alpha, score, mips etc. */ |
| 825 | ".pdr", /* alpha, score, mips etc. */ | 826 | ".pdr", /* alpha, score, mips etc. */ |
| 826 | ".stab*", | 827 | ".stab*", |
| 827 | ".note*", | 828 | ".note*", |
| 828 | ".got*", | 829 | ".got*", |
| 829 | ".toc*", | 830 | ".toc*", |
| 831 | ".xt.prop", /* xtensa */ | ||
| 832 | ".xt.lit", /* xtensa */ | ||
| 830 | NULL | 833 | NULL |
| 831 | }; | 834 | }; |
| 832 | 835 | ||
diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 8a7b15598ea9..62d8234f8787 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar | |||
| @@ -28,15 +28,15 @@ case "${1}" in | |||
| 28 | file_ext="" | 28 | file_ext="" |
| 29 | ;; | 29 | ;; |
| 30 | targz-pkg) | 30 | targz-pkg) |
| 31 | compress="gzip -c9" | 31 | compress="gzip" |
| 32 | file_ext=".gz" | 32 | file_ext=".gz" |
| 33 | ;; | 33 | ;; |
| 34 | tarbz2-pkg) | 34 | tarbz2-pkg) |
| 35 | compress="bzip2 -c9" | 35 | compress="bzip2" |
| 36 | file_ext=".bz2" | 36 | file_ext=".bz2" |
| 37 | ;; | 37 | ;; |
| 38 | tarxz-pkg) | 38 | tarxz-pkg) |
| 39 | compress="xz -c9" | 39 | compress="xz" |
| 40 | file_ext=".xz" | 40 | file_ext=".xz" |
| 41 | ;; | 41 | ;; |
| 42 | *) | 42 | *) |
| @@ -109,7 +109,7 @@ esac | |||
| 109 | if tar --owner=root --group=root --help >/dev/null 2>&1; then | 109 | if tar --owner=root --group=root --help >/dev/null 2>&1; then |
| 110 | opts="--owner=root --group=root" | 110 | opts="--owner=root --group=root" |
| 111 | fi | 111 | fi |
| 112 | tar cf - . $opts | ${compress} > "${tarball}${file_ext}" | 112 | tar cf - boot/* lib/* $opts | ${compress} > "${tarball}${file_ext}" |
| 113 | ) | 113 | ) |
| 114 | 114 | ||
| 115 | echo "Tarball successfully created in ${tarball}${file_ext}" | 115 | echo "Tarball successfully created in ${tarball}${file_ext}" |
diff --git a/scripts/sign-file b/scripts/sign-file new file mode 100644 index 000000000000..e58e34e50ac5 --- /dev/null +++ b/scripts/sign-file | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # | ||
| 3 | # Sign a module file using the given key. | ||
| 4 | # | ||
| 5 | # Format: sign-file <key> <x509> <src-file> <dst-file> | ||
| 6 | # | ||
| 7 | |||
| 8 | scripts=`dirname $0` | ||
| 9 | |||
| 10 | CONFIG_MODULE_SIG_SHA512=y | ||
| 11 | if [ -r .config ] | ||
| 12 | then | ||
| 13 | . ./.config | ||
| 14 | fi | ||
| 15 | |||
| 16 | key="$1" | ||
| 17 | x509="$2" | ||
| 18 | src="$3" | ||
| 19 | dst="$4" | ||
| 20 | |||
| 21 | if [ ! -r "$key" ] | ||
| 22 | then | ||
| 23 | echo "Can't read private key" >&2 | ||
| 24 | exit 2 | ||
| 25 | fi | ||
| 26 | |||
| 27 | if [ ! -r "$x509" ] | ||
| 28 | then | ||
| 29 | echo "Can't read X.509 certificate" >&2 | ||
| 30 | exit 2 | ||
| 31 | fi | ||
| 32 | if [ ! -r "$x509.signer" ] | ||
| 33 | then | ||
| 34 | echo "Can't read Signer name" >&2 | ||
| 35 | exit 2; | ||
| 36 | fi | ||
| 37 | if [ ! -r "$x509.keyid" ] | ||
| 38 | then | ||
| 39 | echo "Can't read Key identifier" >&2 | ||
| 40 | exit 2; | ||
| 41 | fi | ||
| 42 | |||
| 43 | # | ||
| 44 | # Signature parameters | ||
| 45 | # | ||
| 46 | algo=1 # Public-key crypto algorithm: RSA | ||
| 47 | hash= # Digest algorithm | ||
| 48 | id_type=1 # Identifier type: X.509 | ||
| 49 | |||
| 50 | # | ||
| 51 | # Digest the data | ||
| 52 | # | ||
| 53 | dgst= | ||
| 54 | if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ] | ||
| 55 | then | ||
| 56 | prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14" | ||
| 57 | dgst=-sha1 | ||
| 58 | hash=2 | ||
| 59 | elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ] | ||
| 60 | then | ||
| 61 | prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C" | ||
| 62 | dgst=-sha224 | ||
| 63 | hash=7 | ||
| 64 | elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ] | ||
| 65 | then | ||
| 66 | prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20" | ||
| 67 | dgst=-sha256 | ||
| 68 | hash=4 | ||
| 69 | elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ] | ||
| 70 | then | ||
| 71 | prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30" | ||
| 72 | dgst=-sha384 | ||
| 73 | hash=5 | ||
| 74 | elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ] | ||
| 75 | then | ||
| 76 | prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40" | ||
| 77 | dgst=-sha512 | ||
| 78 | hash=6 | ||
| 79 | else | ||
| 80 | echo "$0: Can't determine hash algorithm" >&2 | ||
| 81 | exit 2 | ||
| 82 | fi | ||
| 83 | |||
| 84 | ( | ||
| 85 | perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $? | ||
| 86 | openssl dgst $dgst -binary $src || exit $? | ||
| 87 | ) >$src.dig || exit $? | ||
| 88 | |||
| 89 | # | ||
| 90 | # Generate the binary signature, which will be just the integer that comprises | ||
| 91 | # the signature with no metadata attached. | ||
| 92 | # | ||
| 93 | openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $? | ||
| 94 | signerlen=`stat -c %s $x509.signer` | ||
| 95 | keyidlen=`stat -c %s $x509.keyid` | ||
| 96 | siglen=`stat -c %s $src.sig` | ||
| 97 | |||
| 98 | # | ||
| 99 | # Build the signed binary | ||
| 100 | # | ||
| 101 | ( | ||
| 102 | cat $src || exit $? | ||
| 103 | echo '~Module signature appended~' || exit $? | ||
| 104 | cat $x509.signer $x509.keyid || exit $? | ||
| 105 | |||
| 106 | # Preface each signature integer with a 2-byte BE length | ||
| 107 | perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $? | ||
| 108 | cat $src.sig || exit $? | ||
| 109 | |||
| 110 | # Generate the information block | ||
| 111 | perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $? | ||
| 112 | ) >$dst~ || exit $? | ||
| 113 | |||
| 114 | # Permit in-place signing | ||
| 115 | mv $dst~ $dst || exit $? | ||
diff --git a/scripts/tags.sh b/scripts/tags.sh index cff8faad73d1..79fdafb0d263 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh | |||
| @@ -154,7 +154,9 @@ exuberant() | |||
| 154 | --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ | 154 | --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ |
| 155 | --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ | 155 | --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ |
| 156 | --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ | 156 | --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ |
| 157 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' | 157 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ |
| 158 | --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ | ||
| 159 | --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' | ||
| 158 | 160 | ||
| 159 | all_kconfigs | xargs $1 -a \ | 161 | all_kconfigs | xargs $1 -a \ |
| 160 | --langdef=kconfig --language-force=kconfig \ | 162 | --langdef=kconfig --language-force=kconfig \ |
| @@ -197,7 +199,9 @@ emacs() | |||
| 197 | --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ | 199 | --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ |
| 198 | --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ | 200 | --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ |
| 199 | --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ | 201 | --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ |
| 200 | --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' | 202 | --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ |
| 203 | --regex='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ | ||
| 204 | --regex='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' | ||
| 201 | 205 | ||
| 202 | all_kconfigs | xargs $1 -a \ | 206 | all_kconfigs | xargs $1 -a \ |
| 203 | --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' | 207 | --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' |
diff --git a/scripts/x509keyid b/scripts/x509keyid new file mode 100755 index 000000000000..c8e91a4af385 --- /dev/null +++ b/scripts/x509keyid | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | #!/usr/bin/perl -w | ||
| 2 | # | ||
| 3 | # Generate an identifier from an X.509 certificate that can be placed in a | ||
| 4 | # module signature to indentify the key to use. | ||
| 5 | # | ||
| 6 | # Format: | ||
| 7 | # | ||
| 8 | # ./scripts/x509keyid <x509-cert> <signer's-name> <key-id> | ||
| 9 | # | ||
| 10 | # We read the DER-encoded X509 certificate and parse it to extract the Subject | ||
| 11 | # name and Subject Key Identifier. The provide the data we need to build the | ||
| 12 | # certificate identifier. | ||
| 13 | # | ||
| 14 | # The signer's name part of the identifier is fabricated from the commonName, | ||
| 15 | # the organizationName or the emailAddress components of the X.509 subject | ||
| 16 | # name and written to the second named file. | ||
| 17 | # | ||
| 18 | # The subject key ID to select which of that signer's certificates we're | ||
| 19 | # intending to use to sign the module is written to the third named file. | ||
| 20 | # | ||
| 21 | use strict; | ||
| 22 | |||
| 23 | my $raw_data; | ||
| 24 | |||
| 25 | die "Need three filenames\n" if ($#ARGV != 2); | ||
| 26 | |||
| 27 | my $src = $ARGV[0]; | ||
| 28 | |||
| 29 | open(FD, "<$src") || die $src; | ||
| 30 | binmode FD; | ||
| 31 | my @st = stat(FD); | ||
| 32 | die $src if (!@st); | ||
| 33 | read(FD, $raw_data, $st[7]) || die $src; | ||
| 34 | close(FD); | ||
| 35 | |||
| 36 | my $UNIV = 0 << 6; | ||
| 37 | my $APPL = 1 << 6; | ||
| 38 | my $CONT = 2 << 6; | ||
| 39 | my $PRIV = 3 << 6; | ||
| 40 | |||
| 41 | my $CONS = 0x20; | ||
| 42 | |||
| 43 | my $BOOLEAN = 0x01; | ||
| 44 | my $INTEGER = 0x02; | ||
| 45 | my $BIT_STRING = 0x03; | ||
| 46 | my $OCTET_STRING = 0x04; | ||
| 47 | my $NULL = 0x05; | ||
| 48 | my $OBJ_ID = 0x06; | ||
| 49 | my $UTF8String = 0x0c; | ||
| 50 | my $SEQUENCE = 0x10; | ||
| 51 | my $SET = 0x11; | ||
| 52 | my $UTCTime = 0x17; | ||
| 53 | my $GeneralizedTime = 0x18; | ||
| 54 | |||
| 55 | my %OIDs = ( | ||
| 56 | pack("CCC", 85, 4, 3) => "commonName", | ||
| 57 | pack("CCC", 85, 4, 6) => "countryName", | ||
| 58 | pack("CCC", 85, 4, 10) => "organizationName", | ||
| 59 | pack("CCC", 85, 4, 11) => "organizationUnitName", | ||
| 60 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", | ||
| 61 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", | ||
| 62 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", | ||
| 63 | pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", | ||
| 64 | pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", | ||
| 65 | pack("CCC", 85, 29, 19) => "basicConstraints" | ||
| 66 | ); | ||
| 67 | |||
| 68 | ############################################################################### | ||
| 69 | # | ||
| 70 | # Extract an ASN.1 element from a string and return information about it. | ||
| 71 | # | ||
| 72 | ############################################################################### | ||
| 73 | sub asn1_extract($$@) | ||
| 74 | { | ||
| 75 | my ($cursor, $expected_tag, $optional) = @_; | ||
| 76 | |||
| 77 | return [ -1 ] | ||
| 78 | if ($cursor->[1] == 0 && $optional); | ||
| 79 | |||
| 80 | die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" | ||
| 81 | if ($cursor->[1] < 2); | ||
| 82 | |||
| 83 | my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 84 | |||
| 85 | if ($expected_tag != -1 && $tag != $expected_tag) { | ||
| 86 | return [ -1 ] | ||
| 87 | if ($optional); | ||
| 88 | die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, | ||
| 89 | " not ", $expected_tag, ")\n"; | ||
| 90 | } | ||
| 91 | |||
| 92 | $cursor->[0] += 2; | ||
| 93 | $cursor->[1] -= 2; | ||
| 94 | |||
| 95 | die $src, ": ", $cursor->[0], ": ASN.1 long tag\n" | ||
| 96 | if (($tag & 0x1f) == 0x1f); | ||
| 97 | die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n" | ||
| 98 | if ($len == 0x80); | ||
| 99 | |||
| 100 | if ($len > 0x80) { | ||
| 101 | my $l = $len - 0x80; | ||
| 102 | die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" | ||
| 103 | if ($cursor->[1] < $l); | ||
| 104 | |||
| 105 | if ($l == 0x1) { | ||
| 106 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); | ||
| 107 | } elsif ($l = 0x2) { | ||
| 108 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 109 | } elsif ($l = 0x3) { | ||
| 110 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; | ||
| 111 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); | ||
| 112 | } elsif ($l = 0x4) { | ||
| 113 | $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); | ||
| 114 | } else { | ||
| 115 | die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; | ||
| 116 | } | ||
| 117 | |||
| 118 | $cursor->[0] += $l; | ||
| 119 | $cursor->[1] -= $l; | ||
| 120 | } | ||
| 121 | |||
| 122 | die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" | ||
| 123 | if ($cursor->[1] < $len); | ||
| 124 | |||
| 125 | my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; | ||
| 126 | $cursor->[0] += $len; | ||
| 127 | $cursor->[1] -= $len; | ||
| 128 | |||
| 129 | return $ret; | ||
| 130 | } | ||
| 131 | |||
| 132 | ############################################################################### | ||
| 133 | # | ||
| 134 | # Retrieve the data referred to by a cursor | ||
| 135 | # | ||
| 136 | ############################################################################### | ||
| 137 | sub asn1_retrieve($) | ||
| 138 | { | ||
| 139 | my ($cursor) = @_; | ||
| 140 | my ($offset, $len, $data) = @$cursor; | ||
| 141 | return substr($$data, $offset, $len); | ||
| 142 | } | ||
| 143 | |||
| 144 | ############################################################################### | ||
| 145 | # | ||
| 146 | # Roughly parse the X.509 certificate | ||
| 147 | # | ||
| 148 | ############################################################################### | ||
| 149 | my $cursor = [ 0, length($raw_data), \$raw_data ]; | ||
| 150 | |||
| 151 | my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); | ||
| 152 | my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 153 | my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); | ||
| 154 | my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); | ||
| 155 | my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 156 | my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 157 | my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 158 | my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 159 | my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 160 | my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); | ||
| 161 | my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); | ||
| 162 | my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); | ||
| 163 | |||
| 164 | my $subject_key_id = (); | ||
| 165 | my $authority_key_id = (); | ||
| 166 | |||
| 167 | # | ||
| 168 | # Parse the extension list | ||
| 169 | # | ||
| 170 | if ($extension_list->[0] != -1) { | ||
| 171 | my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 172 | |||
| 173 | while ($extensions->[1]->[1] > 0) { | ||
| 174 | my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 175 | my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); | ||
| 176 | my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); | ||
| 177 | my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); | ||
| 178 | |||
| 179 | my $raw_oid = asn1_retrieve($x_oid->[1]); | ||
| 180 | next if (!exists($OIDs{$raw_oid})); | ||
| 181 | my $x_type = $OIDs{$raw_oid}; | ||
| 182 | |||
| 183 | my $raw_value = asn1_retrieve($x_val->[1]); | ||
| 184 | |||
| 185 | if ($x_type eq "subjectKeyIdentifier") { | ||
| 186 | my $vcursor = [ 0, length($raw_value), \$raw_value ]; | ||
| 187 | |||
| 188 | $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | ############################################################################### | ||
| 194 | # | ||
| 195 | # Determine what we're going to use as the signer's name. In order of | ||
| 196 | # preference, take one of: commonName, organizationName or emailAddress. | ||
| 197 | # | ||
| 198 | ############################################################################### | ||
| 199 | my $org = ""; | ||
| 200 | my $cn = ""; | ||
| 201 | my $email = ""; | ||
| 202 | |||
| 203 | while ($subject->[1]->[1] > 0) { | ||
| 204 | my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); | ||
| 205 | my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 206 | my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); | ||
| 207 | my $n_val = asn1_extract($attr->[1], -1); | ||
| 208 | |||
| 209 | my $raw_oid = asn1_retrieve($n_oid->[1]); | ||
| 210 | next if (!exists($OIDs{$raw_oid})); | ||
| 211 | my $n_type = $OIDs{$raw_oid}; | ||
| 212 | |||
| 213 | my $raw_value = asn1_retrieve($n_val->[1]); | ||
| 214 | |||
| 215 | if ($n_type eq "organizationName") { | ||
| 216 | $org = $raw_value; | ||
| 217 | } elsif ($n_type eq "commonName") { | ||
| 218 | $cn = $raw_value; | ||
| 219 | } elsif ($n_type eq "emailAddress") { | ||
| 220 | $email = $raw_value; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | my $id_name = $email; | ||
| 225 | |||
| 226 | if ($org && $cn) { | ||
| 227 | # Don't use the organizationName if the commonName repeats it | ||
| 228 | if (length($org) <= length($cn) && | ||
| 229 | substr($cn, 0, length($org)) eq $org) { | ||
| 230 | $id_name = $cn; | ||
| 231 | goto got_id_name; | ||
| 232 | } | ||
| 233 | |||
| 234 | # Or a signifcant chunk of it | ||
| 235 | if (length($org) >= 7 && | ||
| 236 | length($cn) >= 7 && | ||
| 237 | substr($cn, 0, 7) eq substr($org, 0, 7)) { | ||
| 238 | $id_name = $cn; | ||
| 239 | goto got_id_name; | ||
| 240 | } | ||
| 241 | |||
| 242 | $id_name = $org . ": " . $cn; | ||
| 243 | } elsif ($org) { | ||
| 244 | $id_name = $org; | ||
| 245 | } elsif ($cn) { | ||
| 246 | $id_name = $cn; | ||
| 247 | } | ||
| 248 | |||
| 249 | got_id_name: | ||
| 250 | |||
| 251 | ############################################################################### | ||
| 252 | # | ||
| 253 | # Output the signer's name and the key identifier that we're going to include | ||
| 254 | # in module signatures. | ||
| 255 | # | ||
| 256 | ############################################################################### | ||
| 257 | die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" | ||
| 258 | if (!$subject_key_id); | ||
| 259 | |||
| 260 | my $id_key_id = asn1_retrieve($subject_key_id->[1]); | ||
| 261 | |||
| 262 | open(OUTFD, ">$ARGV[1]") || die $ARGV[1]; | ||
| 263 | print OUTFD $id_name; | ||
| 264 | close OUTFD || die $ARGV[1]; | ||
| 265 | |||
| 266 | open(OUTFD, ">$ARGV[2]") || die $ARGV[2]; | ||
| 267 | print OUTFD $id_key_id; | ||
| 268 | close OUTFD || die $ARGV[2]; | ||
