Document

[ Top ] [ ROBODoc ] [ Modules ]

FUNCTION

This module contains functions to manipulate the central data structure (RB_Document) that contains information about the source files, and documentation files, and headers.

The name is a bit confusing because it sort of implies that it contains the documentation extracted from the sourcefiles.

For each run a RB_Document structure is created, it is filled by the analyser and directory module and then used by the generator module to create the documentation.

MODIFICATION HISTORY


RB_Document_Add_Part

[ Top ] [ Document ] [ Functions ]

FUNCTION

Add a new part to the document.

SYNOPSIS

void RB_Document_Add_Part(
    struct RB_Document *document,
    struct RB_Part *part )

INPUTS

SOURCE

{
    part->next = document->parts;
    document->parts = part;
}

RB_Document_Collect_Headers

[ Top ] [ Document ] [ Functions ]

FUNCTION

Create a table of pointers to all headers. This is done to have easy access to all heades without having to scan all RB_Parts.

INPUTS

OUTPUT

SOURCE

void RB_Document_Collect_Headers(
    struct RB_Document *document )
{
    struct RB_Part     *i_part;
    struct RB_header  **headers;        /* Pointer to an array of pointers RB_headers. */
    unsigned long       count = 0;
    unsigned long       part_count = 0;
    unsigned long       i = 0;

    RB_Say( "Collecting all headers in a single table\n", SAY_INFO );
    for ( i_part = document->parts; i_part; i_part = i_part->next )
    {
        struct RB_header   *i_header;

        /* Count the number of headers */
        for ( part_count = 0, i_header = i_part->headers;
              i_header; i_header = i_header->next )
        {
            part_count++;
        }
        /* Compute the total count */
        count += part_count;
    }
    headers =
        ( struct RB_header ** ) calloc( count, sizeof( struct RB_header * ) );
    for ( i_part = document->parts; i_part; i_part = i_part->next )
    {
        struct RB_header   *i_header;

        for ( i_header = i_part->headers;
              i_header; i_header = i_header->next )
        {
            headers[i] = i_header;
            i++;
        }
    }
    document->headers = headers;
    document->no_headers = count;
}

RB_Document_Create_DocFilePaths

[ Top ] [ Document ] [ Functions ]

FUNCTION

This function creates the whole document directory tree. It tests if the directories exist and if they do not the directory is created.

SYNOPSIS

void RB_Document_Create_DocFilePaths(
    struct RB_Document *document )

INPUTS

SOURCE

{
    struct RB_Path     *path;

    for ( path = document->srctree->first_path; path; path = path->next )
    {
        char               *pathname = NULL;
        char               *c2 = NULL;

        RB_Say( "Trying to create directory %s\n", SAY_INFO, path->docname );
        /* Don't want to modify the docname in the path
           structure. So we make a copy that we later
           destroy. */

        pathname = RB_StrDup( path->docname );
        for ( c2 = pathname + 1;        /* We skip the leading '/' */
              *c2; ++c2 )
        {
            if ( *c2 == '/' )
            {
                struct stat         dirstat;

                *c2 = '\0';     /* Replace the '/' with a '\0'. */
                /* We now have one of the paths leading up to the
                   total path. Test if it exists. */
                if ( stat( pathname, &dirstat ) == 0 )
                {
                    /* Path exists. */
                }
                else if ( ( strlen( pathname ) == 2 ) &&
                          ( utf8_isalpha( pathname[0] ) ) &&
                          ( pathname[1] == ':' ) )
                {
                    /* Is is a drive indicator, ( A: B: C: etc )
                     * stat fails on this, but we should not
                     * create either, so we do nothing.
                     */
                }
                else
                {
                    int                 result;

#if defined(__MINGW32__)
                    result = mkdir( pathname );
#else
                    result = mkdir( pathname, 0770 );
#endif
                    if ( result == 0 )
                    {
                        /* Path was created. */
                    }
                    else
                    {
                        perror( NULL );
                        RB_Panic( "Can't create directory %s\n", pathname );
                    }
                }
                /* Put the '/' back in it's place. */
                *c2 = '/';
            }
        }
        free( pathname );
    }
}

RB_Document_Create_Parts

[ Top ] [ Document ] [ Functions ]

FUNCTION

Create all the parts of a document based on the sourcefiles in the source tree. This creates a new RB_Part for each file in the source tree.

INPUTS

SOURCE

void RB_Document_Create_Parts(
    struct RB_Document *document )
{
    struct RB_Filename *i_file = NULL;

    assert( document );
    assert( document->srctree );

    for ( i_file = document->srctree->first; i_file; i_file = i_file->next )
    {
        struct RB_Part     *rbpart;

        rbpart = RB_Get_RB_Part(  );
        RB_Part_Add_Source( rbpart, i_file );
        RB_Document_Add_Part( document, rbpart );
    }
}

RB_Document_Determine_DocFilePaths

[ Top ] [ Document ] [ Functions ]

FUNCTION

Determine the path of each of the documentation files based on the path of the source file and the documentation root path and the source root path.

SYNOPSIS

void RB_Document_Determine_DocFilePaths(
    struct RB_Document *document )

EXAMPLE

srcpath = ./test/mysrc/sub1/sub2 srcroot = ./test/mysrc/ docroot = ./test/mydoc/

     ==>

docpath = ./test/mydoc/sub1/sub2

SOURCE

{
    struct RB_Path     *path;
    int                 docroot_length;
    int                 srcroot_length;
    int                 length;

    assert( document->srctree );
    assert( document->srcroot );
    assert( document->docroot );

    docroot_length = strlen( document->docroot->name );
    srcroot_length = strlen( document->srcroot->name );

    for ( path = document->srctree->first_path; path; path = path->next )
    {
        char               *name;
        char               *new_name;
        char               *tail;

        name = path->name;
        length = strlen( name );
        assert( length >= srcroot_length );
        tail = name + srcroot_length;
        new_name = calloc( docroot_length +
                           ( length - srcroot_length ) + 1, sizeof( char ) );
        assert( new_name );
        strcat( new_name, document->docroot->name );
        if ( document->actions.do_no_subdirectories )
        {
            /* No subdirectory */
        }
        else
        {
            strcat( new_name, tail );
        }
        path->docname = new_name;
    }
}

RB_Fill_Header_Filename

[ Top ] [ Document ] [ Functions ]

FUNCTION

Fill the file_name attribute of all headers based either on the part or the singledoc name. The file_name tells in which file the documentation for the header is to be stored.

SYNOPSIS

void RB_Fill_Header_Filename(
    struct RB_Document *document )

SOURCE

{
    struct RB_Part     *i_part;

    RB_Say( "Computing file_name attribute for all headers.\n", SAY_DEBUG );
    for ( i_part = document->parts; i_part; i_part = i_part->next )
    {
        struct RB_header   *i_header;

        for ( i_header = i_part->headers;
              i_header; i_header = i_header->next )
        {
            if ( document->actions.do_singledoc )
            {
                i_header->file_name = document->singledoc_name;
            }
            else if ( document->actions.do_multidoc )
            {
                i_header->file_name = RB_Get_FullDocname( i_part->filename );
            }
            else if ( document->actions.do_singlefile )
            {
                i_header->file_name = document->singledoc_name;
            }
            else
            {
                assert( 0 );
            }
        }
    }
}

RB_Get_RB_Document

[ Top ] [ Document ] [ Functions ]

FUNCTION

Allocate and initialize an RB_Document structure.

SYNOPSIS

struct RB_Document *RB_Get_RB_Document(
    void )

RESULT

An initialized document structure.

SOURCE

{
    struct RB_Document *document = 0;
    document =
        ( struct RB_Document * ) malloc( sizeof( struct RB_Document ) );
    if ( document )
    {
        document->cur_part = NULL;
        document->parts = NULL;
        document->links = NULL;
        document->headers = NULL;
        document->doctype = UNKNOWN;
        document->actions = No_Actions();
        document->srctree = NULL;
        document->srcroot = NULL;
        document->docroot = NULL;
        document->singledoc_name = NULL;
        document->no_headers = 0;
        document->charset = NULL;
        document->extension = NULL;
        document->first_section_level = 1;
        document->doctype_name = NULL;
        document->doctype_location = NULL;
    }
    else
    {
        RB_Panic( "out of memory" );
    }
    return document;
}

RB_Loop_Check

[ Top ] [ Document ] [ Functions ]

FUNCTION

This function checks for loops in the headersr; that is by mistake the following relation between headers can be specified.

     y.parent -> x.parent -> z.parent -+
     ^                                 |
     |---------------------------------+

This functions detects these loops, prints a warning and breaks the loop.

If left unbroken ROBODoc can hang.

SYNOPSIS

void RB_Loop_Check(
    struct RB_Document *document
        )

 /* INPUTS
  *   document -- document to be checked for loops.

SOURCE

{
    int i;

    RB_Say( "Check all %d headers for loops.\n", SAY_INFO, document->no_headers );
    for ( i = 0; i < document->no_headers; i++ )
    {
        struct RB_header   *parent;
        struct RB_header   *grant_parent;
        parent = ( document->headers )[i];
        for ( grant_parent = parent->parent;
              grant_parent && ( parent != grant_parent );
              grant_parent = grant_parent->parent ) {
            /* Empty */
        }
        if ( parent == grant_parent ) {
            /* Problem, from a parent I can get
             * back to the parent itself. This means 
             * there is a loop. Warn the user about this.
             */

             RB_Warning( "Warning: Header %s/%s eventually points back to itself.\n",
                   parent->module_name, parent->function_name  );
             /* TODO print whole linkage line */
             for ( grant_parent = parent->parent;
                   grant_parent && ( parent != grant_parent );
                   grant_parent = grant_parent->parent ) {
                    /* Empty */
                 RB_Warning("--> %s/%s\n", 
                   grant_parent->module_name, grant_parent->function_name  );
             }
             parent->parent = NULL;
             RB_Warning( "Breaking the linkage for %s/%s\n",
                   parent->module_name, parent->function_name  );
        }
    }
}

RB_Open_SingleDocumentation

[ Top ] [ Document ] [ Functions ]

FUNCTION

Open the file that will contain the documentation in case we create a single document.

SYNOPSIS

FILE               *RB_Open_SingleDocumentation(
    struct RB_Document *document )

RESULT

An opened file.

SOURCE

{
    FILE               *file;
    static char        *default_name = "singledoc";
    char               *name = NULL;
    size_t              size = 0;

    if ( document->singledoc_name )
    {
        size += strlen( document->singledoc_name );
    }
    else
    {
        size += strlen( default_name );
    }
    size++;                     /* and the '\0'; */
    size += RB_Get_Len_Extension( document->extension );

    name = ( char * ) calloc( size, sizeof( char ) );
    assert( name );
    if ( document->singledoc_name )
    {
        strcat( name, document->singledoc_name );
    }
    else
    {
        strcat( name, default_name );
    }
    RB_Add_Extension( document->extension, name );

    file = fopen( name, "w" );
    if ( file )
    {
        /* File opened  */
    }
    else
    {
        RB_Panic( "Can't open %s\n", name );
    }
    free( name );
    return file;
}