Coding/Guidelines

From UFO:AI

< Coding(Redirected from Coding guidelines)

Contents

General

  • If you change a function prototype make sure that all other prototypes for all the ports out there are changed, too (otherwise you will break the port)
  • Use ANSI C89, except in platform specific code, even then only use something else if you ABSOLUTELY have to.
  • Use K&R style of coding (what, you DON'T own a copy?)
  • C-style comments ONLY!
    /* comment */
  • If you need to temporarily disable a chunk of code, use #if 0 ... #endif, rather than just a /* comment */.
  • One declaration per line please.
  • Guard headers with <dir under src>_<filename without .h>_H in capitals. For example ./src/client/cdaudio.h is guarded with:
#ifndef CLIENT_CDAUDIO_H
#define CLIENT_CDAUDIO_H

...

#endif /* CLIENT_CDAUDIO_H */
  • remember to put a blank line at the end of the file (GCC will complain if you don't.)
  • All files must contain a GPL notification (google GPL or just lookup an existing file).
  • Always use braces in if-else blocks. Doing anything else is error-prone. One line ifs are okay. E.g.
/* This is okay */
if (x)
    printf("Blah"); 

/* This may look okay, but can get very messy when you start nesting */
if (x) 
    printf("Meep");
else if (y)
    printf("Moop");
else

/* This is the worst of all */
if (x) {
    printf("A");
    if (z)
        printf("B");
    else if (j) {
        printf("X");
    } else
        printf("Z");
} else if (y)
    printf("C");
else
    printf("D");
  • Feel free to use indent (Unix / Cygwin). Current command: indent -kr -l160 -bad -bap -ut -i4 -ts4 <filename>

TABs

  1. Use TABs instead of spaces.
  2. Use a TAB-wide of 4 characters (editor settings). Do NOT SAVE THE SPACES in the files, see first point.

Whitespaces in function declarations, definitions and calls

These are guidelines about whitespace usage between the function name and the left bracket that starts the argument list.

Omit it in the headers in function declarations:

void prototype(void);

Include it in function definitions:

void prototype (void)
{
  /* implementation */
}

Omit it in function calls:

void someother (void)
{
[...]
  prototype();
[...]
}

This format makes it easy to find functions in the code. It also makes the code easier to read.

General function & variable names

  • Function names look like: CL_MyRandomFunction(), where CL is the abreviation of the compilation unit (the C-file the function is located in). This includes #define macros that work like functions.
  • Console vars look like this: cl_lower_case

Identifiers and names inside structs

There is alot of (deprecated) code where there are the following variables defined inside a struct:

  • name or kurz - ('kurz' is german for 'short') short string-identifier from the ufo-files.
  • title - Translated full name.

They should not be used and replaced with the following:

  • id - short string-identifier from the ufo-files. [replaces name from above]
  • name - xxx [replaces title from above]
  • idx - xxx

Attention has to be paid to the different meaning of the name variable. Please try to not mix them up.

Structures / Typedefs

Structures / typedefs are:
typedef struct menuNode_s {} menuNode_t;
YES, you WILL typedef your structs!

Text being sent to the user

Any text being sent to the user needs to be written in English. Yes, in English - not Polish English or German English. That means - start with uppercase letter, end with dot. Bad:

  • CL_DisplayHudMessage(_("your soldier is dazed\n"), 2000);

Ok:

  • CL_DisplayHudMessage(_("Your soldier is dazed.\n"), 2000);

Plural forms

Use ngettext function to handle plurals. It can select right form in regard of item count. DO NOT prefix texts with _(). Usage: ngettext("singular", "plural", cnt). See Full Example.

Full Example

/**
 * @file main.c
 * @brief Main source file.
 *
 * Contains the main() function and many associated functions and typedefs.
 */

/*
 * All original material Copyright (C) 2002-2006 UFO: Alien Invasion team.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

/**
 * @brief Holds information about individual nodes in a menu.
 */
typedef struct menuNode_s {
    int blah; /**< This is a documentation comment. */    
    int a; /* armour */ /**< Calling this 'a' then putting a comment immediately after is just dumb. Don't do it; use meaningful names */
    int blahBlah; /**< The total number of blahs. */
} menuNode_t;

/**
 * @brief Does this and that
 * @return Returns blah if blub.
 */
int Function (void)
{

}

/* This is an ordinary C comment. 
If you encounter one of these you will need to update it to a full doxygen comment where appropriate.
*/
int R_DrawStuff (void)
{

}

/**
 * @brief The main function and program entry point.
 *
 * The line above is the brief description of the function below.
 * Anything after the blank line is the detailed description (these two lines).
 * @return Returns the interesting result.
 */
int main (void)
{
    int x;
    int y;

    if (x < y) {
        x *= y;
    } else if (x > y) {
        y = x;
    } else {
        printf("Blah!");
    }
    
    for (x = 10; x > 0; x--) {
        /* Do something interesting */
        printf(ngettext("Remain %i day\n", "Remain %i days\n", x), x);
    }

    return 0;
}

Subversion

Each line of a commit message should begin with a *. If you are committing changes to multiple files at one time, please include the file that has changed.

Examples:

Only changed one file.

* Added function xyz to do blah.

Changing multiple files.

* cl_main.h: Rewrote main to be cooler.
* cl_menu.c: Added help commands.

Documenting code

Use doxygen to document code.

Doxygen comments are very much like Javadoc. The main exception is that the comment for the file (At the top of the file) needs the @file command, as shown in the example above.

Brief comments should describe WHAT something does, NOT how. For example, a good comment.

/**
 * @brief Calculates the chance to hit.
 * @param[in] skill <What skill is.>
 * @param[in] distance) <What distance) is.>
 * @return <What is returned in what case>
 */
float ToHit (int skill, float distance)
{
}

And a bad one - it should be apparent from the code:

/**
 * @brief Calculates the chance to hit by taking the skill, dividing it by the distance and multiplying by F.
 */
float ToHit (int skill, float distance)
{
}

The detailed description should include enough detail to understand how the function works, in the above example, the detailed description should probably describe the factors involved in shooting, so that someone testing the gameplay could experiment with a spreadsheet.

There is a doxygen config file to generate HTML documentation (latex disable for now) for every typdef, function and non-local variable in the entire source tree (except for the tools).

Blank Documentation

Blank documentation is bad. Do not leave blank doxygen commands like this:

/**
 * @brief
 * @param
 * @sa
 */
void someFunction (void)
{
...
}

There is no reason to do this. It hides the fact that this code is undocumented. It might even confuse doxygen. If you do not want to document code then don't even start.

Code TODO's

Use the doxygen @todo command to mark TODO's in the code. For example:

/* @todo: make the numbers work here. */

Always remember that Doxygen's commands are case sensitive. @todo is different from @TODO. The latter is not a valid command.

TODO: Needs to be more comprehensive.


Preprocessor

Use DEBUG to surround statements that are not needed for the game but are good for debugging purposes

 #ifdef DEBUG
 dosomething();
 #endif

PARANOID surrounds some speed influencing checks for variable values and overflows. Very good for debugging - statements enclosed by PARANOID may slow down the game a lot.

 #ifdef PARANOID
 dosomething()
 #endif

Links

Coding

project-navigation