sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 899c641da2397952ea0404cceea094386e385c0a
parent 03ae8b43ac644738ef243a526f794bb3ed980c3d
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sun,  7 Apr 2019 15:13:03 +0200

rework code-style page

- Add punctuation for list items.
- Avoid nested code-blocks in list items, this is not well-defined in markdown
  and does not work consistently across parsers.
- Remove some guidelines.
- Clarify some guidelines.
- ... etc ...

Diffstat:
Msuckless.org/coding_style/index.md | 234+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 134 insertions(+), 100 deletions(-)

diff --git a/suckless.org/coding_style/index.md b/suckless.org/coding_style/index.md @@ -2,159 +2,193 @@ Style ===== Note that the following are guidelines and the most important aspect of style is consistency. Strive to keep your style consistent with the project on which -you are working. +you are working. It is up to the project maintainer to take some liberty in the +style **guidelines**. + Recommended Reading ------------------- The following contain good information, some of which is repeated below, some of which is contradicted below. +* <https://man.openbsd.org/style> * <http://doc.cat-v.org/bell_labs/pikestyle> * <https://www.kernel.org/doc/Documentation/process/coding-style.rst> -* <https://man.openbsd.org/style> + File Layout ----------- -* Comment with LICENSE and possibly short explanation of file/tool +* Comment with LICENSE and possibly short explanation of file/tool. * Headers * Macros * Types -* Function declarations - * Include variable names - * For short files these can be left out - * Group/order in logical manner -* Global variables -* Function definitions in same order as declarations +* Function declarations: + * Include variable names. + * For short files these can be left out. + * Group/order in logical manner. +* Global variables. +* Function definitions in same order as declarations. * `main` + C Features ---------- -* Use C99 without extensions (ISO/IEC 9899:1999) - * When using gcc compile with -std=c99 -pedantic -* Use POSIX.1-2008 - * When using gcc define `_POSIX_C_SOURCE 200809L` - * Alternatively define `_XOPEN_SOURCE 700` -* Do not mix declarations and code -* Do not use for loop initial declarations -* Use `/* */` for comments, not `//` -* Variadic macros are acceptable, but remember - * `__VA_ARGS__` not a named parameter - * Arg list cannot be empty +* Use C99 without extensions (ISO/IEC 9899:1999). +* Use POSIX.1-2008: + * When using gcc define `_POSIX_C_SOURCE 200809L`. + * Alternatively define `_XOPEN_SOURCE 700`. +* Do not mix declarations and code. +* Do not use for loop initial declarations. +* Use `/* */` for comments, not `//`. +* Variadic macros are acceptable, but remember: + * `__VA_ARGS__` not a named parameter. + * Arg list cannot be empty. + Blocks ------ -* All variable declarations at top of block -* `{` on same line preceded by single space (except functions) -* `}` on own line unless continuing statement (`if else`, `do while`, ...) -* Use block for single statement iff - * Inner statement needs a block - for (;;) { - if (foo) { - bar; - baz; - } - } - * Another branch of the same statement needs a block - if (foo) { - bar; - } else { - baz; - qux; - } +* All variable declarations at top of block. +* `{` on same line preceded by single space (except functions). +* `}` on own line unless continuing statement (`if else`, `do while`, ...). + +Use block for single statement if inner statement needs a block. + + for (;;) { + if (foo) { + bar; + baz; + } + } + +Use another branch of the same statement needs a block: + + if (foo) { + bar; + } else { + baz; + qux; + } + Leading Whitespace ------------------ -* Use tabs for indentation -* Use spaces for alignment - * This means no tabs except beginning of line - * Everything will line up independent of tab size - * Use spaces not tabs for multiline macros as the indentation level is 0, where the `#define` began +Use tabs for indentation and spaces for alignment. This ensures everything will +line up independent of tab size. This means: + +* No tabs except beginning of line. +* Use spaces - not tabs - for multiline macros as the indentation level is 0, + where the `#define` began. + Functions --------- -* Return type and modifiers on own line -* Function name and argument list on next line -* Opening `{` on own line (function definitions are a special case of blocks as they cannot be nested) -* Functions not used outside translation unit should be declared and defined `static` +* Return type and modifiers on own line. +* Function name and argument list on next line. This allows to grep for function + names simply using `grep ^functionname(`. +* Opening `{` on own line (function definitions are a special case of blocks as + they cannot be nested). +* Functions not used outside translation unit should be declared and defined + `static`. + +Example: + + static void + usage(void) + { + eprintf("usage: %s [file ...]\n", argv0); + } + Variables --------- -* Global variables not used outside translation unit should be declared `static` -* In declaration of pointers the `*` is adjacent to variable name, not type +* Global variables not used outside translation unit should be declared `static`. +* In declaration of pointers the `*` is adjacent to variable name, not type. + Keywords -------- -* Use a space after `if`, `for`, `while`, `switch` (they are not function calls) -* Do not use a space after the opening `(` and before the closing `)` -* Always use `()` with `sizeof` -* Do not use a space with `sizeof()` (it does act like a function call) +* Use a space after `if`, `for`, `while`, `switch` (they are not function calls). +* Do not use a space after the opening `(` and before the closing `)`. +* Preferably use `()` with `sizeof`. +* Do not use a space with `sizeof()`. + Switch ------ -* Do not indent cases another level -* Comment cases that FALLTHROUGH +* Do not indent cases another level. +* Comment cases that FALLTHROUGH. + +Example: + + switch (value) { + case 0: /* FALLTHROUGH */ + case 1: + case 2: + break; + default: + break; + } + Headers ------- -* Place system/libc headers first in alphabetical order - * If headers must be included in a specific order comment to explain -* Place local headers after an empty line -* When writing and using local headers - * Do not use `#ifndef` guards - * Instead ensure they are included where and when they are needed +* Place system/libc headers first in alphabetical order. + * If headers must be included in a specific order add a comment to explain. +* Place local headers after an empty line. +* When writing and using local headers. + * Try to avoid cyclic header inclusion dependencies. + * Instead ensure they are included where and when they are needed. * Read <https://talks.golang.org/2012/splash.article#TOC_5.> * Read <http://plan9.bell-labs.com/sys/doc/comp.html> + User Defined Types ------------------ -* Do not use `type_t` naming (it is reserved for POSIX and less readable) -* Typedef opaque structs -* Do not typedef builtin types -* Capitalize the type name -* Typedef the type name, if possible without first naming the struct +* Do not use `type_t` naming (it is reserved for POSIX and less readable). +* Typedef opaque structs. +* Do not typedef builtin types. +* Use `CamelCase` for typedef'd types. - typedef struct { - double x, y, z; - } Point; Line Length ----------- -* Keep lines to reasonable length (current debate as to reasonable) -* If your lines are too long your code is likely too complex +* Keep lines to reasonable length (max 79 characters). + Tests and Boolean Values ------------------------ -* Do not test against `NULL` explicitly -* Do not test against `0` explicitly -* Do not use `bool` types (stick to integer types) -* Assign at declaration when possible +* Do not use C99 `bool` types (stick to integer types). +* Otherwise use compound assignment and tests unless the line grows too long: - Type *p = malloc(sizeof(*p)); - if (!p) - hcf(); -* Otherwise use compound assignment and tests unless the line grows too long + if (!(p = malloc(sizeof(*p)))) + hcf(); - if (!(p = malloc(sizeof(*p)))) - hcf(); Handling Errors --------------- -* When functions `return -1` for error test against `0` not `-1` - if (func() < 0) - hcf(); -* Use `goto` to unwind and cleanup when necessary instead of multiple nested levels -* `return` or `exit` early on failures instead of multiple nested levels -* Unreachable code should have a NOTREACHED comment -* Think long and hard on whether or not you should cleanup on fatal errors - -Enums vs #define ----------------- -* Use enums for values that are grouped semantically and #define otherwise - #define MAXSZ 4096 - #define MAGIC1 0xdeadbeef - - enum { - DIRECTION_X, - DIRECTION_Y, - DIRECTION_Z - }; +* When functions `return -1` for error test against `0` not `-1`: + + if (func() < 0) + hcf(); + +* Use `goto` to unwind and cleanup when necessary instead of multiple nested + levels. +* `return` or `exit` early on failures instead of multiple nested levels. +* Unreachable code should have a NOTREACHED comment. +* Think long and hard on whether or not you should cleanup on fatal errors. + For simple "one-shot" programs (not daemons) it can be OK to not free memory. + It is advised to cleanup temporary files however. + + +Enums and #define +----------------- +Use enums for values that are grouped semantically and #define otherwise: + + #define MAXSZ 4096 + #define MAGIC1 0xdeadbeef + + enum { + DIRECTION_X, + DIRECTION_Y, + DIRECTION_Z + };