Switch all print statements to print() functions

Switch all print statements to print() functions per PEP 3105.
Python 3 *only* supports print() functions, so this begins to
move the code towards simultaneously supporting python 2 and 3.

This implements "stage1" of futurize.  In theory, "stage1" is
supposed to be "low risk", but in fact a *large* number of
manual fixes had to be made to make the program work again.

Python 2's traditional print statement includes the "softspace"
feature. This is "a semi-secret attribute on files currently used to tell
print whether to insert a space before the first item".  The print()
function does not have the "softspace" feature, so there is no direct
translation for any situation that depended on softspaces.
Flawfinder used softspaces extensively, as they were convenient,
so it took a little work to make print() functions work.

Signed-off-by: David A. Wheeler <dwheeler@dwheeler.com>
This commit is contained in:
David A. Wheeler 2017-08-12 19:33:49 -04:00
parent f9d6e11cdf
commit ea67f5dbca
1 changed files with 118 additions and 117 deletions

View File

@ -49,6 +49,7 @@
# than Python 2.7. # than Python 2.7.
from __future__ import division from __future__ import division
from __future__ import print_function
import functools import functools
import sys import sys
import re import re
@ -244,7 +245,7 @@ def load_patch_info(input_patch_file):
try: try:
hPatch = open(input_patch_file, 'r') hPatch = open(input_patch_file, 'r')
except BaseException: except BaseException:
print "Error: failed to open", h(input_patch_file) print("Error: failed to open", h(input_patch_file))
sys.exit(1) sys.exit(1)
patched_filename = "" # Name of new file patched by current hunk. patched_filename = "" # Name of new file patched by current hunk.
@ -258,7 +259,7 @@ def load_patch_info(input_patch_file):
elif is_gnu_diff(sLine): elif is_gnu_diff(sLine):
fn_get_filename = gnu_diff_get_filename fn_get_filename = gnu_diff_get_filename
else: else:
print "Error: Unrecognized patch format" print("Error: Unrecognized patch format")
sys.exit(1) sys.exit(1)
while True: # Loop-and-half construct. Read a line, end loop when no more while True: # Loop-and-half construct. Read a line, end loop when no more
@ -328,18 +329,18 @@ def print_multi_line(text):
prefix = " " prefix = " "
starting_position = len(prefix) + 1 starting_position = len(prefix) + 1
# #
print prefix, print(prefix, end='')
position = starting_position position = starting_position
# #
for w in text.split(): for w in text.split():
if len(w) + position >= width: if len(w) + position >= width:
print print()
print prefix, print(prefix, end='')
position = starting_position position = starting_position
print w, print(' ', end='')
print(w, end='')
position = position + len(w) + 1 position = position + len(w) + 1
# This matches references to CWE identifiers, so we can HTMLize them. # This matches references to CWE identifiers, so we can HTMLize them.
# We don't refer to CWEs with one digit, so we'll only match on 2+ digits. # We don't refer to CWEs with one digit, so we'll only match on 2+ digits.
link_cwe_pattern = re.compile(r'(CWE-([1-9][0-9]+))([,()])') link_cwe_pattern = re.compile(r'(CWE-([1-9][0-9]+))([,()])')
@ -431,49 +432,49 @@ class Hit(object):
self.show_csv() self.show_csv()
return return
if output_format: if output_format:
print "<li>", print("<li>", end='')
sys.stdout.write(h(self.filename)) sys.stdout.write(h(self.filename))
if show_columns: if show_columns:
print ":%(line)s:%(column)s:" % self, print(":%(line)s:%(column)s:" % self, end='')
else: else:
print ":%(line)s:" % self, print(":%(line)s:" % self, end='')
if output_format: if output_format:
print "<b>", print(" <b>", end='')
# Extra space before risk level in text, makes it easier to find: # Extra space before risk level in text, makes it easier to find:
print " [%(level)s]" % self, print(" [%(level)s]" % self, end=' ')
if output_format: if output_format:
print "</b>", print("</b> ", end='')
print "(%(category)s)" % self, print("(%(category)s)" % self, end=' ')
if output_format: if output_format:
print "<i>", print("<i> ", end='')
print h("%(name)s:" % self), print(h("%(name)s:" % self), end='')
main_text = h("%(warning)s. " % self) main_text = h("%(warning)s. " % self)
if output_format: # Create HTML link to CWE definitions if output_format: # Create HTML link to CWE definitions
main_text = link_cwe_pattern.sub( main_text = link_cwe_pattern.sub(
r'<a href="http://cwe.mitre.org/data/definitions/\2.html">\1</a>\3', r'<a href="http://cwe.mitre.org/data/definitions/\2.html">\1</a>\3',
main_text) main_text)
if single_line: if single_line:
print main_text, print(main_text, end='')
if self.suggestion: if self.suggestion:
print h(self.suggestion) + ".", print(" " + h(self.suggestion) + ".", end='')
print h(self.note), print(' ' + h(self.note), end='')
else: else:
if self.suggestion: if self.suggestion:
main_text = main_text + h(self.suggestion) + ". " main_text = main_text + h(self.suggestion) + ". "
main_text = main_text + h(self.note) main_text = main_text + h(self.note)
print print()
print_multi_line(main_text) print_multi_line(main_text)
if output_format: if output_format:
print "</i>", print(" </i>", end='')
print print()
if show_context: if show_context:
if output_format: if output_format:
print "<pre>" print("<pre>")
print h(self.context_text) print(h(self.context_text))
if output_format: if output_format:
print "</pre>" print("</pre>")
# The "hitlist" is the list of all hits (warnings) found so far. # The "hitlist" is the list of all hits (warnings) found so far.
@ -499,7 +500,7 @@ def add_warning(hit):
def internal_warn(message): def internal_warn(message):
print h(message) print(h(message))
# C Language Specific # C Language Specific
@ -1442,9 +1443,9 @@ def process_c_file(f, patch_infos):
# This file isn't in the patch list, so don't bother analyzing it. # This file isn't in the patch list, so don't bother analyzing it.
if not quiet: if not quiet:
if output_format: if output_format:
print "Skipping unpatched file ", h(f), "<br>" print("Skipping unpatched file ", h(f), "<br>")
else: else:
print "Skipping unpatched file", f print("Skipping unpatched file", f)
sys.stdout.flush() sys.stdout.flush()
return return
@ -1453,13 +1454,13 @@ def process_c_file(f, patch_infos):
else: else:
# Symlinks should never get here, but just in case... # Symlinks should never get here, but just in case...
if (not allowlink) and os.path.islink(f): if (not allowlink) and os.path.islink(f):
print "BUG! Somehow got a symlink in process_c_file!" print("BUG! Somehow got a symlink in process_c_file!")
num_links_skipped = num_links_skipped + 1 num_links_skipped = num_links_skipped + 1
return return
try: try:
input = open(f, "r") input = open(f, "r")
except BaseException: except BaseException:
print "Error: failed to open", h(f) print("Error: failed to open", h(f))
sys.exit(1) sys.exit(1)
# Read ENTIRE file into memory. Use readlines() to convert \n if necessary. # Read ENTIRE file into memory. Use readlines() to convert \n if necessary.
@ -1472,9 +1473,9 @@ def process_c_file(f, patch_infos):
if not quiet: if not quiet:
if output_format: if output_format:
print "Examining", h(f), "<br>" print("Examining", h(f), "<br>")
else: else:
print "Examining", f print("Examining", f)
sys.stdout.flush() sys.stdout.flush()
text = string.join(input.readlines(), "") text = string.join(input.readlines(), "")
@ -1606,8 +1607,8 @@ def expand_ruleset(ruleset):
if string.find(rule, "|") != -1: # We found a rule to expand. if string.find(rule, "|") != -1: # We found a rule to expand.
for newrule in string.split(rule, "|"): for newrule in string.split(rule, "|"):
if newrule in ruleset: if newrule in ruleset:
print "Error: Rule %s, when expanded, overlaps %s" % ( print("Error: Rule %s, when expanded, overlaps %s" % (
rule, newrule) rule, newrule))
sys.exit(1) sys.exit(1)
ruleset[newrule] = ruleset[rule] ruleset[newrule] = ruleset[rule]
del ruleset[rule] del ruleset[rule]
@ -1620,18 +1621,18 @@ def display_ruleset(ruleset):
sortedkeys = sorted(ruleset.keys()) sortedkeys = sorted(ruleset.keys())
# Now, print them out: # Now, print them out:
for key in sortedkeys: for key in sortedkeys:
print key + "\t" + str( print(key + "\t" + str(
ruleset[key][1] ruleset[key][1]
) + "\t" + ruleset[key][2] # function name, default level, default warning ) + "\t" + ruleset[key][2]) # function name, default level, default warning
def initialize_ruleset(): def initialize_ruleset():
expand_ruleset(c_ruleset) expand_ruleset(c_ruleset)
if showheading: if showheading:
print "Number of rules (primarily dangerous function names) in C/C++ ruleset:", len( print("Number of rules (primarily dangerous function names) in C/C++ ruleset:", len(
c_ruleset) c_ruleset))
if output_format: if output_format:
print "<p>" print("<p>")
if list_rules: if list_rules:
display_ruleset(c_ruleset) display_ruleset(c_ruleset)
sys.exit(0) sys.exit(0)
@ -1653,20 +1654,20 @@ def display_header():
print( print(
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ' '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" '
+ '"http://www.w3.org/TR/html4/loose.dtd">') + '"http://www.w3.org/TR/html4/loose.dtd">')
print "<html>" print("<html>")
print "<head>" print("<head>")
print '<meta http-equiv="Content-type" content="text/html; charset=utf8">' print('<meta http-equiv="Content-type" content="text/html; charset=utf8">')
print "<title>Flawfinder Results</title>" print("<title>Flawfinder Results</title>")
print '<meta name="author" content="David A. Wheeler">' print('<meta name="author" content="David A. Wheeler">')
print '<meta name="keywords" lang="en" content="flawfinder results, security scan">' print('<meta name="keywords" lang="en" content="flawfinder results, security scan">')
print "</head>" print("</head>")
print "<body>" print("<body>")
print "<h1>Flawfinder Results</h1>" print("<h1>Flawfinder Results</h1>")
print "Here are the security scan results from" print("Here are the security scan results from")
print '<a href="http://www.dwheeler.com/flawfinder">Flawfinder version %s</a>,' % version print('<a href="http://www.dwheeler.com/flawfinder">Flawfinder version %s</a>,' % version)
print '(C) 2001-2017 <a href="http://www.dwheeler.com">David A. Wheeler</a>.' print('(C) 2001-2017 <a href="http://www.dwheeler.com">David A. Wheeler</a>.')
else: else:
print "Flawfinder version %s, (C) 2001-2017 David A. Wheeler." % version print("Flawfinder version %s, (C) 2001-2017 David A. Wheeler." % version)
displayed_header = 1 displayed_header = 1
@ -1780,7 +1781,7 @@ def process_file_args(files, patch_infos):
def usage(): def usage():
print """ print("""
flawfinder [--help | -h] [--version] [--listrules] flawfinder [--help | -h] [--version] [--listrules]
[--allowlink] [--followdotdir] [--nolink] [--allowlink] [--followdotdir] [--nolink]
[--patch filename | -P filename] [--patch filename | -P filename]
@ -1866,7 +1867,7 @@ flawfinder [--help | -h] [--version] [--listrules]
For more information, please consult the manpage or available For more information, please consult the manpage or available
documentation. documentation.
""" """)
def process_options(): def process_options():
@ -1944,19 +1945,19 @@ def process_options():
loadhitlist = value loadhitlist = value
display_header() display_header()
if showheading: if showheading:
print "Loading hits from", value print("Loading hits from", value)
elif opt == "--savehitlist": elif opt == "--savehitlist":
savehitlist = value savehitlist = value
display_header() display_header()
if showheading: if showheading:
print "Saving hitlist to", value print("Saving hitlist to", value)
elif opt == "--diffhitlist": elif opt == "--diffhitlist":
diffhitlist = value diffhitlist = value
display_header() display_header()
if showheading: if showheading:
print "Showing hits not in", value print("Showing hits not in", value)
elif opt == "--version": elif opt == "--version":
print version print(version)
sys.exit(0) sys.exit(0)
elif opt in ['-h', '-?', '--help']: elif opt in ['-h', '-?', '--help']:
# We accept "-?" but do not document it. On Unix-like systems the # We accept "-?" but do not document it. On Unix-like systems the
@ -1977,7 +1978,7 @@ def process_options():
# use "getopt.error" here so it's compatible with both # use "getopt.error" here so it's compatible with both
# Python 1.5 and Python 2. # Python 1.5 and Python 2.
except getopt.error as text: except getopt.error as text:
print "*** getopt error:", text print("*** getopt error:", text)
usage() usage()
sys.exit(1) sys.exit(1)
@ -1993,7 +1994,7 @@ def process_files():
patch_infos = load_patch_info(patch_file) patch_infos = load_patch_info(patch_file)
files = sys.argv[1:] files = sys.argv[1:]
if not files: if not files:
print "*** No input files" print("*** No input files")
return None return None
process_file_args(files, patch_infos) process_file_args(files, patch_infos)
return 1 return 1
@ -2009,13 +2010,13 @@ def show_final_results():
for i in range(0, 6): # Initialize count_per_level for i in range(0, 6): # Initialize count_per_level
count_per_level_and_up[i] = 0 count_per_level_and_up[i] = 0
if show_immediately or not quiet: # Separate the final results. if show_immediately or not quiet: # Separate the final results.
print print()
if showheading: if showheading:
if output_format: if output_format:
print "<h2>Final Results</h2>" print("<h2>Final Results</h2>")
else: else:
print "FINAL RESULTS:" print("FINAL RESULTS:")
print print()
hitlist.sort() hitlist.sort()
# Display results. The HTML format now uses # Display results. The HTML format now uses
# <ul> so that the format differentiates each entry. # <ul> so that the format differentiates each entry.
@ -2025,125 +2026,125 @@ def show_final_results():
diff_file = open(diffhitlist) diff_file = open(diffhitlist)
diff_hitlist = pickle.load(diff_file) diff_hitlist = pickle.load(diff_file)
if output_format: if output_format:
print "<ul>" print("<ul>")
for hit in hitlist: for hit in hitlist:
if hit not in diff_hitlist: if hit not in diff_hitlist:
hit.show() hit.show()
count_per_level[hit.level] = count_per_level[hit.level] + 1 count_per_level[hit.level] = count_per_level[hit.level] + 1
count = count + 1 count = count + 1
if output_format: if output_format:
print "</ul>" print("</ul>")
diff_file.close() diff_file.close()
else: else:
if output_format: if output_format:
print "<ul>" print("<ul>")
for hit in hitlist: for hit in hitlist:
hit.show() hit.show()
count_per_level[hit.level] = count_per_level[hit.level] + 1 count_per_level[hit.level] = count_per_level[hit.level] + 1
if output_format: if output_format:
print "</ul>" print("</ul>")
count = len(hitlist) count = len(hitlist)
# Done with list, show the post-hitlist summary. # Done with list, show the post-hitlist summary.
if showheading: if showheading:
if output_format: if output_format:
print "<h2>Analysis Summary</h2>" print("<h2>Analysis Summary</h2>")
else: else:
print print()
print "ANALYSIS SUMMARY:" print("ANALYSIS SUMMARY:")
if output_format: if output_format:
print "<p>" print("<p>")
else: else:
print print()
if count > 0: if count > 0:
print "Hits =", count print("Hits =", count)
else: else:
print "No hits found." print("No hits found.")
if output_format: if output_format:
print "<br>" print("<br>")
# Compute the amount of time spent, and lines analyzed/second. # Compute the amount of time spent, and lines analyzed/second.
# By computing time here, we also include the time for # By computing time here, we also include the time for
# producing the list of hits, which is reasonable. # producing the list of hits, which is reasonable.
time_analyzing = time.time() - starttime time_analyzing = time.time() - starttime
if required_regex: if required_regex:
print "Hits limited to regular expression " + required_regex print("Hits limited to regular expression " + required_regex)
print "Lines analyzed = %d" % sumlines, print("Lines analyzed = %d" % sumlines, end='')
if time_analyzing > 0 and not omit_time: # Avoid divide-by-zero. if time_analyzing > 0 and not omit_time: # Avoid divide-by-zero.
print "in approximately %.2f seconds (%.0f lines/second)" % ( print(" in approximately %.2f seconds (%.0f lines/second)" % (
time_analyzing, (sumlines / time_analyzing)) time_analyzing, (sumlines / time_analyzing)))
else: else:
print print()
if output_format: if output_format:
print "<br>" print("<br>")
print "Physical Source Lines of Code (SLOC) = %d" % sloc print("Physical Source Lines of Code (SLOC) = %d" % sloc)
if output_format: if output_format:
print "<br>" print("<br>")
# Output hits@each level. # Output hits@each level.
print "Hits@level =", print("Hits@level =", end='')
for i in range(0, 6): for i in range(0, 6):
print "[%d] %3d" % (i, count_per_level[i]), print(" [%d] %3d" % (i, count_per_level[i]), end='')
if output_format: if output_format:
print "<br>" print(" <br>")
else: else:
print print()
# Compute hits at "level x or higher" # Compute hits at "level x or higher"
print "Hits@level+ =", print("Hits@level+ =", end='')
for i in range(0, 6): for i in range(0, 6):
for j in range(i, 6): for j in range(i, 6):
count_per_level_and_up[ count_per_level_and_up[
i] = count_per_level_and_up[i] + count_per_level[j] i] = count_per_level_and_up[i] + count_per_level[j]
# Display hits at "level x or higher" # Display hits at "level x or higher"
for i in range(0, 6): for i in range(0, 6):
print "[%d+] %3d" % (i, count_per_level_and_up[i]), print(" [%d+] %3d" % (i, count_per_level_and_up[i]), end='')
if output_format: if output_format:
print "<br>" print(" <br>")
else: else:
print print()
if sloc > 0: if sloc > 0:
print "Hits/KSLOC@level+ =", print("Hits/KSLOC@level+ =", end='')
for i in range(0, 6): for i in range(0, 6):
print "[%d+] %3g" % ( print(" [%d+] %3g" % (
i, count_per_level_and_up[i] * 1000.0 / sloc), i, count_per_level_and_up[i] * 1000.0 / sloc), end='')
if output_format: if output_format:
print "<br>" print(" <br>")
else: else:
print print()
# #
if num_links_skipped: if num_links_skipped:
print "Symlinks skipped =", num_links_skipped, "(--allowlink overrides but see doc for security issue)" print("Symlinks skipped =", num_links_skipped, "(--allowlink overrides but see doc for security issue)")
if output_format: if output_format:
print "<br>" print("<br>")
if num_dotdirs_skipped: if num_dotdirs_skipped:
print "Dot directories skipped =", num_dotdirs_skipped, "(--followdotdir overrides)" print("Dot directories skipped =", num_dotdirs_skipped, "(--followdotdir overrides)")
if output_format: if output_format:
print "<br>" print("<br>")
if num_ignored_hits > 0: if num_ignored_hits > 0:
print "Suppressed hits =", num_ignored_hits, "(use --neverignore to show them)" print("Suppressed hits =", num_ignored_hits, "(use --neverignore to show them)")
if output_format: if output_format:
print "<br>" print("<br>")
print "Minimum risk level = %d" % minimum_level print("Minimum risk level = %d" % minimum_level)
if output_format: if output_format:
print "<br>" print("<br>")
if count > 0: if count > 0:
print "Not every hit is necessarily a security vulnerability." print("Not every hit is necessarily a security vulnerability.")
if output_format: if output_format:
print "<br>" print("<br>")
print "There may be other security vulnerabilities; review your code!" print("There may be other security vulnerabilities; review your code!")
if output_format: if output_format:
print "<br>" print("<br>")
print "See '<a href=\"http://www.dwheeler.com/secure-programs\">Secure Programming for Linux and Unix HOWTO</a>'" print("See '<a href=\"http://www.dwheeler.com/secure-programs\">Secure Programming for Linux and Unix HOWTO</a>'")
print "(<a href=\"http://www.dwheeler.com/secure-programs\">http://www.dwheeler.com/secure-programs</a>) for more information." print("(<a href=\"http://www.dwheeler.com/secure-programs\">http://www.dwheeler.com/secure-programs</a>) for more information.")
else: else:
print "See 'Secure Programming for Linux and Unix HOWTO'" print("See 'Secure Programming for Linux and Unix HOWTO'")
print "(http://www.dwheeler.com/secure-programs) for more information." print("(http://www.dwheeler.com/secure-programs) for more information.")
if output_format: if output_format:
print "</body>" print("</body>")
print "</html>" print("</html>")
def save_if_desired(): def save_if_desired():
# We'll save entire hitlist, even if only differences displayed. # We'll save entire hitlist, even if only differences displayed.
if savehitlist: if savehitlist:
print "Saving hitlist to", savehitlist print("Saving hitlist to", savehitlist)
f = open(savehitlist, "w") f = open(savehitlist, "w")
pickle.dump(hitlist, f) pickle.dump(hitlist, f)
f.close() f.close()
@ -2162,4 +2163,4 @@ if __name__ == '__main__':
try: try:
flawfind() flawfind()
except KeyboardInterrupt: except KeyboardInterrupt:
print "*** Flawfinder interrupted" print("*** Flawfinder interrupted")