Files
scst/scripts/specialize-patch
Bart Van Assche 74e73e3694 Merge trunk r6221 into iser branch
git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@6222 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2015-06-09 00:32:21 +00:00

615 lines
18 KiB
Awk
Executable File

#!/usr/bin/gawk -f
############################################################################
#
# Script that removes preprocessor checks on the kernel version. Somewhat
# related to the v4l-scripts-gentree.pl script.
#
# Copyright (C) 2008-2009 Bart Van Assche <bvanassche@acm.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, version 2
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
############################################################################
# Usage:
# * Specify the kernel version code as follows: -v kernel_version=...
# * Provide the patch to be processed to stdin.
#
# The output of this script will be a patch that is specialized for the
# specified kernel version.
# Convert a kernel version in the x.y.z format into numeric form, just like
# the KERNEL_VERSION() macro.
function version_code(kver, array) {
if (!match(kver, "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$", array))
match(kver, "^([0-9]+)\\.([0-9]+)$", array)
return 65536*array[1] + 256*array[2] + array[3]
}
# Evaluate a preprocessor statement via repeated substitutions.
# Mathematicians call this algorithm 'term rewriting'.
# Note: the order in which the substitutions appear below is important --
# it is the same order as the order of operators in C.
function evaluate(stmnt, pattern, arg, op, result) {
if (debug)
printf "/* debug specialize-patch: (a) %s */\n", stmnt
# Remove C-style comments.
gsub("[[:blank:]]*\\/\\*[^*]*\\*\\/[[:blank:]]*", "", stmnt)
# Remove the spaces before the #-sign.
gsub("^+[[:blank:]]*#[[:blank:]]*", "+#", stmnt)
if (match(stmnt, "^+#ifdef (.*)$", arg))
{
stmnt = "+#if defined(" arg[1] ")"
}
if (match(stmnt, "^+#ifndef (.*)$", arg))
{
stmnt = "+#if !defined(" arg[1] ")"
}
gsub("LINUX_VERSION_CODE", LINUX_VERSION_CODE, stmnt)
pattern="KERNEL_VERSION\\([[:blank:]]*([0-9]+)[[:blank:]]*,[[:blank:]]*([0-9]+)[[:blank:]]*,[[:blank:]]*([0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] * 65536 + op[2] * 256 + op[3], stmnt)
}
gsub("defined\\(INSIDE_KERNEL_TREE\\)", "1", stmnt)
gsub("defined\\(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19\\)", "0", stmnt)
gsub("defined\\(CONFIG_SUSE_KERNEL\\)", "0", stmnt)
if (RHEL_MAJOR == "")
{
gsub("defined\\(RHEL_MAJOR\\)", "0", stmnt)
gsub("RHEL_MAJOR", "", stmnt)
}
else
{
gsub("defined\\(RHEL_MAJOR\\)", "1", stmnt)
gsub("RHEL_MAJOR", RHEL_MAJOR, stmnt)
}
if (RHEL_MINOR == "")
{
gsub("defined\\(RHEL_MINOR\\)", "0", stmnt)
gsub("RHEL_MINOR", "0", stmnt)
}
else
{
gsub("defined\\(RHEL_MINOR\\)", "1", stmnt)
gsub("RHEL_MINOR", RHEL_MINOR, stmnt)
}
gsub("defined\\(RHEL_RELEASE_VERSION\\)", "1", stmnt)
if (RHEL_MAJOR == "" || RHEL_MINOR == "")
{
gsub("defined\\(RHEL_RELEASE_CODE\\)", "0", stmnt)
gsub("RHEL_RELEASE_CODE", "", stmnt)
gsub("RHEL_RELEASE_VERSION\\([^,)]*,[ ]*[^,)]*\\)", "0", stmnt)
}
else
{
gsub("defined\\(RHEL_RELEASE_CODE\\)", "1", stmnt)
gsub("RHEL_RELEASE_CODE", RHEL_MAJOR * 256 + RHEL_MINOR, stmnt)
stmnt = gensub("RHEL_RELEASE_VERSION\\(([^,)]*),[ ]*([^,)]*)\\)",
"(\\1) * 256 + (\\2)", "g", stmnt)
}
if (SCSI_EXEC_REQ_FIFO_DEFINED != "")
{
gsub("defined[[:blank:]]+SCSI_EXEC_REQ_FIFO_DEFINED",
SCSI_EXEC_REQ_FIFO_DEFINED, stmnt)
gsub("defined[[:blank:]]*\\([[:blank:]]*SCSI_EXEC_REQ_FIFO_DEFINED[[:blank:]]*\\)",
SCSI_EXEC_REQ_FIFO_DEFINED, stmnt)
}
if (SCST_IO_CONTEXT != "")
{
gsub("defined[[:blank:]]+SCST_IO_CONTEXT", SCST_IO_CONTEXT, stmnt)
gsub("defined[[:blank:]]*\\([[:blank:]]*SCST_IO_CONTEXT[[:blank:]]*\\)", SCST_IO_CONTEXT, stmnt)
}
if (generating_upstream_patch_defined)
{
gsub("defined[[:blank:]]+GENERATING_UPSTREAM_PATCH", 1, stmnt)
gsub("defined[[:blank:]]*\\([[:blank:]]*GENERATING_UPSTREAM_PATCH[[:blank:]]*\\)", 1, stmnt)
}
if (config_tcp_zero_copy_transfer_completion_notification_undefined)
{
gsub("defined[[:blank:]]+CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION", 0, stmnt)
gsub("defined[[:blank:]]*\\([[:blank:]]*CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION[[:blank:]]*\\)", 0, stmnt)
}
gsub("defined[[:blank:]]+CONFIG_SCST_PROC", !config_scst_proc_undefined, stmnt)
gsub("defined[[:blank:]]*\\([[:blank:]]*CONFIG_SCST_PROC[[:blank:]]*\\)", !config_scst_proc_undefined,
stmnt)
if (debug)
printf "/* debug specialize-patch: (b) %s */\n", stmnt
do
{
last_stmnt = stmnt
pattern = "![[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] == 0, stmnt)
}
pattern = "![[:blank:]]*\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] == 0, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*(\\*|/)[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
result="error"
if (op[2] == "*") result = op[1] * op[3]
else if (op[2] == "/" && op[3] != 0) result = op[1] / op[3]
sub(pattern, result, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*(\\+|-)[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
result="error"
if (op[2] == "+") result = op[1] + op[3]
else if (op[2] == "-") result = op[1] - op[3]
sub(pattern, result, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*(<<|>>)[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
result="error"
if (op[2] == "<<") result = int(op[1] * (2**op[3]))
else if (op[2] == ">>") result = int(op[1] / (2**op[3]))
sub(pattern, result, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*(<|<=|>|>=|==|!=)[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
result="error"
if (op[2] == "<" ) result = op[1] < op[3]
else if (op[2] == "<=") result = op[1] <= op[3]
else if (op[2] == ">" ) result = op[1] > op[3]
else if (op[2] == ">=") result = op[1] >= op[3]
else if (op[2] == "==") result = op[1] == op[3]
else if (op[2] == "!=") result = op[1] != op[3]
sub(pattern, result, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*\\&\\&[[:blank:]]*\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*\\&\\&[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
}
pattern="^+#if[[:blank:]]*([01])[[:blank:]]*\\&\\&[[:blank:]]*(!*[[:blank:]]*defined[[:blank:]]*\\([[:blank:]]*[A-Za-z_]*[[:blank:]]*\\))$"
while (match(stmnt, pattern, op) != 0)
{
stmnt = "+#if " (op[1] != 0 ? op[2] : op[1])
}
pattern="^+#if[[:blank:]]*(!*[[:blank:]]*defined[[:blank:]]*\\([[:blank:]]*[A-Za-z_]*[[:blank:]]*\\))\\&\\&[[:blank:]]*([01])[[:blank:]]*$"
while (match(stmnt, pattern, op) != 0)
{
stmnt = "+#if " (op[2] != 0 ? op[1] : op[2])
}
pattern="^+#if[[:blank:]]*(!*[[:blank:]]*[A-Za-z_]*)[[:blank:]]*\\&\\&[[:blank:]]*([01])[[:blank:]]*$"
while (match(stmnt, pattern, op) != 0)
{
stmnt = "+#if " (op[2] != 0 ? op[1] : op[2])
}
pattern="(-*[0-9]+)[[:blank:]]*\\|\\|[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, (op[1] != 0) || (op[2] != 0), stmnt)
}
pattern="^+#if[[:blank:]]*([01])[[:blank:]]*\\|\\|[[:blank:]]*(!*[[:blank:]]*defined[[:blank:]]*\\([[:blank:]]*[A-Za-z_]*[[:blank:]]*\\))$"
while (match(stmnt, pattern, op) != 0)
{
stmnt = "+#if " (op[1] == 0 ? op[2] : op[1])
}
pattern="\\(([01])[[:blank:]]*\\|\\|[[:blank:]]*(!*[[:blank:]]*defined[[:blank:]]*\\([[:blank:]]*[A-Za-z_]*[[:blank:]]*\\))\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] == 0 ? op[2] : op[1], stmnt)
}
pattern="\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1], stmnt)
}
if (debug)
printf "/* debug specialize-patch: (c) %s -> %s */\n", last_stmnt, stmnt
} while (stmnt != last_stmnt)
return stmnt
}
# Evaluate !stmnt
function invert(stmnt) {
return evaluate(gensub("^+#if (.*)$", "+#if !(\\1)", "g", stmnt))
}
# Handle #if or #elif
function handle_if(evaluated)
{
# Only act on preprocessor conditional expressions with regard to the Linux
# kernel version, and do not interpret other expressions.
if ($0 ~ "LINUX_VERSION_CODE" \
|| $0 ~ "INSIDE_KERNEL_TREE" \
|| $0 ~ "CONFIG_SCST_PROC" \
|| $0 ~ "RHEL_MAJOR" \
|| $0 ~ "RHEL_MINOR" \
|| $0 ~ "RHEL_RELEASE_CODE" \
|| generating_upstream_patch_defined \
&& $0 ~ "GENERATING_UPSTREAM_PATCH" \
|| $0 ~ "CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION" \
|| ($0 ~ "CONFIG_SCST_PROC" && config_scst_proc_undefined) \
|| ($0 ~ "SCSI_EXEC_REQ_FIFO_DEFINED" && SCSI_EXEC_REQ_FIFO_DEFINED!="") \
|| ($0 ~ "SCST_IO_CONTEXT" && SCST_IO_CONTEXT != ""))
{
}
else
{
evaluated = "+#if undecided"
}
if (debug)
printf "/* debug specialize-patch: (d) %s -> %s */\n", $0, evaluated
if (evaluated ~ "^+#if")
{
if_stmnt[if_nesting_level] = evaluated
any_section_output[if_nesting_level] = 0
decision[if_nesting_level] = evaluated
inv_decision[if_nesting_level] = evaluate(sprintf("+#if !%s", substr(evaluated, 6)))
if (debug)
printf "/* debug specialize-patch: (f) %s / %s */\n", \
decision[if_nesting_level], inv_decision[if_nesting_level]
}
else
{
sub("^+#elif ",
sprintf("+#if %s \\&\\& ", substr(inv_decision[if_nesting_level], 6)),
evaluated)
if (debug)
printf "/* debug specialize-patch: (e) %s */\n", evaluated
evaluated = evaluate(evaluated)
decision[if_nesting_level] = evaluated
inv_decision[if_nesting_level] \
= evaluate(sprintf("+#if %s && !%s", \
substr(inv_decision[if_nesting_level], 6), \
substr(evaluated, 6)))
if (debug)
printf "/* debug specialize-patch: (f) %s / %s */\n", \
decision[if_nesting_level], inv_decision[if_nesting_level]
}
matching_if = if_stmnt[if_nesting_level]
return evaluated
}
# Decide whether or not to print the preprocessor statement $0.
function process_preprocessor_statement(evaluated, condition) {
evaluated = evaluate($0)
condition = 1
ei = evaluated_if_stmnt[if_nesting_level];
if (evaluated ~ "^+#if")
{
if_nesting_level++
evaluated_if_stmnt[if_nesting_level] = evaluated
evaluated = handle_if(evaluated)
}
else if (evaluated ~ "^+#elif")
{
evaluated = handle_if(evaluated)
}
else if (evaluated ~ "^+#else")
{
matching_if = if_stmnt[if_nesting_level]
decision[if_nesting_level] = inv_decision[if_nesting_level]
}
else if (evaluated ~ "^+#endif")
{
matching_if = if_stmnt[if_nesting_level]
if_nesting_level--
}
else
{
condition = 0
}
if (condition)
{
output = 1
for (i = if_nesting_level; i >= 0; i--) {
if (debug)
printf "/* debug specialize-patch: (g1) %s: decision[%d] = %s */\n", \
evaluated, i, decision[i]
output = output && decision[i] != "+#if 0" && decision[i] != "+#elif 0"
}
if (output)
any_section_output[if_nesting_level] = 1
if (debug)
printf "/* debug specialize-patch: (g2) %s: output = %d */\n", \
evaluated, output
}
if (evaluated ~ "^+#define SCSI_EXEC_REQ_FIFO_DEFINED$" \
&& SCSI_EXEC_REQ_FIFO_DEFINED != "" \
|| evaluated ~ "^+#define SCST_IO_CONTEXT$" \
&& SCST_IO_CONTEXT != "" \
|| (evaluated ~ "^+#define CONFIG_SCST_PROC$" \
&& config_scst_proc_undefined))
{
discard = 1
delete_next_blank_line = 1
}
else if (output && (!condition \
|| condition && matching_if !~ "^+#if [01]" \
&& matching_if !~ "^+#elif [01]"))
{
if (evaluated == "+#if undecided" \
|| (evaluated !~ "^+#if" \
&& evaluated !~ "^+#elif" \
&& evaluated !~ "^+#endif"))
{
for (i = 0; i < input_line_count; i++)
line[lines++] = input_line[i]
} else {
# If the statement being processed is an #else or #endif that is not a
# header file include guard and if that statement has a trailing comment,
# replace that comment by the partially evaluated matching #if expression.
if (evaluated ~ "^+#else" || evaluated ~ "^+#endif") {
if ($0 ~ "\\*/") {
if ($0 ~ "_H_* \\*/$") {
evaluated = $0
} else {
if (ei ~ "^+#if ")
ei = substr(ei, 6)
else if (ei ~ "^+#ifdef")
ei = substr(ei, 9)
evaluated = sprintf("%s /* %s */",
$0 ~ " " ? substr($0, 1, index($0, " ")) : $0,
ei);
if (match(evaluated, "([^/ ]*) */\\* defined\\(([^()]*)\\) \\*/",
arg))
{
evaluated = sprintf("%s /* %s */", arg[1], arg[2])
}
}
} else {
evaluated = $0
}
if (debug)
printf "/* debug specialize-patch: (h) %s */\n", evaluated
}
line[lines++] = evaluated
lines_less_added += input_line_count - 1
}
}
else
{
discard = 1
if (lines >= 1 && line[lines - 1] == "+")
delete_next_blank_line = 1
}
}
function reset_hunk_state_variables() {
lines = 0
lines_less_added = 0
lines_less_deleted = 0
output = 1
if_nesting_level = -1
delete_next_blank_line = 0
h[0] = ""
}
function dump_lines() {
# Detect empty hunks
first_modif = -1
for (i = 0; i < lines; i++)
{
if (line[i] ~ "^[+-]")
{
first_modif = i
break
}
}
# Dump line[] as a hunk, but only if the hunk is not empty.
if (first_modif >= 0)
{
if (h[0] != "")
printf "@@ -%d,%d +%d,%d @@%s\n",h[1],h[2]-lines_less_deleted,h[3],h[4]-lines_less_added,h[5]
for (i = 0; i < lines; i++)
print line[i]
}
}
BEGIN {
# Verify arguments.
if (kernel_version == "")
{
printf "Error: kernel_version was not specified.\n"
exit 1
}
LINUX_VERSION_CODE = version_code(kernel_version)
if (LINUX_VERSION_CODE < 2*65536 || LINUX_VERSION_CODE > 4*65536)
{
printf "Error: kernel version (%s) is out of range.\n", kernel_version
exit 1
}
if (blank_deleted_code != 0 && blank_deleted_code != 1)
blank_deleted_code = 0
if (generating_upstream_patch_defined != 0 && generating_upstream_patch_defined != 1)
generating_upstream_patch_defined = 0
if (config_tcp_zero_copy_transfer_completion_notification_undefined != 0 && config_tcp_zero_copy_transfer_completion_notification_undefined != 1)
config_tcp_zero_copy_transfer_completion_notification_undefined = 0
if (config_scst_proc_undefined != 0 && config_scst_proc_undefined != 1)
config_scst_proc_undefined = 0
# Variable initialization.
is_c_source = 0
reset_hunk_state_variables()
}
{
if (match($0, "^diff[ \t]+[^ \t]+[ \t]+[^ \t]+[ \t]+([^ \t]+)$", filename) \
|| match($0, "^\\+\\+\\+[ \t]+([^ \t]+)[ \t]+", filename))
{
# Start of new file.
dump_lines()
reset_hunk_state_variables()
is_c_source = match(filename[1], "\\.[ch]$") != 0
}
if (!is_c_source)
{
print
next
}
if (!config_scst_proc_undefined)
{
gsub("^+/\\* #define CONFIG_SCST_PROC \\*/$", "+#define CONFIG_SCST_PROC")
}
else
{
gsub("^+/\\* #define CONFIG_SCST_PROC \\*/$", "+")
}
input_line[0] = $0
input_line_count = 1
# Join continued lines before processing these.
while (match($0, "\\\\$"))
{
previous_line = $0
sub("[ \t]*\\\\$", "", previous_line)
getline
input_line[input_line_count++] = $0
sub("^+[ \t]*", "", $0)
$0 = previous_line " " $0
}
discard = 0
# If the line currently being processed is a hunk header, print all lines
# that were stored in the array line[] since the last hunk header was read.
if (match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$"))
{
/* print h[1], h[2], h[3], h[4], h[5] */
dump_lines()
reset_hunk_state_variables()
match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$", h)
}
else if (delete_next_blank_line && $0 == "+")
{
discard = 1
delete_next_blank_line = 0
}
else if (lines >= 2 && !match(line[lines-2], ":$") &&
line[lines-1] == "+\x9return;" && $0 == "+}")
{
line[lines-1] = $0
lines_less_added++
}
else
{
delete_next_blank_line = 0
if (match($0, "^+ *#"))
{
if (debug)
printf "/* debug specialize-patch: line %d: %s*/\n", NR, $0
process_preprocessor_statement()
}
else if (output)
{
# Store the lines that were just read.
for (i = 0; i < input_line_count; i++)
line[lines++] = input_line[i]
# Convert double blank lines into a single blank line.
if (line[lines-1] == "+")
delete_next_blank_line = 1
}
else
{
discard = 1
if (lines >= 1 && line[lines-1] == "+")
delete_next_blank_line = 1
}
}
if (discard)
{
for (i = 0; i < input_line_count; i++)
{
if (blank_deleted_code)
{
if (input_line[i] ~ "^+")
line[lines++] = "+"
else
line[lines++] = input_line[i]
}
else
{
if (input_line[i] ~ "^+")
lines_less_added++
else if (input_line[i] ~ "^-")
lines_less_deleted++
}
}
}
}
END {
# Dump processed contents of the last read hunk.
dump_lines()
}
# Local variables:
# indent-tabs-mode: nil
# c-basic-offset: 2
# End: