Added variable generating_upstream_patch_defined. When set to 1, this
[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   if (SCSI_EXEC_REQ_FIFO_DEFINED != "")
95   {
96     gsub("defined  *SCSI_EXEC_REQ_FIFO_DEFINED",
97          SCSI_EXEC_REQ_FIFO_DEFINED, stmnt)
98     gsub("defined *\\( *SCSI_EXEC_REQ_FIFO_DEFINED *\\)",
99          SCSI_EXEC_REQ_FIFO_DEFINED, stmnt)
100   }
101
102   if (SCST_IO_CONTEXT != "")
103   {
104     gsub("defined  *SCST_IO_CONTEXT", SCST_IO_CONTEXT, stmnt)
105     gsub("defined *\\( *SCST_IO_CONTEXT *\\)", SCST_IO_CONTEXT, stmnt)
106   }
107
108   if (generating_upstream_patch_defined)
109   {
110     gsub("defined  *GENERATING_UPSTREAM_PATCH", 1, stmnt)
111     gsub("defined *\\( *GENERATING_UPSTREAM_PATCH *\\)", 1, stmnt)
112   }
113
114   do
115   {
116     last_stmnt = stmnt
117
118     pattern = "! *([0-9]+)"
119     while (match(stmnt, pattern, op) != 0)
120     {
121       sub(pattern, op[1] == 0, stmnt)
122     }
123     
124     pattern="KERNEL_VERSION\\( *([0-9]+) *, *([0-9]+) *, *([0-9]+) *\\)"
125     while (match(stmnt, pattern, op) != 0)
126     {
127       sub(pattern, op[1] * 65536 + op[2] * 256 + op[3], stmnt)
128     }
129   
130     pattern="(-*[0-9]+) *(\\*|/) *(-*[0-9]+)"
131     while (match(stmnt, pattern, op) != 0)
132     {
133       result="error"
134       if      (op[2] == "*") result = op[1] * op[3]
135       else if (op[2] == "/" && op[3] != 0) result = op[1] / op[3]
136       sub(pattern, result, stmnt)
137     }
138   
139     pattern="(-*[0-9]+) *(\\+|-) *(-*[0-9]+)"
140     while (match(stmnt, pattern, op) != 0)
141     {
142       result="error"
143       if      (op[2] == "+") result = op[1] * op[3]
144       else if (op[2] == "-") result = op[1] / op[3]
145       sub(pattern, result, stmnt)
146     }
147   
148     pattern="(-*[0-9]+) *(<|<=|>|>=|==) *(-*[0-9]+)"
149     while (match(stmnt, pattern, op) != 0)
150     {
151       result="error"
152       if      (op[2] == "<" ) result = op[1] <  op[3]
153       else if (op[2] == "<=") result = op[1] <= op[3]
154       else if (op[2] == ">" ) result = op[1] >  op[3]
155       else if (op[2] == ">=") result = op[1] >= op[3]
156       else if (op[2] == "==") result = op[1] == op[3]
157       sub(pattern, result, stmnt)
158     }
159   
160     pattern="(-*[0-9]+) *\\&\\& *(-*[0-9]+)"
161     while (match(stmnt, pattern, op) != 0)
162     {
163       sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
164     }
165   
166     pattern="(-*[0-9]+) *\\|\\| *(-*[0-9]+)"
167     while (match(stmnt, pattern, op) != 0)
168     {
169       sub(pattern, (op[1] != 0) || (op[2] != 0), stmnt)
170     }
171   
172     pattern="\\((-*[0-9]+)\\)"
173     while (match(stmnt, pattern, op) != 0)
174     {
175       sub(pattern, op[1], stmnt)
176     }
177   } while (stmnt != last_stmnt)
178
179   return stmnt
180 }
181
182
183 # Evaluate ! stmnt
184 function invert(stmnt) {
185   sub("^+#if ", "+#if ! ", stmnt)
186   return evaluate(stmnt)
187 }
188
189
190 # Handle #if or #elif
191
192 function handle_if()
193 {
194   # Only act on preprocessor conditional expressions with regard to the Linux
195   # kernel version, and do not interpret other expressions.
196   if ($0 ~ "LINUX_VERSION_CODE"    \
197       || $0 ~ "INSIDE_KERNEL_TREE" \
198       || $0 ~ "RHEL_MAJOR"         \
199       || $0 ~ "RHEL_MINOR"         \
200       || $0 ~ "RHEL_RELEASE_CODE"  \
201       || $0 ~ "GENERATING_UPSTREAM_PATCH" \
202       || $0 ~ "SCSI_EXEC_REQ_FIFO_DEFINED" \
203       || $0 ~ "SCST_IO_CONTEXT")
204   {
205     #print $0 " -> " evaluated
206     $0 = evaluated
207   }
208   else
209   {
210     evaluated = "+#if undecided"
211   }
212   #printf "%s -> %s\n", $0, evaluated
213   if (evaluated ~ "^+#if")
214   {
215     if_stmnt[if_nesting_level] = evaluated
216     any_section_output[if_nesting_level] = 0
217   }
218   else
219   {
220     sub("^+#elif ",
221         sprintf("+#if ! %d \\&\\& ", decision[if_nesting_level]),
222         evaluated)
223     evaluated = evaluate(evaluated)
224   }
225   decision[if_nesting_level] = evaluated
226   matching_if = if_stmnt[if_nesting_level]
227 }
228
229
230 # Decide whether or not to print the preprocessor statement $0.
231
232 function process_preprocessor_statement() {
233   last_if_nesting_level = if_nesting_level
234   orig_stmnt = $0
235   evaluated = evaluate($0)
236   condition = 1
237   delete_next_blank_line = 0
238   if (evaluated ~ "^+#if")
239   {
240     if_nesting_level++
241     handle_if()
242   }
243   else if (evaluated ~ "^+#elif")
244   {
245     handle_if()
246   }
247   else if (evaluated ~ "^+#else")
248   {
249     matching_if = if_stmnt[if_nesting_level]
250     decision[if_nesting_level] = invert(decision[if_nesting_level])
251   }
252   else if (evaluated ~ "^+#endif")
253   {
254     matching_if = if_stmnt[if_nesting_level]
255     delete_next_blank_line = ! any_section_output[if_nesting_level]
256     if_nesting_level--
257   }
258   else
259   {
260     condition = 0
261   }
262   if (condition)
263   {
264     output = 1
265     for (i = if_nesting_level; i >= 0; i--)
266     {
267       output = output && decision[i] != "+#if 0"
268     }
269     if (output)
270       any_section_output[if_nesting_level] = 1
271   }
272   if (delete_disabled_code                                      \
273       && (evaluated ~ "^+#define SCSI_EXEC_REQ_FIFO_DEFINED$"   \
274           || evaluated ~ "^+#define SCST_IO_CONTEXT$"))
275   {
276     lines_deleted++
277     delete_next_blank_line = 1
278   }
279   else if (delete_disabled_code == 0 || (output && (! condition || condition && matching_if !~ "^+#if [01]")))
280   {
281     line[lines++] = orig_stmnt
282   }
283   else
284   {
285     lines_deleted++
286   }
287 }
288
289 function reset_hunk_state_variables() {
290   lines = 0
291   lines_deleted = 0
292   output = 1
293   if_nesting_level = -1
294   delete_next_blank_line = 0
295 }
296
297 function dump_lines() {
298   # Detect empty hunks
299   first_modif = -1
300   for (i = 0; i < lines; i++)
301   {
302     if (line[i] ~ "^[+-]")
303     {
304       first_modif = i
305       break
306     }
307   }
308
309   # Dump line[] as a hunk, but only if the hunk is not empty.
310   if (first_modif >= 0)
311   {
312     if (h[0] != "")
313       printf "@@ -%d,%d +%d,%d @@%s\n",h[1],h[2],h[3],h[4]-lines_deleted,h[5]
314     for (i = 0; i < lines; i++)
315     print line[i]
316   }
317   reset_hunk_state_variables()
318 }
319
320 BEGIN {
321   # Verify arguments.
322   if (kernel_version == "")
323   {
324     printf "Error: kernel_version was not specified.\n"
325     exit 1
326   }
327   LINUX_VERSION_CODE = version_code(kernel_version)
328   if (LINUX_VERSION_CODE < 2*65536 || LINUX_VERSION_CODE > 3*65536)
329   {
330     printf "Error: kernel version (%s) is out of range.\n", kernel_version
331     exit 1
332   }
333   if (delete_disabled_code != 0 && delete_disabled_code != 1)
334     delete_disabled_code = 0
335   if (generating_upstream_patch_defined != 0 && generating_upstream_patch_defined != 1)
336     generating_upstream_patch_defined = 0
337
338   # Variable initialization.
339   reset_hunk_state_variables()
340 }
341
342
343 {
344   # Dump continued lines without trying to process these -- the parsing code
345   # in this script cannot handle continued lines yet.
346   if (match($0, "\\\\$"))
347   {
348     line[lines++]=$0
349     do
350     {
351       getline
352       line[lines++]=$0
353     } while (match($0, "\\\\$"))
354     getline
355   }
356
357   # If the line currently being processed is a hunk header, print all lines
358   # that were stored in the array line[] since the last hunk header was read.
359   if (match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$"))
360   {
361     /* print h[1], h[2], h[3], h[4], h[5] */
362     dump_lines()
363     match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$", h)
364   }
365   else if (delete_disabled_code && delete_next_blank_line && match($0, "^+$"))
366   {
367     lines_deleted++
368     delete_next_blank_line = 0
369   }
370   else
371   {
372     delete_next_blank_line = 0
373     if (match($0, "^+ *#"))
374     {
375       process_preprocessor_statement()
376     }
377     else if (delete_disabled_code == 0 || output)
378     {
379       # Store the line that was just read.
380       line[lines++]=$0
381     }
382     else
383     {
384       # Discard the last read line.
385       lines_deleted++
386     }
387   }
388 }
389
390 END {
391   # Dump processed contents of the last read hunk.
392   dump_lines()
393 }