Hacking INN

    This file is for people who are interested in making modifications to
    INN.  Normal users can safely skip reading it.  It is intended primarily
    as a guide, resource, and accumulation of tips for maintainers and
    contributors, and secondarily as documentation of some of INN's
    internals.

    This is $Revision: 1.5 $ dated $Date: 2000/04/06 02:27:37 $.

Configuring

    INN uses autoconf to probe the system on which it is being compiled and
    adjust how it does things to try to be as portable as possible.  The
    shell script configure at the top level of the source tree is
    autogenerated by autoconf from configure.in, and include/config.h.in is
    autogenerated by autoheader from configure.in and include/acconfig.h. 
    At configure time, configure generates include/config.h and several
    other files based on options it was given and what it discovers about
    the target system.

    All modifications to configure should instead be made to configure.in. 
    Similarly, modifications to include/config.h.in should instead be made
    to include/acconfig.h.  The autoconf manual (available using info
    autoconf if you have autoconf and the GNU info utilities installed on
    your system) is a valuable reference when making any modifications.

    To regenerate configure, just run `autoconf'.  To regenerate
    include/config.h.in, run:

        autoheader -l include

    to tell it where to find acconfig.h.

    The generated files are checked into the CVS repository so that people
    working on INN don't have to have autoconf on their system, and to make
    packaging easier.

    At the time of this writing, autoconf 2.13 is required.

    The supporting files for autoconf are in the support subdirectory,
    including the files config.guess and config.sub to determine the system
    name and the files ltconfig and ltmain.sh for libtool support.  The
    latter two files come from the libtool distribution; the canonical
    version of the former are maintained in the autoconf repository but the
    latest versions are available with the latest release of autoconf,
    automake, or libtool.

    For maintainers with CVS access, these four files are on a separate
    vendor branch (the 1.1.2 branch in the repository).  When a new version
    of libtool is released, put those four files in a directory and import
    them onto that branch with something like

        cvs import -m "Import of libtool 1.4 support files" -b 1.1.2 \
        inn/support FSF LIBTOOL-1_4

    (all on one line) and then merge that vendor branch into the mainline. 
    See the cvs manual under Tracking Sources and specifically Multiple
    Vendor Branches for more details.

    This process can optionally be done with just config.guess and
    config.sub when new versions of those are released between libtool
    releases.

    INN should not compile with libtool by default, only when requested,
    since otherwise normal compilations are quite slow.  (Using libtool is
    not without some cost.)  Basic compilation with libtool works fine as of
    this writing, with both static and shared compiles, but the dependencies
    aren't quite right for make -j using libtool.

Documentation

    INN's documentation is currently somewhat in a state of flux.  The vast
    majority is still in the form of man pages written directly in nroff. 
    Some parts of the documentation have been rewritten in POD; that
    documentation can be found in doc/pod.  The canonical source for README,
    README.perl_hook, INSTALL, NEWS, and this file are also in POD.  In
    addition, DocBook SGML versions of the POD documentation are included in
    the CVS tree (although not in releases at this time, since they're
    programmatically generated and occasionally of somewhat poor quality)
    and periodically updated both for the use of DocBook translators and to
    make conversion to SGML easier if necessary down the road.

    If you're modifying some part of INN's documentation and see that it has
    a POD version in doc/pod, it's preferred if you can make the
    modifications to the POD source and then regenerate the derived files. 
    For a quick introduction to POD, see the perlpod(1) man page on your
    system (it should be installed if you have Perl installed).

    When writing new documentation, write in whatever format you care to; if
    necessary, we can always convert it to POD or whatever else we want to
    use.  Having the documentation exist in *some* form is more important
    than what language you write it in.  If you really don't have any
    particular preference, there's a slight preference currently for POD.

    The pod2text and pod2man scripts that come with Perl versions prior to
    5.6.0 are adequate but not ideal for processing INN's documentation. 
    The best converters are available as part of the podlators package,
    available from CPAN (ftp.perl.org or another mirror) in
    modules/by-module/Pod; fairly recent versions of the podlators utilities
    (and good enough for INN documentation) come with Perl 5.6.0.  This
    module also requires installation of PodParser for Perl versions before
    5.6.0, found in the same directory, and File::Spec for versions of Perl
    before 5.005.  File::Spec you can find in modules/by-module/File.

    To generate text documentation (like INSTALL or README), use:

        pod2text -s -l install.pod > ../../INSTALL

    from the doc/pod directory.  `-s' preserves two spaces after periods and
    `-l' adds a blank line after major headings.

    To generate a man page from POD source, use:

        pod2man -c "InterNetNews Documentation" -r "INN 2.3" in > out

    where in is the name of the POD file and out is what to name the *roff
    output.  For some documentation, you also have to provide -s <section>
    to set the correct manual section (pod2man will assume section 1 if -s
    isn't given).  It's best to run pod2man from the doc/pod directory,
    directing the output to the appropriate file in the doc/man directory,
    since it does some tricks with the name of the file to determine the
    title of the man page and can be confused by longer paths.

    At some point this should go into Makefile rules.

    For conversion of POD to DocBook SGML, use Pod::DocBook, also found on
    CPAN in modules/by-module/Pod.

    The current versions of these tools as of this writing are podlators
    1.01, PodParser 1.13, and Pod::DocBook 0.05.

Makefiles

    All INN makefiles include Makefile.global at the top level, and only
    that makefile is a configure substitution target.  This has the
    disadvantage that configure's normal support for building in a tree
    outside of the source tree doesn't work, but it has the significant
    advantage of making configure run much faster and allowing one to run
    make in any subdirectory and pick up all the definitions and settings
    from the top level configuration.

    The format of INN's makefiles have slowly been standardized; the best
    examples of the current format are probably frontends/Makefile and
    backends/Makefile, at least for directories with lots of separate
    programs.  The ALL variable holds all the files that should be
    generated, EXTRA those additional files that were generated by
    configure, SOURCES the C source files for generating tag information,
    and INSTALLED the final installed paths.

    There are a set of standard installation commands defined in make
    variables by Makefile.global, and these should be used for all file
    installations.  See the comment blocks in Makefile.global.in for
    information on what commands are available and when they should be used.
    There are also variables set for each of the installation directories
    that INN uses, for use in building the list of installed paths to files.

    Each subdirectory makefile should have the targets all (the default),
    clean, clobber, install, tags, and profiled.  The tags target generates
    vi tags files, and the profiled target generates a profiling version of
    the programs (although this hasn't been tested much recently).  These
    rules should be present and empty in those directories where they don't
    apply.

    Be sure to test compiling with both static and dynamic libraries and
    make sure that all the libtool support works correctly.  All linking
    steps, and the compile steps for all library source, should be done
    through $(LIBTOOL) (which will be set to empty in Makefile.global if
    libtool support isn't desired).

Scripts

    INN comes with and installs a large number of different scripts, both
    Bourne shell and Perl, and also comes with support for Tcl scripts
    (although it doesn't come with any).  Shell variables containing both
    configure-time information and configuration information from inn.conf
    are set by the innshellvars support libraries, so the only
    system-specific configuration that should have to be done is fixing the
    right path to the interpretor and adding a line to load the appropriate
    innshellvars.

    support/fixscript, built by configure, does this.  It takes a .in file
    and generates the final script (removing the .in) by fixing the path to
    the interpretor on the first line and replacing the second line,
    whatever it is, with code to load the innshellvars appropriate for that
    interpretor.  (If invoked with -i, it just fixes the interpretor path.)

    Scripts should use innshellvars (via fixscript) to get the right path
    and the right variables whenever possible, rather than having configure
    substitute values in them.  Any values needed at run-time should instead
    be available from all of the different innshellvars.

    See the existing scripts for examples of how this is done.

Include Files

    Include files relevant to all of INN, or relevant to the two libraries
    built as part of INN (the utility libinn library and the libstorage
    library that contains all storage and overview functions) are found in
    the include directory; other include files relevant only to a portion of
    INN are found in the relevant directory.

    Practically all INN source files will start with:

        #include "config.h"
        #include "clibrary.h"

    The first picks up all defines generated by autoconf and is necessary
    for types that may not be present on all systems (uid_t, pid_t, size_t,
    int32_t, and the like).  It therefore should be included before any
    other headers that use those types, as well as to get general
    configuration information.

    The second is portably equivalent to:

        #include <sys/types.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <stddef.h>
        #include <stdint.h>
        #include <string.h>
        #include <unistd.h>

    except that it doesn't include headers that are missing on a given
    system, replaces functions not found on the system with the INN
    equivalents, provides macros that INN assumes are available but which
    weren't found, and defines some additional portability things.  Even if
    this is more headers than the source file actually needs, it's generally
    better to just include clibrary.h rather than trying to duplicate the
    autoconf-driven hackery that it does to do things portably.  The primary
    exception is for source files in lib that only define a single function
    and are used for portability; those may want to include only config.h so
    that they can be easily used in other projects that use autoconf. 
    config.h is a fairly standard header name for this purpose.

    clibrary.h does also include config.h, but it's somewhat poor form to
    rely on this; it's better to explicitly list the header dependencies for
    the benefit of someone else reading the code.

    Another frequently included header file is macros.h, which defines the
    NEW(), COPY(), and DISPOSE() macros that are used throughout INN for
    memory management rather than directly calling malloc(), strdup(), and
    free().  (They actually use xmalloc() instead so you don't have to check
    the return value, they include the file name and line number in error
    messages resulting from out-of-memory conditions, and they make it
    easier to plug in a debugging memory allocator when trying to track down
    memory leaks or clobbers.)

    paths.h includes a wide variety of paths determined at configure time,
    both default paths to various parts of INN and paths to programs.  Don't
    just use the default paths, though, if they're also configurable in
    inn.conf; instead, call ReadInnConf() and use the global innconf
    structure.

    Other files in include, most notably libinn.h, are interfaces to
    particular bits of INN library functionality or are used for other
    purposes; see the comments in each file.

    Finally, many INN source files still include configdata.h; this header
    file is now obsolete (merged into config.h and clibrary.h) and should be
    removed where it appears.

Coding Style

    INN has quite a variety of coding styles intermixed.  As with all
    programs, it's preferrable when making minor modifications to keep the
    coding style of the code you're modifying.  In INN, that will vary by
    file.

    If you're writing a substantial new piece of code, the prevailing
    "standard" INN coding style appears to be something like the following:

    *  Roughly BSD style (four space indents, no space before the parens
       around function arguments, open brace on the same line as
       if/while/for, and close and open brace on the same line as else).

    *  Introductory comments for functions or files are generally written
       as:

           /*
           **  Introductory comment.
           */

       Other multiline comments in the source are generally written as:

           /* This is a
              multiline comment. */

       Comments before functions saying what they do are nice to have.  In
       general, the RCS/CVS Id tag is on the first line of each source file.

    *  Checks for NULL pointers are preferrably written out explicitly; in
       other words, use:

           if (p != NULL)

       rather than:

           if (p)

       to make it clearer what the code is assuming.

    The source is currently full of some rather odd casts, including a lot
    of casts to void when calling standard functions.  These are historical,
    designed to make lint shut up.  Don't feel like you have to preserve
    them provided that gcc -Wall doesn't complain when they're removed.

    Note that this is only a rough guideline and the maintainers aren't
    style nazis; we're more interested in your code contribution than in how
    you write it.

    Finally, if possible, please don't use tabs in source files, since they
    can expand differently in different environments.  In particular, please
    try not to use the mix of tabs and spaces that is the default in emacs. 
    If you use emacs to edit INN code, you may want to put:

        ; Use only spaces when indenting or centering, no tabs.
        (setq-default indent-tabs-mode nil)

    in your ~/.emacs file.

References

    Some additional references that may be hard to find and may be of use to
    people working on INN:

    <http://www.mibsoftware.com/userkt/inn/dev/>
        Forrest Cavalier provides several tools for following INN
        development at this page and elsewhere in the Usenet RKT.  Under
        here is a web-accessible checked-out copy of the current INN source
        tree and pointers to how to use CVSup.

    <http://www.sas.com/standards/large.file/>
        The standards for large file support on Unix that are being
        generally implemented by vendors.  INN sort of partially uses these,
        but a good full audit of the code to check them should really be
        done and there are occasional problems.

