Difference between revisions of "Coding standard"

From OdaWiki
(Requirements)
(General)
 
(16 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
==Overview==
 
==Overview==
Odamex relies on a coding standard to help keep consistency between subprojects, this also helps things like reduce bugs and also provides easy readability of the code.
+
Odamex relies on a coding standard to ensure continuity, this reduces bugs and provides easy readability of the code.
 
+
Some of the existing doom code in Odamex breaks these guidelines, which is exempt, unless you want to rewrite it!
+
  
 
==Requirements==
 
==Requirements==
  
This is a list that must be adhered to when you are:
 
* An Odamex developer.
 
* A patch submitter.
 
 
Rules:
 
* Add a [[test]] for every change
 
* Do not fix code that already works
 
 
* Make logical changes in separate patches
 
* Make logical changes in separate patches
 +
* Minimise the number of changes in each patch
 +
* Provide an off switch for every new feature
 +
* Do not submit things you cannot test (e.g. code for alternative platforms)
  
==Formatting==
+
==Code guidelines==
 +
=== General ===
 +
Things you should definitely do in your code:
 +
* Include a GPL header at the top of any new files.
 +
* Write code that is clear and avoids being too "tricky".
 +
* Write code that is defensive and secure, don't make assumptions about inputs.
 +
* Write comments that are descriptive and are of reasonable size, without being overly verbose.
 +
* Maintain traditional naming conventions, for consistency.
 +
* Use <code>NULL</code> for null pointers, not <code>0</code>.
 +
* Add a [[test]] for every change (or an explanation of why this is impossible).
  
* If creating a new file, include a GPL header at the top of it, as seen in other files.
+
Things you should definitely AVOID in your code:
* Descriptive comments
+
* Changing code that already works.
* Comments of reasonable size. (not too big and not too small)
+
* Precompiler macros.
* Comment formatting. (in c/c++, either // for 1 liners or /* */ for multiple lines)
+
* Global variables; they can create problems elsewhere in code.
* Indentations to be of 1 tab character, using 4 space width tabs
+
* Variants (tagged unions); they can present a performance problem.
* Be sure your editor/IDE's EOL mode is LF, not CRLF or CR
+
* Passing non-trivial data structures by value; pass them by <code>const</code> reference instead.
* 80 line character limit, for devs with text-based editors
+
* Magic numbers; use <code>#define</code> or <code>const</code> in your code for fixed numbers, at the top of files.
* if you can, limit functions to a maximum size (like the amount that would fit on a monitor with a reasonable screen resolution)
+
* Hungarian notation such as <code>intVarname</code>; it's just plan evil.
 +
* C-style <code>char*</code> strings; replace them with C++ [http://en.cppreference.com/w/cpp/string/basic_string std::string] where it is safe to do so.
 +
* C-style casts like <code>(int)</code>; use [http://en.cppreference.com/w/cpp/language/static_cast static_cast], [http://en.cppreference.com/w/cpp/language/const_cast const_cast] or [http://en.cppreference.com/w/cpp/language/reinterpret_cast reinterpret_cast] instead.
 +
* <code>goto</code>.
  
==Code==
+
=== Style Guidelines ===
 +
* Set your editor to use Unix line-endings (LF), not Windows (CRLF).
 +
* Use tabs for indentation and spaces for alignment [http://www.emacswiki.org/SmartTabs like so].
 +
** If this is done correctly, it does not matter what tab-width you use.
 +
* Use [http://en.wikipedia.org/wiki/Indent_style#Allman_style Allman] brace style: opening and closing braces go on their own line.
 +
* Use of braceless blocks is allowed.
 +
* Try to limit functions to a maximum size (like the amount that would fit on a monitor with a reasonable screen resolution).
 +
* Set your editor to strip trailing whitespace on save.
  
Things you should definitely AVOID in your code:
+
=== File Operations ===
* Precompiler macros
+
When using file i/o based functions, such as fopen() etc or filename string functions, there are some that are not provided, ie retrieving the length of a file, checking if a file exists or not.
* Global variables (they can create problems elsewhere in code)
+
 
* Variants (tagged unions) - they can present a performance problem
+
Thankfully, Odamex provides some internal functions for doing such. Be sure to check out '''m_fileio.h''' before writing your own, it may have already been implemented! If it isn't, write us a patch and send it in.
* Magic numbers (use #define or const in your code for fixed numbers, at the top of files)
+
 
* Hungarian notation (just plan evil)
+
Some of the useful functions included are:
* C style strings. (replace them with C++ types where it is safe to do so)
+
* SDWORD M_FileLength(FILE *) - Returns the length of an open file handle
* goto
+
 
 +
Filename operations:
 +
* BOOL M_FileExists(std::string Filename) - Checks if a file exists or not
 +
* BOOL M_AppendExtension(std::string &Filename, std::string Extension, bool If_Needed = true) - Add an extension on to the end of a filename, If_Needed detects if Extension is in Filename, if it isn't, it is added
 +
* void M_ExtractFilePath(std::string Filename, std::string &Destination) - Returns the path of a filename in Destination
 +
* BOOL M_ExtractFileExtension(std::string Filename, std::string &Destination) - Returns the extension of Filename in Destination
 +
* void M_ExtractFileBase(std::string Filename, std::string &Destination) - Returns the base name of Filename in Destination
 +
* void M_ExtractFileName(std::string Filename, std::string &Destination) - Returns the complete filename of Filename in Destination
 +
 
 +
Others include:
 +
* BOOL M_WriteFile(std::string Filename, void *Buffer, QWORD Length) - Creates/overwrites a file and writes a block of data to it.
 +
* QWORD M_ReadFile(std::string Filename, BYTE **Buffer) - Allocates a buffer using Z_Malloc and reads the data into it from a file, lifetime is PU_STATIC.
 +
 
 +
=== Memory Management ===
 +
If you need to use malloc(), calloc(), realloc(), free() functions. Use the '''macros''' located in '''m_alloc.h''', these are provided because they are much better when it comes to debugging code and such:
 +
 
 +
* M_Malloc(size_t Size)
 +
* M_Calloc(size_t Items, size_t Size)
 +
* M_Realloc(void *Pointer, size_t Size)
 +
* M_Free(uintptr_t &Reference)
  
What you should strive for:
+
A list of features these functions offer:
* Clarity of code
+
* Defensive and secure coding practices
+
* Maintain traditional naming conventions, for consistency
+
  
==See Also==
+
* The Size value can NEVER be 0, this prevents platform-specific behaviour.
 +
* M_Free uses a reference instead of a pointer, it still does the same as normal free(), but will NULL the address on return.
 +
* They will abort the program if their operation fails.
  
* none
+
=== Z_Zone Memory Management ===
 +
* Be aware that the all Z_Zone allocated memory is freed when the WAD changes
  
 
==External Links==
 
==External Links==
  
 
* [http://www.jwz.org/doc/tabs-vs-spaces.html tabs-vs-spaces]
 
* [http://www.jwz.org/doc/tabs-vs-spaces.html tabs-vs-spaces]

Latest revision as of 05:14, 4 July 2012

Overview

Odamex relies on a coding standard to ensure continuity, this reduces bugs and provides easy readability of the code.

Requirements

  • Make logical changes in separate patches
  • Minimise the number of changes in each patch
  • Provide an off switch for every new feature
  • Do not submit things you cannot test (e.g. code for alternative platforms)

Code guidelines

General

Things you should definitely do in your code:

  • Include a GPL header at the top of any new files.
  • Write code that is clear and avoids being too "tricky".
  • Write code that is defensive and secure, don't make assumptions about inputs.
  • Write comments that are descriptive and are of reasonable size, without being overly verbose.
  • Maintain traditional naming conventions, for consistency.
  • Use NULL for null pointers, not 0.
  • Add a test for every change (or an explanation of why this is impossible).

Things you should definitely AVOID in your code:

  • Changing code that already works.
  • Precompiler macros.
  • Global variables; they can create problems elsewhere in code.
  • Variants (tagged unions); they can present a performance problem.
  • Passing non-trivial data structures by value; pass them by const reference instead.
  • Magic numbers; use #define or const in your code for fixed numbers, at the top of files.
  • Hungarian notation such as intVarname; it's just plan evil.
  • C-style char* strings; replace them with C++ std::string where it is safe to do so.
  • C-style casts like (int); use static_cast, const_cast or reinterpret_cast instead.
  • goto.

Style Guidelines

  • Set your editor to use Unix line-endings (LF), not Windows (CRLF).
  • Use tabs for indentation and spaces for alignment like so.
    • If this is done correctly, it does not matter what tab-width you use.
  • Use Allman brace style: opening and closing braces go on their own line.
  • Use of braceless blocks is allowed.
  • Try to limit functions to a maximum size (like the amount that would fit on a monitor with a reasonable screen resolution).
  • Set your editor to strip trailing whitespace on save.

File Operations

When using file i/o based functions, such as fopen() etc or filename string functions, there are some that are not provided, ie retrieving the length of a file, checking if a file exists or not.

Thankfully, Odamex provides some internal functions for doing such. Be sure to check out m_fileio.h before writing your own, it may have already been implemented! If it isn't, write us a patch and send it in.

Some of the useful functions included are:

  • SDWORD M_FileLength(FILE *) - Returns the length of an open file handle

Filename operations:

  • BOOL M_FileExists(std::string Filename) - Checks if a file exists or not
  • BOOL M_AppendExtension(std::string &Filename, std::string Extension, bool If_Needed = true) - Add an extension on to the end of a filename, If_Needed detects if Extension is in Filename, if it isn't, it is added
  • void M_ExtractFilePath(std::string Filename, std::string &Destination) - Returns the path of a filename in Destination
  • BOOL M_ExtractFileExtension(std::string Filename, std::string &Destination) - Returns the extension of Filename in Destination
  • void M_ExtractFileBase(std::string Filename, std::string &Destination) - Returns the base name of Filename in Destination
  • void M_ExtractFileName(std::string Filename, std::string &Destination) - Returns the complete filename of Filename in Destination

Others include:

  • BOOL M_WriteFile(std::string Filename, void *Buffer, QWORD Length) - Creates/overwrites a file and writes a block of data to it.
  • QWORD M_ReadFile(std::string Filename, BYTE **Buffer) - Allocates a buffer using Z_Malloc and reads the data into it from a file, lifetime is PU_STATIC.

Memory Management

If you need to use malloc(), calloc(), realloc(), free() functions. Use the macros located in m_alloc.h, these are provided because they are much better when it comes to debugging code and such:

  • M_Malloc(size_t Size)
  • M_Calloc(size_t Items, size_t Size)
  • M_Realloc(void *Pointer, size_t Size)
  • M_Free(uintptr_t &Reference)

A list of features these functions offer:

  • The Size value can NEVER be 0, this prevents platform-specific behaviour.
  • M_Free uses a reference instead of a pointer, it still does the same as normal free(), but will NULL the address on return.
  • They will abort the program if their operation fails.

Z_Zone Memory Management

  • Be aware that the all Z_Zone allocated memory is freed when the WAD changes

External Links