tor/scripts/coccinelle/ctrl-reply.cocci
2019-04-30 13:18:46 -05:00

88 lines
1.9 KiB
Plaintext

// Script to edit control_*.c for refactored control reply output functions
@ initialize:python @
@@
import re
from coccilib.report import *
# reply strings "NNN-foo", "NNN+foo", "NNN foo", etc.
r = re.compile(r'^"(\d+)([ +-])(.*)\\r\\n"$')
# Generate name of function to call based on which separator character
# comes between the numeric code and the text
def idname(sep, base):
if sep == '+':
return base + "datareply"
elif sep == '-':
return base + "midreply"
else:
return base + "endreply"
# Generate the actual replacements used by the rules
def gen(s, base, p):
pos = p[0]
print_report(pos, "%s %s" % (base, s))
m = r.match(s)
if m is None:
# String not correct format, so fail match
cocci.include_match(False)
print_report(pos, "BAD STRING %s" % s)
return
code, sep, s1 = m.groups()
if r'\r\n' in s1:
# Extra CRLF in string, so fail match
cocci.include_match(False)
print_report(pos, "extra CRLF in string %s" % s)
return
coccinelle.code = code
# Need a string that is a single C token, because Coccinelle only allows
# "identifiers" to be output from Python scripts?
coccinelle.body = '"%s"' % s1
coccinelle.id = idname(sep, base)
return
@ match @
identifier f;
position p;
expression E;
constant s;
@@
(
connection_printf_to_buf@f@p(E, s, ...)
|
connection_write_str_to_buf@f@p(s, E)
)
@ script:python sc1 @
s << match.s;
p << match.p;
f << match.f;
id;
body;
code;
@@
if f == 'connection_printf_to_buf':
gen(s, 'control_printf_', p)
elif f == 'connection_write_str_to_buf':
gen(s, 'control_write_', p)
else:
raise(ValueError("%s: %s" % (f, s)))
@ replace @
constant match.s;
expression match.E;
identifier match.f;
identifier sc1.body, sc1.id, sc1.code;
@@
(
-connection_write_str_to_buf@f(s, E)
+id(E, code, body)
|
-connection_printf_to_buf@f(E, s
+id(E, code, body
, ...)
)