# IRC Services Technical Reference Manual

## Appendix D. Coding style guidelines

Table of Contents

The following guidelines were observed when writing the Services source code. Note, however, that they were treated as guidelines, not rules, with the cardinal rule being "readability first".

### D-1. Formatting

- Lines must not be longer than 79 columns.
- The basic indentation unit is four columns.
- Tab (ASCII `\011`) characters are not permitted in source files; indents should always be done using using spaces (`\040`). The source files distributed with Services include settings for the Emacs and Vim editors that cause the Tab key to insert spaces rather than a tab character.
- Only one statement is allowed per line. Statements (including the empty statement "`;`") may not be written on the same line as a control keyword (`if`, `for`, or `while`).
- Spaces are placed between binary operators and their operands, except for the member-reference operators "`->`" and "`.`"; spaces are not placed between unary operators and their operands. However, spaces may be omitted around binary operators when it would improve readability. Examples:
  i = j * 2; user->channelcount++; result += i*60 + (j+59)/60;
- `NULL`, not `0`, should always be used in pointer comparisons. For character comparisons, `0` is preferred to `'\0'`, but the latter may also be used if it does not go against the style of the surrounding code. Do not use `'\0'` with variables declared as type `int8` or `uint8`, even though these types are usually equivalent to `char` and `unsigned char`.
- The construct "`!!expression`" should not be used. Use "`expression != 0`" (for characters or integers) or "`expression != NULL`" (for pointers) instead.
- Parentheses are required when `&&` and `||` are used in the same expression to explicitly indicate order of evaluation; do not rely on the default order of evaluation. (Not using parentheses will generate a warning when using `gcc -Wall`.)
- Parentheses following the control statements "`if`", "`for`", and "`while`", as well as the macros `LIST_FOREACH`, `LIST_FOREACH_SAFE`, and `ARRAY_FOREACH`, are preceded by a space. Parentheses following function or macro calls (other than the above) are not preceded by a space. Example:
  if (flag) function();
- Spaces are placed after the comma of each parameter to a function or macro; however, they may be omitted in function calls which are themselves parameters to a function or macro, or when including them would make the line exceed the length limit. Spaces are also placed after (but not before) the semicolons in a `for` statement. Spaces are not placed after the opening parenthesis or before the closing parenthesis of a function/macro call or control statement. Examples:
  function(param1, param2); function(param1, strchr(string,'/'), param3); for (i = 0; i < count; i++) ...
- Opening braces of control statement blocks go on the same line as the control statement (`if`, `for`, etc.) associated with the block; function blocks and "naked blocks" (those not associated with any control statement or function) have the opening brace alone on a line, indented to the same level as the surrounding code. Closing braces are indented to the same level as the line containing the opening brace. Examples:
  if (flag) { /* indented code goes here */ ... } int function(int param1, char *param2) { /* indented code goes here */ ... /* start of a naked block */ { int foo; ... } }
- If an `if` statement is longer than one line, it should be broken at logical operators (`&&` or `||`); the operator should be placed at the beginning of the next line, and should be indented to show which term the operator belongs with. The closing parenthesis for the `if` statement and the subsequent open brace should be alone on a line, aligned with the first line of the `if` statement. (Braces are required in this case.) Conditions for `for` and `while` statements should never span multiple lines, though a `for` statement may be broken at the semicolons if necessary. Examples:
  if (ok && (strcmp(option, "option-name-1") == 0 || strcmp(option, "option-name-2") == 0) ) { ... } if (!init_first() || !init_second() || !init_third() || !init_fourth() ) { /* This example outdents the || by three spaces to line * up the terms. Such outdenting is acceptable if it * makes the code easier to read and understand. */ ... } for (exception = first_maskdata(MD_EXCEPTION); exception != NULL; exception = next_maskdata(MD_EXCEPTION) ) { ... }
- An `else` followed by an `if` is considered to be a single keyword, "`else if`". The `if` part should always be placed on the same line as and immediately following the `else`; the `else if` should never be split up onto two lines, nor should braces be used around the `if` block. The exception to this is when the `else` and `if` refer to two conceptually distinct sets of conditions, in which case the `if` block should be enclosed by braces and indented. Example:
  res = check_password( /* ... */ ); if (res == 0) { ... } else if (res == 1) { /* "else if" on a single line */ ... } else { if (user->ni != NULL) { /* "if" condition is different from "else" * condition, thus separate */ ... } }
- Braces are always placed around the body of a control statement (`if`, `for`, etc.). The two exceptions are `else` followed by `if`, mentioned above, and statements for which the body, as well as the bodies of any `else if` or `else` statements for an `if` statement, are all one statement in length and do not contain any nested control statements; in this latter case, braces are optional (but recommended if any of the statements span multiple lines). Examples:
  for (i = 0; i < count; i++) function(i); while (!done) { /* Braces required because of the nested "if" */ if (do_stuff()) done = 1; } if (state == 0) { a = b; } else if (state == 1) { /* Every if/else body gets braces because this body * has two statements */ b += a; a = 0; } else { state = 0; }
- When using multiply-nested control statements, or a single control statement which has a long block, the closing brace of the block should be followed by a comment indicating what control statement the block belongs to. This should usually be the content of the control statement, but may be abbreviated as long as its meaning is clear. If a long `if` block is followed by an `else` clause, the `else` should likewise be documented. Examples:
  while (i < count) { ... } /* while (i < count) */ if (flag) { ... } else { /* !flag */ ... } /* if (flag) */ for (node = first; node != NULL; node = node->next) { ... } /* for all nodes */
- `case` and `default` labels for a `switch` should be indented half of a normal indentation unit (two columns) from the line containing the `switch` with which they are associated; statements associated with a case should be indented a full unit from the line containing the `switch` (half a unit from the `case`). If a case requires its own block, such as when it declares its own local variables, the opening brace is placed after the colon on the `case` line. Example:
  switch (variable) { case 123: { int foo; ... break; } /* case 123 */ default: ... return -1; }
- When a case in a `switch` block does not contain a `break` (or `return`) statement and deliberately "falls through" to the next case, a comment to this effect should be made at the bottom of the case. Example:
  switch (state) { case 0: ... /* fall through */ case 1: ... break; }
- Inline comments (comments placed to the right of a line of code) should be aligned to start on the same column, when this does not place too much space between the comment and the code or cause the line to exceed 79 columns in length. Inline comments after unusually long lines (such as long field declarations in structures) should be placed alone on the following line, indented the proper amount.
- The `goto` statement should not be used except in error handling situations where it will help avoid multiple levels of `if` nesting or other awkward code. Labels for `goto` should be outdented half of an indentation unit from the surrounding code (i.e., indented two columns less than the surrounding code).

Back to top

### D-2. Identifier naming

- Global variables and type names should use mixed upper- and lower-case, with an upper-case letter at the beginning of each distinct word in the name.
- Preprocessor constants and macros should use all upper-case letters, with an underscore between distinct words in the name.
- Structure names and local variables should use all lower-case letters, with an underscore between distinct words in the name.
- Structure names for structures with an associated type name (i.e., from `typedef`) should be given the same name as the type, except with all letters in lowercase and followed by an underscore. Example:
  typedef struct mytype_ MyType; struct mytype_ { MyType *next, *prev; ... };
- Names should be descriptive. For global variables, preprocessor macros and constants, type names, and structure names, names should generally consist of one or more full words. For local variables, short names and abbreviations are permitted as long as it is clear what the variables are used for. In general, one-letter local variable names should not be used other than the following:
  - `c`: character
  - `f`: file pointer (`FILE *`)
  - `i`, `j`, `k`: integers (usually counters)
  - `n`, `p`, `q`: integers (`p` may also be a pointer variable)
  - `s`: string
  - `t`: string or temporary variable
  - `x`, `y`, `z`: integers (usually position variables)
  Two-letter variable names are often formed from initials of type names, such as `NickInfo *ni`; see the source code for examples.

Back to top

Table of Contents