Paul's Thoughts on Coding
Style and Philosophy
Over the years since 1962 when I first began writing programs, I have developed a style of coding that greatly enhances the ability of people, including myself, to read and understand the logic of the code.
Have you ever looked at a piece of code you wrote a few years ago and had difficulty following and understanding the code?
Unix coding philosophy
It seems that the coding style currently being taught in universities is all about coding speed and neglects the poor guy (or gal) who must, some day, come behind the original coder and understand the program logic in order to repair or improve it.
Video displays used to view code have a very limited number of horizontal lines which can cause readers to be constantly scrolling up and down to understand the logic of a piece of code.
The inability of the reader to see a complete set of logic without scrolling, introduces an element of error, since the viewer must be doing two operations at once (reading/understanding and scroll) instead of just concentrating on understanding the logic.
There are two objectives of computer coding:
1 get the computer to do what you want.
2 make the logic of the program easily understood by anyone reading the code.
This second objective us usually neglected or ignored (in the name of haste) by todays coders.
I believe that consistency in coding style is extremely important for the reader (the compiler couldn't care less).
At the end of this doc are some code snippets from msg.c in the infrastructure which illustrate the following guidelines.
Coding Guidelines:
-
1.Conserve vertical space (due to the limited view imposed by screen size).
-
2.Expend horizontal space to conserve vertical space and make code more understandable.
-
3.Only 1 empty or blank line inside a function (separate variable definitions from the logic with a single blank line).
-
4. The left curly brace at the beginning of a code block shall always be directly under the first letter of the conditional keyword that invokes the block. This is an excellent place for a comment about what the block does or why we are going to it.
-
5. Indent the contents of a block 1 tab more than the enclosing curly braces.
-
6. The right curly brace at the end of a code block shall be indented the same distance as the leading curly brace for the block.
-
7. A 'C' keyword or function name is IMMEDIATELY followed by the left parin enclosing the arguments (no intervening space) and the left parin is always followed by a space. This makes keywords and function names stand out, more easily found by a reader.
-
8. Operators are always preceded and followed by a single space.
-
9. Commas separating function arguments should always be followed by a single space.
-
10. Always use extra parins in complex logic expressions to group sub expressions (make the logic more apparent).
-
11. Make variable and function names meaningful without being overly verbose. The function name "operation_to_force_mary_to_seek_employment_elsewhere()" could be reduced to "fireMary()". Not only does the longer name burn up a lot of horizontal space, but it promotes typos. About terseness, consonants carry the sound of a word so try removing the vowels in a variable or function name to shorten it without loosing it's sound (an occasional vowel is not necessarily a bad thing). Articles and conjunctions are an important part of the English language, but they shouldn't be used in variable or function names. When a variable or function name includes several words, make the first letter in each word upper case, don't use underscores. Another thought, since you can call a funcion and pass it's return as an argument to another function call { barf( firMry() }, a really long function name, used as an argument, can make this line of code wrap. Local variables, since they are local to the current function in scope, don't need to have the function name as part of the variable name.
-
12. In general try not to wrap lines for a single operation, but if you need to, make sure an operator is the first character on following or wrapped lines.
-
13. Try to keep functions to about 60 lines. If a function requires a lot of logic, try breaking it into several functions which are called from the original function.
14. In variable definitions use several spaces after the type and align the beginning of variable names (It makes them easier to see/find). Place basic 'C' types at the beginning followed by system types. Don't be overly concerned about commenting in the variable definition section, do it in the code.
-
15. Code from top to bottom (yes you'll have to prototype). Put main first, the the functions it immediately calls, the the functions they call etc. I also place all static functions at the last of the module.
-
16. Function an local variable names always start with lower case letters using a single upper case letter at the beginning of each word within the name. The upper casing of each word within a global variable name is also a good thing.
-
17. All local functions not used by outside modules should always be prototyped and declared "static". Variables global to the current module and not used by other modules should always be declared "static".
-
18. Global variables always start with an upper case letter, local variables always start with a lower case letter.
-
19. Defined constants are all upper case except where wrapping a function to provide compiler generated info (like table size). When I wrap a function within a macro, I always spell the function just like the macro except add a leading underscore.
-
20. Casting all functions to (void) where the return code is not used is a waste of time and clutters the listing.
/*H********************************************************************
* Opaque Request Response message system.
* Copyright Paul Turner Sept 1997
* "$Id: msg.c,v 1.67 2008/07/23 17:52:31 pturner Exp $";
*H*********************************************************************/
#include
#include
#include
#include "inf.h"
#include "msg.h"
// ===================== DEFINITIONS ====================================
#ifndef _UCHAR
#define _UCHAR
typedef unsigned char uchar;
#endif
#define DFLTTIMEOUT 10000 // 10 SEC
#define MSGDFLTLEN 40000
#define MSGDTF 0X00000001
#define MSGREQ 0X00000002
#define MSGPEND 0X00000004
#define SEPCHR ESC
#define RNDUP(val,mdl) (mdl>0?((val +(mdl-1))&-mdl):val)
#define barf( tblA ) _barf( tblA, sizeof( tblA ))
typedef struct msgs { // MESSAGE CONTROL BLOCK
int sd;
int flags;
int type;
int code;
int reqId;
int eType;
int eCode;
int tid;
char questor[STRMAX];
char rPath[STRMAX];
clok_t stamp;
char *mp;
char peer[STRMAX];
}msgs_t;
typedef struct msgThd { // MESSAGE THREAD CONTROL BLOCK
int tid;
int flags;
char *mp;
#ifdef INF_PTHREADS
pthread_mutex_t mut;
pthread_cond_t cond;
#else
char *mut;
char *cond;
#endif
}mThd_t;
// ====================== PROTOTYPES ====================================
static int freeHndl( int hndl );
static int msgCtl( char *msg, char *ap );
static int msgDconn( void *context, int sd );
static int msgGetBigFld( int hndl, char *fNam, int typ, int outSiz, char *out);
static int msgPutBigBin( int hndl, char *fldNam, int datLen, char *dat );
static int msgPutBigStr( int hndl, char *fldNam, int datLen, char *dat );
static int multiPktRcv( int hdl, char *fNam, int typ, int bSiz, void *dat);
static char *pkt_rcv( int timOut );
static char *pkt_rcvL( int timOut );
static int msgReOpn( msgs_t *mc );
static char *multiPktSnd( char *msg, int hndl );
static int msg_snd( char*mp );
static int newHndl();
// =================== GLOBAL VARIABLES =================================
static int MsgTimeOut = DFLTTIMEOUT, MsgDfltLen = MSGDFLTLEN;
static int HndlUse, HndlFree;
static msgs_t *Msgs[MAXMSGS];
static mThd_t Mthd[MAXPTIDS];
#ifdef INF_PTHREADS
static pthread_mutex_t HndlLck = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t RxLck = PTHREAD_MUTEX_INITIALIZER;
#else
static char *HndlLck;
static char *RxLck;
#endif
CFG_BGN( "Msg" ) // CONFIGURATION VARIABLE DEFINITION
CFG_INT( "MSG_DFLT_LEN", MsgDfltLen )
CFG_INT( "MSG_DFLT_TIMOT", MsgTimeOut )
CFG_END
CTL_BGN // INFCTL DEFINITIONS
CTL_CB( "Msg", msgCtl )
CTL_END
/*F**********************************************************************
* DESC: Wait to receive a message.
* RTRN: message handle else ERR.
*F**********************************************************************/
int
msgRcv( int watTim )
{
int hndl;
char *mp, *sp;
if( !(mp = pkt_rcv( watTim )) || ((int)mp == ERR) )
return( (int)mp );
hndl = newHndl(); // ALLOCATE A HANDLE FOR THE NEW MESSAGE
Msgs[hndl]->mp = mp;
Msgs[hndl]->sd = ioGetHndl( mp );
if( !Msgs[hndl]->peer[0] )
{
if( !(sp = ioGetPeer( mp )))
return( trcErr( "no peer, discard msg, Sd %d", ioGetHndl(mp)));
strcpy( Msgs[hndl]->peer, ioGetPeer( mp ) );
zotChr( Msgs[hndl]->peer, ATSIGN );
}
moGetI( mp, "type", Msgs[hndl]->type );
moGetI( mp, "code", Msgs[hndl]->code );
moGetI( mp, "reqId", Msgs[hndl]->reqId );
moGetI( mp, "msgTid", Msgs[hndl]->tid );
moGetS( mp, "questor", Msgs[hndl]->questor );
if( moGetI( mp, "execType", Msgs[hndl]->eType ) > 0 );
{ // ITS A ROUTED MESSAGE
moGetI( mp, "execCode", Msgs[hndl]->eCode );
moGetS( mp, "rtrPath" , Msgs[hndl]->rPath );
}
moRew( mp ); // REWIND THE MESSAGE BEFORE RETURNING IT TO CALLER
trc( TRC_MSG +20, "OK, hndl:%d, mp: 0X%08lX", hndl, (long)mp );
return( hndl +1 ); // INCR HANDLE BEFORE RETURNING IT TO CALLER
}
/*F**********************************************************************
* DESC: make a response to a received message.
* RTRN: The new message handle.
*F**********************************************************************/
int
msgMkRsp( int oHndl, int stat )
{
int nHndl;
char *mpo, *mpn, *pp;
msgs_t *mcn;
trc( TRC_MSG +20, "hndl: %d, stat %d", oHndl -1
, stat );
if( (--oHndl >MAXMSGS) || (oHndl <0) || !Msgs[oHndl] // DECR HANDLE
|| !(mpo=Msgs[oHndl]->mp))
return( trcErr( "bad handle %d or no mp", oHndl));
pp = ioGetPeer( mpo );
zotChr( pp, ATSIGN );
if( !(mpn = ioDupMsg( mpo, MsgDfltLen )))
return( trcErr( "ioDupMsg error"));
nHndl = newHndl();
mcn = Msgs[nHndl];
mcn->mp = mpn;
moSetFlg( mpn, MO_RSP ); // MARK MSG AS RESPONSE
mcn->code = RESPONSE;
mcn->type = Msgs[oHndl]->type; // MULTI-PKT NEEDS THIS
mcn->reqId = Msgs[oHndl]->reqId; // MULTI-PKT NEEDS THIS
if( Msgs[oHndl]->eType != 0 )
{ // ITS A ROUTER TYPE MESSAGE GET THE PERTINENT STUFF
mcn->eType = Msgs[oHndl]->eType;
mcn->eCode = Msgs[oHndl]->eCode;
strcpy( mcn->rPath, Msgs[oHndl]->rPath );
}
strcpy( mcn->peer, pp );
moRst( mpn, MsgDfltLen );
if( trcIsMsk( TRC_SRC ) )
moSetFlg( mpn, MO_TRC );
moPutI( mpn, "type", Msgs[oHndl]->type );
moPutI( mpn, "code", RESPONSE );
moPutI( mpn, "status", stat );
moPutI( mpn, "reqId", Msgs[oHndl]->reqId );
if( Msgs[oHndl]->tid ) // NEW pt 08/30/07 @ 09:53
moPutI( mpn, "msgTid", Msgs[oHndl]->tid );
if( Msgs[oHndl]->eType != 0 )
{ // ITS A ROUTER TYPE MESSAGE PUT THE PERTINENT STUFF
moPutI( mpn, "execType", Msgs[oHndl]->eType );
moPutI( mpn, "execCode", Msgs[oHndl]->eCode );
moPutS( mpn, "rtrPath", Msgs[oHndl]->rPath );
}
return( nHndl +1); // INCR HANDLE BEFORE RETURNING IT
}
/*F**********************************************************************
* DESC: Search a message for the next field.
* RTRN: OK, else ERR, else NOTFND.
*F**********************************************************************/
int
msgNxtFld( int hndl, char *fldNam, int *fLen )
{
int rtn, tot, cnt, len;
char *mp, *dp, nam[STRMAX], fNam[STRMAX], dat[STRMAX];
if( (--hndl >MAXMSGS) || (hndl <0) || !Msgs[hndl] || !(mp=Msgs[hndl]->mp) )
return( trcErr( "bad handle %d, Fld %s", hndl, fldNam));
while( 1 )
{
if( moTstFldFlg( mp, "*", MOBIGFLD ) )
{ // CURRENT IS BIG FIELD, READ THROUGH IT
moCurDat( mp, nam, dat );
moGetI( mp, nam, tot );
dp = malloc( MsgDfltLen +1);
for( cnt =1; (tot >0) ; cnt++, tot -= len )
{
sprintf( fNam, "%s%c%d", nam, SEPCHR, cnt );
len = multiPktRcv( hndl, fNam, MO_STR, MsgDfltLen +1, dp );
}
free( dp );
}
if( (rtn = moNxtFld( mp, fldNam, fLen )) >0 )
{
if( moTstFldFlg( mp, "*", MOBIGFLD ) )
{
switch( rtn )
{
case MO_INT:
case MO_BIN:
break;
case MO_STR:
if( moGetS( mp, fldNam, dat ) <=0 )
trcErr( "bigFld [%s] Str get len failed", fldNam );
*fLen = atol( dat );
break;
}
}
return( trc( TRC_MSG +20, "hndl: %d, %s, Typ:%d", hndl, fldNam, rtn), rtn);
}
if( !rtn && (moIsNxtRcd( mp ) || !moTstFlg( mp, MO_DTF )))
return( NOTFND );
ioFree( mp );
trc( TRC_MSG +20, "receiving, hndl: %d", hndl );
if( !MsgTimeOut )
{
rtn =trcErr( "MsgTimeOut Zero???" );
break;
}
if( !(mp = pkt_rcv( MsgTimeOut )) || ((int)mp == ERR) )
{
rtn = 0;
trcErr( "pkt_rcv timeout [%d] or err %d", MsgTimeOut, (int)mp );
break;
}
Msgs[hndl]->mp = mp;
}
return( rtn );
}