This document superceeds any other prior documentation or commentary regarding
the formatting of the Hamlib C and C++ source code.  This document does not
apply to the Autotools build system, i.e. configure.ac, Makefile.am or the
Autoconf macros in the 'macros/' directory.


0. Background

Throughout its life, a number of coding styles have found their way into the
Hamlib source tree.  Besides lacking a readable consistency, recent compilers
have reported logic errors likely due to inconsistent formatting.  Such errors
can escape notice during casual scanning of a source file.


1. Objective

Adopt certain mandatory and recommended coding guidelines to aid in
readability of the Hamlib C source code and avoid logic errors due to
inconsistent code formatting to the extent possible.


2. Mandatory rules

* The use of tab characters, ASCII hexadecimal 0x09, shall no longer be
  permitted for the indentation and alignment of C or C++ source or header
  files, only spaces, ASCII hexadecimal 0x20, shall be used for indentation
  and alignment.  The use of the '\t' escape sequence in rig_debug() output,
  static strings, and the like is permitted.

* Indentation shall be 4 spaces.  Alignment shall consist of the number of
  spaces necessary after indentation.

Discussion: Plenty has been written regarding the use of the tab character in
source files and the proper setup of the various editors.  There is no point
in rehashing that here, except to say that spaces are universal.  Modern
editors are configurable to setting indents to four spaces and tab stops to
four spaces.

* Bare conditionals shall be avoided.  All conditionals--'if', 'else', 'for',
  'while', and 'do while' shall have their statements enclosed in braces.

  NOTE: Exceptions will be allowed in certain rare circumstances.  See
  Recommended coding style bullet points below.

Discussion:  Consider this conditional:

             if (something);
                do_that();

No harm, eh?  Look again.  The programmer gave the 'if' conditional a null
statement with the trailing ';' at the end of the line and also indented the
'do_that();' statement.  As a result, 'do_that()' will be called whether
'something' is true or not.  Is that what the programmer intended?

If, instead, the code is formatted to:

             if (something)
             {
                ;
                do_that();
             }

the null statement becomes harmless and 'do_that()' is called depending on the
truth of 'something'.

Here proper indentation and alignment is only half the battle in finding such
bugs, enclosing all statement blocks in braces is the other half.

Patch submissions will be checked for adherence to these two rules.  While
patches won't be rejected outright, the corrections will be applied and the
patch set rebased before being pushed to the repositories.


3. Recommended coding style

The following bullet points follow the formatting the Artistic Style code
formatter will apply when using the included 'scripts/astylerc' configuration
file.  Any version from 2.03 or later should work.  It can be invoked from a
backend directory as follows:

    $ astyle --options=../scripts/astylerc moonmelter.c

The old file will be copied to 'moonmelter.c.orig' as a back up.

* Brace style is Allman where the opening brace of a function definition is on
  a new line in the far left column following the function signature.

  For conditionals, the opening brace is also on a new line after the
  conditional test and aligned in the same column as the first letter of the
  keyword.

  In all cases the closing brace is on a line of its own and lines up
  vertically with the opening brace.

  The 'else', 'else if', or 'while' from a 'do while' loop keywords are not
  cuddled after the closing brace but placed on a new line after the closing
  brace of the previous block.

* Indents are four spaces as detailed above.  Each level of code should be one
  indent further to the right.

* Isolate conditional blocks with a blank line before and after.  Like
  paragraphs in prose that focus on a topic, it's important that conditionals
  be obvious to the reader.  An exception is where another conditional follows
  immediately on the next line.  Indentation is sufficient.

* No space between parentheses and the enclosed characters.

* One space on either side of operators and between function arguments.

* One space between a conditional key word and its opening parentheses.

* No space between a function name and its opening paretheses.

* No space between a pointer operator ('*') and the pointer name.  Likewise
  for the address operator ('&').  Exception:  In a function prototype and
  definition, a space should be put between the '*' operator and the
  function/macro name to indicate a pointer is returned, not that the
  function/macro name is an assigned pointer value.

* Keep code lines under 80 characters.  This will require some judgement on
  where the break works best.  A couple of keys are, a) break conditionals
  before a comparison operator so it appears at the beginning of the next
  line, and, b) when breaking a function call, put all arguments on their own
  line.  It is sometimes necessary for strings to go beyond the 80 character
  point.  This is fine.  If needed, a C compiler will concatenate strings that
  are split across multiple lines.

* Avoid trailing comments when possible.  Comments should precede the
  statement(s) they describe.

* One line conditionals should enclose the statement in braces, as in:

      if (whatsit == 5) { return whatsit; }

  or:

      do { x++; } while (x < 10)

  When choosing not to use braces on a simple one line conditional, please
  comment your intention:

      /* NOP unless x is true. */
      while (!x);

3.1 Shell scripts

Shell scripts should be written for POSIX portability as much as possible.
Avoid using '/bin/bash' in the shebang line.  Use '/bin/sh' instead to allow
for use of the system shell (some systems may not have Bash installed at all!)
when the script is run.  The caveat is that some favorite Bash extensions are
not POSIX portable so care is needed.  To help avoid the pitfalls, various
tools exist such as 'checkbashisms' which will report syntax that is not
portable.

* Use four space indents as with the C style above.

* Vertical space around conditional blocks can aid readability (newlines are
  cheap!).

* Try to keep line length between 80 and 100 characters if possible.
  Backslashes (\) can sometimes be used to break up long lines.  Be careful as
  the shell is often less forgiving than the C compiler with extra spaces.
  Experiment.

* Avoid the use of backticks (`) to invoke a subshell, also known as the grave
  accent and backquote, in shell scripts, configure.ac, any Makefile.am, or
  .m4 files we maintain.  While their use will likely be long supported, they
  do require some care in use and can be difficult to read on the screen.

  The preferred construct is to use parentheses to invoke a subshell and the
  '$()' construct when the output of the command is intended to be captured in
  a shell variable.  This answer covers the reasoning well:

        https://unix.stackexchange.com/a/126928

  In Makefile.am files use the '$$()' construct to capture subshell command
  output into a make variable.

  Exceptions:

  Files intended to be formatted in Markdown syntax use backticks as a
  formatting cue.  In these files such use is permitted.

  There are a number of files sourced from the GNU Project where the
  backtick is used extensively as an opening single quote character.  As we
  don't usually maintain these files except to update them as needed, these
  rules are waived for those files.

3.2 Python

Python authors are already well aware of the classic PEP8 and need no further
instruction on the matter.

3.3 Perl

Perl authors already know their code can resemble modem line noise and it will
work flawlessly.  Somehow.

3.4 Makefile

When indenting a line in a Makefile.am (and the resulting Makefile) that a
real Tab character (0x09) is required.  Spaces will cause 'make' errors.


4. Use of code formatting tools

There are a number of tools that can be used to format the source code.  Some
are standalone and others are part of an editor or IDE.

4.1 astyle

Use of the Artistic Style (astyle) formatter (http://astyle.sourceforge.net/)
with the included options file ('scripts/astylerc') will provide most of the
objectives outlined above.  Some manual formatting may be required.  For
example, if a line is already less than 80 characters and ends with an
operator, astyle will not move the operator to the beginning of the next line
where it is preferred.

4.2 GNU Indent

GNU Indent lacked a few of the features of astyle for padding conditional
blocks and enforcing spaces around operators and between comma separated
arguments (if I'm mistaken, please provide a working example--N0NB).
Otherwise, acceptable results should be possible.

4.3 GNU Emacs

GNU Emacs with the included C Mode can be configured to provide acceptable
formatting while editing source files.  Eventually a custom Hamlib style elisp
file will be included in the 'scripts/' directory.

Useful minor modes include:

modeline-char:             Displays the character and its Unicode value on the
                           modeline.
fill-column-indicator:     Draws a vertical line at fill column.

highlight-numbers:         Applies a color face to numeric constants.

highlight-parentheses:     Highlights parentheses and the nesting braces
                           around point (cursor).
cwarn:                     Parses the C code for harmful constructs.

whitespace:                Shows whitespace--tabs, spaces, and newlines in the
                           buffer.

4.4 Other editors & IDEs

Other editors and IDEs likely have various ways to apply ones preferred
style.  The main things to configure are having the <Tab> key produce four
spaces and that tab stops be every four positions across the screen (if
configurable).


5 Summary

Hamlib source code is no place for an entry into the obfuscated C contest!
Many of us are hobbyists and write this for fun.  Easy to read and understand
logic is preferred over a clever solution.  If your solution must be written
in a clever fashion, please document it well in your comments.

73, Nate, N0NB
