circuit-board Displaying source code in technical documents

Use the Indent command to help you display source code listings in documents.

Several years ago, I wrote a book to help new programmers write their first program in the C programming language. C is an old programming language, but it’s not “legacy.” The TIOBE Index that tracks the popularity of programming languages via search queries continues to list C in the top three programming languages. Depending on the month, TIOBE actually ranks C in the #1, #2 or #3 spot.

There are many ways to write C code. If you ask a dozen programmers about their style preference, you might get six different answers, including GNU style, “K&R” style, Allman style, Stroustrup style, or Linux kernel style. Each style has pros and cons for readability. Fortunately, you don’t have to pick just one style; you can use the Indent tool to reformat or “re-indent” your code for you, to use the style most appropriate for the technical document you are writing.

Changing the code style with Indent

The Indent command changes the programming style C programs without altering their functionality. The C programming language is a very flexible programming language, where each instruction is usually terminated with a semicolon (;) and code blocks are enclosed in { and } braces. The Indent command can use these rules to restructure source code to other programming styles.

Indent originated with the UCB version of Unix, but is also available on Linux and other Unix-like systems. The GNU version of Indent uses a long list of command line options to control how it restructures source code, such as -bad or --blank-lines-after-declarations to start a new line after every block of declarations, and -cn or --comment-indentationn to start comments to the right of code statements at column n, and -ce or --cuddle-else to put the else statement on the same line as the terminating brace from the previous if statement. By combining these options, you can control exactly how you want the code to look when Indent reformats it.

A sample program

Let’s start with a simple program that demonstrates several features of C programming, so we can use Indent to style the source code according to different coding styles. This program uses recursion to print the factorial of the numbers 0 to 5. For example, the factorial of 5 is:

5! = 5 × 4 × 3 × 2 × 1 = 120

Note that the factorials of 0 and 1 are both 1. For numbers less than 0, the program prints an error message and returns 0.

#include <stdio.h>

int
fact(int n)
{
   if ((n == 0) || (n == 1)) {
      return 1;
   }
   else if (n > 1) {
      return (n * fact(n - 1));
   }
   else {
      puts("Error!");
      return 0; /* return zero */
   }
}

int
main()
{
   int i;

   for (i = 0; i <= 5; i++) {
      printf("%d! is %d\n", i, fact(i));
   }

   return 0; /* exit program */
}

If we save this as fact.c then compile and run the program, it prints the factorials from 0 to 5:

$ cc -o fact fact.c
$ cat fact.c
0! is 1
1! is 1
2! is 2
3! is 6
4! is 24
5! is 120

Reformat code with Indent

One way to write this is using the GNU style, which uses two spaces to indent each level of braces, and each brace starts on a new line. The GNU style is the preferred style for the GNU Project, a set of Unix-like tools and other programs such as editors and compilers. Fans of the GNU style like it because each brace starts on a new line, which makes it easy to see where blocks begin and end.

Indent assumes these defaults for GNU coding style, such as -bl to print braces on the line after an if statement, and -i2 to set each level of indentation to 2 spaces:

-nbad -bap -nbc -bbo -bl -bli2 -bls -ncdb -nce -cp1 -cs -di2
-ndj -nfc1 -nfca -hnl -i2 -ip5 -lp -pcs -nprs -psl -saf -sai
-saw -nsc -nsob

The GNU style is the standard mode for the GNU Indent program, so you don’t need to give these options when reformatting code, but you can if you wish. You can also use the -gnu option, which assumes those values. With these values, Indent will restructure the code like this:

$ indent -gnu fact.c
$ cat fact.c
#include <stdio.h>

int
fact (int n)
{
  if ((n == 0) || (n == 1))
    {
      return 1;
    }
  else if (n > 1)
    {
      return (n * fact (n - 1));
    }
  else
    {
      puts ("Error!");
      return 0;			/* return zero */
    }
}

int
main ()
{
  int i;

  for (i = 0; i <= 5; i++)
    {
      printf ("%d! is %d\n", i, fact (i));
    }

  return 0;			/* exit program */
}

However, this produces very long output that can add several unnecessary pages in printed documents such as books and workbooks. If you write technical documents intended for print, you may prefer a more compact programming style.

One such style is the one used in the first book about C programming. The C programming language was created by Dennis Ritchie at Bell Labs in 1972. Brian Kernighan, also at Bell Labs, co-authored a book about C programming with Ritchie. Their style in the book is therefore commonly referred to as “K&R C,” using the first letter of their last names.

K&R C uses four spaces to indent each level of code, and puts the opening brace on the same line as the statement that uses it (such as for or else). However, main and other functions start the braces at the same level as the function name.

The Indent program recognizes the K&R C style using the -kr option, which is equivalent to this list of command line options. For example, this uses -c33 to start comments in column 33, -ce to “cuddle” the else statement after the previous if block, and -i4 to set each indentation level to 4 spaces.

-nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0
-cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs
-nprs -npsl -saf -sai -saw -nsc -nsob -nss -par

With these options, Indent will restructure the source code in a more compact way:

$ indent -kr fact.c
$ cat fact.c
#include <stdio.h>

int fact(int n)
{
    if ((n == 0) || (n == 1)) {
	return 1;
    } else if (n > 1) {
	return (n * fact(n - 1));
    } else {
	puts("Error!");
	return 0;		/* return zero */
    }
}

int main()
{
    int i;

    for (i = 0; i <= 5; i++) {
	printf("%d! is %d\n", i, fact(i));
    }

    return 0;			/* exit program */
}

The Linux kernel uses a variation of the K&R C style. You can use Indent to reformat the code using the -linux option, which is equivalent to all of these individual options:

-nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4
-cli0 -d0 -di1 -nfc1 -i8 -ip0 -l80 -lp -npcs -nprs -npsl -sai
-saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1

Note that Linux uses tabs instead of spaces to indent each level, with a default tab size of 8 spaces (-ts8). However, tabs don’t always work well on websites, so I’ve converted these to spaces using a separate program called untab. The output looks like this:

$ indent -linux fact.c
$ untab fact.c
#include <stdio.h>

int fact(int n)
{
        if ((n == 0) || (n == 1)) {
                return 1;
        } else if (n > 1) {
                return (n * fact(n - 1));
        } else {
                puts("Error!");
                return 0;       /* return zero */
        }
}

int main()
{
        int i;

        for (i = 0; i <= 5; i++) {
                printf("%d! is %d\n", i, fact(i));
        }

        return 0;               /* exit program */
}

Make it look the way you want

You can combine options or add other command line arguments to modify a common style to one you prefer. For example, my personal coding style is similar to the K&R C style, but with a few changes: I always prefer spaces instead of tabs, and comments start at column 40 (halfway across the screen on an old-style 80-column display). I also prefer to put else statements on a new line from the if statement above it. To change this behavior from the K&R style, I add a few options after -kr on the command line:

$ indent -kr --no-tabs -c40 --dont-cuddle-else fact.c
$ cat fact.c
#include <stdio.h>

int fact(int n)
{
    if ((n == 0) || (n == 1)) {
        return 1;
    }
    else if (n > 1) {
        return (n * fact(n - 1));
    }
    else {
        puts("Error!");
        return 0;                      /* return zero */
    }
}

int main()
{
    int i;

    for (i = 0; i <= 5; i++) {
        printf("%d! is %d\n", i, fact(i));
    }

    return 0;                          /* exit program */
}

I find that this provides a good balance of readability without using too much vertical space, for the instances where I need to include that code in printed material such as books.

Rather than remember those extra options every time I use Indent, I created a 1-line script called reindent that does it for me. Note that in Bash scripts, "$@" expands to list each command line option separately, but as though each were enclosed in its own quotes.

#!/bin/bash
# wrapper to GNU indent
# use K&R style, but spaces instead of tabs, comments at col 40,
# don't cuddle '}' and 'else'

indent -kr --no-tabs -c40 --dont-cuddle-else "$@"

By using a formatting tool like Indent, you can restructure source code to make it easier to include source code in your technical documents. This is also useful if you need to include source code that uses different styles - such as programming samples written by one person, combined with code listings written by another programmer - so that all of your code samples are formatted consistently.