Introduction
The change _to_stroustrup_style.py program is a very simple program to change the bracketing style of code that is written completely using the Allman bracketing style. The code is very simple and is 'not' a general pretty-printer. All that is done is that opening brackets that are on a line with whitespace are moved to the end of the preceding line after a space character.
The program is useful for it's intended purpose. I posted three C or C++ code generators on codeproject, and all of them write code using the Allman bracketing style. This is my preferred style, but I realize it's not what everyone likes.
An example of the Allman style is:
if (a == b)
{
c = a;
}
else
{
d = a;
}
Even if the Allman style wasn't my preferred style, I'd always write code generators to output that style, because the brackets for that style are always on a line by themselves, and thus no complicated parsing is necessary for a program that converts to some other style.
The change_to_stroustrup_style.py program changes the style of a Allman style code file to have Stroustrup-style bracketing. If the code above is changed to have the Stroustrup style, it becomes:
if (a == b) {
c = a;
}
else {
d = a;
}
The program will only work correctly on properly formatted Allman-style programs.
This program also provides a simple example of using a Python generator.
Using the code
The format of the command is:
python change_to_stroustrup_style.py <file_name> [-b]
The '-b' switch, or the '--backup' switch can be used if the user wishes to save a backup of the original file.
The code
In Python , it's common to iterate over all lines in a file using a simple 'for' loop, shown below
for line in input_file:
# Code to process the string 'line' goes here.
<code omitted>
For this case, where an opening bracket on the next line of code must be added to the end of the preceding line, the simple loop requires more complicated code than using a Python generator to get each successive line of the file.
So, this code takes advantage of the Python generator feature. The following function produces a generator from any iterable item. The function returns a generator instance. The 'yield' statement returns the next item
when the returned instance's 'next' method is called. When the final item is returned, the next call to the 'next' method raises an exception of type StopIteration.
def get_iterable_item_generator(iterable_instance):
""" Create a generator that provides one iterable
item at a time.
"""
for item in iterable_instance:
yield item
The Program
#!/usr/bin/env python
#=======================================================================
# Copyright (C) 2013 William Hallahan
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#=======================================================================
"""
python change_to_stroustrup_style.py <file_name> [-b]
Change bracketing style of an Allman-style C program
to Stroustrup-style bracketing. For example:
if (a == b)
{
c = a;
}
else
{
d = a;
}
becomes:
if (a == b) {
c = a;
}
else {
d = a;
}
"""
import sys
import os
from shutil import copyfile
from argparse import ArgumentParser
def get_iterable_item_generator(iterable_instance):
""" Create a generator that provides one iterable
item at a time.
"""
for item in iterable_instance:
yield item
def execute_change_to_stroustrup_style(input_file_name, backup):
""" Convert Allman-style to Stroustrup-style. """
# Make a copy of the file.
backup_file_name = 'backup_{0}'.format(input_file_name)
copyfile(input_file_name, backup_file_name)
# Read the copied file and write to a new file with the original
# file name.
with open(input_file_name, 'w') as outfile:
with open(backup_file_name) as infile:
line_generator = get_iterable_item_generator(infile)
line = ''
try:
line = line_generator.next().strip('\n')
while True:
next_line = line_generator.next()
while next_line.strip() == '{':
line = '{0} {1}'.format(line, '{')
next_line = line_generator.next()
outfile.write('{0}\n'.format(line))
line = next_line.strip('\n')
except StopIteration:
pass
outfile.write('{0}\n'.format(line))
# Optionally delete the copy of the original file.
if not backup:
os.remove(backup_file_name)
return 0
# Start of main program.
def main(argv=None):
# Initialize the command line parser.
parser = ArgumentParser(description='The program converts C or C++ code formatted in Allman-style to Strousop-style.',
epilog='Copyright (c) 2013 William Hallahan - All Rights Reserved.',
add_help=True,
argument_default=None, # Global argument default
usage=__doc__)
parser.add_argument(action='store', dest='input_file_name', help='Print the help information.')
parser.add_argument('-b', '--backup', action='store_true', dest='backup', default=False,
help='Save a backup of the original file.')
# Parse the command line.
arguments = parser.parse_args(args=argv)
input_file_name = arguments.input_file_name
backup = arguments.backup
status = 0
try:
execute_change_to_stroustrup_style(input_file_name, backup)
except ValueError as value_error:
print value_error
status = -1
except EnvironmentError as environment_error:
print environment_error
status = -1
return status
if __name__ == "__main__":
sys.exit(main())
Points of Interest
This program could be easily modified to write the K&R style. The K&R style formates the 'else' clause of an 'if' statement differently than the Stroustrup style. The K&R style for the earlier examples is:
if (a == b) {
c = a;
} else {
d = a;
}
By the way, I always add opening and closing brackets, even when they're not needed, as in the example above. This makes it easier to maintain the code. Business's have found that, typically, 85% of the cost of code is maintenance, so ease of maintenance often trumps other considerations.
History