# NetHack 3.7  code_style.txt       $NHDT-Date: 1694890786 2023/09/16 18:59:46 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $
# Copyright (c) 2015 by Derek S. Ray
# NetHack may be freely redistributed.  See license for details.

NetHack DevTeam Coding Style
============================

NetHack is written in C, with a little bit of C++ to access platform
libraries. This coding style document is concerned primarily with the style
used for C source files. We do not have a defined style for C++ files, but C++
should be styled in keeping with C.

The code base in C files was, close to the 3.6 release, reformatted using a
version of the clang-format tool patched to support K&R-style argument
declarations. Due to some incompatibilities, the patch is not publicly
available and clang-format is not expected to be regularly used.  Since then,
function declarations and definitions have been switched to ANSI.

Developers should do their best to adhere to the coding style to promote
legible, easy-to-edit code. Legibility is paramount, so in some cases, it may
be better not to fully adhere to the style guidelines.

Recipes for common text editors can be found at the end of this file.

Indentation and Spacing
-----------------------

The basic indentation is 4 spaces wide. All indentation is done using space
characters, not tabs.

Lines should be at most 78 characters wide. If a line would be longer than the
limit, the line should be wrapped and the wrapped portion should be aligned
with the parentheses or brackets containing the wrap. If there is no set of
parentheses or brackets, the line should be indented four spaces. Wrapping
should normally occur after a comma or before a binary operator, when
possible:

    int index
        = SomeExcessivelyLongExpression;

    fcall(arg1,
          arg2, (cond13
                 && cond2));

Single blank lines should be used wherever convenient to improve readability.

Functions and Control Statements
--------------------------------

For a function definition, the return type, declarator, and opening brace
should each appear on a line of their own. Arguments are defined in the following
parenthesis, per ANSI.  There are two general styles.  One with no comments, where
arguments are added one after another, with a wrap aligning to the first argument
if there is an overflow.

    void
    foo(int i, char c)
    {
        /* function body */
    }

    void
    long_function_name(int first_arg, struct long_name *second_arg,
                       int third_arg, int forth_arg)
    {
        /* function body */
    }

Alternatively, arguments can be one per line if they are commented:

    void
    long_function_name(int first_arg,                /* main operation */
                       struct long_name *second_arg, /* control details */
                       int third_arg,                /* local conditions - if
                                                        they apply */
                       int forth_arg)                /* remote conditions */
    {
        /* function body */
    }

If the function takes no parameters:

    int
    long_function_name(void)
    {
        /* function body */
    }

Opening braces of control statements appear on the same line as the control
statement:

    if (condition) {
        /* body */
    }

Else statements and the while statements of do-while blocks appear on the same
line as the closing brace of the if or do statement. Otherwise, closing braces
always get a line of their own.

    if (condition) {
        /* body */
    } else if (condition) {
        do {
            /* body */
        } while (condition);
    } else {
        /* body */
    }

If a control block has only a single statement, it can appear on a line of its
own, with an indent. If the statement is a null statement, then it should be
expressed as an empty set block, not with a semicolon, because many compilers
will warn if a null statement is used:

    if (condition)
        fcall();

    if (condition) {
    } else
        fcall();

If multiple control blocks are being used in a row, it may be more readable to
use braces even for single statements, and they should be used if they improve
readability. The following is an example of poor usage:

    if (condition) {
        /* long body */
    } else if (condition)
        statement;
    else {
        /* very long body */
    }

Switch statements should have the case labels unindented, and the statements
should be indented normally. The default case should occur last unless there's
a compelling reason not to, and fallthroughs should be explicitly marked as
such with a comment, to avoid Yeenoghu getting the touch of death again:

    switch (condition) {
    case FOO:
    case BAR:
        fcall();
        /* fall-through */
    case BAZ:
        fcall();
        break;

    default:
        statement;
    }

Variables should never be declared in a condition or a for loop
initialization, and if an assignment is used as a condition, it should be
wrapped in an additional set of parentheses for clarity:

    int *p;
    if ((p = fcall())) {
        /* body */
    }

    int i;
    for (i = 1; i < 10; ++i) {
        /* body */
    }

Variable names to avoid
-----------------------

    near, far    Some compilers and cross-compilers that target old
                 processors with segmented architectures may treat
                 those as keywords. It is safest to just avoid them.

    NEARDATA     Some data is marked with this define; the Amiga port uses
                 it to mark data items to be used with a short addressing mode.
                 You don't need to use this.

static vs staticfn
------------------

The staticfn macro evaluates to either "static" or to nothing (see config.h).
If possible, functions in src/*.c that would otherwise be marked static should
be marked staticfn so platforms that do not name static functions in their
stack traces can be forced to do so; this means function names cannot be
reused.  Never use staticfn with data.

Spaces in Expressions
---------------------

Spaces should appear around binary operators, after commas, after a C-style
cast, and after the keyword in a control statement. They should not appear
between a function name and the opening parenthesis of a function call, nor
immediately inside a pair of parentheses:

    foo(i, j, l);
    if ((boolean) condition) {
        /* body */
    }

Casts and sizeof
----------------

Casts should separate the cast operator and its expression with a space:
    '(char *) str'
'sizeof (type)' requires the parentheses.  'sizeof expression' does not;
using them is not wrong but omitting them avoids some visual clutter.
Using them without the separating space gives the false impression of a
function call or macro-with-argument(s) expansion; 'sizeof' is an operator
and the parentheses required for '(type)' are to treat it like a cast.

Comments
--------

Some block comments are undecorated, just split into reasonable width lines:
    /* this is
       a comment */
They usually don't include sentence punctuation.

Others are more elaborate:
    /*
     * This is
     * another comment.
     */
This style is usually used with sentence punctuation, particularly if they
contain more than one sentence.

End-of-line comments which need to span lines
    somecode(); /* this comment
                 * is ok */
should start every continuation line with an asterisk, otherwise clang-format
would convert them into a block comment
    othercode(); /* this comment
                    should be avoided */
because it would be converted into
    othercode();
    /* this comment
       should be avoided */
if another bulk reformatting ever gets performed.  Similarly, multiple
comments intended to read as one
    morecode(); /* start of comment */
                /* more of comment  */
                /* end of comment   */
are deprecated because they will end up losing the indentation of the
followup lines if reformatted.

Many files end with
    /*filename*/
usually preceded by a blank line.  This was intended as a workaround for a
comment--somewhere, possibly in Amiga or Atari code--that stated that some
compiler or other didn't always process the last line of the file.  If that
last line is a comment, nothing is lost.  The real issue almost certainly
was source file(s) that didn't end in newline.  These days we try to force
the final newline for every file, prior to release if not always maintained
day-to-day.  The name at the end can still be worthwhile when editing or
browsing multiple files.

Vim Configuration
=================

For vim, the following settings are encouraged when editing NetHack code, to
ensure that indentation is done correctly:

    set shiftwidth=4
    set softtabstop=4
    set expandtab
    set tabstop=4
    set shiftround
    set textwidth=78
    set cindent
    set filetype=c


Visual Studio Configuration
===========================

In Visual Studio under Tools->Options->Text Editor->C/C++, you can set the
following options to obtain desired behavior:

[Tabs]
Indenting: Smart
Tab size: 4
Indent size: 4
Insert Spaces

There are a number of other options under [Formatting] that should be
checked (Indentation, New Lines, Spacing, and Wrapping), but there are so
many entries that reproducing them here is impractical. Fortunately, the
options are in plain English, so walking through them with a copy of
this Guide handy and making changes as required will suffice.

Emacs Configuration
===================

There are no doubt umpteen different ways to handle this in Emacs.
Putting the following in ~/.emacs.el is one

(defun hook-c ()
  (setq c-set-style "k&r")
  (setq c-basic-offset 4)
  (setq indent-tabs-mode nil))
(add-hook 'c-mode-common-hook 'hook-c)

