1 Overview
This document describes the coding style and practices that will be followed by this project. The goal of these guidelines is to produce consistent, maintainable code. However, since style is a personal thing, feel free develop in a style and environment that best suits your needs. However, before any code is accepted by the project, it must comply with the following guidelines. Over time, we hope to build/assemble tools and processes that automatically check code and/or convert it to the required format and style. Until then, the best rule of thumb is to follow the lead of the code that already exists.
1.1 Revision
$Id: README.STYLE,v 1.1 2005/04/29 18:55:03 mavrik Exp $
1.2 Table of Contents
Section 1 .................... Overview Section 1.1 .................. Revision Section 1.2 .................. Table of Contents Section 1.3 .................. General Section 1.3.1 ................ Caveats Section 1.4 .................. Margins Section 1.4.1 ................ Margins for Code Section 1.4.2 ................ Margins for Comments Section 1.5 .................. Indentation Section 1.6 .................. Headers Section 1.6.1 ................ Header for C Section 1.6.2 ................ Header for Perl Section 1.6.3 ................ Header for Shell Section 1.7 .................. Comments Section 1.7.1 ................ Comments for C Section 1.7.2 ................ Comments for Perl Section 1.7.3 ................ Comments for Shell Section 1.7.4 ................ Comments for CVS Section 1.8 .................. Braces Section 1.9 .................. Variables Section 1.9.1 ................ Variable Names Section 1.9.1.1 .............. Variable Names for C Section 1.9.1.2 .............. Variable Names for Perl Section 1.10 ................. Functions Section 1.10.1 ............... Function Declarations Section 1.10.1.1 ............. Function Declarations for C Section 1.10.1.2 ............. Function Declarations for Perl Section 1.10.2 ............... Function Prototypes Section 1.10.2.1 ............. Function Prototypes for C Section 1.10.2.2 ............. Function Prototypes for Perl Section 1.11 ................. Whitespace Section 1.11.1 ............... Trailing Spaces Section 1.11.2 ............... Tabs Section 1.11.3 ............... Calls and Conditionals Section 1.11.4 ............... Parentheses and Arguments
1.3 General
As a general rule, before any changes are checked in, they must conform to the style guidelines and code must compile cleanly and run on all supported platforms.
1.3.1 Caveats
This document is a work in progress. It's not perfect; it's not complete; but it's better than nothing.
1.4 Margins
1.4.1 Margins for Code
A hard margin is not imposed for code. Whenever possible, code should be written such that there is one statement per line.
As a general rule, if you can print the code out in landscape mode without the lines wrapping, you're probably fine. Also, if you can resize your xterm such that the entire line can be viewed on a single screen without wrapping, you're probably fine.
In situations where this is not practical or readable, let the following examples guide you. The idea is to stack items (e.g., arguments or logic tests) vertically.
In the example shown here, putting the entire statement on one line is too much -- even on a fairly wide xterm.
snprintf(acData, iLength, "Some format with a lot of arguments %s, %s, %s, %s, %s, %s\n", psProperties->acSomeVariable1, psProperties->acSomeVariable2, psProperties->acSomeVariable3, psProperties->acSomeVariable4, psProperties->acSomeVariable5, psProperties->acSomeVariable6);
Thus, it should be reformatted as follows:
snprintf(acData, iLength, "Some format with a lot of arguments %s, %s, %s, %s, %s, %s\n",
psProperties->acSomeVariable1,
psProperties->acSomeVariable2,
psProperties->acSomeVariable3,
psProperties->acSomeVariable4,
psProperties->acSomeVariable5,
psProperties->acSomeVariable6
);
It should not, however, be reformatted like this:
snprintf(acData, iLength, "Some format with a lot of arguments %s, %s, %s, %s, %s, %s\n",
psProperties->acSomeVariable1, psProperties->acSomeVariable2, psProperties->acSomeVariable3,
psProperties->acSomeVariable4, psProperties->acSomeVariable5, psProperties->acSomeVariable6);
Here's an example of a large if statement:
if ((conditionA && conditionB && conditionC && conditionD) || (conditionE && conditionF && conditionG && conditionH) || (conditionI && conditionJ && conditionK && conditionL) || (conditionM && conditionN && conditionO && conditionP))
This should be reformatted as follows:
if
(
(conditionA && conditionB && conditionC && conditionD) ||
(conditionE && conditionF && conditionG && conditionH) ||
(conditionI && conditionJ && conditionK && conditionL) ||
(conditionM && conditionN && conditionO && conditionP)
)
1.4.2 Margins for Comments
The soft and hard margins for comments are 68 and 70, respectively. Here's an example:
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
####################################################################
#
# If you are inserting a descriptive comment, try to ensure that it
# does not exceed the soft margin like the previous line just did.
#
####################################################################
If that happens, try running the comment lines through the fmt(1) command. Here's the previous comment after it has been processed by fmt:
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
####################################################################
#
# If you are inserting a descriptive comment, try to ensure that
# it does not exceed the soft margin like the previous line just
# did.
#
####################################################################
1.5 Indentation
Use 2 spaces for each additional indentation level. Tabs are not allowed. If your editor automatically inserts tabs, you'll need to figure out how to disable that behavior, or you'll need a way to convert tabs into the correct number of spaces.
1.6 Headers
All text files (i.e., scripts, C code, Makefiles, etc.) should display a standard header that includes a CVS Id and a copyright.
1.6.1 Header for C
123456789012345678901234567890123456789012345678901234567890123456789012
1 2 3 4 5 6 7 /*-
*
- $Id: README.STYLE,v 1.1 2005/04/29 18:55:03 mavrik Exp $
*
* - Copyright <YYYY> - <YYYY> The <Name> Project, All Rights Reserved.
*
*/ #include "all-includes.h"
/*-
*
- Main
*
*/ int main(int iArgumentCount, char *ppcArgumentVector[]) { <code> }
1.6.2 Header for Perl
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
#!/usr/bin/perl -w
######################################################################
#
# $Id: README.STYLE,v 1.1 2005/04/29 18:55:03 mavrik Exp $
#
######################################################################
#
# Copyright <YYYY> - <YYYY> The <Name> Project, All Rights Reserved.
#
######################################################################
#
# Purpose: <Description>
#
######################################################################
use strict;
use File::Basename;
######################################################################
#
# Main
#
######################################################################
######################################################################
#
# Main Routine
#
######################################################################
####################################################################
#
# Punch in and go to work.
#
####################################################################
my ($sProgram);
$sProgram = basename(__FILE__);
####################################################################
#
# Get Options.
#
####################################################################
my (%hOptions);
if (!getopts('<your_list>', \%hOptions))
{
Usage($sProgram);
}
1.6.3 Header for Shell
For shell scripts, three variables should always be set: PROGRAM, PATH, and IFS. The standard IFS variable should contain the following characters: space, tab, and newline. Note that cutting and pasting this header may corrupt the IFS variable, so be sure to check it each time you create a new script.
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
#!/bin/sh
######################################################################
#
# $Id: README.STYLE,v 1.1 2005/04/29 18:55:03 mavrik Exp $
#
######################################################################
#
# Copyright <YYYY> - <YYYY> The <Name> Project, All Rights Reserved.
#
######################################################################
#
# Purpose: <Description>
#
######################################################################
IFS='
'
PATH=/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin
PROGRAM=`basename $0`
1.7 Comments
Major comment blocks and CVS commit messages should be formatted with fmt(1). This can be done in vi as follows:
From edit mode (cursor on first line of the paragraph):
!}fmt
From command mode macro (cursor on first line of the paragraph):
map #1 :.,/^$/!fmt^[}
Note: The ^[ in this macro is created by typing CTRL-v followed by ESC.
Note: The expression /^$/ matches empty lines. Therefore, it is important to periodically remove trailing spaces that crop up from time to time -- usually they are the product of a cut and paste operation (see section 1.11).
1.7.1 Comments for C
Minor, inline comments in the code body should be appended to the end of the line as follows:
iIndex = 1; /* This is an inline comment. */
Major comments in the code body should be formated as follows:
123456789012345678901234567890123456789012345678901234567890123456789012
1 2 3 4 5 6 7 /*-
*
- This is a level one comment.
*
*/
123456789012345678901234567890123456789012345678901234567890123456789012
1 2 3 4 5 6 7 /*-
*
- This is a level two comment.
*
*/
123456789012345678901234567890123456789012345678901234567890123456789012
1 2 3 4 5 6 7 /*-
*
* This is a level three comment.
*
*******************************************************************
*/
1.7.2 Comments for Perl
Minor, inline comments in the code body should be appended to the end of the line as follows:
$sIndex = 1; # This is an inline comment.
Major comments in the code body should be formated as follows:
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
######################################################################
#
# This is a level one comment.
#
######################################################################
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
####################################################################
#
# This is a level two comment.
#
####################################################################
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
##################################################################
#
# This is a level three comment.
#
##################################################################
1.7.3 Comments for Shell
Minor, inline comments in the code body should be appended to the end of the line as follows:
INDEX=1 # This is an inline comment.
Major comments follow the same conventions as for Perl.
1.7.4 Comments for CVS
Comment for CVS logs should always be formatted with fmt(1). They also need to have any trailing spaces removed (see Trailing Spaces section).
1.8 Braces { }
Always use braces, and always format them as follows:
if (test == 1)
{
logic;
}
The following are examples of forms that that are not accepted.
if (test == 1) {
logic;
}
if (test == 1)
logic;
1.9 Variables
1.9.1 Variable Names
Variable names should be descriptive and be expressed in the form of an object (e.g., iCount, pcFilename).
When possible, initialize variables as they are declared.
The use of global variables should be minimized, and unless there is a good reason, they should not be used at all. That being said, the naming convention for globals is the same as for locals with one difference: all globals are to be prefixed with the letter 'g'. For example:
char *gpcFilename;
1.9.1.1 Variable Names for C
Specify the variable type in small letters. Then, capitalize the first letter of each successive word (e.g., iTimeLimit).
Simple ints such as i, j, k, n, x, and y do not require the type specifier (i.e., iI, iJ, etc.) as that would make them overly cumbersome. However their use is not encouraged either. Simple chars can be declared as c, ac, or pc.
Here are some example declarations:
FILE *pFile; char acBuffer[SIZE]; char *pc; int iTimeCounter; long lContentLength;
unsigned long ulAddress;
unsigned long long ullFileSize;
1.9.1.2 Variable Names for Perl
Unless there is a good reason, all variables should be declared using my. The first letter of the variable should be a lower case letter (a, h, o, s) that indicates the type (i.e., array, hash, object, or scalar). Then, capitalize the first letter of each successive word.
Here are some example declarations:
my @aName; # Array
my %hName; # Hash
my $oName; # Object
my $sName; # Scalar
All reference (i.e., pointer) variable names should be prefixed with the letter 'p'. Continuing with the examples from above:
my $paName = \@aName; # Array Reference my $phName = \%hName; # Hash Reference my $poName = \$oName; # Object Reference my $psName = \$sName; # Scalar Reference
1.10 Functions
Function and subroutine names should be descriptive and be expressed in the form of an action (e.g., GetHostname, ConvertToHex).
Capitalize the first letter of each word (e.g., ExampleRoutine). If one of the words in the name is an acronym (e.g., SSL), then capitalize the first letter of that word and force the remaining letters to lower case (e.g., ExampleSslRoutine).
Additionally, these names should not be prone to name collisions. To help prevent that from happening, prefix each routine with the <name> of the project or a logical grouping to which it belongs. For example, suppose you had a routine for the WebJob project that you wanted to call GetProperties. Under this naming convention, that routine should be called WebJobGetProperties.
Function and subroutine names should always be called with the parentheses snuggled up to the name as follows:
ExampleRoutine()
but not like this
ExampleRoutine ()
1.10.1 Function Declarations
All functions and subroutines should have 2 blank lines above them.
1.10.1.1 Function Declarations for C
123456789012345678901234567890123456789012345678901234567890123456789012
1 2 3 4 5 6 7 /*-
*
- ExampleRoutine1
*
*/ void ExampleRoutine1(char *pcName, char *pcError) { <code> }
/*-
*
- ExampleRoutine2
*
*/ int ExampleRoutine2(int iIndex, char *pcError) { <code> }
/*-
*
- ExampleRoutine3
*
*/ char * ExampleRoutine3(PROPERTIES *pcProperties, char *pcError) { <code> }
1.10.1.2 Function Declarations for Perl
In general, don't pass anything but scalars to subroutines. If you need to pass an array, hash, or object into a subroutine, pass it as a reference (i.e., \@, \%, or \$).
Call subroutines like this:
ExampleRoutine();
but not like this:
&ExampleRoutine;
1234567890123456789012345678901234567890123456789012345678901234567890
1 2 3 4 5 6 7
######################################################################
#
# ExampleRoutine1
#
######################################################################
sub ExampleRoutine1
{
my ($sScalar1, $paArray1, $phHash1, $poObject1) = @_;
<code>
}
1.10.2 Function Prototypes
1.10.2.1 Function Prototypes for C
C function prototypes should be specified in a local include file with the entire prototype being specified on a single line.
void ExampleRoutine1(char *pcName, char *pcError);
1.10.2.2 Function Prototypes for Perl
Perl function prototypes are not generally used by this project.
1.11 Whitespace
1.11.1 Trailing Spaces
Before checking in any text-based files, make sure that there are no unwanted trailing spaces. A quick way to do this in vi is as
- follows
-
:%s/ *$//gc;
Here's a macro to do the same:
map #3 :%s/ *$//gc^[
Note: The ^[ in this macro is created by typing CTRL-v followed by ESC.
Note: Trailing spaces should also be removed from CVS comments prior to the final commit.
1.11.2 Tabs
No tabs are allowed. The exceptions are the IFS variable in shell scripts and any tabs used by the program or script being coded.
1.11.3 Calls and Conditionals
There should be no space between a function or subroutine call and its opening parenthesis.
ExampleRoutine()
There should be one space between a conditional and its opening parenthesis.
if ()
while ()
switch ()
Here are examples of forms that are not allowed:
ExampleRoutine ()
if()
1.11.4 Parentheses and Arguments
There should be no space inside of parentheses except between arguments. A single space should be used to separate arguments.
Here are examples of the required form:
if (iCount <= 3 || iCount >= 9)
ExampleRoutine(pcName1, pcName2, pcName3);
Here are examples of forms that are not allowed:
if ( iCount <= 3 || iCount >= 9 )
if (iCount<=3||iCount>=9)
ExampleRoutine( pcName1, pcName2, pcName3 );
ExampleRoutine(pcName1,pcName2,pcName3);
