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