From 99dee87f30b4d437fa6b5e4ba862526d07b9f08b Mon Sep 17 00:00:00 2001 From: "Field G. Van Zee" Date: Sun, 17 Dec 2017 16:47:27 -0600 Subject: [PATCH 1/3] Reimplemented flatten-headers.sh in python. Details: - Added flatten-headers.py, a python implementation of the bash script flatten-headers.sh. The new script appears to be 25-100x faster, depending on the operating system, filesystem, etc. The python script abides by the same command line interface as its predecessor and targets python 2.7 or later. (Thanks to Devin Matthews for suggesting that I look into a python replacement for higher performance.) - Activated use of flatten-headers.py in common.mk via the FLATTEN_H variable. - Made minor tweaks to flatten-headers.sh such as spelling corrections in comments. --- build/flatten-headers.py | 507 +++++++++++++++++++++++++++++++++++++++ build/flatten-headers.sh | 22 +- common.mk | 3 +- 3 files changed, 517 insertions(+), 15 deletions(-) create mode 100755 build/flatten-headers.py diff --git a/build/flatten-headers.py b/build/flatten-headers.py new file mode 100755 index 000000000..6087789a7 --- /dev/null +++ b/build/flatten-headers.py @@ -0,0 +1,507 @@ +#!/usr/bin/env python +# +# BLIS +# An object-based framework for developing high-performance BLAS-like +# libraries. +# +# Copyright (C) 2014, The University of Texas at Austin +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# - Neither the name of The University of Texas at Austin nor the names +# of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# + +# Import modules +import os +import sys +import getopt +import re + +def print_usage(): + + print " " + print "", script_name + print " " + print " Field G. Van Zee" + print " " + print " Generate a monolithic header by recursively replacing all #include" + print " directives in a selected file with the contents of the header files" + print " they reference." + print " " + print " Usage:" + print " " + print " ", script_name, "header header_out temp_dir dir_list" + print " " + print " Arguments:" + print " " + print " header The filepath to the top-level header, which is file that" + print " will #include all other header files. NOTE: It is okay if" + print " this file resides somewhere in root_dir, described below." + print " " + print " header_out The filepath of the file into which the script will output" + print " the monolithic header." + print " " + print " temp_dir A directory in which temporary files may be created." + print " NOTE: No temporary files are created in the current" + print " implementation, but this argument must still be specified." + print " " + print " dir_list The list of directory paths in which to search for the" + print " headers that are #included by 'header'. By default, these" + print " directories are scanned for .h files, but sub-directories" + print " within the various directories are not inspected. If the" + print " -r option is given, these directories are recursively" + print " scanned. In either case, the subset of directories scanned" + print " that actually contains .h files is then searched whenever" + print " a #include directive is encountered in 'header' (or any" + print " file subsequently #included). If a referenced header file" + print " is not found, the #include directive is left untouched and" + print " translated directly into 'header_out'." + print " " + print " The following options are accepted:" + print " " + print " -r recursive" + print " Scan the directories listed in 'dir_list' recursively when" + print " searching for .h header files. By default, the directories" + print " are not searched recursively." + print " " + print " -c strip C-style comments" + print " Strip comments enclosed in /* */ delimiters from the" + print " output, including multi-line comments. By default, C-style" + print " comments are not stripped." + print " " + print " -o SCRIPT output script name" + print " Use SCRIPT as a prefix when outputting messages instead" + print " the script's actual name. Useful when the current script" + print " is going to be called from within another, higher-level" + print " driver script and seeing the current script's name might" + print " unnecessarily confuse the user." + print " " + print " -v [0|1|2] verboseness level" + print " level 0: silent (no output)" + print " level 1: default (single character '.' per header)" + print " level 2: verbose (several lines per header)." + print " " + print " -h help" + print " Output this information and exit." + print " " + + +# ------------------------------------------------------------------------------ + +def canonicalize_ws( s ): + + return re.sub( '\s+', ' ', s ).strip() + +# --- + +#def echov1( s ): +# +# if verbose_flag == "1": +# print "%s: %s" % ( output_name, s ) + +def echov1_n( s ): + + if verbose_flag == "1": + sys.stdout.write( s ) + sys.stdout.flush() + +def echov1_n2( s ): + + if verbose_flag == "1": + print "%s" % s + +# --- + +def echov2( s ): + + if verbose_flag == "2": + print "%s: %s" % ( output_name, s ) + +def echov2_n( s ): + + if verbose_flag == "2": + sys.stdout.write( output_name ) + sys.stdout.write( ": " ) + sys.stdout.write( s ) + sys.stdout.flush() + +def echov2_n2( s ): + + if verbose_flag == "2": + print "%s" % s + +# ------------------------------------------------------------------------------ + +def list_contains_header( items ): + + rval = False + for item in items: + + is_h = re.search( "\.h", item ) + + if is_h: + rval = True + break + + return rval + +# ------------------------------------------------------------------------------ + +def get_header_path( filename, header_dirpaths ): + + filepath = None + + # Search each directory path for the filename given. + for dirpath in header_dirpaths: + + # Construct a possible path to the sought-after file. + cur_filepath = "%s/%s" % ( dirpath, filename ) + + # Check whether the file exists. + found = os.path.exists( cur_filepath ) + if found: + filepath = cur_filepath + break + + return filepath + +# ------------------------------------------------------------------------------ + +def strip_cstyle_comments( string ): + + return re.sub( "/\*.*?\*/", "", string, flags=re.S ) + +# ------------------------------------------------------------------------------ + +def replace_pass( inputfile, header_dirpaths, cursp ): + + # This string is inserted after #include directives after having + # determined that they are not present in the directory tree. + skipstr = "// skipped" + beginstr = "// begin " + endstr = "// end " + + ostring = "" + + # Open the input file to process. + ifile = open( inputfile, "r" ) + + # Iterate over the lines in the file. + while True: + + # Read a line in the file. + line = ifile.readline() + + # Check for EOF. + if line == '': break + + # Check for the #include directive and isolate the header name within + # a group (parentheses). + #result = re.match( '^[\s]*#include', line ) + result = re.search( '^[\s]*#include (["<])([\w\.\-/]*)([">])', line ) + + # If the line contained a #include directive, we must try to replace + # it with the contents of the header referenced by the directive. + if result: + + # Extract the header file referenced in the #include directive, + # saved as the second group in the regular expression + # above. + header = result.group(2) + + echov2( "%sfound reference to '%s'." % ( cursp, header ) ) + + # Search for the path to the header referenced in the #include + # directive. + header_path = get_header_path( header, header_dirpaths ) + + # If the header was found, we recurse. Otherwise, we output + # the #include directive with a comment indicating that it + # was skipped. + if header_path: + + echov2( "%slocated file '%s'; recursing." \ + % ( cursp, header_path ) ) + + # Mark the beginning of the header being inserted. + ostring += "%s%s%c" % ( beginstr, header, '\n' ) + + # Recurse on the header, accumulating the string. + ostring += replace_pass( header_path, header_dirpaths, cursp + " " ) + + # Mark the end of the header being inserted. + ostring += "%s%s%c" % ( endstr, header, '\n' ) + + echov2( "%sheader file '%s' fully processed." \ + % ( cursp, header_path ) ) + + else: + + markl = result.group(1) + markr = result.group(3) + + echov2( "%scould not locate file '%s'; marking as skipped." \ + % ( cursp, header ) ) + + # If the header was not found, output the line with a + # comment that the header was skipped. + ostring += "#include %c%s%c %s%c" \ + % ( markl, header, markr, skipstr, '\n' ) + # endif + + else: + # If the line did not contain a #include directive, simply output + # the line verbatim. + ostring += "%s" % line + + # endif + + # endwhile + + # Close the input file. + ifile.close() + + echov1_n( "." ) + + return ostring + +# ------------------------------------------------------------------------------ + +def find_header_dirs( dirpath ): + + header_dirpaths = [] + for root, dirs, files in os.walk( dirpath, topdown=True ): + + echov2_n( "scanning contents of %s" % root ) + + if list_contains_header( files ): + + echov2_n2( "...found headers" ) + header_dirpaths.append( root ) + + else: + echov2_n2( "" ) + + #endif + + #endfor + + return header_dirpaths + + +# ------------------------------------------------------------------------------ + +# Global variables. +script_name = None +output_name = None +strip_comments = None +recursive_flag = None +verbose_flag = None + + +def main(): + + global script_name + global output_name + global strip_comments + global recursive_flag + global verbose_flag + + # Obtain the script name. + path, script_name = os.path.split(sys.argv[0]) + + output_name = script_name + + strip_comments = False + recursive_flag = False + verbose_flag = "1" + + nestsp = " " + + # Process our command line options. + try: + opts, args = getopt.getopt( sys.argv[1:], "o:rchv:" ) + + except getopt.GetoptError as err: + # print help information and exit: + print str(err) # will print something like "option -a not recognized" + print_usage() + sys.exit(2) + + for opt, optarg in opts: + if opt == "-o": + output_name = optarg + elif opt == "-r": + recursive_flag = True + elif opt == "-c": + strip_comments = True + elif opt == "-v": + verbose_flag = optarg + elif opt == "-h": + print_usage() + sys.exit() + else: + print_usage() + sys.exit() + + # Make sure that the verboseness level is valid. + if ( verbose_flag != "0" and + verbose_flag != "1" and + verbose_flag != "2" ): + print "%s: %s: %s" % ( output_name, "Invalid verboseness argument", verbose_flag ) + sys.exit() + + # Print usage if we don't have exactly four arguments. + if len( args ) != 4: + print_usage() + print "Wrong number of arguments!" + print "n_args: ", len( args ) + print "opts: ", opts + print "rem arguments: ", args + sys.exit() + + # Acquire the four required arguments: + # - the input header file, + # - the output header file, + # - the temporary directory in which we can write intermediate files, + # - the list of directories in which to search for the headers. + inputfile = args[0] + outputfile = args[1] + temp_dir = args[2] + dir_list = args[3] + + # Separate the directories into distinct strings. + dir_list = dir_list.split() + + # First, confirm that the directories in dir_list are valid. + dir_list_checked = [] + for item in dir_list: + + #absitem = os.path.abspath( item ) + + echov2_n( "checking " + item ) + + if os.path.exists( item ): + dir_list_checked.append( item ) + echov2_n2( "...directory exists." ) + else: + echov2_n2( "...invalid directory; omitting." ) + + # endfor + + # Overwrite the original dir_list with the updated copy that omits + # invalid directories. + dir_list = dir_list_checked + + echov2( "check summary:" ) + echov2( " accessible directories:" ) + echov2( " %s" % ' '.join( dir_list ) ) + + # Generate a list of directories (header_dirpaths) which will be searched + # whenever a #include directive is encountered. The method by which + # header_dirpaths is compiled will depend on whether the recursive flag + # was given. + if recursive_flag: + + #print "recursive flag not yet implemented!" + #sys.exit(1) + + header_dirpaths = [] + for d in dir_list: + + # For each directory in dir_list, recursively walk that directory + # and return a list of directories that contain headers. + d_dirpaths = find_header_dirs( d ) + + # Add the list resulting from the current search to the running + # list of directory paths that contain headers. + header_dirpaths += d_dirpaths + + # endfor + + else: + + # If the recursive flag was not given, we can just use dir_list + # as-is, though we opt to filter out the directories that don't + # contain .h files. + + header_dirpaths = [] + for d in dir_list: + + echov2_n( "scanning %s" % d ) + + # Acquire a list of the directory's contents. + sub_items = os.listdir( d ) + + # If there is at least one header present, add the current + # directory to the list of header directories. + if list_contains_header( sub_items ): + header_dirpaths.append( d ) + echov2_n2( "...found headers." ) + else: + echov2_n2( "...no headers found." ) + # endif + + # endfor + + # endfor + + echov2( "scan summary:" ) + echov2( " headers found in:" ) + echov2( " %s" % ' '.join( header_dirpaths ) ) + + echov2( "preparing to monolithify '%s'" % inputfile ) + + echov2( "new header will be saved to '%s'" % outputfile ) + + echov1_n( "." ) + + # Open the output file. + ofile = open( outputfile, "w" ) + + # Recursively substitute headers for occurrences of #include directives. + final_string = replace_pass( inputfile, header_dirpaths, nestsp ) + + # Strip C-style comments from the final output, if requested. + if strip_comments: + final_string = strip_cstyle_comments( final_string ) + + # Write the lines to the file. + ofile.write( final_string ) + + # Close the output file. + ofile.close() + + echov2( "substitution complete." ) + echov2( "monolithic header saved as '%s'" % outputfile ) + + echov1_n2( "." ) + + return 0 + + + + +if __name__ == "__main__": + main() diff --git a/build/flatten-headers.sh b/build/flatten-headers.sh index 55bd7db2c..9d5e87d72 100755 --- a/build/flatten-headers.sh +++ b/build/flatten-headers.sh @@ -84,10 +84,8 @@ print_usage() echo " " echo " -c strip C-style comments" echo " Strip comments enclosed in /* */ delimiters from the" - echo " output, including multi-line comments. (This only applies" - echo " to #included headers; C-style comments in the top-level" - echo " 'header' are never stripped.) By default, C-style comments" - echo " are not stripped." + echo " output, including multi-line comments. By default, C-style" + echo " comments are not stripped." echo " " echo " -o SCRIPT output script name" echo " Use SCRIPT as a prefix when outputting messages instead" @@ -291,12 +289,8 @@ replace_pass() intermfile="${temp_dir}/${intermfile}.interm" # This string is inserted after #include directives after having - # determined that they are not present in the directory tree and should - # be ignored when assessing whether there are still #include directives - # that need to be expanded. Note that it is formatted as a comment and - # thus will be ignored when the monolithic header is eventually read C - # preprocessor and/or compiler. - skipstr="\/\/skipped" + # determined that they are not present in the directory tree. + skipstr="\/\/ skipped" # Initialize the list of headers referenced in #include directives # found in the current header file. @@ -316,7 +310,7 @@ replace_pass() # Check whether the line begins with a #include directive, but ignore # the line if it contains the skip string. - result=$(echo ${curline} | grep '^[[:space:]]*#include ' | grep -v "${skipstr}") + result=$(echo ${curline} | grep '^[[:space:]]*#include ') # If the #include directive was found... if [ -n "${result}" ]; then @@ -344,7 +338,7 @@ replace_pass() # Make a copy of inputfile stripped of its C-style comments and # save it to intermfile. This substitution leaves behind a single - # blank line, which is deleted. + # blank line. cat ${inputfile} \ | perl -0777 -pe "s/\/\*.*?\*\///gs" \ > "${intermfile}" @@ -443,13 +437,13 @@ replace_pass() main() { - # The name of the script, stripped of any preceeding path. + # The name of the script, stripped of any preceding path. script_name=${0##*/} # The script name to use in informational output. Defaults to ${script_name}. output_name=${script_name} - # Whether or not we should strip C-style comments from the outout. (Default + # Whether or not we should strip C-style comments from the output. (Default # is to not strip C-style comments.) strip_comments="" diff --git a/common.mk b/common.mk index e58aacf51..70faa0092 100644 --- a/common.mk +++ b/common.mk @@ -212,7 +212,8 @@ RANLIB := ranlib INSTALL := install -c # Script for creating a monolithic header file. -FLATTEN_H := $(DIST_PATH)/$(BUILD_DIR)/flatten-headers.sh +#FLATTEN_H := $(DIST_PATH)/$(BUILD_DIR)/flatten-headers.sh +FLATTEN_H := $(DIST_PATH)/$(BUILD_DIR)/flatten-headers.py # Default archiver flags. AR := ar From 90b11b79c302f208791bdfb1ed754873103c7ce5 Mon Sep 17 00:00:00 2001 From: "Field G. Van Zee" Date: Sun, 17 Dec 2017 17:34:32 -0600 Subject: [PATCH 2/3] Modest performance boost to flatten-headers.py. Details: - Updated flatten-headers.py to pre-compile the main regular expression used to isolate #include directives and the header filenames they reference. The compiled regex object is then used over and over on each header file in the tree of referenced headers. This appears to have provided a 1.7-2x performance increase in the best case. - Other minor tweaks, such as renaming the main recursive function from replace_pass() to flatten_header(). --- build/flatten-headers.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/build/flatten-headers.py b/build/flatten-headers.py index 6087789a7..389cbf688 100755 --- a/build/flatten-headers.py +++ b/build/flatten-headers.py @@ -194,7 +194,7 @@ def strip_cstyle_comments( string ): # ------------------------------------------------------------------------------ -def replace_pass( inputfile, header_dirpaths, cursp ): +def flatten_header( inputfile, header_dirpaths, cursp ): # This string is inserted after #include directives after having # determined that they are not present in the directory tree. @@ -218,8 +218,8 @@ def replace_pass( inputfile, header_dirpaths, cursp ): # Check for the #include directive and isolate the header name within # a group (parentheses). - #result = re.match( '^[\s]*#include', line ) - result = re.search( '^[\s]*#include (["<])([\w\.\-/]*)([">])', line ) + #result = re.search( '^[\s]*#include (["<])([\w\.\-/]*)([">])', line ) + result = regex.search( line ) # If the line contained a #include directive, we must try to replace # it with the contents of the header referenced by the directive. @@ -248,7 +248,7 @@ def replace_pass( inputfile, header_dirpaths, cursp ): ostring += "%s%s%c" % ( beginstr, header, '\n' ) # Recurse on the header, accumulating the string. - ostring += replace_pass( header_path, header_dirpaths, cursp + " " ) + ostring += flatten_header( header_path, header_dirpaths, cursp + " " ) # Mark the end of the header being inserted. ostring += "%s%s%c" % ( endstr, header, '\n' ) @@ -318,7 +318,7 @@ def find_header_dirs( dirpath ): strip_comments = None recursive_flag = None verbose_flag = None - +regex = None def main(): @@ -327,6 +327,7 @@ def main(): global strip_comments global recursive_flag global verbose_flag + global regex # Obtain the script name. path, script_name = os.path.split(sys.argv[0]) @@ -480,8 +481,13 @@ def main(): # Open the output file. ofile = open( outputfile, "w" ) + # Precompile the main regular expression used to isolate #include + # directives and the headers they reference. This regex object will + # get reused over and over again in flatten_header(). + regex = re.compile( '^[\s]*#include (["<])([\w\.\-/]*)([">])' ) + # Recursively substitute headers for occurrences of #include directives. - final_string = replace_pass( inputfile, header_dirpaths, nestsp ) + final_string = flatten_header( inputfile, header_dirpaths, nestsp ) # Strip C-style comments from the final output, if requested. if strip_comments: From 0084531d3eea730a319ecd7018428148c81bbba7 Mon Sep 17 00:00:00 2001 From: "Field G. Van Zee" Date: Sun, 17 Dec 2017 18:58:25 -0600 Subject: [PATCH 3/3] Updated flatten-headers.py for python3. Details: - Modifed flatten-headers.py to work with python 3.x. This mostly amounted to removing print statements (which I replaced with calls to my_print(), a wrapper to sys.stdout.write()). Thanks to Stefan Husmann for pointing out the script's incompatibility with python 3. - Other minor changes/cleanups. --- build/flatten-headers.py | 157 ++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/build/flatten-headers.py b/build/flatten-headers.py index 389cbf688..d73862a81 100755 --- a/build/flatten-headers.py +++ b/build/flatten-headers.py @@ -40,71 +40,71 @@ def print_usage(): - print " " - print "", script_name - print " " - print " Field G. Van Zee" - print " " - print " Generate a monolithic header by recursively replacing all #include" - print " directives in a selected file with the contents of the header files" - print " they reference." - print " " - print " Usage:" - print " " - print " ", script_name, "header header_out temp_dir dir_list" - print " " - print " Arguments:" - print " " - print " header The filepath to the top-level header, which is file that" - print " will #include all other header files. NOTE: It is okay if" - print " this file resides somewhere in root_dir, described below." - print " " - print " header_out The filepath of the file into which the script will output" - print " the monolithic header." - print " " - print " temp_dir A directory in which temporary files may be created." - print " NOTE: No temporary files are created in the current" - print " implementation, but this argument must still be specified." - print " " - print " dir_list The list of directory paths in which to search for the" - print " headers that are #included by 'header'. By default, these" - print " directories are scanned for .h files, but sub-directories" - print " within the various directories are not inspected. If the" - print " -r option is given, these directories are recursively" - print " scanned. In either case, the subset of directories scanned" - print " that actually contains .h files is then searched whenever" - print " a #include directive is encountered in 'header' (or any" - print " file subsequently #included). If a referenced header file" - print " is not found, the #include directive is left untouched and" - print " translated directly into 'header_out'." - print " " - print " The following options are accepted:" - print " " - print " -r recursive" - print " Scan the directories listed in 'dir_list' recursively when" - print " searching for .h header files. By default, the directories" - print " are not searched recursively." - print " " - print " -c strip C-style comments" - print " Strip comments enclosed in /* */ delimiters from the" - print " output, including multi-line comments. By default, C-style" - print " comments are not stripped." - print " " - print " -o SCRIPT output script name" - print " Use SCRIPT as a prefix when outputting messages instead" - print " the script's actual name. Useful when the current script" - print " is going to be called from within another, higher-level" - print " driver script and seeing the current script's name might" - print " unnecessarily confuse the user." - print " " - print " -v [0|1|2] verboseness level" - print " level 0: silent (no output)" - print " level 1: default (single character '.' per header)" - print " level 2: verbose (several lines per header)." - print " " - print " -h help" - print " Output this information and exit." - print " " + my_print( " " ) + my_print( " %s" % script_name ) + my_print( " " ) + my_print( " Field G. Van Zee" ) + my_print( " " ) + my_print( " Generate a monolithic header by recursively replacing all #include" ) + my_print( " directives in a selected file with the contents of the header files" ) + my_print( " they reference." ) + my_print( " " ) + my_print( " Usage:" ) + my_print( " " ) + my_print( " %s header header_out temp_dir dir_list" % script_name ) + my_print( " " ) + my_print( " Arguments:" ) + my_print( " " ) + my_print( " header The filepath to the top-level header, which is file that" ) + my_print( " will #include all other header files. NOTE: It is okay if" ) + my_print( " this file resides somewhere in root_dir, described below." ) + my_print( " " ) + my_print( " header_out The filepath of the file into which the script will output" ) + my_print( " the monolithic header." ) + my_print( " " ) + my_print( " temp_dir A directory in which temporary files may be created." ) + my_print( " NOTE: No temporary files are created in the current" ) + my_print( " implementation, but this argument must still be specified." ) + my_print( " " ) + my_print( " dir_list The list of directory paths in which to search for the" ) + my_print( " headers that are #included by 'header'. By default, these" ) + my_print( " directories are scanned for .h files, but sub-directories" ) + my_print( " within the various directories are not inspected. If the" ) + my_print( " -r option is given, these directories are recursively" ) + my_print( " scanned. In either case, the subset of directories scanned" ) + my_print( " that actually contains .h files is then searched whenever" ) + my_print( " a #include directive is encountered in 'header' (or any" ) + my_print( " file subsequently #included). If a referenced header file" ) + my_print( " is not found, the #include directive is left untouched and" ) + my_print( " translated directly into 'header_out'." ) + my_print( " " ) + my_print( " The following options are accepted:" ) + my_print( " " ) + my_print( " -r recursive" ) + my_print( " Scan the directories listed in 'dir_list' recursively when" ) + my_print( " searching for .h header files. By default, the directories" ) + my_print( " are not searched recursively." ) + my_print( " " ) + my_print( " -c strip C-style comments" ) + my_print( " Strip comments enclosed in /* */ delimiters from the" ) + my_print( " output, including multi-line comments. By default, C-style" ) + my_print( " comments are not stripped." ) + my_print( " " ) + my_print( " -o SCRIPT output script name" ) + my_print( " Use SCRIPT as a prefix when outputting messages instead" ) + my_print( " the script's actual name. Useful when the current script" ) + my_print( " is going to be called from within another, higher-level" ) + my_print( " driver script and seeing the current script's name might" ) + my_print( " unnecessarily confuse the user." ) + my_print( " " ) + my_print( " -v [0|1|2] verboseness level" ) + my_print( " level 0: silent (no output)" ) + my_print( " level 1: default (single character '.' per header)" ) + my_print( " level 2: verbose (several lines per header)." ) + my_print( " " ) + my_print( " -h help" ) + my_print( " Output this information and exit." ) + my_print( " " ) # ------------------------------------------------------------------------------ @@ -115,6 +115,12 @@ def canonicalize_ws( s ): # --- +def my_print( s ): + + sys.stdout.write( "%s\n" % s ) + +# --- + #def echov1( s ): # # if verbose_flag == "1": @@ -129,14 +135,16 @@ def echov1_n( s ): def echov1_n2( s ): if verbose_flag == "1": - print "%s" % s + sys.stdout.write( "%s\n" % s ) + sys.stdout.flush() # --- def echov2( s ): if verbose_flag == "2": - print "%s: %s" % ( output_name, s ) + sys.stdout.write( "%s: %s\n" % ( output_name, s ) ) + sys.stdout.flush() def echov2_n( s ): @@ -149,7 +157,8 @@ def echov2_n( s ): def echov2_n2( s ): if verbose_flag == "2": - print "%s" % s + sys.stdout.write( "%s\n" % s ) + sys.stdout.flush() # ------------------------------------------------------------------------------ @@ -346,7 +355,7 @@ def main(): except getopt.GetoptError as err: # print help information and exit: - print str(err) # will print something like "option -a not recognized" + my_print( str(err) ) # will print something like "option -a not recognized" print_usage() sys.exit(2) @@ -370,16 +379,13 @@ def main(): if ( verbose_flag != "0" and verbose_flag != "1" and verbose_flag != "2" ): - print "%s: %s: %s" % ( output_name, "Invalid verboseness argument", verbose_flag ) + my_print( "%s Invalid verboseness argument: %s" \ + % output_name, verbose_flag ) sys.exit() # Print usage if we don't have exactly four arguments. if len( args ) != 4: print_usage() - print "Wrong number of arguments!" - print "n_args: ", len( args ) - print "opts: ", opts - print "rem arguments: ", args sys.exit() # Acquire the four required arguments: @@ -425,9 +431,6 @@ def main(): # was given. if recursive_flag: - #print "recursive flag not yet implemented!" - #sys.exit(1) - header_dirpaths = [] for d in dir_list: