Batch Indentation with Emacs

Author: Stan Warford
Email: Message to Warford

Introduction

Most visual text editors for programmers have a re-indent feature. However, for large projects with many C/C++/Java files, I frequently need a script that I can execute from the command line that will indent the code in a source file without manually opening the file in the text editor. Emacs has two versatile commands, c-set-style and indent-region, that are useful when you are editing your program with Emacs. This page describes how to apply these commands in batch mode from the command line without ever getting into Emacs.

The Emacs script

You only need one file with the following content:
;;; File: emacs-format-file
;;; Stan Warford
;;; 17 May 2006

(defun emacs-format-function ()
   "Format the whole buffer."
   (c-set-style "stroustrup")
   (indent-region (point-min) (point-max) nil)
   (untabify (point-min) (point-max))
   (save-buffer)
)
I recommend that you put a copy of this script in your bin directory in a file named emacs-format-file.

The first command is c-set-style. Emacs has a large number of predefined styles including gnu, k&r, bsd, stroustrup, linux, python, java, whitesmith, ellemtel, cc-mode, and user. My current favorite is stroustrup as in the above script. You can replace stroustrup with your own choice of style. The second command indents the entire file. The third command replaces tabs with spaces to make the file printer-friendly. If you want tabs in your file, omit the untabify command. The fourth command saves the re-indented file if necessary, that is, if the previous commands actually changed the file. You might wind up with the usual Emacs ~ backup file as well.

To execute the script issue the following command:
emacs -batch file-to-indent -l ~/bin/emacs-format-file -f emacs-format-function
assuming you have put the script in your bin directory. Emacs will echo the actions it is taking. If the indentation is taking a long time it will even echo its progress.

A Bourne shell script

Of course, you probably don't want to type that long command every time you need to indent a source file. So, here is a Bourne shell script that wraps the command up with all the fancy error checking bells and whistles. I recommend that you put a copy of this script in your directory in a file named my-indent, or whatever else you want to call it. Thanks to Michael Jensen for improving the script to provide multiple file processing and Rick Hull for a bug fix.
#!/bin/sh
# File: my-indent
# Opens a set of files in emacs and executes the emacs-format-function.
# Assumes the function named emacs-format-function is defined in the
# file named emacs-format-file.

if [ $# -eq 0 ]
then
   echo "my-indent requires at least one argument." 1>&2
   echo "Usage: my-indent files-to-indent" 1>&2
   exit 1
fi
while [ $# -ge 1 ]
do
   if [ -d $1 ]
   then
      echo "Argument of my-indent $1 cannot be a directory." 1>&2
      exit 1
   fi
   # Check for existence of file:
   ls $1 2> /dev/null | grep $1 > /dev/null
   if [ $? != 0 ]
   then
      echo "my-indent: $1 not found." 1>&2
      exit 1
   fi
   echo "Indenting $1 with emacs in batch mode"
   emacs -batch $1 -l ~/bin/emacs-format-file -f emacs-format-function
   echo
   shift 1
done
exit 0