Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Change Allman-style bracketing to Stroustrup-style

4.89/5 (2 votes)
22 Oct 2013CPOL2 min read 19.2K   63  
Program to change the bracketing style of auto-generated code.

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:

C++
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 

  • Initial post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)