Code Style Policy

1. Introduction

The purpose of this document is to provide a reference guide for KiCad developers about how source code should be styled and formatted in KiCad. It is not a comprehensive programming guide because it does not discuss many things such as software engineering strategies, source directories, existing classes, or how to internationalize text. The goal is to make all of the KiCad source conform to this guide.

1.1 Why Coding Style Matters

You may be thinking to yourself that using the style defined in this document will not make you a good programmer and you would be correct. Any given coding style is no substitute for experience. However, any experienced coder will tell that the only thing worse than looking at code that is not in your preferred coding style, is looking at twenty different coding styles that are not your preferred coding style. Consistency makes a) problems easier to spot, and b) looking at code for long periods of time more tolerable.

1.2 Enforcement

The KiCad coding police are not going to break down your door and beat you with your keyboard if you don’t follow these guidelines (although there are those who would argue that they should). However, there are some very sound reasons why you should follow them. If you are contributing patches, you are much more likely to be taken seriously by the primary developers if your patches are formatted correctly. Busy developers don’t have the time to go back and reformat your code. If you have a desire to become a regular KiCad developer with commit access to the development branch, you’re not likely to get a glowing recommendation by the lead developers if you will not follow these guidelines. It is just good programming courtesy to follow this policy because it is respectful of the investment already made by the existing developers. The other KiCad developers will appreciate your effort.

Warning

Do not modify this document without the consent of the project leader. All changes to this document require approval.

1.3 Tools

There are some tools that can help you format your code easily.

clang-format is a formatting tool that can both be used to provide code-style automation to your editor of choice, as well as allow git to check formatting when committing (using a "Git hook"). You should install this program to be able to use the Git hooks.

The style config file is _clang-format, and should be picked up automatically by clang-format when the --style=file option is set.

To enable the Git hooks (only needs to be done once per Git repo):

git config core.hooksPath .githooks

Set the git clang-format tool to use the provided _clang-format file:

git config clangFormat.style file

Then, to enable the format checker, set the kicad.check-format Git config to "true" for the KiCad repo:

git config kicad.check-format true

Without this config, the format checker will not run on commit, but you can still check files staged for commit manually (see below).

If the hook is enabled, when you commit a change, you will be told if you have caused any style violations (only in your changed code). You can then fix the errors, either manually, or with the tools below.

If you are warned about formatting errors, but you are sure your style is correct, you can still commit:

git commit --no-verify

1.3.1 Correcting Formatting Errors

There is a Git aliases file that provides the right commands to show and correct formatting errors. Add to your repository config by running this command from the source directory:

git config --add include.path $(pwd)/helpers/git/format_alias

Then you can use the following aliases:

  • git check-format: show any formatting warnings (but make no changes)

  • git fix-format: correct formatting (you will need to git add afterwards)

These aliases use a script, tools/check_coding.sh, which takes care of only checking the formatting for files that should be formatted. This script has other uses:

  • Make (or see only) violations in files modified in the previous commit (useful when interactive-rebasing):

  • check_coding.sh --amend [--diff]

2. Naming Conventions

Before delving into anything as esoteric as indentation and formatting, naming conventions need to be addressed. This section does not attempt to define what names you use for your code. Rather, it defines the style for naming. See the references section for links to some excellent coding references. When defining multiple word names use the following conventions for improved readability:

  • Use underscores for all upper and all lower case variables to make multiple word names more readable.

  • Use camel case for mixed case variable names.

Avoid mixing camel case and underscores.

Examples

    CamelCaseName           // if camelcase, then no underscores
    all_lower_case_name
    ALL_UPPER_CASE_NAME

2.1 Class, Type Definitions, Name Space, and Macro Names

Class, typedef, enum, name space, and macro names should be comprised of all capital letters.

Examples

    class SIMPLE
    #define LONG_MACRO_WITH_UNDERSCORES
    typedef boost::ptr_vector<PIN>      PIN_LIST;
    enum KICAD_T {...};

2.2 Local, Private and Automatic Variables

The first character of automatic, static local, and private variable names must be lower case. This indicates that the variable will not be “visible” outside of the function, file, or class where they are defined, respectively. The limited visibility is being acknowledged with the lowercase starting letter, where lowercase is considered to be less boisterous than uppercase.

Examples

    int i;
    double aPrivateVariable;
    static char* static_variable = NULL;

Private class and struct members must be prefixed with m_ and the first character after the m_ prefix must also be lowercase:

private:
    int m_privateData;

2.3 Public and Global Variables

The first character of public and global variable names must be uppercase. This indicates that the variable is visible outside the class or file in which it was defined. (An exception is the use of prefix g_ which is also sometimes used to indicate a global variable.)

Example

    char* GlobalVariable;

In general, classes should not use public member variables, and instead should use getter/setter methods to access private members. The exception is classes that are essentially data structures with some helper methods. For example, the SEG class is used frequently as a data structure representing a line segment between two points. This class has public member variables A and B storing those points. This is acceptable because the SEG class meets that definition of being essentially a data structure, and because there is no need for side-effects when changing A or B.

2.4 Local, Private and Static Functions

The first character of local, private, and static functions should be lower case. This indicates that the function is not visible outside the class or file where it is defined.

Example

    bool isModified();
    static int buildList( int* list );

2.5 Function Arguments

Function arguments are prefixed with an 'a' to indicate these are arguments to a function. The 'a' stands for “argument”, and it also enables clever and concise Doxygen comments.

Example

    /**
     * Copy aFoo into this instance.
     */
    void SetFoo( int aFoo );

Notice how the reader can say “a Foo” to himself when reading this.

2.6 Pointers

It is not desired to identify a pointer by building a 'p' into the variable name. The pointer aspect of the variable pertains to type, not purpose.

Example

    MODULE*   module;

The purpose of the variable is that it represents a MODULE. Something like p_module would only make that harder to discern.

Use smart pointers where it makes sense to simplify memory management. Where using smart pointers, the STL types std::shared_ptr / std::unique_ptr are preferred. Do not use Boost smart pointers.

2.7 Accessing Member Variables and Member Functions

We do not use this→ to access either member variables or member functions from within the containing class. We let C++ perform this for us.

2.8 Use of 'auto'

We do -not- use auto to reduce repetition. We do use it to increase readability. This generally means -only- use auto where std::lib gets overly verbose (such as iterators or std::make_shared), or when not using auto would cause line-wraps that can’t otherwise be avoided.

Example

auto   board = m_frame->GetBoard();         // Not permitted, use the actual type name
BOARD* board = m_frame->GetBoard();         // OK
auto   it    = someComplexSTLType.begin();  // OK, improves readability

for( auto& item : container )       // Discouraged where the actual type name isn't very long
for( TYPE& item : container )       // Preferred
for( auto& [key, value] : map )     // C++17 structured binding; acceptable when readable

2.9 Casting

In most circumstances, use of C-style casting is not permitted. Explicit C++-style casting should be used instead.

Example

PCB_TRACK* track = ( PCB_TRACK* )item;               // Not permitted
PCB_TRACK* track = static_cast<PCB_TRACK*>( item );  // OK (when used safely)
PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ); // OK

3. Commenting

Comments in KiCad typically fall into two categories: in line code comments and Doxygen comments. In line comments have no set formatting rules other than they should have the same indent level as the code if they do not follow a statement. In line comments that follow statements should not exceed 99 columns unless absolutely necessary. The prevents word wrapping in an editor when the viewable columns is set to 100. In line comments can use either the C++ or the C commenting style, but C++ comments are preferred for single line comments or comments consisting of only a few lines.

Avoid stating the obvious in comments. Adding a comment that states this is a dtor, ctor, function, iterator, etc. just adds noise to the comment. Any sufficiently experience developer can recognize this. Avoid comments that state what code does. It should be obvious what code does or it should be rewritten so that it is obvious.

3.1 Blank Lines Above Comments

If a comment is the first thing on a line, then that comment should have one or more blank lines above them. One blank line is preferred.

3.2 Doxygen

Doxygen is a C++ source code documenting tool used by the project. Descriptive *.html files can be generated from the source code by installing Doxygen and building the target named doxygen-docs.

    cd <kicad_build_base>
    make doxygen-docs

The generated source *.html files will be placed into <kicad_project_base>/Documentation/doxygen/html/.

Doxygen comments are used to build developer documentation from the source code. They should normally be only placed in header files (.h) and not in source files (.cpp). This eliminates the obligation to keep two comments in agreement with each other. If the class, function, or enum, etc. is only defined in a source file and not present in any header file, in which case the Doxygen comments should go into the source file. Again, avoid duplicating the Doxygen comments in both the header and source files.

KiCad uses the JAVADOC comment style defined in the doccode section of the Doxygen manual. Don’t forget to use the special Doxygen tags : bug, todo, deprecated, etc., so other developers can quickly get useful information about your code. It is good practice to actually generate the Doxygen *.html files by building target doxygen-docs, and then to review the quality of your Doxygen comments with a web browser before submitting a patch.

Avoid defining class and function names and argument and return data types. This redundant information can easily be read by other developers and shows up as redundant information in the generated documentation.

Many legacy Doxygen comments in KiCad start with the function name on a blank line before the rest of the comment. This style is no longer acceptable, and modifications to those legacy function signatures is a good opportunity to remove these lines from the Doxygen comments.

Use Doxygen’s markdown syntax where possible instead of HTML tags. Markdown makes for more readable comments than mark up languages.

Use Doxygen links when referring to other code in Doxygen comments. This makes information easier to find for other developers.

Group related sections of comments together as much as possible using the Doxygen grouping commands. This makes finding related information easier than having it spread across multiple document pages.

3.2.1 Function Comments

These go into a header file, unless the function is a private (i.e. static) function known only to a source file. The format of a function comment is chosen to serve a dual purpose role: delineation of the function declaration within the source code and to create a consistent leading sentence in the Doxygen html output. The chosen format is to use a descriptive single line sentence, followed by a blank line, followed by an optional detailed description as the shown in the example below.

Example

    /**
     * Format and write text to an output stream.
     *
     * A really detailed description goes here if it's needed.
     *
     * @param aMestLevel is the multiple of spaces to precede the output with.
     * @param aFmt is a printf() style format string.
     * @param ... is a variable list of parameters that will get blended into
     *  the output under control of the format string.
     * @return the number of characters output.
     * @throw IO_ERROR, if there is a problem outputting.
     */
    int PRINTF_FUNC Print( int aNestLevel, const char* aFmt, ... );

The single line description goes on the 2nd line of the comment. The @return keyword if present, should describe the return value followed by a hyphen. The @param keyword names a function parameter and the text following should flow like a normal English sentence including proper punctuation.

3.2.2 Class Comments

A class comment describes a class declaration by giving the purpose and use of the class. Its format is similar to a function comment. Doxygen can use the html \<p\> (paragraph designation) to begin a new paragraph in its output. So if the text of the comment is large, break it put into multiple paragraphs as required.

Example

    /**
     * An interface (abstract) class used to output UTF8 text in a
     * convenient way.
     *
     * The primary interface is "printf() like" but with support for
     * indentation control. The destination of the 8 bit wide text is
     * up to the implementer.
     * <p>
     * The implementer only has to implement the write() function, but
     * can also optionally re-implement GetQuoteChar().
     * <p>
     * If you want to output a wxString, then use CONV_TO_UTF8() on it
     * before passing it as an argument to Print().
     * <p>
     * Since this is an abstract interface, only classes derived from
     * this one may actually be used.
     */
    class OUTPUTFORMATTER
    {

4. Formatting

This section defines the formatting style used in the KiCad source.

4.1 Indentation

The indentation level for the KiCad source code is defined as four spaces. Please do not use tabs.

4.1.1 Defines

There should be only one space after a #define statement.

4.1.2 Column Alignment

Please try to align multiple consecutive similar lines into consistent columns when possible, such as #define lines which can be thought of as containing 4 columns: #define, symbol, value, and comment. Notice how all 4 columns are aligned in the example below.

    #define LN_RED        12        // my favorite
    #define LN_GREEN      13        // eco friendly

Another common case is the declaration of automatic variables. These are preferably shown in columns of type and variable name.

4.2 Blank Lines

4.2.1 Function Declarations

There should be 1 blank line above a function declaration in a class file if that function declaration is presented with a Javadoc comment. This is consist with the statement above about blank lines above comments.

4.2.2 Function Definitions

Function definitions in *.cpp files will not typically be accompanied by any comment, since those are normally only in the header file. It is desirable to set off the function definition within the *.cpp file by leaving two blank lines above the function definition.

4.2.3 Control Statements

There should be one blank line before the opening statement and after the closing curly brace or statement for all control statement blocks so that it is easy to see where control blocks begin and end. This includes if, for, while, do, and switch control blocks.

For example, a blank line is required here between the variable declaration and the if statement:

bool isTrue = checkSomething();

if( isTrue )
    doSomething();

Curly braces themselves count as blank lines for the purposes of this style rule. For example, a nested control statement may be written as:

while( aCondition )
{
    if( checkSomething() )
    {
        break;
    }
}

4.3 Line Length

The maximum line width is 99 columns. An exception to this is a long quoted string such as the internationalized text required to satisfy MSVC++, described below.

4.4 Line-breaking Strings

The KiCad project team no longer supports compiling with Microsoft Visual C++. When you need to break long strings into smaller substrings, please use the C99 compliant method for improved readability. Using any of previously accepted methods defined below for breaking long internationalized strings will no longer be accepted.

Examples

    // This works with C99 compliant compilers is the **only** accepted method:
    wxChar* foo = _( “this is a long string broken ”
                     “into pieces for readability.” );

    // This works with MSVC, breaks POEdit, and is **not** acceptable:
    wxChar* foo = _( “this is a long string broken ”
                    L“into pieces for readability” );

    // This works with MSVC, is ugly, and is **not** accepted:
    wxChar* foo = _( “this is a long string \
    broken into pieces for readability” );

A second acceptable solution is to simply put the text all on one line, even if it exceeds the 99 character line length limit. However, the preferred method is to break strings within the 99 character limit whenever possible to prevent wrapping.

4.5 Line-breaking Expressions

When line breaking expressions the operators should appear at the beginning of a line, not at the end.

    if( SomeMethodCall( some_parameter, other_parameter )
            || some_local_variable == foo )

4.6 Trailing Whitespace

Many programming editors conveniently indent your code for you. Some of them do it rather poorly and leave trailing whitespace. Thankfully, most editors come with a remove trailing whitespace macro or at least a setting to make trailing whitespace visible so you can see it and manually remove it. Trailing whitespace is known to break some text parsing tools. It also leads to unnecessary diffs in the version control system. Please remove trailing whitespace.

4.7 Multiple Statements per Line

It is generally preferred that each statement be placed on its own line. This is especially true for statements without keywords.

    x=1; y=2; z=3; // Bad, should be on separate lines.

4.8 Braces

Braces should be placed on the line proceeding the keyword and indented to the same level. It is not necessary to use braces if there is only a single line statement after the keyword. In the case of if..else if..else, indent all to the same level.

    void function()
    {
        if( foo )
        {
            statement1;
            statement2;
        }
        else if( bar )
        {
            statement3;
            statement4;
        }
        else
            statement5;
    }

Braces are required if the control statement spans more than one line, even if the control block is a single line. This makes it easier to visually parse.

    if( GetSomeProperty( parameter ) == SOME_CONSTANT_VALUE
            || GetSomeProperty( parameter ) == SOME_OTHER_CONSTANT_VALUE )
    {
        single_statement;
    }

4.9 Parenthesis

Parenthesis should be placed immediately after function names and keywords. Spaces should be placed after the opening parenthesis, before the closing parenthesis, and between the comma and the next argument in functions. No space is needed if a function has no arguments.

    void Function( int aArg1, int aArg2 )
    {
        while( busy )
        {
            if( a || b || c )
                doSomething();
            else
                doSomethingElse();
        }
    }

4.10 Switch Formatting

The case statement is to be indented to the same level as the switch.

    switch( foo )
    {
    case 1:
        doOne();
        break;
    case 2:
        doTwo();
        // Fall through.
    default:
        doDefault();
    }

It is preferred to place all cases on a single line when that makes the code more readable. This is often done for look-ups or mapping functions. In this case, you will have to manually align for readability as appropriate and reject clang-format’s suggested changes, if you use it:

    switch( m_orientation )
    {
    case PIN_RIGHT: m_orientation = PIN_UP;    break;
    case PIN_UP:    m_orientation = PIN_LEFT;  break;
    case PIN_LEFT:  m_orientation = PIN_DOWN;  break;
    case PIN_DOWN:  m_orientation = PIN_RIGHT; break;
    }

4.11 Lamdas

The braces and statements of the body should be indented as you would a method, with the braces lined up under the capture block:

    auto belowCondition = []( const SELECTION& aSel )
                          {
                              return g_CurrentSheet->Last() != g_RootSheet;
                          };

or:

    auto belowCondition =
            []( const SELECTION& aSel )
            {
                return g_CurrentSheet->Last() != g_RootSheet;
            };

4.12 Class Definition Layout

When defining classes, member variables should be placed at the bottom and methods should be placed above the member variables. The scope ordering of the class should be public, protect, then private. Do not redefine the same scope multiple times in a row. Here is an example class definition:

    class FOO
    {
    public:
        FOO();
        void FooPublicMethod();

    protected:
        void fooProtectedMethod();

    private:
        void fooPrivateMethod();

        // Private not redefined here unless no private methods.
        int m_privateMemberVariable;
    };

4.13 Getters and Setters

Class methods used to read and write from private class members without any other side effects are permitted to violate several of the normal formatting rules in order to improve legibility. These methods can exist all on one line, with no blank line between:

public:
    wxString GetFoo() const { return m_foo; }
    void SetFoo( const wxString& aFoo ) { m_foo = aFoo; }

5. License Statement

There is a the file copyright.h which you can copy into the top of your new source files and edit the \<author\> field. KiCad depends on the copyright enforcement capabilities of copyright law, and this means that source files must be copyrighted and not be released into the public domain. Each source file has one or more owners.

6. Debugging Output

Debugging output is a common method for validating code. However, it should not always active in debug builds. This makes it difficult for other developers to see their debugging output and can have a significant impact on the performance of debug builds. I you need to use debugging output, use wxLogDebug instead of printf or C++ output stream. If you accidentally leave the debugging output in the source, it will expand to nothing on release builds. All debugging output code should be removed from the source tree before pushing changes to the main KiCad repo. Do not comment out debugging output. This just adds more cruft to the code base. If you need to leave debugging output for, future testing, use tracing output (see 6.1).

6.1 Using Tracing for Debugging Output

There are occasions when you want to see debugging output to ensure existing code performs as expected. In this case, use wxLogTrace which allows debugging output to be controlled by the WXTRACE environment variable. When using wxLogTrace, the trace environment variable string should be documented by either adding it to the trace_helper.{h/cpp} source files or locally using the Doxygen comment \ingroup trace_env_vars. To prevent WXTRACE name space conflicts, all trace variable strings should be prefixed with "KICAD_".

7. Header Files

Project *.h source files should:

  • contain a license statement

  • contain a nested include #ifndef

  • be fully self standing and not depend on other headers that are not included within it.

The license statement was described above.

7.1 Nested Include #ifndef

Each header file should include an #ifndef which is commonly used to prevent compiler errors in the case where the header file is seen multiple times in the code stream presented to the compiler. Just after the license statement, at the top of the file there should be lines similar to these (but with a file name specific token other than RICHIO_H_):

    #ifndef RICHIO_H_
    #define RICHIO_H_

And at the very bottom of the header file, use a line like this one:

    #endif // RICHIO_H_

The #ifndef wrapper begins after the license statement, and ends at the very bottom of the file. It is important that it wrap any nested #include statements, so that the compiler can skip them if the #ifndef evaluates to false, which will reduce compilation time.

7.2 Headers Without Unsatisfied Dependencies

Any header file should include other headers that it depends on. (Note: KiCad is not at this point now, but this section is a goal of the project.)

It should be possible to run the compiler on any header file within the project, and with proper include paths being passed to the compiler, the header file should compile without error.

Example

$ cd path_to_kicad_source/include
$ g++ `wx-config --cxxflags` -I . xnode.h -o /tmp/junk

Such structuring of the header files removes the need within a client *.cpp file to include some project header file before some other project header file. (A client *.cpp file is one that intends to use, not implement, the public API exposed within the header file.)

Client code should not have to piece together things that a header file wishes to expose. The exposing header file should be viewed as a fully sufficient ticket to use the public API of that header file.

This is not saying anything about how much to expose, only that that which is exposed needs to be fully usable merely by including the header file that exposes it, with no additional includes.

For situations where there is a class header file and an implementation *.cpp file, it is desirable to hide as much of the private implementation as is practical and any header file that is not needed as part of the public API can and should be included only in the implementation *.cpp file. However, the number one concern of this section is that client (using) code can use the public API which is exposed in the header file, merely by including that one header file.

8. When in Doubt…​

When editing existing source code files and there are multiple acceptable code formatting options or no formatting is defined, follow the existing formatting in the file.

9. I Wrote X Lines of Code Before I Read This Document

It’s OK. We all make mistakes. Fortunately, KiCad provides a configuration file for the code beautifier uncrustify. Uncrustify won’t fix your naming problems but it does a pretty decent job of formatting your source code. There are a few places where uncrustify makes some less than ideal indentation choices. It struggles with the string declaration macros wxT(“”) and \_(“”) and functions used as arguments to other functions. After you uncrustify your source code, please review the indentation for any glaring errors and manually fix them. See the uncrustify [website][uncrustify] for more information.

10. Show Me an Example

Nothing drives the point home like an example. The source file richio.h below was taken directly from the KiCad source.

    /*
     * This program source code file is part of KICAD, a free EDA CAD application.
     *
     * Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
     * Copyright (C) 2007 KiCad Developers, see AUTHORS.txt for contributors.
     *
     * 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, you may find one here:
     * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
     * or you may search the http://www.gnu.org website for the version 2 license,
     * or you may write to the Free Software Foundation, Inc.,
     * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
     */

    #ifndef RICHIO_H_
    #define RICHIO_H_


    // This file defines 3 classes useful for working with DSN text files and is named
    // "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.


    #include <string>
    #include <vector>

    // I really did not want to be dependent on wxWidgets in richio
    // but the errorText needs to be wide char so wxString rules.
    #include <wx/wx.h>
    #include <cstdio>       // FILE



    /**
     * A class used to hold an error message and may be used to throw exceptions
     * containing meaningful error messages.
     */
    struct IOError
    {
        wxString    errorText;

        IOError( const wxChar* aMsg ) :
            errorText( aMsg )
        {
        }

        IOError( const wxString& aMsg ) :
            errorText( aMsg )
        {
        }
    };


    /**
     * Read single lines of text into a buffer and increments a line number counter.
     */
    class LINE_READER
    {
    public:

        /**
         * @param aFile is an open file in "ascii" mode, not binary mode.
         * @param aMaxLineLength is the number of bytes to use in the line buffer.
         */
        LINE_READER( FILE* aFile, unsigned aMaxLineLength );

        ~LINE_READER()
        {
            delete[] line;
        }

        /*
        int  CharAt( int aNdx )
        {
            if( (unsigned) aNdx < capacity )
                return (char) (unsigned char) line[aNdx];
            return -1;
        }
        */

        /**
         * Read a line of text into the buffer and increments the line number
         * counter.
         *
         * @return is the number of bytes read, 0 at end of file.
         * @throw IO_ERROR when a line is too long.
         */
        int ReadLine();

        operator char* ()
        {
            return line;
        }

        int LineNumber()
        {
            return lineNum;
        }

        unsigned Length()
        {
            return length;
        }

    protected:

        FILE*               fp;
        int                 lineNum;
        unsigned            maxLineLength;
        unsigned            length;
        char*               line;
        unsigned            capacity;
    };



    /**
     * An interface (abstract class) used to output ASCII text in a convenient way.
     *
     * The primary interface is printf() like with support for indentation control.
     * The destination of the 8 bit wide text is up to the implementer. If you want
     * to output a wxString, then use CONV_TO_UTF8() on it before passing it as an
     * argument to Print().
     * <p>
     * Since this is an abstract interface, only classes derived from this one
     * will be the implementations.
     * </p>
     */
    class OUTPUTFORMATTER
    {

    #if defined( __GNUG__ )   // The GNU {cpp} compiler defines this

    // When used on a {cpp} function, we must account for the "this" pointer,
    // so increase the STRING-INDEX and FIRST-TO_CHECK by one.
    // See http://docs.freebsd.org/info/gcc/gcc.info.Function_Attributes.html
    // Then to get format checking during the compile, compile with -Wall or -Wformat
    #define PRINTF_FUNC       __attribute__ ((format (printf, 3, 4)))

    #else
    #define PRINTF_FUNC       // nothing
    #endif

    public:

        /**
         * Format and write text to the output stream.
         *
         * @param nestLevel is the multiple of spaces to preceed the output with.
         * @param fmt is a printf() style format string.
         * @param ... is a variable list of parameters that will get blended into
         *  the output under control of the format string.
         * @return the number of characters output.
         * @throw IO_ERROR if there is a problem outputting, such as a full disk.
         */
        virtual int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) = 0;

        /**
         * Return the quoting character required for aWrapee.
         *
         * Return the quote character as a single character string for a given
         * input wrapee string.  If the wrappee does not need to be quoted,
         * the return value is "" (the null string), such as when there are no
         * delimiters in the input wrapee string.  If you want the quote character
         * to be assuredly not "", then pass in "(" as the wrappee.
         * <p>
         * Implementations are free to override the default behavior, which is to
         * call the static function of the same name.
         * </p>
         *
         * @param aWrapee is a string that might need wrapping on each end.
         * @return the quote character as a single character string, or ""
         *   if the wrapee does not need to be wrapped.
         */
        virtual const char* GetQuoteChar( const char* aWrapee ) = 0;

        virtual ~OUTPUTFORMATTER() {}

        /**
         * Get the quote character according to the Specctra DSN specification.
         *
         * @param aWrapee is a string that might need wrapping on each end.
         * @param aQuoteChar is a single character C string which provides the current
         *          quote character, should it be needed by the wrapee.
         *
         * @return the quote_character as a single character string, or ""
         *   if the wrapee does not need to be wrapped.
         */
        static const char* GetQuoteChar( const char* aWrapee, const char* aQuoteChar );
    };


    /**
     * Implement an OUTPUTFORMATTER to a memory buffer.
     */
    class STRINGFORMATTER : public OUTPUTFORMATTER
    {
    public:

        /**
         * Reserve space in the buffer
         */
        STRINGFORMATTER( int aReserve = 300 ) :
            buffer( aReserve, '\0' )
        {
        }


        /**
         * Clears the buffer and empties the internal string.
         */
        void Clear()
        {
            mystring.clear();
        }

        /**
         * Remove whitespace, '(', and ')' from the internal string.
         */
        void StripUseless();


        std::string GetString()
        {
            return mystring;
        }


        //-----<OUTPUTFORMATTER>------------------------------------------------
        int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... );
        const char* GetQuoteChar( const char* wrapee );
        //-----</OUTPUTFORMATTER>-----------------------------------------------

    private:

        std::vector<char>       buffer;
        std::string             mystring;

        int sprint( const char* fmt, ... );
        int vprint( const char* fmt,  va_list ap );
    };


    #endif // RICHIO_H_

11. Resources

There are plenty of excellent resources on the Internet on C++ coding styles and coding do’s and don’ts. Here are a few useful ones. In most cases, the coding styles do not follow the KiCad coding style but there is plenty of other good information here. Besides, most of them have some great humor in them enjoyable to read. Who knows, you might even learn something new.

Last Modified