Next: Using the console, Previous: Compilation tips, Up: Hacker's guide

### 3.5 Coding guidelines

#### 3.5.1 Project goals reminder

One of the purposes of Liquid War 6 is to make a cleaner implementation of Liquid War than the previous one, namely Liquid War 5. While the latter has achieved the practical goal of providing a playable implementation of the game, it failed at providing an evolutive platform. Network capabilities where finally added to Liquid War 5, but anyone who played on Internet with someone a few hundreds of milliseconds away would agree that it's far from being perfect. The main reason for this is that it is really had to hack on Liquid War 5, especially when you are not the core developper. The core developper himself, even knowing all the various hacks in the game, is very quickly lost when trying to implement major changes.

To put it short, Liquid War 5 is a global variable hell, a pile of hacks on top of a quick and dirty implementation. Still, it works.

With Liquid War 6, the idea is to take the time to make something stable, something nice which will enable developpers to implement the cool features, and have fun along the way. Of course, this is only a dream, and in the (hopefully "very") long run, Liquid War 6 will also end up as a big unmaintainable mess, like any real-life program, until then, it should remain hackable.

#### 3.5.2 Common sense

Here are a few guidelines which I think are common sense advice, but they are still worth mentionning:

- try and respect the GNU coding standards;
- absolutely no `strcpy` or `sprintf` anywhere in the code. Nowhere. Use their equivalent `strncpy` and `snprintf` systematically, as they are part of the glibc and are an order of magnitude safer. Moreover, Liquid War 6 provides wrappers, such as `lw6sys_new_sprintf` which handles all the nasty dirty memory allocation stuff for you;
- keep global variables for when there is something truely global, and even in that case try to fit them in clearly identified structures.

#### 3.5.3 Unitary tests

Each of the internal libraries in Liquid War has a “test” program associated with it. For instance `liquidwar6sys-test` is associated to `libliquidwar6sys`, and its purpose is to test the features of this library.

While it is fairly easy to test out unitary functions which require no peculiar context, testing high-level functions which requires files, graphical and possibly network contexts to exist is obviously harder to achieve. There's no easy way to draw the line, but the idea is to put in these test executables as many features as possible, to be sure that what is tested in them is rock solid, bullet proof, and that one can safely rely on it and trust that code when running it in a more complex environnement.

These test executables are also very good places to see a library API in action, find code fragments, and make experiments.

#### 3.5.4 Memory allocation

Liquid War 6 provides macros to allocate and free memory. One should use them systematically, except when trying to free something allocated by another library, and in very special cases, mostly concerning low-low level operations which are seldom hacked on.

Usage of macros `LW6SYS_MALLOC`, `LW6SYS_CALLOC` and `LW6SYS_FREE` is straightforward, read any random chunk of code, for instance `./src/lib/sys/sys-test.c` to see them in action. They are defined in `sys/sys.h`.

#### 3.5.5 Private and public interfaces

Each library exports a public interface and hides its internal. Since Liquid War 6 uses standard C and no C++, there's no real standard way to handle public/private features. The convention used in Liquid War 6 is to show internal structures as opaque pointers (`void *`) whenever some function needs to operate on a structure which has possibly private fields. This way the caller function has no way to access the internals, and we are sure that no reference to any internal implementation specific feature will appear.

Here's a code excerpt from `src/gfx/setup.c`:

         void _lw6gfx_quit(_LW6GFX_CONTEXT *context) {
           /*
            * Implementation here.
            */
         [...]
         }

         void lw6gfx_quit(void *context) {
           _lw6gfx_quit((_LW6GFX_CONTEXT *) context);
         }

The function `_lw6gfx_quit` (note the “_”) is internal, declared in `internal.h` whereas the function `lw6gfx_quit` is public, and is therefore exported in `gfx.h`.

This way, functions in the program using `lw6gfx_quit` do not know what is in the `_LW6GFX_CONTEXT` structure, and they need not know it.

This does not mean it is not possible to have public structures, only these structures must reflect some truely public, accessible and safe to access structures.