summaryrefslogtreecommitdiff
path: root/doc/CODING-STYLE
diff options
context:
space:
mode:
Diffstat (limited to 'doc/CODING-STYLE')
-rw-r--r--doc/CODING-STYLE312
1 files changed, 312 insertions, 0 deletions
diff --git a/doc/CODING-STYLE b/doc/CODING-STYLE
new file mode 100644
index 0000000..4287cd2
--- /dev/null
+++ b/doc/CODING-STYLE
@@ -0,0 +1,312 @@
+
+1. General Style
+
+Indentation level is 4. The indentation character is space, regardless of
+the overall indentation level. IOW, even if nested indentation causes the
+overall indentation level to be greater or equal to 8 use spaces only.
+Don't leave trailing white space at the end of lines.
+
+Line length is 80 columns. You need to break up longer lines to multiple
+chunks at reasonable boundaries. What counts as a reasonable boundary
+depends on what you are breaking up. There is very seldom, if ever, a
+good enough reason to break the 80-column line rule.
+
+
+2. Layout and Tabulation
+
+2.1 Curly Braces
+
+Opening curly braces are put last on the line, while closing curly braces
+are on lines of their own. Generally this applies to all control-flow
+blocks, IOW to if, for, while, do, and switch statements. The most notable
+exceptions are the while in a do-while statement, if-else-if chains and
+functions.
+
+Some examples:
+
+ if (!condition) {
+ foo();
+ foobar();
+ }
+ else {
+ bar();
+ barfoo();
+ }
+
+ while (check) {
+ do_something();
+ and_something_else();
+ }
+
+Exceptions:
+
+ do {
+ process();
+ and_more();
+ } while (need_to);
+
+ if (foo < bar) {
+ foo();
+ bar();
+ } else if (bar < foo) {
+ foobar();
+ barfoo();
+ } else {
+ frobnicate();
+ xyzzy();
+ }
+
+In a function you put both the opening and the closing braces on lines
+of their own:
+
+ int foo(int x)
+ {
+ if (x < 10)
+ return foobar(x);
+ else
+ return barfoo(x);
+ }
+
+
+If you have a single statement in a block, you can omit the opening
+and closing braces. However in an if-else it is preferred to keep the
+braces unless both branches are single statements. Also, do not omit
+the braces for do-while statements.
+
+Examples:
+
+ if (x < 0)
+ foo(x);
+ else
+ bar(x);
+
+Note however, that we prefer to keep braces here:
+
+ if (y < 10) {
+ foo(y);
+ }
+ else {
+ foobar(y);
+ barfoo(x);
+ }
+
+ do {
+ x = xyzzy();
+ } while (x < 10);
+
+
+2.2 Indentation and Spaces
+
+Individual cases and the default case is indented to align with the
+switch statement itself:
+
+ switch (foo) {
+ case 1:
+ so_its_one();
+ break;
+ case 2:
+ uh_two();
+ break;
+ case 3:
+ oh_boy_three();
+ break;
+ default:
+ oh_no(foo);
+ }
+
+If you have a more complex set of statements in the cases, it is preferable
+to include an extra empty line for clarity before all but the first case and
+the default branch.
+
+ switch (x) {
+ case 1:
+ if (y < 10)
+ horribly(x);
+ else if (y < 20)
+ complex(x);
+ else if (x + y > 200)
+ processing(x, y);
+ break;
+
+ case 2:
+ ...
+ break;
+
+ ...
+ default:
+ ...
+ }
+
+The general rule for space usage is the following:
+
+ - use one space after control-flow keywords (if, for, while, do,
+ switch, case)
+ - use one space around binary and and ternary operators (=, +, -,
+ *, /, %, |, &, ^, <, >, <=, >=, ==, !=, ? :)
+ - don't use space after unary operators (&, *, +, -, ~, !)
+ - don't use space after the following keywords: sizeof, typeof,
+ alignof, __attribute__
+ - don't use spaces before postincrement/postdecrement or pre-
+ increment/predecrement operators (++, --)
+ - don't use spaces around structure or union member operators (., ->)
+ - don't use spaces after the preprocessor directive 'defined'
+
+
+Deviating from these basic preferences is okay if it helps increasing
+readibility, for instance by resulting in more compact code and hence
+more code per editor surface area. For example, one might choose an
+alternative, more compact layout for a switch statement that consists
+only of trivially simple case branches, like this:
+
+ switch (f->value.type) {
+ case SI_TYPE_INT16: f->value.i16 = va_arg(ap, int32_t); break;
+ case SI_TYPE_UINT16: f->value.u16 = va_arg(ap, uint32_t); break;
+ case SI_TYPE_INT32: f->value.i32 = va_arg(ap, int32_t); break;
+ case SI_TYPE_UINT32: f->value.u32 = va_arg(ap, uint32_t); break;
+ case SI_TYPE_INT64: f->value.i64 = va_arg(ap, int64_t); break;
+ case SI_TYPE_UINT64: f->value.u64 = va_arg(ap, uint64_t); break;
+ case SI_TYPE_BOOL: f->value.bln = va_arg(ap, int); break;
+ case SI_TYPE_DOUBLE: f->value.dbl = va_arg(ap, double); break;
+ default:
+ return FALSE;
+}
+
+
+2.3 Accepted Tabulation Schemes
+
+There are two tabulation schemes you can choose from:
+
+ 1) obsessive alignitis: the manic alignment of variable definitions,
+ structure and union member definitions, variable assignments within
+ a code block end so forth
+
+ 2) traditional K&R-ish reductionist style, minimizing the amount of
+ white space while adhering to the rules of the above sections
+
+But be consistent with yourself, do not try to mix these. Choose one
+and stick with it within a component. Also if you are touching any
+existing code obey the existing style.
+
+
+2.4 Code Layout
+
+Put licensing information to the beginning of every file.
+Within a module put includes and macro definitions in the beginning
+(of course). Then put type definitions, any necessary static function
+prototypes and finally module-local variables before the actual
+functions of the module.
+
+Within a function, define variables in the beginning of the function.
+You can also put variable definitions at the beginning of code blocks
+with curly braces, eg. within if, else, for, while, and switch-constructs.
+Please do not pull variables out of your arse^H^H^H^Hstack in the middle
+of a function at any other place.
+
+
+2.5 Error Handling
+
+There are two acceptable error-indication mechanism from functions:
+boolean style and libc style. It depends on your component which one makes
+sense. If upon failure it is of no use to the caller to get more
+information than the mere fact of failure use boolean style error
+indication returning true on success and false otherwise. In this case,
+include stdbool.h in your public header and use bool as the return type
+of your function to indicate the boolean convention to your readers. If
+you choose the libc-style, return 0 on success, return -1 on failure and
+also set errno to some reasonable error code in this case. Never ever
+clear errno on success. Naturally, functions that return objects should
+return NULL on failure with both of these styles.
+
+Whenever you have a non-trivial function with complex control-flow try
+to organise your code so that there is a single common error cleanup
+and return path. You can put this at the end of your function, label it
+as 'fail', and use goto's to jump from the middle of the function to the
+error-handling branch.
+
+
+2.6 Function Prototypes
+
+Use function prototypes with variable names in public header files.
+
+
+3. Naming Conventions
+
+The basic general naming rule is no CamelCase, use only lower-case
+letters, use underscore ('_') as a word separator within symbol names
+for functions and variables. Macros are all upper-case with the exception
+of function-like macros that take arguments. Just like functions, these
+can be all-lower case at will if this makes more sense. Typical cases
+when this makes sense would be a macro that wraps a function call and
+extends the argument list with additional parameters, or a guarding
+convenience wrapper macro with extra error checks for calling a function
+in some external component that does not handle some common error cases,
+such as being called with a NULL pointer on cleanup code paths.
+
+For Murphy core, all externally visible symbols must be prefixed with
+mrp_ to avoid name-space collisions with other components.
+
+3.1 Type Names
+
+Externally visible types (at least structs, unions and enums) must be
+typedef'd. The chosen type name must be prefixed consistently with the
+other publicly visible types from the same component. All typedef'd
+names are suffixed with _t. If you need to also have a non-typedef'd
+struct, or union for internal use for some reason, suffix it with _s
+or _u depending on its type.
+
+3.2 Function and Variable Names
+
+All externally visible functions and variables must be prefixed with
+a component-specific prefix-. For Murphy core this is mrp_. For libraries
+that can be easily re-used without Murphy, you can chose any prefix you
+like, but keep it short, preferably up to 3 or 4 characters max.
+
+For global variables always use fulle/long descriptive names, keeping in
+mind the lower-case only and underscore restrictions. For local variables
+and function arguments try to strike the right balance between compactness
+and descriptiveness. On one hand too long names hurt readability and waste
+a lot of precious real estate on our 80 character character terminals from
+the 70's. On the other hand too short or unintuitively shortened names
+fail to provide the right association about the usage of the variables for
+the reader. So this is not that black and white and it is not easy to give
+a set of strict rules that one could blindly follow. If someone familiar
+with the subject your code is addressing gets constantly confused with
+what your variables are for, you are probably overdoing the compactness
+part. If the same person gets constantly frustrated/tired reading your
+variable names, you are probably underdoing it...
+
+Library global function and variable names, ie. symbols whose visibility
+is limited to the scope of the library, should be prefixed with the module
+prefix within the library they are defined in.
+
+3.3 File Naming Conventions
+
+Don't prefix your file names with a component name. Use dashes instead
+of underscores in file and directory names.
+
+
+4. Miscallanea
+
+4.1 Use of Goto
+
+There are cases when the careful use of gotos make the code both easier
+to read/follow and less error-prone to modify/extend than with any of
+the alternatives. Typical examples are consolidated bailout/cleanup code
+on error paths from complex functions with nested blocks of if/for/while
+statements. Also it is often cleaner to use directly gotos instead of
+emulating them with an while-(0)-break non-loop construct.
+
+
+
+
+
+
+
+
+Generally speaking, it would be beneficial to come up with a basic set
+of rules that can also be expressed as a set of command line options to
+indent (or any other available alternative). That would provide a canonical
+way for people to check their code for indentation-conformance. Also we
+could use it ourselves in git hooks to warn about code with non-conformant
+style which otherwise might be difficult to avoid in the beginning.
+