ROBODoc

[ Top ] [ Modules ]

FUNCTION

ROBODoc is intended to be a replacement for the original AutoDocs program. ROBODoc will extract the comment headers from a source file, and put them into a separate documentation file. General Flow

      Sourcecode  ---> [ROBODoc] ---> Document.

The whole ROBODoc process consists of three steps: scanning, analysing, generating.

Scanning

ROBODoc scans the source directory tree. This collects the names of all the source files.

Analysing

ROBODOc analyses all the sourcefiles. This reads the content of all source files and collects all the headers.

Generating

In this step the headers are written to one or more documentation files. In addition

The data collected during scanning and analysing is stored in a number of structures.

RB_Directory, it stores the names of the sourcefiles and directories in the source direcory tree. File names are stored in a RB_Filename structure, directory names in a RB_Path structure. Each RB_Filename contains a pointer (path) to a RB_Path structure that tells in which directory a file is located. Each RB_Path has a pointer (parent) to another RB_Path structure that tells in which directory is a directory located (of which directory it is a subdirectory). The only exception is the root directory.

Besides the name of the sourcefile, the RB_Filename also stores the name of the documentation file.

For each sourcefile there is an RB_Part structure. It contains a pointer (filename) to the RB_Filename and a list (headers) of RB_Header structure containing the headers found in the sourcefile.

Every RB_Header structure contains a pointer (owner) to the RB_Part structure to which it belongs. Headers can form a hierarchy that is used to create sections and subsections in the documentation. To store this hierarchy every RB_header structure contains a pointer (parent) to its parent header. For instance, given the following two headers, SubModule is the parent of SubSubModule.

     ****h* TopModule/SubModule
     *
     **** 

     ****h* SubModule/SubSubModule
     *
     **** 

In the documentation this creates the sections

      1.TopModule
      1.1 SubModule
      1.1.1 SubSubModule

The RB_Directory and the linked list of RB_Part structures are stored in a RB_Document structure.

During the generation of the documentation ROBODoc tries to create cross links between the mention of a header's name (an object) and the documentation generated from that header (the documentation for the object).

To aid this proces there is an array of RB_link structures. This array is sorted for quick searching. RB_link structures the name of a header and the name of the label under which the documentation can be found in the documentation file.

AUTHOR

See AUTHORS in the archive.

CREATION DATE

20-Dec-94 Jacco van Weert.

MODIFICATION HISTORY

See ChangeLog in the archive. Latest version can be found on:

BUGS

Other bugs? Catch them in a jar and send them to rfsber -(at)- xs4all.nl


UserInterface

[ Top ] [ ROBODoc ] [ Modules ]

FUNCTION

This module contains functions to parse the command line and inform the user about any errors.


copying

[ Top ] [ UserInterface ] [ Variables ]

FUNCTION

Information about the ROBODoc licence.

AUTHOR

Frans


Find_And_Fix_Path

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Searches through the options to find a path. This path is converted to a propper path if it contains errors such as the use of '\' or when it does not start with ./ or a drive name. The option must exist.

SYNOPSIS

static char        *Find_And_Fix_Path(
    char *option_name )

INPUTS

RESULT

SOURCE

{
    char               *temp;
    char               *temp2;

    temp = Find_Parameterized_Option( option_name );
    assert( temp );
    temp = Path_Convert_Win32_to_Unix( temp );
    temp2 = Fix_Path( temp );
    free( temp );
    return temp2;
}

Find_Option

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Search configuration.options for a specific option.

SYNOPSIS

int Find_Option(
    char *option )
/* INPUTS
 *   o option -- the option to be found.

RESULT

SOURCE

{
    unsigned int        parameter_nr;
    int                 found = FALSE;

    for ( parameter_nr = 0;
          parameter_nr < configuration.options.number; parameter_nr++ )
    {
        if ( !RB_Str_Case_Cmp
             ( configuration.options.names[parameter_nr], option ) )
        {
            found = TRUE;
            break;
        }
    }
    return found;
}

Find_Parameterized_Option

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Search for an option of the form

     --a_option_name a_value

in configuration.options.

SYNOPSIS

char               *Find_Parameterized_Option(
    char *optionname )

INPUTS

optionname -- the name of the option to search for.

RESULT

NULL if the option is not found, a pointer to the value otherwise.

NOTES

Results in a Panic if the option is found but no value is specified.

SOURCE

{
    return General_Find_Parameterized_Option( configuration.options.number,
                                              &( configuration.options.
                                                 names[0] ), optionname );
}

Fix_Path

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Add a "./" to a path if it does not start with a "./" or does not contain a ":". If the path was "." just add a "/". Adding a "./" simplifies the creating of relative links during the generation process.

SYNOPSIS

static char        *Fix_Path(
    char *path )

INPUTS

RESULT

A pointer to a newly allocated string containing the path.

SOURCE

{
    char               *result = 0;

    if ( !PathBegin_Check( path ) )
    {
        char               *prefix = "./";

        if ( strcmp( path, "." ) == 0 )
        {
            result = RB_StrDup( prefix );
        }
        else
        {
            int                 l = strlen( path );

            l += strlen( prefix ) + 1;
            result = malloc( l );
            assert( result );
            result[0] = '\0';
            strcat( result, prefix );
            strcat( result, path );
        }
    }
    else
    {
        result = RB_StrDup( path );
    }
    return result;
}

General_Find_Parameterized_Option

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Search for an option of the form

     --a_option_name a_value

SYNOPSIS

static char        *General_Find_Parameterized_Option(
    int n,
    char **options,
    char *optionname )

INPUTS

RESULT

NULL if the option is not found, a pointer to the value otherwise.

NOTES

Results in a Panic if the option is found but no value is specified.

SOURCE

{
    int                 parameter_nr;
    char               *value = NULL;

    for ( parameter_nr = 0; parameter_nr < n; parameter_nr++ )
    {
        if ( !RB_Str_Case_Cmp( options[parameter_nr], optionname ) )
        {
            if ( parameter_nr < n - 1 )
            {
                value = options[parameter_nr + 1];
                if ( ( value[0] == '-' ) && ( value[1] == '-' ) )
                {
                    value = NULL;
                }
            }
            else
            {
                /* to few parameters. */
            }
            if ( !value )
            {
                RB_Panic( "you must be more specific"
                          " with the %s option\n", optionname );
            }
        }
    }
    return value;
}

main

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Get and parse the arguments. Analyse document and generate the documentation. Everything starts from here.

TODO

This function is too long.

SYNOPSIS

int main(
    int argc,
    char **argv )

SOURCE

{
    struct RB_Document *document = NULL;
    struct RB_Directory *srctree = NULL;
    char               *optstr = NULL;
    char               *used_rc_file = NULL;
    long                debug = 0;

/*
   TODO, make setlocale work.
    char * loc;

    if ( (loc = getenv("LC_CTYPE") ) != NULL ) 
    {
        printf( ".... %s\n", loc );
        setlocale( LC_ALL, loc);
    }
    else
    {
        setlocale(LC_ALL, "");
    }
*/

    whoami = argv[0];           /* global me,myself&i */

    /* Init Actions global */
    course_of_action = No_Actions(  );

    /* Read the configuration file. This might contain
       addition options. */
    RB_SetCurrentFile( NULL );
    used_rc_file = ReadConfiguration( argc, argv,
                                      RB_Find_In_Argv_Parameterized_Option
                                      ( argc, argv, "--rc" ) );

    /* Force debug mode early if the user wants the debug mode */
    debugmode = Find_DebugMode(  );

    if ( Check_Options(  ) == EXIT_FAILURE )
    {

        return EXIT_FAILURE;
    }

    if ( Find_Option( "-c" ) )
    {
        printf( "%s", copying );
        return EXIT_SUCCESS;
    }

    if ( Find_Option( "--version" ) )
    {
        dump_version(  );
        return EXIT_SUCCESS;
    }

    if ( Find_Option( "--config" ) )
    {
        dump_config(  );
        return EXIT_SUCCESS;
    }


    if ( Find_Option( "--help" ) )
    {
        printf( "%s%s%s%s%s%s", use, use_usage, use_options1, use_options2,
                use_options3, use_authors );
        return EXIT_SUCCESS;
    }

    output_mode = Find_DocType(  );     /* one of the globals that are still left */
    if ( output_mode == UNKNOWN )
    {
        Print_Short_Use(  );
        return EXIT_SUCCESS;
    }

    /* First the basics. */
    document = RB_Get_RB_Document(  );
    document->doctype = output_mode;
    document->actions = Find_Actions(  );
    debug = document->debugmode = Find_DebugMode(  );
    document->charset = Find_Parameterized_Option( "--charset" );
    document->extension = Find_Parameterized_Option( "--ext" );
    document->css = Find_Parameterized_Option( "--css" );
    document->compress = Find_Parameterized_Option( "--compress" );
    document->section = Find_Parameterized_Option( "--mansection" );
    document_title = Find_Parameterized_Option( "--documenttitle" );
    optstr = Find_Parameterized_Option( "--first_section_level" );
    if ( optstr )
    {
        document->first_section_level = atoi( optstr );
    }

    course_of_action = document->actions;       /* a global */
    debugmode = document->debugmode;    /* a global */

    RB_Say( "Using %s for defaults\n", SAY_INFO, used_rc_file );
    free( used_rc_file );       /* No longer necessary */
    used_rc_file = NULL;

    if ( document->css )
    {
        document->css = Path_Convert_Win32_to_Unix( document->css );
    }

    if ( ( document->actions.do_index ) && output_mode == TROFF )
    {
        RB_Warning( "Index generation not supported for TROFF format.\n" );
        document->actions.do_index = FALSE;
    }

    if ( Find_Parameterized_Option( "--doctype_name" ) &&
         Find_Parameterized_Option( "--doctype_location" ) )
    {
        document->doctype_name =
            Find_Parameterized_Option( "--doctype_name" );
        document->doctype_location =
            Find_Parameterized_Option( "--doctype_location" );
    }

    /* Find tab sizes and tab stops */
    Find_Tabstops(  );

    /* Find master index file name */
    Find_And_Install_Document_Name( "--masterindex", HT_MASTERINDEXTYPE );

    /* Find source index file name */
    Find_And_Install_Document_Name( "--sourceindex", HT_SOURCEHEADERTYPE );

    /* Find DOT tool name */
    optstr = Find_Parameterized_Option( "--dotname" );
    if ( optstr )
    {
        dot_name = optstr;
    }

    /* Find number of headers before linebreak  */
    optstr = Find_Parameterized_Option( "--header_breaks" );
    if ( optstr )
    {
        int                 breaks = atoi( optstr );

        if ( breaks == 0 )
        {
            breaks = MAX_HEADER_BREAKS;
        }
        header_breaks = breaks;
    }

    /* Get extension */
    if ( !document->extension )
    {
        document->extension = RB_Get_Default_Extension( document->doctype );
    }


    /* Test if there is a --src and --doc */
    if ( !Find_Parameterized_Option( "--src" ) )
    {
        printf( "Error: you need to specify a source"
                " file or directory with --src.\n" );
        Print_Short_Use(  );
        return EXIT_FAILURE;
    }
    if ( !Find_Parameterized_Option( "--doc" ) )
    {
        printf( "Error: you need to specify a documentation file"
                " or directory with --doc.\n" );
        Print_Short_Use(  );
        return EXIT_FAILURE;
    }

    /* What mode are we using? */
    if ( Find_Option( "--multidoc" ) )
    {
        char               *srcrootname;        /* directory */
        char               *docrootname;

        srcrootname = Find_And_Fix_Path( "--src" );
        if ( !Stat_Path( 'e', srcrootname ) )
        {
            printf( "Error: %s does not exists\n", srcrootname );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        }

        if ( !Stat_Path( 'd', srcrootname ) )
        {
            printf( "Error: %s is not a directory\n", srcrootname );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        }
        document->srcroot = RB_Get_RB_Path( srcrootname );

        docrootname = Find_And_Fix_Path( "--doc" );
        Path_Check( srcrootname, docrootname );

        document->docroot = RB_Get_RB_Path( docrootname );

        srctree = RB_Get_RB_Directory( srcrootname, docrootname );
        document->srctree = srctree;

        RB_Document_Create_Parts( document );
        RB_Analyse_Document( document );
        RB_Generate_Documentation( document );

        RB_Free_RB_Path( document->srcroot );
        document->srcroot = 0;
        RB_Free_RB_Path( document->docroot );
        document->docroot = 0;
        RB_Free_RB_Directory( srctree );
        document->srctree = 0;
    }
    else if ( output_mode == TROFF )
    {
        RB_Panic( "Only --multidoc is supported for TROFF output.\n" );
    }
    else if ( Find_Option( "--singledoc" ) )
    {
        char               *srcrootname;        /* directory */

        srcrootname = Find_And_Fix_Path( "--src" );
        if ( !Stat_Path( 'e', srcrootname ) )
        {
            printf( "Error: %s does not exists\n", srcrootname );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        }

        if ( !Stat_Path( 'd', srcrootname ) )
        {
            printf( "Error: %s is not a directory\n", srcrootname );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        };
        document->srcroot = RB_Get_RB_Path( srcrootname );

        document->docroot = 0;
        document->singledoc_name = Find_And_Fix_Path( "--doc" );

        srctree = RB_Get_RB_Directory( srcrootname, NULL );
        document->srctree = srctree;

        RB_Document_Create_Parts( document );
        RB_Analyse_Document( document );
        RB_Generate_Documentation( document );

        RB_Free_RB_Directory( srctree );
    }
    else if ( Find_Option( "--singlefile" ) )
    {
        char               *srcfile;    /* file */
        char               *docfile;    /* file */

        document->docroot = 0;
        docfile = Find_And_Fix_Path( "--doc" );
        document->singledoc_name = docfile;
        srcfile = Find_And_Fix_Path( "--src" );
        if ( !Stat_Path( 'e', srcfile ) )
        {
            printf( "Error: %s does not exists\n", srcfile );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        };

        if ( !Stat_Path( 'f', srcfile ) )
        {
            printf( "Error: %s is not a file\n", srcfile );
            Print_Short_Use(  );
            return EXIT_FAILURE;
        };

        document->srctree = RB_Get_RB_SingleFileDirectory( srcfile );
        document->srcroot =
            RB_Get_RB_Path( document->srctree->first_path->name );

        RB_Document_Create_Parts( document );
        RB_Analyse_Document( document );
        RB_Generate_Documentation( document );

        RB_Free_RB_Directory( document->srctree );
    }
    else
    {
        Print_Short_Use(  );
        printf
            ( "\n\nError: Use either --multidoc, --singledoc, or --singlefile\n" );
        return EXIT_FAILURE;
    }

    RB_Summary( document );
    RB_Free_RB_Document( document );
    Free_Configuration(  );

#ifdef __APPLE__
    /* Mac OS X specific: print memory leaks */
    if ( debug & SAY_DEBUG )
    {
        char                cmd[32];

        sprintf( cmd, "/usr/bin/leaks %d", getpid(  ) );
        system( cmd );
    }
#endif /* __APPLE__ */

    return EXIT_SUCCESS;
}

Path_Check

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Test the validity of the doc and source path. The doc path should not be a sub directory of the source path otherwise the generated documentation will be part of the generated documentation if robodoc is run more than once.

SYNOPSIS

static void Path_Check(
    char *sourcepath,
    char *docpath )

INPUTS

OUTPUT

SOURCE

{
    if ( docpath )
    {
        int                 dl;
        int                 sl;

        dl = strlen( docpath );
        sl = strlen( sourcepath );
        if ( dl >= sl )
        {
            int                 i;
            int                 equal = TRUE;

            for ( i = 0; i < sl; ++i )
            {
                if ( docpath[i] != sourcepath[i] )
                {
                    equal = FALSE;
                    break;
                }
            }
            if ( equal && ( dl == sl ) )
            {
                RB_Panic
                    ( "The source path and document path can not be equal\n" );
            }
            else
            {
                /* OK  */
            }
        }
    }
}

Path_Convert_Win32_to_Unix

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Although people are supposed to specify all paths with a '/' as seperator, sometimes people on Win32 use '\', this causes problems later on in some other function of robodoc that expect a '/'. So to prevent this we replace all the '\' in a path with '/'

    

In addition people sometimes add a '/' at the end of the path. We remove it.

SYNOPSIS

static char        *Path_Convert_Win32_to_Unix(
    char *path )

INPUTS

RESULT

SOURCE

{
    size_t              i;

    /* First make a copy */
    path = RB_StrDup( path );
    for ( i = 0; i < strlen( path ); ++i )
    {
        if ( path[i] == '\\' )
        {
            path[i] = '/';
        }
    }

    /* Remove trailing '/' if there is one. */
    if ( path[strlen( path ) - 1] == '/' )
    {
        path[strlen( path ) - 1] = '\0';
    }

    return path;
}

PathBegin_Check

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Checks the validity of a path. A path should start with

     ./

or

     /

or

     have a ':' some where

SYNOPSIS

static int PathBegin_Check(
    char *path )

INPUTS

RESULT

SOURCE

{
    int                 result = FALSE;
    int                 l = strlen( path );

    if ( l == 1 )
    {
        result = ( path[0] == '.' );
    }
    else if ( l >= 2 )
    {
        result = ( ( path[0] == '.' ) && ( path[1] == '/' ) ) ||
            ( path[0] == '/' ) || ( strchr( path, ':' ) != NULL );
    }
    else
    {
        /* Empty */
    }
    return result;
}

RB_Find_In_Argv_Parameterized_Option

[ Top ] [ UserInterface ] [ Functions ]

FUNCTION

Search for an option of the form

     --a_option_name a_value

in argv. The function is used to look for the

     --rc  

option that can be used to specify an alternate robodoc configuration file.

SYNOPSIS

char               *RB_Find_In_Argv_Parameterized_Option(
    int argc,
    char **argv,
    char *optionname )

INPUTS

RESULT

NULL if the option is not found, a pointer to the value otherwise.

NOTES

Results in a Panic if the option is found but no value is specified.

SOURCE

{
    return General_Find_Parameterized_Option( argc, argv, optionname );
}

use

[ Top ] [ UserInterface ] [ Variables ]

NAME

use -- usage string

FUNCTION

Inform the user how to use ROBODoc.

AUTHOR

Koessi

SOURCE

char                use[] =
/*           1         2         3         4         5         6         7         8
    12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
    "ROBODoc Version " VERSION "    autodocs formatter ($Revision: 1.115 $)\n"
    "(c) 1994-2010 Frans Slothouber, Petteri Kettunen, \n"
    "              Gergely Budai and Jacco van Weert\n"
    "ROBODoc comes with ABSOLUTELY NO WARRANTY.\n"
    "This is free software, and you are welcome to redistribute it\n"
    "under certain conditions; type `robodoc -c' for details.\n" "\n";
char                use_usage[] =
    "Usage:\n"
    "   robodoc --src <directory> --doc <directory> --multidoc   [type] [options]\n"
    "   robodoc --src <directory> --doc <file>      --singledoc  [type] [options]\n"
    "   robodoc --src <file>      --doc <file>      --singlefile [type] [options]\n"
    "\n"
    "Type:\n" "   --html, --rtf, --latex, --ascii, --dbxml, --troff\n" "\n";
char                use_options1[] =
    "Options:\n"
    "   --charset NAME   Add character encoding information (html only).\n"
    "   --cmode          Use ANSI C grammar in source items (html only).\n"
    "   --config         Print configuration info and exit.\n"
    "   --css            Specify the stylesheet to use.\n"
    "   --ext EXTENSION  Set extension for generated files.\n"
    "   --footless       Do not create the foot of a document.\n"
    "   --headless       Do not create the head of a document.\n"
    "   --index          Add an index.\n";
char                use_options2[] =
    "   --internal       Also include internal headers.\n"
    "   --internalonly   Only include internal headers.\n"
    "   --lock           Recognize only one header marker per file.\n"
    "   --nodesc         Do not descent into subdirectories.\n"
    "   --no_subdirectories\n"
    "                    Do no create documentation subdirectories.\n"
    "   --nopre          Do not use <PRE> </PRE> in the HTML output.\n"
    "   --nosort         Do not sort the headers.\n"
    "   --nosource       Do not include SOURCE items.\n"
    "   --nogeneratedwith\n"
    "                    Do not add the 'generated by robodoc' message\n"
    "                    at the top of each documentation file.\n"
    "   --ignore_case_when_linking\n"
    "                    Ignore the case of the symbols when trying\n"
    "                    to create crosslinks.\n";
char                use_options3[] =
    "   --rc             Specify an alternate configuration file.\n"
    "   --sections       Add sections and subsections.\n"
    "   --first_section_level NUMBER\n"
    "                    Start the first section not at 1 but at \n"
    "                    level NUMBER.\n"
    "   --tabsize NUMBER Set the tab size.\n"
    "   --tabstops a,b,..,n\n"
    "                    Set TAB stops \n"
    "   --tell           ROBODoc will tell you what it is doing.\n"
    "   --debug          same as --tell, but with lots more details.\n"
    "   --toc            Add a table of contents.\n"
    "   --version        Print version info and exit.\n"
    "   --sectionnameonly\n"
    "                    Generate section header with name only.\n"
    "   --compress       Only supported by TROFF output format. Defines by which\n"
    "                    program manpages will be compressed. Either bzip2 or gzip.\n"
    "   --mansection     Manual section where pages will be inserted (default: 3).\n"
    "   --documenttitle TITLE\n"
    "                    Set the document title\n"
    "   --altlatex       Alternate LaTeX file format (bigger / clearer than normal)\n"
    "   --latexparts     Make the first module level as PART in LaTeX output\n"
    "   --syntaxcolors   Turn on all syntax highlighting features in SOURCE items\n"
    "                    (html only)\n"
    "   --syntaxcolors_enable quotes,squotes,line_comments,block_comments,\n"
    "                         keywords,non_alpha\n"
    "                    Enable only specific syntax highlighting features in\n"
    "                    SOURCE items (html only)\n"
    "   --dotname NAME   Specify the name (and path / options) of DOT tool\n"
    "   --masterindex title,filename\n"
    "                    Specify the tile and filename for master index page\n"
    "   --sourceindex title,filename\n"
    "                    Specify the tile and filename for source files index page\n"
    "   --one_file_per_header\n"
    "                    Create a separate documentation file for each header\n"
    "   --header_breaks NUMBER\n"
    "                    Insert a linebreak after every NUMBER header names\n"
    "                    (default value: 2, set to zero to disable)\n"
    "   --source_line_numbers\n"
    "                    Display original source line numbers for SOURCE items\n"
    "   --use_source_comments ITEM\n"
    "                    Add found source comment lines to documenatation of ITEM\n"
    "\n";
char                use_authors[] =
    "Authors/Contributors:\n"
    "   Frans Slothouber, Jacco van Weert, Petteri Kettunen, Bernd Koesling,\n"
    "   Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, Sasha Vasko,\n"
    "   Kai Hofmann, Thierry Pierron, Friedrich Haase, Gergely Budai.\n";