| Datalight Coding Style | |
| ====================== | |
| This is a description of the Datalight Coding Style intended for third parties | |
| who want to contribute code to Reliance Edge. This document is derived from the | |
| DDSS Coding Guidelines, but only contains a subset of the content which is most | |
| likely to be relevant to third party contributors. | |
| Reliance Edge complies with the MISRA-C:2012 coding guidelines, which includes | |
| many rules that affect coding style. Unfortunately the MISRA-C:2012 document is | |
| not freely available, and is much too long to be effectively summarized, but if | |
| you are familiar with the rules, adhere to them. A few important rules of | |
| thumb: avoid the goto and continue keywords; avoid using more than one break | |
| in a loop; and avoid having more than one return from a function (single point | |
| of exit); default cases in every switch statement; avoid recursion; and make | |
| generous use of parentheses. Outside of the file system driver, in tests and | |
| host tools, the MISRA-C rules are relaxed. | |
| Beyond MISRA-C, Datalight has a standard coding style. Most aspects of this | |
| style are matters of preference, but when contributing code to Datalight an | |
| effort should be made to use this style for the sake of consistency. | |
| Below is an example function, which illustrates several key points of Datalight | |
| Coding Style: | |
| /** @brief One-sentence description of what this function does. | |
| Additional description. | |
| @param ulFirstParameter Description of the parameter. | |
| @param pszPointer Description of the parameter. | |
| @return Describe the return value. | |
| @retval true Optional description of specific return value. | |
| @retval false Optional description of specific return value. | |
| */ | |
| bool ExampleFunction( | |
| uint32_t ulFirstParameter, | |
| char *pszPointer) | |
| { | |
| bool fStatus = true; | |
| /* This is a single-line comment. | |
| */ | |
| if(ulFirstParameter > 0U) | |
| { | |
| /* This is a multi-line comment. Filler text: Lorem ipsum dolor sit | |
| amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt | |
| ut labore et dolore magna aliqua. | |
| */ | |
| FunctionCall(); | |
| while(fStatus) | |
| { | |
| fStatus = AnotherFunction(ulFirstParameter, pszPointer); | |
| } | |
| } | |
| return fStatus; | |
| } | |
| Tab Stop Conventions | |
| -------------------- | |
| In all C code (.c/.h), use a tab width of four spaces, and use soft tabs (in | |
| other words, tabs are expanded to spaces). In Makefiles, use hard tabs and a | |
| tab width of 8. | |
| Naming | |
| ------ | |
| Datalight uses CamelCase for functions and variables. Type names are generally | |
| UPPERCASE, except for standard types like uint32_t. Preprocessor macros are | |
| UPPERCASE, with words separated by underscores (for example, INODE_INVALID). | |
| Doxygen Documentation | |
| --------------------- | |
| Doxygen is used to document functions (including static functions), along with | |
| types, structures, files, etc. For Doxygen tags, use '@' instead of a backslash | |
| (thus "@param" not "\param"). | |
| Function Declarations | |
| --------------------- | |
| Multi-line function declarations are preferred, as they tend to be more | |
| readable. Use the following form: | |
| static bool ExampleFunctionDeclaration( | |
| uint32_t ulFirstParameter, | |
| char *pszPointer, | |
| uint8_t **ppbBuffer) | |
| { | |
| uint16_t uLocalVar; /* descriptive comment */ | |
| uint8_t *pbBuffer = NULL; /* descriptive comment */ | |
| Function body... | |
| } | |
| The following guidelines should be used: | |
| - Align both the data-type and the variable names, for parameters and locals, at | |
| the same level if practical. | |
| - For pointer types, the '*' belongs to the variable name---it's not part of the | |
| data-type, so keep it with the variable name. | |
| - If useful, single line comments may be used to describe local variables (not | |
| a requirement). | |
| - For functions with no parameters, the "void" declaration does not need to be | |
| on a separate line. | |
| - Generally each variable should be declared on a separate line. This promotes | |
| readability, and facilitates having a comment for each variable. | |
| Function declarations should be spaced apart by two blank lines between the | |
| closing brace which ends a function and the Doxygen comment which starts the | |
| next. | |
| Curly Braces | |
| ------------ | |
| Datalight lines up all curly braces vertically. As per MISRA-C, curly braces | |
| are never omitted, even if the braces contain only a single statement. | |
| For consistency, even structure declarations and initializations should use the | |
| same style, with the curly braces lined up vertically. One exception is for | |
| structure initializations where both the opening and closing curly braces can | |
| fit on the same line. If so, do it. | |
| Code Comments | |
| ------------- | |
| Datalight uses the standard C style /* comments */. C++ style comments (//) are | |
| never used. The Datalight standard comment style is shown below. This style | |
| applies to all general comments within the code. | |
| /* This is a single-line comment. | |
| */ | |
| if(ulFirstParameter > 0U) | |
| { | |
| /* This is a multi-line comment. Filler text: Lorem ipsum dolor sit amet, | |
| consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore | |
| et dolore magna aliqua. | |
| */ | |
| while(fStatus) | |
| { | |
| } | |
| } | |
| Note the characteristics: | |
| - The /* and */ align with the natural 4 character indentation. | |
| - The comment text is exactly indented another 4 characters. | |
| - The comment text starts on the same line as the opening /*. | |
| - The terminating */ is on its own line. | |
| - There is usually a single blank line preceding the comment, however if the | |
| preceding line is an opening curly brace, then an extra blank line is not | |
| necessary. | |
| - There is usually no blank line after the comment, but rather the closing */ | |
| "attaches" the comment to the code about which the comment refers. | |
| - These comments should always fit with the standard 80 character margin. | |
| Comments where the /* and */ are on the same line may be used in a few places: | |
| - For variable or parameter descriptions, where the comment fits on the same | |
| line as the declaration. | |
| - For structure member declarations, where the comment fits on the same line as | |
| the declaration. | |
| - For macros or preprocessor logic, where the comment fits on the same line. | |
| It is OK for such comments to exceed the 80 character margin by a small amount, | |
| if necessary, as this sometimes promotes code readability. | |
| Indentation Style | |
| ----------------- | |
| The general paradigm used in Datalight code is that curly braces line up | |
| vertically, and everything in between them is indented. This should include all | |
| comments, labels, and preprocessor symbols. The only things which are aligned | |
| at the left-most columns are: | |
| - Symbols, variables, declarations, and preprocessor logic which are at the | |
| module-scope (outside of a function) | |
| - Comments which are outside of a function | |
| - Function declarations | |
| - Function open and closing curly braces | |
| Typically comments are always lined up directly with the code to which they | |
| apply. | |
| Labels (when used; gotos are disallowed in driver code) are lined up two | |
| characters to the left of the code they reside in, to make them stand out, while | |
| as the same time, still remaining subservient to the level of curly braces in | |
| which they reside. For example: | |
| bool ExampleLabelUsage(void) | |
| { | |
| MutexLock(); | |
| Lots of complicated code... | |
| Unlock: | |
| MutexUnlock(); | |
| return fSuccess; | |
| } | |
| Preprocessor logic, such as controlling features which are conditionally | |
| compiled in or out, should not disrupt the flow of the code, but rather should | |
| be indented in similar fashion to the code it controls, but positioned two | |
| characters to the left. For example, consider the following code snippet. The | |
| preprocessor conditions are both indented relative to the outer curly braces, | |
| but do not disrupt the normal code flow. | |
| int32_t red_statvfs( | |
| const char *pszVolume, | |
| REDSTATFS *pStatvfs) | |
| { | |
| REDSTATUS ret; | |
| ret = PosixEnter(); | |
| if(ret == 0) | |
| { | |
| uint8_t bVolNum; | |
| ret = RedPathSplit(pszVolume, &bVolNum, NULL); | |
| #if REDCONF_VOLUME_COUNT > 1U | |
| if(ret == 0) | |
| { | |
| ret = RedCoreVolSetCurrent(bVolNum); | |
| } | |
| #endif | |
| if(ret == 0) | |
| { | |
| ret = RedCoreVolStat(pStatvfs); | |
| } | |
| PosixLeave(); | |
| } | |
| return PosixReturn(ret); | |
| } | |
| Note that, like anything else between curly brackets, the contents of a switch | |
| statement are indented: | |
| switch(ulSignature) | |
| { | |
| case META_SIG_MASTER: | |
| fValid = (uFlags == BFLAG_META_MASTER); | |
| break; | |
| case META_SIG_IMAP: | |
| fValid = (uFlags == BFLAG_META_IMAP); | |
| break; | |
| case META_SIG_INODE: | |
| fValid = (uFlags == BFLAG_META_INODE); | |
| break; | |
| case META_SIG_DINDIR: | |
| fValid = (uFlags == BFLAG_META_DINDIR); | |
| break; | |
| case META_SIG_INDIR: | |
| fValid = (uFlags == BFLAG_META_INDIR); | |
| break; | |
| default: | |
| fValid = false; | |
| break; | |
| } | |
| Maximum Line Length | |
| ------------------- | |
| The maximum line length for code need not be rigidly limited to the traditional | |
| 80 characters. Nevertheless the line lengths should be kept reasonable. | |
| Anything longer than 100 to 120 characters should probably be broken up. The | |
| most important consideration is readability---fitting on the screen is important | |
| for readability, but equally important is facilitating an easy understanding of | |
| the logical code flow. | |
| There are a few exceptions on both sides of the issue. Generally comments | |
| should be limited to 80 characters always. Some lines of code may exceed the | |
| 120 character length by a large margin, if it makes the code more understandable | |
| and maintainable. This is especially true when dealing with code that generates | |
| output which needs to be lined up. | |
| Regardless of everything else, no lines should exceed 250 characters because | |
| some editors cannot handle anything larger. | |
| Maximum Display Output Line Length | |
| ---------------------------------- | |
| Any code which displays TTY style output, whether on a screen or a terminal, | |
| should be constructed so the output is readable and wraps properly on an 80 | |
| character wide display. This primarily applies to the "standard" output from | |
| various tests and tools as well as syntax output for those tests and tools; | |
| debug output can violate this rule. | |
| Preprocessor Notation | |
| --------------------- | |
| Don't use preprocessor notation where the # is separated from the keyword by one | |
| or more white spaces. For example, don't do: | |
| #ifndef SYMBOL1 | |
| # define SYMBOL1 | |
| #endif | |
| Instead, do: | |
| #ifndef SYMBOL1 | |
| #define SYMBOL1 | |
| #endif | |
| Hexadecimal Notation | |
| -------------------- | |
| Use uppercase for any alphabetic hexadecimal digits, and lower case for the | |
| notational element. For example: | |
| #define HEXNUM 0x123abd /* Bad */ | |
| #define HEXNUM 0X123ABD /* Bad */ | |
| #define HEXNUM 0x123ABD /* Good */ | |
| Hungarian Notation | |
| ------------------ | |
| Datalight uses Hungarian notation. The following type prefixes are used: | |
| Type Prefix | Meaning | |
| ----------- | ------- | |
| c | char | |
| uc | unsigned char | |
| i | int | |
| n | unsigned int or size_t | |
| b | uint8_t | |
| u | uint16_t | |
| ul | uint32_t | |
| ull | uint64_t | |
| sz | array of char that will be null-terminated | |
| f | bool | |
| h | A handle | |
| fn | A function (always used with the "p" modifier) | |
| There is no official Hungarian for int8_t, int16_t, int32_t, or int64_t, | |
| although some code uses unofficial variants (like "ll" for int64_t). | |
| The following modifiers may be used in combination with the type prefixes | |
| defined above, or in combination with other types: | |
| Modifier | Meaning | |
| -------- | ------- | |
| a | An array | |
| p | A pointer | |
| g | A global variable | |
| Notes: | |
| - There is no standard Hungarian for structure declarations, however the use of | |
| the "a" and "p" modifiers is completely appropriate (and expected). | |
| - For those data types which do not have any standard defined Hungarian prefix, | |
| using none is preferable to misusing another prefix which would lead to | |
| confusion. | |
| - The "p" pointer modifier must be used such that a variable which is a pointer | |
| to a pointer uses multiple "p" prefixes. A general rule-of-thumb is that the | |
| variable name should have the same number of "p" prefixes as the declaration | |
| has asterisks. This allows pointer expressions to be easily decoded using | |
| cancellation. | |
| Variable Scope | |
| -------------- | |
| Declare a variable in the narrowest scope in which it is meaningful. | |
| Unnecessarily declaring all variables at the beginning of a function, where they | |
| may be physically far from where they are actually used, makes the code harder | |
| to maintain. | |
| When multiple blocks of code share a variable, but not its value, declare the | |
| variable separately for each code block. | |
| For example, if two separate blocks contain loops indexed by a variable ulIndex | |
| declare it separately in each block rather than declaring it once in a wider | |
| scope and using it in both places. | |
| Using distinct declarations in the two blocks allows the compiler to check for | |
| failure to initialize the variable in the second block. If there is a single | |
| declaration, the (now meaningless) value left over from the first block can be | |
| used erroneously in the second block. | |