Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C++
Tip/Trick

An awk Program to Indent Source

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
3 Aug 2021CPOL1 min read 10.1K   5   11
On certain occasions, Visual Studio does not indent as intended so here is an awk program which does the trick.
In this tip, you will see an awk program that fixes the problem of VS not indenting code in C++ as intended when previous line does not end in a semi-colon.

Introduction

Visual Studio auto-indent on C++ files does not work as I intend if the previous line does not end in a semi-colon. This can result in intolerably indented code as can be seen below. The awk program here solves it easily and can be automated for the current document via a batch file invoked via Tools->External Tools. The same file post-processing is shown below. You, of course, can modify the code to utilize the indent string you prefer and can set the block open/close characters to that which your language requires. Be sure to invoke this on a saved file, otherwise you will be prompted to choose if you wish to reload it i.e. the processed file and lose any prior changes you have edited. Please note the code has been updated 7/21/2021 to repair a bug. Please note the code has been updated 8/3/2021 to optionally indent class member access specifiers at the enclosing brace level. Also the code has been enhanced to optionally search for unmatched braces and parentheses.

C++
BEGIN {
    # to indent the member access specifiers at the same level as the enclosing brace set below to 1
    # to indent the member access specifiers at the same level as the enclosed code set below to 0
    MEMBER_ACCESS_ENCLOSING_BRACE_LEVEL = 1
    # to search for unmatched braces or parentheses set below to 1 else 0
    # when searching the current brace depth and current parentheses depth will be displayed following each line of code
    SEARCH_UNMATCHED = 0

    INDENT_STRING = "\t"
    INCREASE_INDENT_CHARACTER = "{"; DECREASE_INDENT_CHARACTER = "}"
    MEMBER_ACCESS_STRINGS[0] = "private:"; MEMBER_ACCESS_STRINGS[1] = "PRIVATE:"; MEMBER_ACCESS_STRINGS[2] = "public:"; MEMBER_ACCESS_STRINGS[3] = "PUBLIC:"; MEMBER_ACCESS_STRINGS[4] = "protected:"; MEMBER_ACCESS_STRINGS[5] = "PROTECTED:";
    PRIVATE_LENGTH = 8 # length of "private:"
    PUBLIC_LENGTH = 7 # length of "public:"
    PROTECTED_LENGTH = 10 # length of "protected:"

    OPEN_PAREN = "("; CLOSE_PAREN = ")";
    INDENT_DEPTH = 0
    PAREN_DEPTH = 0
    NEED_NEWLINE = 0
}

END {
    # to only obtain a final value of unmatched braces and parentheses the line below can be uncommented and the above value "SEARCH_UNMATCHED" set to 0
    # if(SEARCH_UNMATCHED != 0) printf("\nFINAL: INDENT_DEPTH %d PAREN_DEPTH %d", INDENT_DEPTH, PAREN_DEPTH)
}

{OPEN = NUMBER_OF_OPEN(); INDENT_DEPTH += OPEN}
{CLOSE = NUMBER_OF_CLOSE(); INDENT_DEPTH -= CLOSE}
{PAREN_DEPTH += NUMBER_OF(OPEN_PAREN)}
{PAREN_DEPTH -= NUMBER_OF(CLOSE_PAREN)}
{INDENT()}
{if(SEARCH_UNMATCHED) {if (NEED_NEWLINE != 0) printf("\n"); printf("INDENT DEPTH %d PAREN DEPTH %d ", INDENT_DEPTH, PAREN_DEPTH); NEED_NEWLINE = 1} }

function NUMBER_OF_OPEN() { return NUMBER_OF(INCREASE_INDENT_CHARACTER) }
function NUMBER_OF_CLOSE() { return NUMBER_OF(DECREASE_INDENT_CHARACTER) }
function NUMBER_OF(_SUB_STRING)
{
    N = 0
        INDEX = 0
        STRING = $0
        while ((INDEX = index(STRING, _SUB_STRING)) > 0)
        {
            ++N
                if (INDEX < length(STRING))
                    STRING = substr(STRING, INDEX + 1)
                else
                    break
        }
    return N
}
function INDENT()
{
    if (NEED_NEWLINE != 0) printf("\n")
        if (length($0) == 0) { printf("\n"); NEED_NEWLINE = 0 }
        else
        {
            # find first non - blank character
                if (match($0, "[^[:blank:]]"))
                {
                    # RSTART is where the match of the pattern starts
                        # RLENGTH is the length of the matched pattern
                        # before = substr($0, 1, RSTART - 1)
                            # after = substr($0, RSTART + RLENGTH)
                        matched_pattern = substr($0, RSTART)
                        if (MEMBER_ACCESS_ENCLOSING_BRACE_LEVEL != 0 && MEMBER_ACCESS_CONTROL(matched_pattern) != 0)
                        {
                            for (i = 1; i < INDENT_DEPTH; ++i) printf("%s", INDENT_STRING)
                                printf("%s", matched_pattern)
                                NEED_NEWLINE = 1
                        }
                        else
                        {
                                i = 0;
                            if (OPEN > CLOSE) i = 1
                                for (; i < INDENT_DEPTH; ++i) printf("%s", INDENT_STRING)
                                    printf("%s", matched_pattern)
                                    NEED_NEWLINE = 1
                        }
                }
        }
}
function MEMBER_ACCESS_CONTROL(_STRING)
{
        for (i = 0; i < 2; ++i)
                if (substr(_STRING, 0, PRIVATE_LENGTH) == MEMBER_ACCESS_STRINGS[i]) return 1
        for (i = 2; i < 4; ++i)
                if (substr(_STRING, 0, PUBLIC_LENGTH) == MEMBER_ACCESS_STRINGS[i]) return 1
        for (i = 4; i < 6; ++i)
                if (substr(_STRING, 0, PROTECTED_LENGTH) == MEMBER_ACCESS_STRINGS[i]) return 1
    return 0
}

Before processing with the above awk program liberally copied from Mr. Bruce Barnett: Correcting this manually for a five-hundred line file is intolerable.

C++
}
template<typename scalarType> requires CONCEPT_scalar<scalarType>
    this_type& write(file_offset_type offset,
    const unique_ptr<scalarType[]>&buffer, size_t count)
    {
        HANDLE_NO_HANDLE
            seekp(offset);
        return write(buffer, count);
    }
    template<typename scalarType> requires CONCEPT_scalar<scalarType>
        this_type& write(file_offset_type offset,
        const csmart_unique_ptr<scalarType[]>&buffer, size_t count)
        {
            HANDLE_NO_HANDLE
                seekp(offset);
            return write(buffer, count);
        }
        template<typename scalarType> requires CONCEPT_scalar<scalarType>
            this_type& write(file_offset_type offset,
            const csmart_unique_ptr<scalarType[]>&buffer)
            {
                HANDLE_NO_HANDLE
                    seekp(offset);
                return write(buffer);
            }
            this_type& write(const void* buffer, size_t nbytes)
            {
                HANDLE_NO_HANDLE
                    if (nbytes == 0) return *this;
                DEBUG_ASSERT(buffer != nullptr, nullptr_msg, ARGUMENT_VA_ARG(nbytes));
                DWORD nbytes_written = 0;
                osapi::WriteFile(m_handle, buffer, nbytes, &nbytes_written, NULL);
                return *this;

The same lines after processing with the above awk program: Voila! All with a mere two clicks via Tools.

C++
}
template<typename scalarType> requires CONCEPT_scalar<scalarType>
this_type& write(file_offset_type offset,
                 const unique_ptr<scalarType[]>&buffer, size_t count)
{
    HANDLE_NO_HANDLE
    seekp(offset);
    return write(buffer, count);
}
template<typename scalarType> requires CONCEPT_scalar<scalarType>
this_type& write(file_offset_type offset,
const csmart_unique_ptr<scalarType[]>&buffer, size_t count)
{
    HANDLE_NO_HANDLE
    seekp(offset);
    return write(buffer, count);
}
template<typename scalarType> requires CONCEPT_scalar<scalarType>
this_type& write(file_offset_type offset,
const csmart_unique_ptr<scalarType[]>&buffer)
{
    HANDLE_NO_HANDLE
    seekp(offset);
    return write(buffer);
}
this_type& write(const void* buffer, size_t nbytes)
{
    HANDLE_NO_HANDLE
    if (nbytes == 0) return *this;
    DEBUG_ASSERT(buffer != nullptr, nullptr_msg, ARGUMENT_VA_ARG(nbytes));
    DWORD nbytes_written = 0;
    osapi::WriteFile(m_handle, buffer, nbytes, &nbytes_written, NULL);
    return *this;
}
this_type& write(const_byte_ptr_type buffer, size_t nbytes)
{
    HANDLE_NO_HANDLE
    if (nbytes == 0) return *this;

History

  • 13th July, 2021: Initial version

License

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


Written By
United States United States
MS Physics Drake University
BA Mathematics Dominican University
Wrote world's first user configurable binary file editor utilizing templates to specify file structure id est to wit in particular to be specific "FileRay" unfortunately not a commercial success. Some years later Sweetscape did a better job w/ "010 Editor" and seems to be a success.
Enjoy physical simulation. Did some work in this regard in astro-physics and options market making.

Home Page
https://mypaltrythoughts.blogspot.com/

Below is my "Signature" apologies for no apologies if offends
My sympathies to the SPAM moderator
"I once put instant coffee into the microwave and went back in time." - Steven Wright
"Shut up and calculate" - apparently N. David Mermin possibly Richard Feynman
“I want to sing, I want to cry, I want to laugh. Everything together. And jump and dance. The day has arrived — yippee!” - Desmond Tutu
“When the green flag drops the bullshit stops!”
"It is cheaper to save the world than it is to ruin it."
"I must have had lessons" - Reverend Jim Ignatowski / Christopher Lloyd
"Dripping water hollows out stone, not through force, but through persistence." - Ovid, Roman poet
"... as likely as lightning striking a leprechaun whilst riding a unicorn."
"Don't worry, the planet will do just fine without us."
"We can't solve today's problems with the mentality that created them." Albert Einstein
“Much becomes obvious in ­hindsight, ... Yet it is striking how in both physics and mathematics there is a lack of ­proportion between the effort needed to understand something for the first time and the simplicity and naturalness of the solution once all the required stages have been completed.” - Giorgio Parisi, recipient of the 2021 Nobel Prize in Physics
"The only place where Success comes before Work is in the dictionary." Vidal Sassoon, 1928 - 2012
"Insanity in individuals is rare, but in groups, parties, nations, it is the rule." - Nietzsche

Comments and Discussions

 
GeneralMy vote of 5 Pin
Vincent Radio5-Aug-21 22:50
professionalVincent Radio5-Aug-21 22:50 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA2-Aug-21 15:30
professionalȘtefan-Mihai MOGA2-Aug-21 15:30 
QuestionWould clang-format be a wiser choice? Pin
scjurgen26-Jul-21 0:32
professionalscjurgen26-Jul-21 0:32 
AnswerRe: Would clang-format be a wiser choice? Pin
BernardIE531726-Jul-21 7:29
BernardIE531726-Jul-21 7:29 
Questionerror in program Pin
BernardIE531720-Jul-21 22:58
BernardIE531720-Jul-21 22:58 
GeneralMy vote of 5 Pin
CPallini18-Jul-21 23:08
mveCPallini18-Jul-21 23:08 
Questionis this a C++ program? Pin
Southmountain13-Jul-21 10:12
Southmountain13-Jul-21 10:12 
AnswerRe: is this a C++ program? Pin
BernardIE531713-Jul-21 20:18
BernardIE531713-Jul-21 20:18 
GeneralRe: is this a C++ program? Pin
Southmountain14-Jul-21 8:02
Southmountain14-Jul-21 8:02 
GeneralRe: is this a C++ program? Pin
BernardIE531714-Jul-21 12:48
BernardIE531714-Jul-21 12:48 
GeneralRe: is this a C++ program? Pin
BernardIE531721-Jul-21 8:26
BernardIE531721-Jul-21 8:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.