1Datalight Coding Style 2====================== 3 4This is a description of the Datalight Coding Style intended for third parties 5who want to contribute code to Reliance Edge. This document is derived from the 6DDSS Coding Guidelines, but only contains a subset of the content which is most 7likely to be relevant to third party contributors. 8 9Reliance Edge complies with the MISRA-C:2012 coding guidelines, which includes 10many rules that affect coding style. Unfortunately the MISRA-C:2012 document is 11not freely available, and is much too long to be effectively summarized, but if 12you are familiar with the rules, adhere to them. A few important rules of 13thumb: avoid the goto and continue keywords; avoid using more than one break 14in a loop; and avoid having more than one return from a function (single point 15of exit); default cases in every switch statement; avoid recursion; and make 16generous use of parentheses. Outside of the file system driver, in tests and 17host tools, the MISRA-C rules are relaxed. 18 19Beyond MISRA-C, Datalight has a standard coding style. Most aspects of this 20style are matters of preference, but when contributing code to Datalight an 21effort should be made to use this style for the sake of consistency. 22 23Below is an example function, which illustrates several key points of Datalight 24Coding Style: 25 26/** @brief One-sentence description of what this function does. 27 28 Additional description. 29 30 @param ulFirstParameter Description of the parameter. 31 @param pszPointer Description of the parameter. 32 33 @return Describe the return value. 34 35 @retval true Optional description of specific return value. 36 @retval false Optional description of specific return value. 37*/ 38bool ExampleFunction( 39 uint32_t ulFirstParameter, 40 char *pszPointer) 41{ 42 bool fStatus = true; 43 44 /* This is a single-line comment. 45 */ 46 if(ulFirstParameter > 0U) 47 { 48 /* This is a multi-line comment. It is a comment that spans multiple 49 lines. It is explaining the important following function call. 50 This is the last line of this multi-line comment. 51 */ 52 FunctionCall(); 53 54 while(fStatus) 55 { 56 fStatus = AnotherFunction(ulFirstParameter, pszPointer); 57 } 58 } 59 60 return fStatus; 61} 62 63Tab Stop Conventions 64-------------------- 65 66In all C code (.c/.h), use a tab width of four spaces, and use soft tabs (in 67other words, tabs are expanded to spaces). In Makefiles, use hard tabs and a 68tab width of 8. 69 70Naming 71------ 72 73Datalight uses CamelCase for functions and variables. Type names are generally 74UPPERCASE, except for standard types like uint32_t. Preprocessor macros are 75UPPERCASE, with words separated by underscores (for example, INODE_INVALID). 76 77Doxygen Documentation 78--------------------- 79 80Doxygen is used to document functions (including static functions), along with 81types, structures, files, etc. For Doxygen tags, use '@' instead of a backslash 82(thus "@param" not "\param"). 83 84Function Declarations 85--------------------- 86 87Multi-line function declarations are preferred, as they tend to be more 88readable. Use the following form: 89 90static bool ExampleFunctionDeclaration( 91 uint32_t ulFirstParameter, 92 char *pszPointer, 93 uint8_t **ppbBuffer) 94{ 95 uint16_t uLocalVar; /* descriptive comment */ 96 uint8_t *pbBuffer = NULL; /* descriptive comment */ 97 98 Function body... 99} 100 101The following guidelines should be used: 102 103- Align both the data-type and the variable names, for parameters and locals, at 104 the same level if practical. 105- For pointer types, the '*' belongs to the variable name---it's not part of the 106 data-type, so keep it with the variable name. 107- If useful, single line comments may be used to describe local variables (not 108 a requirement). 109- For functions with no parameters, the "void" declaration does not need to be 110 on a separate line. 111- Generally each variable should be declared on a separate line. This promotes 112 readability, and facilitates having a comment for each variable. 113 114Function declarations should be spaced apart by two blank lines between the 115closing brace which ends a function and the Doxygen comment which starts the 116next. 117 118Curly Braces 119------------ 120 121Datalight lines up all curly braces vertically. As per MISRA-C, curly braces 122are never omitted, even if the braces contain only a single statement. 123 124For consistency, even structure declarations and initializations should use the 125same style, with the curly braces lined up vertically. One exception is for 126structure initializations where both the opening and closing curly braces can 127fit on the same line. If so, do it. 128 129Code Comments 130------------- 131 132Datalight uses the standard C style /* comments */. C++ style comments (//) are 133never used. The Datalight standard comment style is shown below. This style 134applies to all general comments within the code. 135 136/* This is a single-line comment. 137*/ 138if(ulFirstParameter > 0U) 139{ 140 /* This is a multi-line comment. It is a comment that spans multiple 141 lines. It is explaining the important following function call. 142 This is the last line of this multi-line comment. 143 */ 144 while(fStatus) 145 { 146 } 147} 148 149Note the characteristics: 150 151- The /* and */ align with the natural 4 character indentation. 152- The comment text is exactly indented another 4 characters. 153- The comment text starts on the same line as the opening /*. 154- The terminating */ is on its own line. 155- There is usually a single blank line preceding the comment, however if the 156 preceding line is an opening curly brace, then an extra blank line is not 157 necessary. 158- There is usually no blank line after the comment, but rather the closing */ 159 "attaches" the comment to the code about which the comment refers. 160- These comments should always fit with the standard 80 character margin. 161 162Comments where the /* and */ are on the same line may be used in a few places: 163 164- For variable or parameter descriptions, where the comment fits on the same 165 line as the declaration. 166- For structure member declarations, where the comment fits on the same line as 167 the declaration. 168- For macros or preprocessor logic, where the comment fits on the same line. 169 170It is OK for such comments to exceed the 80 character margin by a small amount, 171if necessary, as this sometimes promotes code readability. 172 173Indentation Style 174----------------- 175 176The general paradigm used in Datalight code is that curly braces line up 177vertically, and everything in between them is indented. This should include all 178comments, labels, and preprocessor symbols. The only things which are aligned 179at the left-most columns are: 180 181- Symbols, variables, declarations, and preprocessor logic which are at the 182 module-scope (outside of a function) 183- Comments which are outside of a function 184- Function declarations 185- Function open and closing curly braces 186 187Typically comments are always lined up directly with the code to which they 188apply. 189 190Labels (when used; gotos are disallowed in driver code) are lined up two 191characters to the left of the code they reside in, to make them stand out, while 192as the same time, still remaining subservient to the level of curly braces in 193which they reside. For example: 194 195bool ExampleLabelUsage(void) 196{ 197 MutexLock(); 198 199 Lots of complicated code... 200 201 Unlock: 202 203 MutexUnlock(); 204 205 return fSuccess; 206} 207 208Preprocessor logic, such as controlling features which are conditionally 209compiled in or out, should not disrupt the flow of the code, but rather should 210be indented in similar fashion to the code it controls, but positioned two 211characters to the left. For example, consider the following code snippet. The 212preprocessor conditions are both indented relative to the outer curly braces, 213but do not disrupt the normal code flow. 214 215int32_t red_statvfs( 216 const char *pszVolume, 217 REDSTATFS *pStatvfs) 218{ 219 REDSTATUS ret; 220 221 ret = PosixEnter(); 222 if(ret == 0) 223 { 224 uint8_t bVolNum; 225 226 ret = RedPathSplit(pszVolume, &bVolNum, NULL); 227 228 #if REDCONF_VOLUME_COUNT > 1U 229 if(ret == 0) 230 { 231 ret = RedCoreVolSetCurrent(bVolNum); 232 } 233 #endif 234 235 if(ret == 0) 236 { 237 ret = RedCoreVolStat(pStatvfs); 238 } 239 240 PosixLeave(); 241 } 242 243 return PosixReturn(ret); 244} 245 246Note that, like anything else between curly brackets, the contents of a switch 247statement are indented: 248 249switch(ulSignature) 250{ 251 case META_SIG_MASTER: 252 fValid = (uFlags == BFLAG_META_MASTER); 253 break; 254 case META_SIG_IMAP: 255 fValid = (uFlags == BFLAG_META_IMAP); 256 break; 257 case META_SIG_INODE: 258 fValid = (uFlags == BFLAG_META_INODE); 259 break; 260 case META_SIG_DINDIR: 261 fValid = (uFlags == BFLAG_META_DINDIR); 262 break; 263 case META_SIG_INDIR: 264 fValid = (uFlags == BFLAG_META_INDIR); 265 break; 266 default: 267 fValid = false; 268 break; 269} 270 271Maximum Line Length 272------------------- 273 274The maximum line length for code need not be rigidly limited to the traditional 27580 characters. Nevertheless the line lengths should be kept reasonable. 276Anything longer than 100 to 120 characters should probably be broken up. The 277most important consideration is readability---fitting on the screen is important 278for readability, but equally important is facilitating an easy understanding of 279the logical code flow. 280 281There are a few exceptions on both sides of the issue. Generally comments 282should be limited to 80 characters always. Some lines of code may exceed the 283120 character length by a large margin, if it makes the code more understandable 284and maintainable. This is especially true when dealing with code that generates 285output which needs to be lined up. 286 287Regardless of everything else, no lines should exceed 250 characters because 288some editors cannot handle anything larger. 289 290Maximum Display Output Line Length 291---------------------------------- 292 293Any code which displays TTY style output, whether on a screen or a terminal, 294should be constructed so the output is readable and wraps properly on an 80 295character wide display. This primarily applies to the "standard" output from 296various tests and tools as well as syntax output for those tests and tools; 297debug output can violate this rule. 298 299Preprocessor Notation 300--------------------- 301 302Don't use preprocessor notation where the # is separated from the keyword by one 303or more white spaces. For example, don't do: 304 305#ifndef SYMBOL1 306# define SYMBOL1 307#endif 308 309Instead, do: 310 311#ifndef SYMBOL1 312 #define SYMBOL1 313#endif 314 315Hexadecimal Notation 316-------------------- 317 318Use uppercase for any alphabetic hexadecimal digits, and lower case for the 319notational element. For example: 320 321#define HEXNUM 0x123abd /* Bad */ 322#define HEXNUM 0X123ABD /* Bad */ 323#define HEXNUM 0x123ABD /* Good */ 324 325Hungarian Notation 326------------------ 327 328Datalight uses Hungarian notation. The following type prefixes are used: 329 330Type Prefix | Meaning 331----------- | ------- 332c | char 333uc | unsigned char 334i | int 335n | unsigned int or size_t 336b | uint8_t 337u | uint16_t 338ul | uint32_t 339ull | uint64_t 340sz | array of char that will be null-terminated 341f | bool 342h | A handle 343fn | A function (always used with the "p" modifier) 344 345There is no official Hungarian for int8_t, int16_t, int32_t, or int64_t, 346although some code uses unofficial variants (like "ll" for int64_t). 347 348The following modifiers may be used in combination with the type prefixes 349defined above, or in combination with other types: 350 351Modifier | Meaning 352-------- | ------- 353a | An array 354p | A pointer 355g | A global variable 356 357Notes: 358 359- There is no standard Hungarian for structure declarations, however the use of 360 the "a" and "p" modifiers is completely appropriate (and expected). 361- For those data types which do not have any standard defined Hungarian prefix, 362 using none is preferable to misusing another prefix which would lead to 363 confusion. 364- The "p" pointer modifier must be used such that a variable which is a pointer 365 to a pointer uses multiple "p" prefixes. A general rule-of-thumb is that the 366 variable name should have the same number of "p" prefixes as the declaration 367 has asterisks. This allows pointer expressions to be easily decoded using 368 cancellation. 369 370Variable Scope 371-------------- 372 373Declare a variable in the narrowest scope in which it is meaningful. 374Unnecessarily declaring all variables at the beginning of a function, where they 375may be physically far from where they are actually used, makes the code harder 376to maintain. 377 378When multiple blocks of code share a variable, but not its value, declare the 379variable separately for each code block. 380 381For example, if two separate blocks contain loops indexed by a variable ulIndex 382declare it separately in each block rather than declaring it once in a wider 383scope and using it in both places. 384 385Using distinct declarations in the two blocks allows the compiler to check for 386failure to initialize the variable in the second block. If there is a single 387declaration, the (now meaningless) value left over from the first block can be 388used erroneously in the second block. 389 390