Indent blocks

This simple C program adjusts the indentation of the lines in a file of C or C++ source code according to the levels of the blocks of code. A block of code begins with a left brace { and ends with a right brace }. Indenting the lines of source code according to the level of the block in which each line occurs can help to make source code more readable.

C code

/* To do:

Use temporary file when output file already exists.

Cope with situation where comments begin or end with a line break between / and *.

Provide option to remove line break before braces, but not if the previous character outside a comment was the semicolon (ignoring whitespace).

*/

/* Indent blocks

Adjusts the indentation of the lines in a file of C or C++ source code according to the levels of the blocks of code

Version 1.1 (2015-12-18 revised 2018-02-18) */

#include <stdio.h>

/* Needed for fprintf, fwrite, fputc, fputs, fopen, fseek, ftell, rewind, fread and fclose */

#include <stdlib.h>

/* Needed for malloc and free */


void write_buffer (const char buffer [], const size_t buffer_size, const size_t start_position, const size_t end_position, FILE * file, const char * output_file_name)

{

if (start_position > end_position || start_position >= buffer_size || end_position > buffer_size)

{

/* Should be able to use %Z with size_t */

fprintf (stderr, "Internal error: attempt to write from %lu to %lu in the buffer of size %lu.\n", (unsigned long int) start_position, (unsigned long int) end_position, (unsigned long int) buffer_size);

}

else if (fwrite (&buffer [start_position], sizeof(char), end_position - start_position, file) != end_position - start_position)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

}

return;

}


void write_indent (const unsigned char characters, const char indent_character, FILE * file, const char * output_file_name)

{

unsigned char character;

for (character = 0; character < characters; character ++)

{

if (fputc (indent_character, file) != indent_character)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

}

}

return;

}


int main (int number_of_arguments, char * arguments [])

{

int return_value = 0;

char * input_file_name = NULL, * output_file_name = NULL;

unsigned char indent_characters_for_brace = 1;

char indent_character_for_brace = ' ';

unsigned char indent_characters_for_block = 2;

char indent_character_for_block = ' ';

unsigned char force_line_break_before_left_brace = 0, force_line_break_after_left_brace = 0;

unsigned char force_line_break_before_right_brace = 0, force_line_break_after_right_brace = 0;

unsigned char find_line_break = 0;

char line_break [] = { 0, 0, 0 };

char quiet = 0;

{

int argument;

for (argument = 1; argument < number_of_arguments; argument ++)

{

unsigned char valid_option = 0;

if (arguments [argument][0] == '/' || arguments [argument][0] == '-')

{

/* Looks like an option */

char option_code = arguments [argument][1];

if (option_code != 0)

{

char option_parameter_1 = arguments [argument][2], option_parameter_2 = 0, option_parameter_3 = 0;

if (option_parameter_1 != 0)

{

option_parameter_2 = arguments [argument][3];

if (option_parameter_2 != 0)

{

option_parameter_3 = arguments [argument][4];

}

}

if (option_parameter_1 == 0 && (option_code == 'q' || option_code == 'Q'))

{

valid_option = 1;

quiet = 1;

}

else if (option_parameter_3 == 0 && (option_parameter_2 == 0 || option_parameter_2 == 't' || option_parameter_2 == 'T'))

{

if (option_code == 'b' || option_code == 'B' || option_code == 'i' || option_code == 'I')

{

/* Set number of characters to indent */

if (option_parameter_1 == 0)

{

valid_option = 1;

if (option_code == 'b' || option_code == 'B')

{

indent_characters_for_brace = 0;

}

else

{

indent_characters_for_block = 0;

}

}

else

{

const char parameter_values [] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz";

const unsigned char number_of_parameter_values = sizeof (parameter_values);

unsigned char parameter_number;

unsigned char parameter_match_found = 0;

unsigned char parameter_value = 0;

for (parameter_number = 0; parameter_match_found == 0 && parameter_number < number_of_parameter_values; parameter_number ++)

{

if (option_parameter_1 == parameter_values [parameter_number])

{

parameter_match_found = 1;

if (parameter_number >= 36)

{

parameter_value = parameter_number - 26;

}

else

{

parameter_value = parameter_number;

}

}

}

if (parameter_match_found == 1)

{

valid_option = 1;

if (option_code == 'b' || option_code == 'B')

{

indent_characters_for_brace = parameter_value;

}

else

{

indent_characters_for_block = parameter_value;

}

if (option_parameter_2 == 't' || option_parameter_2 == 'T')

{

/* Indent with tab instead of space */

if (option_code == 'b' || option_code == 'B')

{

indent_character_for_brace = '\t';

}

else

{

indent_character_for_block = '\t';

}

}

}

}

}

else if (option_code == 'f' || option_code == 'F')

{

/* Force line breaks before or after braces */

valid_option = 1;

find_line_break = 1;

if (option_parameter_1 == 'b' || option_parameter_1 == 'B')

{

if (option_parameter_2 == 'l' || option_parameter_2 == 'L')

{

force_line_break_before_left_brace = 1;

}

else if (option_parameter_2 == 'r' || option_parameter_2 == 'R')

{

force_line_break_before_right_brace = 1;

}

else

{

force_line_break_before_left_brace = 1;

force_line_break_before_right_brace = 1;

}

}

else if (option_parameter_1 == 'a' || option_parameter_1 == 'A')

{

if (option_parameter_2 == 'l' || option_parameter_2 == 'L')

{

force_line_break_after_left_brace = 1;

}

else if (option_parameter_2 == 'r' || option_parameter_2 == 'R')

{

force_line_break_after_right_brace = 1;

}

else

{

force_line_break_after_left_brace = 1;

force_line_break_after_right_brace = 1;

}

}

else

{

force_line_break_before_left_brace = 1;

force_line_break_after_left_brace = 1;

force_line_break_before_right_brace = 1;

force_line_break_after_right_brace = 1;

}

}

}

}

}

if (valid_option == 0)

{

if (input_file_name == NULL)

{

input_file_name = arguments [argument];

output_file_name = arguments [argument];

}

else

{

output_file_name = arguments [argument];

}

}

}

}

if (input_file_name == NULL)

{

fputs ("Indent blocks - Adjusts the indentation of the lines in a file of C or C++ source code according to the levels of the blocks of code\n", stderr);

fprintf (stderr, "Usage: %s [/b] [/i] [/f] [/q] input_file [output_file]\n", arguments [0]);

fputs ("Use /b to set the additional indentation for lines beginning with a brace to zero. Append a single digit to use that number of spaces. Additionally append the letter t to indent with tab rather than space. The default behaviour is to indent with 1 space, which is equivalent to /b1.\n", stderr);

fputs ("Use /i to set the additional indentation inside a block to zero. Append a single digit to use that number of spaces. Additionally append the letter t to indent with tab rather than space. The default behaviour is to indent with 2 spaces, which is equivalent to /i2.\n", stderr);

fputs ("Use /f to insert a line break before and after each brace when there is not one there already. Append a letter b or a to only insert a line break before or after each brace respectively. Additionally append a letter l or r to insert a line break only before or after a left or right brace. The default behaviour is not to insert line breaks.\n", stderr);

fputs ("Use /q to set quiet mode, which suppresses information about the block levels.\n", stderr);

fputs ("input_file is the input file name.\n", stderr);

fputs ("output_file is the output file name, if different from the input file name.\n", stderr);

return_value = -1;

}

else

{

FILE * file = fopen (input_file_name, "rb");

if (file == NULL)

{

fprintf (stderr, "Unable to open the input file: %s\n", input_file_name);

return_value = -1;

}

else

{

char * buffer;

size_t buffer_size;

fseek (file, 0, SEEK_END);

buffer_size = ftell (file);

buffer = (char *) malloc (sizeof(char) * buffer_size);

if (buffer == NULL)

{

/* Should be able to use %Z with size_t */

fprintf (stderr, "Unable to allocate sufficient memory (%lu bytes) for the buffer in which to store the input file: %s\n", (unsigned long int) buffer_size, input_file_name);

return_value = -1;

}

else

{

rewind (file);

if (fread (buffer, sizeof(char), buffer_size, file) != buffer_size)

{

fprintf (stderr, "Unable to read the input file: %s\n", input_file_name);

free (buffer);

buffer = NULL;

buffer_size = 0;

return_value = -1;

}

if (fclose (file) != 0)

{

fprintf (stderr, "Unable to close the input file: %s\n", input_file_name);

return_value = -1;

}

if (buffer != NULL)

{

file = fopen (output_file_name, "wb");

if (file == NULL)

{

fprintf (stderr, "Unable to open the output file: %s\n", output_file_name);

return_value = -1;

}

else

{

int level = 0, maximum_level = 0, minimum_level = 0;

size_t position, last_position = 0;

unsigned char line_break_length = 0;

unsigned char new_line = 1, brace_at_start_of_line;

if (find_line_break == 1)

{

/* Look for line breaks in input file buffer */

char character = 0;

for (position = 0; position < buffer_size && character != '\n' && character != '\r'; position ++)

{

character = buffer [position];

}

if (character == 0)

{

/* No line breaks in input file buffer so specify a default line break */

line_break [0] = '\n';

line_break_length = 1;

}

else

{

/* Use the first line break in the input file buffer as the default line break */

line_break [0] = character;

line_break_length = 1;

if (position < buffer_size)

{

character = buffer [position];

if ((character == '\n' || character == '\r') && character != line_break [0])

{

/* The first line break in the input file buffer uses two different characters */

line_break [1] = character;

line_break_length = 2;

}

}

}

}

for (position = 0; position < buffer_size; position ++)

{

if (new_line == 1)

{

write_buffer (buffer, buffer_size, last_position, position, file, output_file_name);

if (buffer [position] == ' ' || buffer [position] == '\t')

{

/* Skip existing indentation */

while ((position < buffer_size) && (buffer [position] == ' ' || buffer [position] == '\t'))

{

position ++;

}

}

last_position = position;

if (position < buffer_size && buffer [position] == '}')

{

write_indent ((level - 1) * indent_characters_for_block, indent_character_for_block, file, output_file_name);

write_indent (indent_characters_for_brace, indent_character_for_brace, file, output_file_name);

brace_at_start_of_line = 1;

}

else

{

write_indent (level * indent_characters_for_block, indent_character_for_block, file, output_file_name);

if (position < buffer_size && buffer [position] == '{')

{

write_indent (indent_characters_for_brace, indent_character_for_brace, file, output_file_name);

brace_at_start_of_line = 1;

}

else

{

brace_at_start_of_line = 0;

}

}


new_line = 0;

}

else

{

brace_at_start_of_line = 0;

}

if (position < buffer_size)

{

if (buffer [position] == '"')

{

/* String literal */

do

{

position ++;

if ((position < buffer_size - 1) && buffer [position] == '\\' && (buffer [position + 1] == '\\' || buffer [position + 1] == '"'))

{

position += 2;

}

}

while (position < buffer_size && buffer [position] != '"');

}

else if (buffer [position] == '\'')

{

/* Character literal */

do

{

position ++;

if ((position < buffer_size - 1) && buffer [position] == '\\' && (buffer [position + 1] == '\\' || buffer [position + 1] == '\''))

{

position += 2;

}

}

while (position < buffer_size && buffer [position] != '\'');

}

else if ((position < buffer_size - 1) && buffer [position] == '/' && buffer [position + 1] == '*')

{

/* Block comment */

position += 2;

do

{

position ++;

}

while (position < buffer_size && (buffer [position] != '/' || buffer [position - 1] != '*'));

}

else if ((position < buffer_size - 1) && buffer [position] == '/' && buffer [position + 1] == '/')

{

/* Single line comment */

do

{

position ++;

if (position < buffer_size && buffer [position] == '\\')

{

do

{

position ++;

}

while (position < buffer_size && (buffer [position] == ' ' || buffer [position] == '\\' || buffer [position] == '\t'));

if (position + 1 < buffer_size && buffer [position] == '\r' && buffer [position + 1] == '\n')

{

position += 2;

}

else if (position < buffer_size && (buffer [position] == '\n' || buffer [position] == '\r'))

{

position ++;

}

}

}

while (position < buffer_size && buffer [position] != '\n' && buffer [position] != '\r');

}

else if (buffer [position] == '\n')

{

new_line = 1;

if (position < buffer_size - 1 && buffer [position + 1] == '\r')

{

position ++;

}

}

else if (buffer [position] == '\r')

{

new_line = 1;

if (position < buffer_size - 1 && buffer [position + 1] == '\n')

{

position ++;

}

}

else if (buffer [position] == '{')

{

if (force_line_break_before_left_brace == 1 && brace_at_start_of_line == 0)

{

write_buffer (buffer, buffer_size, last_position, position, file, output_file_name);

last_position = position;

if (fprintf (file, "%s", line_break) != line_break_length)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

return_value = -1;

}

write_indent (level * indent_characters_for_block, indent_character_for_block, file, output_file_name);

write_indent (indent_characters_for_brace, indent_character_for_brace, file, output_file_name);

}

if (force_line_break_after_left_brace == 1 && (position < buffer_size - 1) && buffer [position + 1] != '\n' && buffer [position + 1] != '\r')

{

write_buffer (buffer, buffer_size, last_position, position + 1, file, output_file_name);

last_position = position + 1;

if (fprintf (file, "%s", line_break) != line_break_length)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

return_value = -1;

}

new_line = 1;

}

level ++;

if (quiet == 0 && level > maximum_level)

{

maximum_level = level;

}

}

else if (buffer [position] == '}')

{

level --;

if (quiet == 0 && level < minimum_level)

{

minimum_level = level;

}

if (force_line_break_before_right_brace == 1 && brace_at_start_of_line == 0)

{

write_buffer (buffer, buffer_size, last_position, position, file, output_file_name);

last_position = position;

if (fprintf (file, "%s", line_break) != line_break_length)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

return_value = -1;

}

write_indent (level * indent_characters_for_block, indent_character_for_block, file, output_file_name);

write_indent (indent_characters_for_brace, indent_character_for_brace, file, output_file_name);

}

if (force_line_break_after_right_brace == 1 && (position < buffer_size - 1) && buffer [position + 1] != '\n' && buffer [position + 1] != '\r')

{

write_buffer (buffer, buffer_size, last_position, position + 1, file, output_file_name);

last_position = position + 1;

if (fprintf (file, "%s", line_break) != line_break_length)

{

fprintf (stderr, "Unable to write to the output file: %s\n", output_file_name);

return_value = -1;

}

new_line = 1;

}

}

}

}

if (last_position < buffer_size)

{

write_buffer (buffer, buffer_size, last_position, buffer_size, file, output_file_name);

}

if (fclose (file) != 0)

{

fprintf (stderr, "Unable to close the output file: %s\n", output_file_name);

return_value = -1;

}

free (buffer);

buffer = NULL;

buffer_size = 0;

if (quiet == 0)

{

if (level != 0 || minimum_level != 0)

{

fputs ("Mismatched braces.\n", stdout);

}

if (minimum_level != 0)

{

fprintf (stdout, "Minimum level: %d\n", minimum_level);

}

fprintf (stdout, "Maximum level: %d\n", maximum_level);

}

}

}

}

}

}

return return_value;

}