Style Guidelines

This document specifies the preferred source code style of files inside the OpenClonk source tree. Some of the style rules are also stated implicitly inside the examples.

All-encompassing Guidelines

Line endings

Use a single line feed character (ASCII 10) for line endings.

Indentation

Indent your code with tabs (ASCII 9). Use space (ASCII 32) for all other formatting.

Braces

Braces are on their own line, on the same level of indentation as the structure they belong to. You may add braces around single statements in if statements if the first block or an else block has them.

if (count < 10)
{
	printf("Too few thingies!");
	AddMore();
}
else
{
	printf("We have enough");
}

Spaces

Function names are not followed by space. Commas are. No space follows opening brackets ("[") or parentheses ("("). Also no space preceeds closing brackets ("]") or parentheses (")"), or commas. "::", "->", "." and unary operators do not require spaces. Other binary operators do.

Keywords (while, for etc.) are followed by a space.

Parentheses

Do not use parentheses unless they are required for precedence or the code gets confusing without them. Remember other people may have confusion thresholds different from you.

Control Structures

Control structures with a single statements are written without braces. If the statement spans multiple lines, you may add braces for readability. Structures without a statement contain a comment denoting this.

while (*dest++ = *src++)
	/* empty */;

Cascades in a switch statement are marked by a FALLTHROUGH comment. Code that cannot be reached has an assertion. case elements are not indented.

switch (foo)
{
case FOO_HEX:
	accept_hex = true;
	// FALLTHROUGH
case FOO_DEC:
	accept_num = true;
	break;
default:
	assert(!"Invalid foo value");
	// Do something meaningful here anyway, if possible;
	// try to not leave the program in an ill-defined state.
}

Comments

// Single-line comments look like this
// Multi-line comments look like this. Using C++-style comments
// helps if you need to comment out large pieces of code later, or if the length of
// the comment changes over time. Of course you could still use #if 0 ... #endif
// to achieve that.
/* You may also write multi-line comments like this. Make sure you write enough
   text to warrant a multi-line comment. Also be sure to write in full sentences. */

Type Casting

Do not use C-style or function style casts. Use a template cast instead.

Source File Layout

Copyright Header

Every source file begins with a copyright header. If you make significant changes to the code, you may (but are not required to) add your name to the list of copyright holders in COPYING. If you choose to add yourself, use your real name, not a nickname. Legally recognized pseudonyms are accepted, as are names of legal entities.

/*
 * OpenClonk, http://www.openclonk.org
 *
 * Copyright (c) 2009-2014, The OpenClonk Team and contributors
 *
 * Other legalese goes here, but has been omitted for brevity. See an
 * existing file for a template.
 */

The copyright header is followed by an empty line. Put a comment explaining the purpose of the file next, and leave another blank line after this.

Inclusion Guards

If you are writing a header file, use #include guards. If your file is called C4Foo.h, your guard should be INC_C4Foo.

#ifndef INC_C4Foo
#define INC_C4Foo
class C4Foo;
#endif

TODO: Precompiled headers.

#include Directives

Include local headers first. Put the filename in double quotes, and use forward slashes as directory separators.

#include "Standard.h"
#include "StdBuf.h"

Leave a blank line before system headers. Use angle brackets to include these, and sort them alphabetically.

#include <map>
#include <vector>

Declarations

Preprocessor Macros

Do not #define values in headers. Use const instead, or enum if you are declaring an enumeration.

Do not #define inline functions either, use inline. If your functions need to work on multiple data types, overload the function or write a template.

If, despite of the above, you still need to write a macro, use an all-uppercase name. If your macro contains a compound statement, enclose it in a do loop to allow its use in if statements. A terminating semicolon should be provided at the place of invocation. This makes parsing the source easier for pretty-printers and editors. Consider undefining your macro when you are done using it.

#define FOO(a, b) do { \
	bar += (a); \
	bar /= (b); \
} while(0)

Data Types

Do not use the Win32 style integer declarations DWORD and BOOL except when interfacing with the Windows API. If you need a guarantee about the size of your variables, use the C99 types intXX_t and uintXX_t. If you don't need that guarantee, use int. If you need a variable that is large enough to store a pointer on your current platform, use intptr_t.

If you come across code that still uses Win32 types, consider changing it if you are working on code in the vicinity. Don't commit changes that only consist of replacing DWORD by uint32_t.

When declaring a pointer, put a space in front of the asterisk, and none after. This saves some confusion when declaring multiple variables at once. The same goes for references.

int *foo, *bar;
char *Qux(const char *quux);

Functions

Functions that are not used outside of the containing file are placed inside of an anonymous namespace.

namespace
{
	int Frobnicate(const char *foo);
}

Functions that are used across multiple files are prototyped inside a common header. The prototypes should be grouped where appropriate, and ordered logically or, failing that, alphabetically.

Function and class names begin with a capital letter, and use camel casing. If you need to embed acronyms inside the name, pretend the acronym was all lower case. Member variables use the same convention, but begin with a lower case letter. Do not use hungarian prefixes.

XmlDocument *ParseXmlFile(const char *file);

When passing arguments that may be changed by the called function, pass them as pointers. This makes it obvious that they may be changed. Use constant references for all other parameters, unless they are a primitive type.

Class Members

No class member variable should be declared public unless necessary. Consider using GetFoo and SetFoo accessors. If you want to declare a compound data type that allows direct access to its members, use struct. Do not add more functions than constructors, destructors, and assignment operators to structs.

Mark all class members that do not change the visible state of the object const. If you need to modify internal state that is not visible from outside of the class, mark the state variable mutable.