mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
- Added support for evaluating #ifdef and #ifndef. - Added support for substituting the macro's RHEL_MAJOR, RHEL_MINOR and RHEL_RELEASE_CODE. - Added more comments. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@637 d57e44dd-8a1f-0410-8b47-8ef2f437770f
288 lines
6.8 KiB
Awk
Executable File
288 lines
6.8 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 Bart Van Assche <bart.vanassche@gmail.com>
|
|
#
|
|
# 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) {
|
|
match(kver, "([0-9]+).([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) {
|
|
gsub(" *\\/\\*[^*]*\\*\\/ *", "", stmnt)
|
|
|
|
gsub("^+ *# *", "+#", 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)
|
|
|
|
gsub("defined\\(INSIDE_KERNEL_TREE\\)", "1", stmnt)
|
|
|
|
if (RHEL_MAJOR == "")
|
|
gsub("defined\\(RHEL_MAJOR\\)", "0", stmnt)
|
|
else
|
|
{
|
|
gsub("defined\\(RHEL_MAJOR\\)", "1", stmnt)
|
|
gsub("RHEL_MAJOR", RHEL_MAJOR, stmnt)
|
|
}
|
|
|
|
if (RHEL_MINOR == "")
|
|
gsub("defined\\(RHEL_MINOR\\)", "0", stmnt)
|
|
else
|
|
{
|
|
gsub("defined\\(RHEL_MINOR\\)", "1", stmnt)
|
|
gsub("RHEL_MINOR", RHEL_MINOR, stmnt)
|
|
}
|
|
|
|
if (RHEL_MAJOR == "" || RHEL_MINOR == "")
|
|
gsub("defined\\(RHEL_RELEASE_CODE\\)", "0", stmnt)
|
|
else
|
|
{
|
|
gsub("defined\\(RHEL_RELEASE_CODE\\)", "1", stmnt)
|
|
gsub("RHEL_RELEASE_CODE", RHEL_MAJOR * 256 + RHEL_MINOR, stmnt)
|
|
}
|
|
|
|
do
|
|
{
|
|
last_stmnt = stmnt
|
|
|
|
pattern = "! *([0-9]+)"
|
|
while (match(stmnt, pattern, op) != 0)
|
|
{
|
|
sub(pattern, op[1] == 0, stmnt)
|
|
}
|
|
|
|
pattern="KERNEL_VERSION\\(([0-9]+) *, *([0-9]+) *, *([0-9]+) *\\)"
|
|
while (match(stmnt, pattern, op) != 0)
|
|
{
|
|
sub(pattern, op[1] * 65536 + op[2] * 256 + op[3], stmnt)
|
|
}
|
|
|
|
pattern="([0-9]+) *(<|<=|>|>=|==) *([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]
|
|
sub(pattern, result, stmnt)
|
|
}
|
|
|
|
pattern="([0-9]+) *\\&\\& *([0-9]+)"
|
|
while (match(stmnt, pattern, op) != 0)
|
|
{
|
|
sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
|
|
}
|
|
|
|
pattern="([0-9]+) *\\|\\| *([0-9]+)"
|
|
while (match(stmnt, pattern, op) != 0)
|
|
{
|
|
sub(pattern, (op[1] != 0) || (op[2] != 0), stmnt)
|
|
}
|
|
|
|
pattern="\\(([0-9]+)\\)"
|
|
while (match(stmnt, pattern, op) != 0)
|
|
{
|
|
sub(pattern, op[1], stmnt)
|
|
}
|
|
} while (stmnt != last_stmnt)
|
|
|
|
return stmnt
|
|
}
|
|
|
|
|
|
# Evaluate ! stmnt
|
|
function invert(stmnt) {
|
|
sub("^+#if ", "+#if ! ", stmnt)
|
|
return evaluate(stmnt)
|
|
}
|
|
|
|
|
|
# Handle #if or #elif
|
|
|
|
function handle_if()
|
|
{
|
|
# 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 ~ "RHEL_MAJOR" \
|
|
|| $0 ~ "RHEL_MINOR" \
|
|
|| $0 ~ "RHEL_RELEASE_CODE")
|
|
{
|
|
#print $0 " -> " evaluated
|
|
$0 = evaluated
|
|
}
|
|
else
|
|
{
|
|
evaluated = "+#if undecided"
|
|
}
|
|
#printf "%s -> %s\n", $0, evaluated
|
|
if (evaluated ~ "^+#if")
|
|
{
|
|
if_stmnt[if_nesting_level] = evaluated
|
|
}
|
|
else
|
|
{
|
|
sub("^+#elif ",
|
|
sprintf("+#if ! %d \\&\\& ", decision[if_nesting_level]),
|
|
evaluated)
|
|
evaluated = evaluate(evaluated)
|
|
}
|
|
decision[if_nesting_level] = evaluated
|
|
matching_if = if_stmnt[if_nesting_level]
|
|
}
|
|
|
|
|
|
# Decide whether or not to print the preprocessor statement $0.
|
|
|
|
function process_preprocessor_statement() {
|
|
last_if_nesting_level = if_nesting_level
|
|
evaluated = evaluate($0)
|
|
condition = 1
|
|
if (evaluated ~ "^+#if")
|
|
{
|
|
if_nesting_level++
|
|
handle_if()
|
|
}
|
|
else if (evaluated ~ "^+#elif")
|
|
{
|
|
handle_if()
|
|
}
|
|
else if (evaluated ~ "^+#else")
|
|
{
|
|
matching_if = if_stmnt[if_nesting_level]
|
|
decision[if_nesting_level] = invert(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--)
|
|
{
|
|
output = output && decision[i] != "+#if 0"
|
|
}
|
|
}
|
|
if (output && (! condition || condition && matching_if !~ "^+#if [01]"))
|
|
{
|
|
line[lines++]=$0
|
|
}
|
|
else
|
|
{
|
|
lines_deleted++
|
|
}
|
|
}
|
|
|
|
function dump_lines() {
|
|
if (h[0] != "")
|
|
printf "@@ -%d,%d +%d,%d @@%s\n",h[1],h[2],h[3],h[4]-lines_deleted,h[5]
|
|
for (i = 0; i < lines; i++)
|
|
print line[i]
|
|
lines = 0
|
|
lines_deleted = 0
|
|
}
|
|
|
|
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 > 3*65536)
|
|
{
|
|
printf "Error: kernel version (%s) is out of range.\n", kernel_version
|
|
exit 1
|
|
}
|
|
|
|
# Variable initialization.
|
|
lines = 0
|
|
lines_deleted = 0
|
|
output = 1
|
|
if_nesting_level = -1
|
|
}
|
|
|
|
|
|
{
|
|
# 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()
|
|
match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$", h)
|
|
}
|
|
else if (match($0, "^+ *#"))
|
|
{
|
|
process_preprocessor_statement()
|
|
}
|
|
else if (output)
|
|
{
|
|
# Store the line that was just read.
|
|
line[lines++]=$0
|
|
}
|
|
else
|
|
{
|
|
# Discard the last read line.
|
|
lines_deleted++
|
|
}
|
|
}
|
|
|
|
END {
|
|
# Dump processed contents of the last read hunk.
|
|
dump_lines()
|
|
}
|