Code Formatting Conventions
Note: These are mostly the ScummVM code formatting conventions, with some minor changes.
Use common sense
These are conventions which we try to follow when writing code for xoreos. Sticking to a common set of formatting / indention rules makes it easier to read through our source base (which now exceed half a million lines of code by far, making this quite important). If you want to submit patches, please try to adhere to these rules.
We don't always follow these rules slavishly, in certain cases it is OK (and in fact might be favorable) to stray from them. Applying common sense, as usual, is a good idea.
In the following examples tabs are replaced by spaces for visual consistency with the Code Formatting Conventions. But in actual code, use tabs for indentations (our tabs are assumed to be 4 spaces wide).
C++ Standard
We mainly follow the C++98 standard, but we also use C99-style known-width integer type. See src/common/types.h for details.
Apart from that, we like to keep the standard as low as possible, for compatibility reasons. If there's a compelling reason, you can of course use C++11 features. But please do so only if you absolutely have to; if the rest of the codebase does something the old-fashioned way, it's best to keep doing it that way. For example, don't introduce auto variables just for the sake of an iterator for-loop.
Hugging braces
Braces in your code should look like the following example:
<syntaxhighlight lang="cpp"> for (int i = 0; i < t; i++) {
[...]
}
if (j < k) {
[...]
} else if (j > k) {
[...]
} else {
[...]
}
class Dummy {
[...]
}; </syntaxhighlight>
Did you see the {}'s on that?
Tabs for indenting, spaces for alignment
Says it all, really.
Whitespaces
Conventional operators surrounded by a space character
<syntaxhighlight lang="cpp"> a = (b + c) * d; </syntaxhighlight>
C++ reserved words separated from opening parentheses by a white space
<syntaxhighlight lang="cpp"> while (true) { </syntaxhighlight>
Commas followed by a white space
<syntaxhighlight lang="cpp"> someFunction(a, b, c); </syntaxhighlight> <syntaxhighlight lang="cpp"> int d, e; </syntaxhighlight>
Semicolons followed by a space character, if there is more on a line
<syntaxhighlight lang="cpp"> for (int a = 0; b < c; d++) </syntaxhighlight> <syntaxhighlight lang="cpp"> doSomething(e); doSomething(f); // This is probably bad style anyway </syntaxhighlight>
Semicolons preceded by a space character, if it ends an empty loop body
It should also contain a comment to make it clear that the loop is intentionally empty. <syntaxhighlight lang="cpp"> while (i < length - 1 && array[++i] != item) ; // Look for index of item with an empty loop </syntaxhighlight> The following syntax is also acceptable: <syntaxhighlight lang="cpp"> while (i < length - 1 && array[++i] != item) ; //this loop is intentionally empty </syntaxhighlight>
When declaring class inheritance and in a ? construct, colons should be surrounded by white space
<syntaxhighlight lang="cpp"> class BusWheel : public RubberInflatable { </syntaxhighlight> <syntaxhighlight lang="cpp"> (isNight) ? colorMeDark() : colorMeBright(); </syntaxhighlight>
Indentation level is not increased after namespace clause
<syntaxhighlight lang="cpp"> namespace Scumm {
byte Actor::kInvalidBox = 0;
void Actor::initActorClass(ScummEngine *scumm) {
_vm = scumm;
}
} // End of namespace Scumm </syntaxhighlight>
Array delete operator has no whitespace before [] <syntaxhighlight lang="cpp"> delete[] foo; </syntaxhighlight>
Template definitions
No whitespace between template keyword and < <syntaxhighlight lang="cpp"> template<typename foo> void myFunc(foo arg) {
// ...
} </syntaxhighlight>
Operator overloading
Operator keyword is NOT separated from the name, except for type conversion operators where it is required. <syntaxhighlight lang="cpp"> struct Foo {
void operator()() { // ... }
operator bool() { return true; }
}; </syntaxhighlight>
Pointers and casts
One whitespace after a cast. <syntaxhighlight lang="cpp"> const char *ptr = (const char *) foobar; </syntaxhighlight>
References
We use the same rule for references as we do for pointers: use a whitespace before the "&" but not after it. <syntaxhighlight lang="cpp"> int i = 0; int &ref = i; </syntaxhighlight>
Switch/Case constructs
<syntaxhighlight lang="cpp"> switch (cmd) {
case kSomeCmd: someCmd(); // Fall Through intended case kSomeVerySimilarCmd: someMoreCmd(); break; case kSaveCmd: save(); break; case kLoadCmd: case kPlayCmd: close(); break; default: Dialog::handleCommand(sender, cmd, data);
} </syntaxhighlight>
- Note comment on whether fall through is intentional.
Naming
Constants
Basically, you have two choices (this has historical reasons, and we probably should try to unify this one day):
- Camel case with prefix 'k':
kSomeKludgyConstantName
- All upper case, with words separated by underscores (no leading/trailing underscores):
SOME_KLUDGY_CONSTANT_NAME
(As a side remark, we recommend avoiding #define for creating constants, because these can lead to weird and difficult to track down conflicts. Instead use enums or the const
keyword.)
Type names
Camel case starting with upper case.
<syntaxhighlight lang="cpp"> class MyClass { /* ... */ }; struct MyStruct { /* ... */ }; typedef int MyInt; </syntaxhighlight>
Class member variables
Prefixed with '_' and in camel case (Yo! no underscore separators), starting with lowercase.
<syntaxhighlight lang="cpp"> char *_someVariableName; </syntaxhighlight>
Class methods
Camel case, starting with lowercase.
<syntaxhighlight lang="cpp"> void thisIsMyFancyMethod(); </syntaxhighlight>
Local variables
Use camel case (Yo! no underscore separators), starting with lowercase.
<syntaxhighlight lang="cpp"> char *someVariableName; </syntaxhighlight>
Note that for POD structures it is fine to use this rule too.
Global variables
In general you should avoid global variables, but if it can't be avoided, use 'g_' as prefix, camel case, and start with lowercase
<syntaxhighlight lang="cpp"> int g_someGlobalVariable; </syntaxhighlight>
Special comments
Special Keywords
The following goes slightly beyond code formatting: We use certain keywords (together with an explanatory text) to mark certain sections of our code. In particular:
- FIXME marks code that contains hacks or bad temporary workarounds, things that really should be revised at a later point.
- TODO marks incomplete code, or things that could be done better but are left for the future.
- WORKAROUND marks code that works around bugs in the original game, like script bugs. Sometimes these bugs worked in the original due to bugs in the original engine, sometimes the bug was visible in the original, too. It's important that you explain here what exactly you work around, and if applicable, refer to relevant tracker items!
Doxygen documentation comments
xoreos uses the Doxygen software to generate HTML documentation for the codebase.
Doxygen supports documentation blocks. These are specially-formatted comments that doxygen prints out in the generated documentation. They are similar in purpose to Java's JavaDoc or Python's docstrings.
There are many ways to mark such comments, but developers are encouraged to use the JavaDoc style:
<syntaxhighlight lang="cpp"> /**
* Move ("warp") the mouse cursor to the specified position in virtual * screen coordinates. * @param x the new x position of the mouse * @param y the new y position of the mouse */
virtual void warpMouse(int x, int y) = 0; </syntaxhighlight>
As shown in the example, documentation blocks also support several special commands such as param. Those are prefixed with either @ or \, but developers should always use @.
If you want to add a brief explanation of a variable or function after its declaration, this is the correct syntax: <syntaxhighlight lang="cpp"> int16 x; ///< The horizontal part of the point int16 y; ///< The vertical part of the point </syntaxhighlight>
For more information, visit the official documentation:
Automatically converting code to our conventions
The following settings for Artistic Style (also known as astyle) approximate our code formatting conventions and can be used to quickly convert a big bunch of source files to our conventions. Note that you may still have to manually clean up some stuff afterwards.
indent=tab=4 brackets=attach pad-oper pad-header align-pointer=name unpad-paren indent-preprocessor convert-tabs
Alternatively, this config file for uncrustify should also work as a starting point for our conventions. Again, you may still clean things up manually.