wiki:KittenStyleGuide

Introduction

This page is an attempt to proclaim the coding style that should be used in the Kitten LWK. Everybody has their own preferred style but it is in the LWK's best interest to use a consistent style throughout. Hopefully this won't be too burdensome on you. It's fairly non-restrictive... the main goal is to get some consistency in things like variable names, function prototypes (we're a little unusual in this dept.), comments, etc. If you'd like to kill an afternoon, you could read through this C++ style guide that is recommended by Bjorne Stroustroup  Joint Strike Figher Coding Style Guide. We're using C (C99) but many of the rules still apply.

Breaking the rules on this page will not land you in kitty jail. At this point, the main goal is prototyping and functionality. At some point, we may actually want to have somebody (perhaps the author of this damn page) go through the code base and beautify it.

File Organization

Files should begin with a brief comment describing the file's purpose. In general, everything in a file should be related to a common theme. Super large files with lots of unrelated functions are not easy to work with.

Here are some templates:

Header File Organization

    /*
     * Description of this header file. 
     */    
    #ifndef _lwk_header_name_h_
    #define _lwk_header_name_h_

    /* Body of header file */

    #endif /* _lwk_header_name_h_ */

In general, a header should include any other headers it is dependent on and no more.

C File Organization

    /** \file
     * Description of this C source file file. 
     */
    /* Header Includes */

    /* Functions, each separated by at least two blank lines */

The use of C-preprocessor conditionals in source files is not encouraged. If possible relegate #ifdef and friends to header files.

Naming Conventions

File Names

Files names should be relatively short and all lower case. Separate words should generally be separated with an _ character (e.g., pci_cfg.h). The name of the file should reflect the file's purpose.

Macro Names

Macros should be defined in headers and be in ALL-CAPS.

#define MACRO_NAME(x) ((x) << 10)

Type Names

Type names should be all lower case with words separated by an _ character. Type names should be descriptive and short. Types created with 'typedef' should be given names ending in '_t'.

Examples:

    typedef struct {
            int    field_a;
            int    field_b;
            int    field_c;
    } type_name_t;
    struct type_name {
            int    field_a;
            int    field_b;
            int    field_c;
    };

Variable Names

Variable names should be all lower case with words separated by an _ character. Variable names should be descriptive and as short.

    int num_mem_areas;

Function Names

Function names should be all lower case with words separated by an _ character. Function names should be descriptive and as short.

Tabs

Hard tabs with a tab stop of 8 should be used to indent. When aligning fields vertically (e.g., to line up comments on separate lines), either spaces or tabs may be used.

Function Prototypes

This is probably the most unusual aspect of the LWK style. Function prototypes should have the following format:

    int
    function_name(
            int           arg1,
            struct foo    arg2,
            struct bar    arg3,
            ...
    )

Notice that the return type is on its own line preceding the function name. This makes it easy to grep a file for a function definition... grep ^function_name file... and makes it clear what the function's return type is.

Also notice that all of the arguments are on their own line and all names are lined up vertically. This makes it easy to see which arguments have changed in diffs.

It may be OK to abandon this style in certain circumstances for clarity. Use good taste. For example:

    /* Read N bits from addr */
    void  read8( void * addr );
    void read16( void * addr );
    void read32( void * addr );

Is more clear than expanding them out as described above.

Return Results

If possible, functions, especially allocator functions, should return a pointer to the new object if successful, or NULL if unsuccessful, rather than taking a copy-out parameter. This makes testing uniform for failure and more closely resembles malloc() or new:

  // Good
  extern struct foo *
  foo_alloc( ... );

  struct foo * const myfoo = foo_alloc( ... );
  if( !foo )
        panic( "No foo!" );
 
  // Bad
  extern int
  foo_alloc( ..., struct foo ** new_foo );

  struct foo * myfoo; // can't be '* const'
  int rc = foo_alloc( ..., &myfoo );
  if( !rc ) // or rc < 0 or rc == 0?
        panic( "No foo!" );

Comments

Either // or /* */ may be used for commenting. The damn author of this page has a slight preference for /* */ everywhere, even though it is harder to type :)

    // A comment
    /* A comment */

Multi-line comments should have the following format:

    /*
     * This is a
     * multi-line comment.
     */

We are using doxygen for automatic documentation of source code. This means that code and documentation are interspersed in the same file. If over used, this can cause source files to become nearly unreadable. Try to avoid this. Public functions should be documented in their public header using doxygen markup.

See the  Doxygen manual for more detailed information. Here are some examples of the most frequently used doxygen markups...

Doxygen comment blocks are signaled by a leading /**. There are other mechanisms but this is the only one that should be used in the LWK. Single line documentation of arguments may be marked with //!<.

Here are a few examples:

    /** Brief description of the following variable */
    int foo = 0xFF;
    /** Brief description of function.
     *
     * More detailed description of function
     *
     * \returns
     *     0 on success
     *    -1 on failure
     */
    int
    function_name(
            int     arg1,    //! IN:  Input argument description.
            int *   arg2,    //! OUT: Output argument description.
            ...
    );

It is possible to group together functions and macros using @{ and @}. The \name is necessary to provide a heading for the group.

    /** \name Some Related Types.
     *
     * This is documentation for both foo and bar, which will be separated from
     * the other parts of the documentation for this file.
     * @{
     */
    typedef uint32_t foo;
    typedef uint32_t bar;
    // @}

This will cause both types to be under the "Some Related Types" heading of the generated doxygen documentation.