import os
import sys
import getopt
import re
def print_usage():
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 the file" )
my_print( " that will #include all other header files." )
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( " " )
def canonicalize_ws( s ):
return re.sub( '\s+', ' ', s ).strip()
def my_print( s ):
sys.stdout.write( "%s\n" % s )
def echov1_n( s ):
if verbose_flag == "1":
sys.stdout.write( s )
sys.stdout.flush()
def echov1_n2( s ):
if verbose_flag == "1":
sys.stdout.write( "%s\n" % s )
sys.stdout.flush()
def echov2( s ):
if verbose_flag == "2":
sys.stdout.write( "%s: %s\n" % ( output_name, s ) )
sys.stdout.flush()
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":
sys.stdout.write( "%s\n" % s )
sys.stdout.flush()
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
for dirpath in header_dirpaths:
cur_filepath = "%s/%s" % ( dirpath, filename )
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 flatten_header( inputfile, header_dirpaths, cursp ):
skipstr = "// skipped"
beginstr = "// begin "
endstr = "// end "
ostring = ""
ifile = open( inputfile, "r" )
lineno = 0
while True:
lineno += 1
line = ifile.readline()
if line == '': break
result = regex.search( line )
if result:
header = result.group(2)
echov2( "%sfound reference to '%s'." % ( cursp, header ) )
header_path = get_header_path( header, header_dirpaths )
if header == root_inputfile:
markl = result.group(1)
markr = result.group(3)
echov2( "%sthis is the root header '%s'; commenting out / skipping." \
% ( cursp, header ) )
ostring += "%s #include %c%s%c %c" \
% ( skipstr, markl, header, markr, '\n' )
elif header_path:
echov2( "%slocated file '%s'; recursing." \
% ( cursp, header_path ) )
ostring += "%s%s%c" % ( beginstr, header, '\n' )
if line_numbers:
ostring += "#line %d \"%s\"%c\n" % ( 1, header_path, '\n' )
ostring += flatten_header( header_path, header_dirpaths, cursp + " " )
ostring += "%s%s%c" % ( endstr, header, '\n' )
if line_numbers:
ostring += "#line %d \"%s\"%c\n" % ( lineno+1, inputfile, '\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 ) )
ostring += "#include %c%s%c %s%c" \
% ( markl, header, markr, skipstr, '\n' )
else:
ostring += "%s" % line
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( "" )
return header_dirpaths
script_name = None
output_name = None
strip_comments = None
recursive_flag = None
line_numbers = None
verbose_flag = None
regex = None
root_inputfile = None
def main():
global script_name
global output_name
global strip_comments
global recursive_flag
global line_numbers
global verbose_flag
global regex
global root_inputfile
path, script_name = os.path.split(sys.argv[0])
output_name = script_name
strip_comments = False
recursive_flag = False
line_numbers = False
verbose_flag = "1"
nestsp = " "
try:
opts, args = getopt.getopt( sys.argv[1:], "o:rclhv:" )
except getopt.GetoptError as err:
my_print( str(err) ) print_usage()
sys.exit(2)
for opt, optarg in opts:
if opt == "-o":
output_name = optarg
elif opt == "-r":
recursive_flag = True
elif opt == "-l":
line_numbers = 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()
if line_numbers and strip_comments:
my_print( "WARNING: stripping comments will result in inaccurate line numbers" )
if ( verbose_flag != "0" and
verbose_flag != "1" and
verbose_flag != "2" ):
my_print( "%s Invalid verboseness argument: %s" \
% output_name, verbose_flag )
sys.exit()
if len( args ) != 4:
print_usage()
sys.exit()
inputfile = args[0]
outputfile = args[1]
temp_dir = args[2]
dir_list = args[3]
root_inputfile = os.path.basename( inputfile )
dir_list = dir_list.split()
dir_list_checked = []
for item in dir_list:
echov2_n( "checking " + item )
if os.path.exists( item ):
dir_list_checked.append( item )
echov2_n2( "...directory exists." )
else:
echov2_n2( "...invalid directory; omitting." )
dir_list = dir_list_checked
echov2( "check summary:" )
echov2( " accessible directories:" )
echov2( " %s" % ' '.join( dir_list ) )
if recursive_flag:
header_dirpaths = []
for d in dir_list:
d_dirpaths = find_header_dirs( d )
header_dirpaths += d_dirpaths
else:
header_dirpaths = []
for d in dir_list:
echov2_n( "scanning %s" % d )
sub_items = os.listdir( d )
if list_contains_header( sub_items ):
header_dirpaths.append( d )
echov2_n2( "...found headers." )
else:
echov2_n2( "...no headers found." )
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( "." )
ofile = open( outputfile, "w" )
regex = re.compile( '^[\s]*#include (["<])([\w\.\-/]*)([">])' )
final_string = flatten_header( inputfile, header_dirpaths, nestsp )
if strip_comments:
final_string = strip_cstyle_comments( final_string )
ofile.write( final_string )
ofile.close()
echov2( "substitution complete." )
echov2( "monolithic header saved as '%s'" % outputfile )
echov1_n2( "." )
return 0
if __name__ == "__main__":
main()