- The expression "defined(SCST_IO_CONTEXT)" is now replaced by "1".
[mirror/scst/.git] / scripts / specialize-patch
1 #!/usr/bin/gawk -f
2
3 ############################################################################
4 #
5 # Script that removes preprocessor checks on the kernel version. Somewhat
6 # related to the v4l-scripts-gentree.pl script.
7 #
8 # Copyright (C) 2008 Bart Van Assche <bart.vanassche@gmail.com>
9 #
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation, version 2
13 # of the License.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 ############################################################################
21
22 # Usage:
23 # * Specify the kernel version code as follows: -v kernel_version=...
24 # * Provide the patch to be processed to stdin.
25 #
26 # The output of this script will be a patch that is specialized for the
27 # specified kernel version.
28
29
30 # Convert a kernel version in the x.y.z format into numeric form, just like
31 # the KERNEL_VERSION() macro.
32
33 function version_code(kver) {
34   match(kver, "([0-9]+).([0-9]+).([0-9]+)", array)
35   return 65536*array[1] + 256*array[2] + array[3]
36 }
37
38
39 # Evaluate a preprocessor statement via repeated substitutions.
40 # Mathematicians call this algorithm 'term rewriting'.
41 # Note: the order in which the substitutions appear below is important --
42 # it is the same order as the order of operators in C.
43
44 function evaluate(stmnt) {
45   # Remove C-style comments.
46   gsub(" *\\/\\*[^*]*\\*\\/ *", "", stmnt)
47
48   # Remove the spaces before the #-sign.
49   gsub("^+ *# *", "+#", stmnt)
50
51   if (match(stmnt, "^+#ifdef (.*)$", arg))
52   {
53     stmnt = "+#if defined(" arg[1] ")"
54   }
55
56   if (match(stmnt, "^+#ifndef (.*)$", arg))
57   {
58     stmnt = "+#if ! defined(" arg[1] ")"
59   }
60
61   gsub("LINUX_VERSION_CODE", LINUX_VERSION_CODE, stmnt)
62
63   gsub("defined\\(INSIDE_KERNEL_TREE\\)", "1", stmnt)
64
65   gsub("defined\\(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19\\)", "0", stmnt)
66
67   if (RHEL_MAJOR == "")
68     gsub("defined\\(RHEL_MAJOR\\)", "0", stmnt)
69   else
70   {
71     gsub("defined\\(RHEL_MAJOR\\)", "1", stmnt)
72     gsub("RHEL_MAJOR", RHEL_MAJOR, stmnt)
73   }
74
75   if (RHEL_MINOR == "")
76     gsub("defined\\(RHEL_MINOR\\)", "0", stmnt)
77   else
78   {
79     gsub("defined\\(RHEL_MINOR\\)", "1", stmnt)
80     gsub("RHEL_MINOR", RHEL_MINOR, stmnt)
81   }
82
83   if (RHEL_MAJOR == "" || RHEL_MINOR == "")
84   {
85     gsub("defined\\(RHEL_RELEASE_CODE\\)", "0", stmnt)
86     gsub("RHEL_RELEASE_CODE", "", stmnt)
87   }
88   else
89   {
90     gsub("defined\\(RHEL_RELEASE_CODE\\)", "1", stmnt)
91     gsub("RHEL_RELEASE_CODE", RHEL_MAJOR * 256 + RHEL_MINOR, stmnt)
92   }
93
94   gsub("defined  *SCSI_EXEC_REQ_FIFO_DEFINED", "1", stmnt)
95   gsub("defined *\\( *SCSI_EXEC_REQ_FIFO_DEFINED *\\)", "1", stmnt)
96
97   gsub("defined  *SCST_IO_CONTEXT", "1", stmnt)
98   gsub("defined *\\( *SCST_IO_CONTEXT *\\)", "1", stmnt)
99
100   do
101   {
102     last_stmnt = stmnt
103
104     pattern = "! *([0-9]+)"
105     while (match(stmnt, pattern, op) != 0)
106     {
107       sub(pattern, op[1] == 0, stmnt)
108     }
109     
110     pattern="KERNEL_VERSION\\( *([0-9]+) *, *([0-9]+) *, *([0-9]+) *\\)"
111     while (match(stmnt, pattern, op) != 0)
112     {
113       sub(pattern, op[1] * 65536 + op[2] * 256 + op[3], stmnt)
114     }
115   
116     pattern="(-*[0-9]+) *(\\*|/) *(-*[0-9]+)"
117     while (match(stmnt, pattern, op) != 0)
118     {
119       result="error"
120       if      (op[2] == "*") result = op[1] * op[3]
121       else if (op[2] == "/" && op[3] != 0) result = op[1] / op[3]
122       sub(pattern, result, stmnt)
123     }
124   
125     pattern="(-*[0-9]+) *(\\+|-) *(-*[0-9]+)"
126     while (match(stmnt, pattern, op) != 0)
127     {
128       result="error"
129       if      (op[2] == "+") result = op[1] * op[3]
130       else if (op[2] == "-") result = op[1] / op[3]
131       sub(pattern, result, stmnt)
132     }
133   
134     pattern="(-*[0-9]+) *(<|<=|>|>=|==) *(-*[0-9]+)"
135     while (match(stmnt, pattern, op) != 0)
136     {
137       result="error"
138       if      (op[2] == "<" ) result = op[1] <  op[3]
139       else if (op[2] == "<=") result = op[1] <= op[3]
140       else if (op[2] == ">" ) result = op[1] >  op[3]
141       else if (op[2] == ">=") result = op[1] >= op[3]
142       else if (op[2] == "==") result = op[1] == op[3]
143       sub(pattern, result, stmnt)
144     }
145   
146     pattern="(-*[0-9]+) *\\&\\& *(-*[0-9]+)"
147     while (match(stmnt, pattern, op) != 0)
148     {
149       sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
150     }
151   
152     pattern="(-*[0-9]+) *\\|\\| *(-*[0-9]+)"
153     while (match(stmnt, pattern, op) != 0)
154     {
155       sub(pattern, (op[1] != 0) || (op[2] != 0), stmnt)
156     }
157   
158     pattern="\\((-*[0-9]+)\\)"
159     while (match(stmnt, pattern, op) != 0)
160     {
161       sub(pattern, op[1], stmnt)
162     }
163   } while (stmnt != last_stmnt)
164
165   return stmnt
166 }
167
168
169 # Evaluate ! stmnt
170 function invert(stmnt) {
171   sub("^+#if ", "+#if ! ", stmnt)
172   return evaluate(stmnt)
173 }
174
175
176 # Handle #if or #elif
177
178 function handle_if()
179 {
180   # Only act on preprocessor conditional expressions with regard to the Linux
181   # kernel version, and do not interpret other expressions.
182   if ($0 ~ "LINUX_VERSION_CODE"    \
183       || $0 ~ "INSIDE_KERNEL_TREE" \
184       || $0 ~ "RHEL_MAJOR"         \
185       || $0 ~ "RHEL_MINOR"         \
186       || $0 ~ "RHEL_RELEASE_CODE"  \
187       || $0 ~ "SCSI_EXEC_REQ_FIFO_DEFINED" \
188       || $0 ~ "SCST_IO_CONTEXT")
189   {
190     #print $0 " -> " evaluated
191     $0 = evaluated
192   }
193   else
194   {
195     evaluated = "+#if undecided"
196   }
197   #printf "%s -> %s\n", $0, evaluated
198   if (evaluated ~ "^+#if")
199   {
200     if_stmnt[if_nesting_level] = evaluated
201   }
202   else
203   {
204     sub("^+#elif ",
205         sprintf("+#if ! %d \\&\\& ", decision[if_nesting_level]),
206         evaluated)
207     evaluated = evaluate(evaluated)
208   }
209   decision[if_nesting_level] = evaluated
210   matching_if = if_stmnt[if_nesting_level]
211 }
212
213
214 # Decide whether or not to print the preprocessor statement $0.
215
216 function process_preprocessor_statement() {
217   last_if_nesting_level = if_nesting_level
218   evaluated = evaluate($0)
219   condition = 1
220   if (evaluated ~ "^+#if")
221   {
222     if_nesting_level++
223     handle_if()
224   }
225   else if (evaluated ~ "^+#elif")
226   {
227     handle_if()
228   }
229   else if (evaluated ~ "^+#else")
230   {
231     matching_if = if_stmnt[if_nesting_level]
232     decision[if_nesting_level] = invert(decision[if_nesting_level])
233   }
234   else if (evaluated ~ "^+#endif")
235   {
236     matching_if = if_stmnt[if_nesting_level]
237     if_nesting_level--
238   }
239   else
240   {
241     condition = 0
242   }
243   if (condition)
244   {
245     output = 1
246     for (i = if_nesting_level; i >= 0; i--)
247     {
248       output = output && decision[i] != "+#if 0"
249     }
250   }
251   if (output && (! condition || condition && matching_if !~ "^+#if [01]") \
252       && evaluated !~ "^+#define SCSI_EXEC_REQ_FIFO_DEFINED$" \
253       && evaluated !~ "^+#define SCST_IO_CONTEXT$")
254   {
255     line[lines++]=$0
256     delete_next_blank_line = 0
257   }
258   else
259   {
260     lines_deleted++
261     delete_next_blank_line = 1
262   }
263 }
264
265 function dump_lines() {
266   # Detect empty hunks
267   first_modif = -1
268   for (i = 0; i < lines; i++)
269   {
270     if (line[i] ~ "^[+-]")
271     {
272       first_modif = i
273       break
274     }
275   }
276
277   # Dump line[] as a hunk, but only if the hunk is not empty.
278   if (first_modif >= 0)
279   {
280     if (h[0] != "")
281       printf "@@ -%d,%d +%d,%d @@%s\n",h[1],h[2],h[3],h[4]-lines_deleted,h[5]
282     for (i = 0; i < lines; i++)
283     print line[i]
284   }
285   lines = 0
286   lines_deleted = 0
287 }
288
289 BEGIN {
290   # Verify arguments.
291   if (kernel_version == "")
292   {
293     printf "Error: kernel_version was not specified.\n"
294     exit 1
295   }
296   LINUX_VERSION_CODE = version_code(kernel_version)
297   if (LINUX_VERSION_CODE < 2*65536 || LINUX_VERSION_CODE > 3*65536)
298   {
299     printf "Error: kernel version (%s) is out of range.\n", kernel_version
300     exit 1
301   }
302
303   # Variable initialization.
304   lines = 0
305   lines_deleted = 0
306   output = 1
307   if_nesting_level = -1
308   delete_next_blank_line = 0
309 }
310
311
312 {
313   # If the line currently being processed is a hunk header, print all lines
314   # that were stored in the array line[] since the last hunk header was read.
315   if (match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$"))
316   {
317     /* print h[1], h[2], h[3], h[4], h[5] */
318     dump_lines()
319     match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$", h)
320   }
321   else if (delete_next_blank_line && match($0, "^+$"))
322   {
323     lines_deleted++
324     delete_next_blank_line = 0
325   }
326   else
327   {
328     delete_next_blank_line = 0
329     if (match($0, "^+ *#"))
330     {
331       process_preprocessor_statement()
332     }
333     else if (output)
334     {
335       # Store the line that was just read.
336       line[lines++]=$0
337     }
338     else
339     {
340       # Discard the last read line.
341       lines_deleted++
342     }
343   }
344 }
345
346 END {
347   # Dump processed contents of the last read hunk.
348   dump_lines()
349 }