Directory

[ Top ] [ ROBODoc ] [ Modules ]

NAME

This module contains function to scan a directory tree and to create a RB_Directory structure. Most of the OS dependend parts of ROBODoc can be found in this module..

This module currently works under:

AUTHOR

Frans Slothouber


content_buffer

[ Top ] [ Directory ] [ Variables ]

FUNCTION

Temporary buffer file file content and filenames.

SOURCE

#define RB_CBUFFERSIZE 8191
char                content_buffer[RB_CBUFFERSIZE + 1];

RB_Directory_Insert_RB_File

[ Top ] [ Directory ] [ Functions ]

SYNOPSIS

void RB_Directory_Insert_RB_Filename(
    struct RB_Directory *arg_rb_directory,
    struct RB_Filename *arg_rb_filename )

FUNCTION

Insert an RB_File structure into a RB_Directory structure. The RB_File is added at the end of the list.

SOURCE

{
    if ( arg_rb_directory->last == 0 )
    {
        arg_rb_directory->first = arg_rb_filename;
        arg_rb_filename->next = 0;
        arg_rb_directory->last = arg_rb_filename;
    }
    else
    {
        arg_rb_directory->last->next = arg_rb_filename;
        arg_rb_filename->next = 0;
        arg_rb_directory->last = arg_rb_filename;
    }
}

RB_Directory_Insert_RB_Path

[ Top ] [ Directory ] [ Functions ]

SYNOPSIS

void RB_Directory_Insert_RB_Path(
    struct RB_Directory *arg_rb_directory,
    struct RB_Path *arg_rb_path )

FUNCTION

Insert a RB_Path into a RB_Directory. The RB_Path is added at the beginning of the list.

SOURCE

{
    arg_rb_path->next = arg_rb_directory->first_path;
    arg_rb_directory->first_path = arg_rb_path;
}

RB_FileType

[ Top ] [ Directory ] [ Functions ]

FUNCTION

Determine the type of the file. This function is used for all compilers except VC++.

If _DIRENT_HAVE_D_TYPE is defined we can find the filetype directly in the a_direntry. If not we have to stat the file to find out.

SYNOPSIS

T_RB_FileType RB_FileType(
    char *arg_pathname,
    struct dirent *a_direntry )

INPUTS

RESULT

The type of the file.


RB_Fill_Directory

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Fill_Directory -- fill a RB_Directory structure

SYNOPSIS

void RB_Fill_Directory(
    struct RB_Directory *arg_rb_directory,
    struct RB_Path *arg_path,
    struct RB_Path *arg_doc_path )

FUNCTION

Walks through all the files in the directory pointed to by arg_path and adds all the files to arg_rb_directory. This is a recursive function.

INPUTS

RESULT

a RB_Directory structure filled with all sourcefiles and subdirectories in arg_path.

NOTE

This a is a recursive function.

SOURCE

{
    struct dirent      *a_direntry;
    DIR                *a_dirstream;

    RB_Say( "Scanning %s\n", SAY_INFO, arg_path->name );
    a_dirstream = opendir( arg_path->name );

    if ( a_dirstream )
    {
        T_RB_FileType       file_type;

        for ( a_direntry = readdir( a_dirstream );
              a_direntry; a_direntry = readdir( a_dirstream ) )
        {
            file_type = RB_FileType( arg_path->name, a_direntry );
            if ( file_type == RB_FT_FILE )
            {
                /* It is a regular file. See if it is a sourcefile. */
                if ( RB_Is_Source_File( arg_path, a_direntry->d_name ) )
                {
                    /* It is, so we add it to the directory tree */
                    RB_Directory_Insert_RB_Filename( arg_rb_directory,
                                                     RB_Get_RB_Filename
                                                     ( a_direntry->d_name,
                                                       arg_path ) );
                }
                else
                {
                    /* It's not a sourcefile so we skip it. */
                }
            }
            else if ( file_type == RB_FT_DIRECTORY )
            {
                if ( ( strcmp( ".", a_direntry->d_name ) == 0 ) ||
                     ( strcmp( "..", a_direntry->d_name ) == 0 ) )
                {
                    /* Don't recurse into . or ..
                       because that will result in an infinite */
                }
                else
                {
                    if ( RB_To_Be_Skipped( a_direntry->d_name ) )
                    {
                        /* User asked this directory to be skipped */
                    }
                    else
                    {
                        if ( course_of_action.do_nodesc )
                        {
                            /* Don't descent into the subdirectories */
                        }
                        else
                        {
                            struct RB_Path     *rb_path =
                                RB_Get_RB_Path2( arg_path->name,
                                                 a_direntry->d_name );

                            rb_path->parent = arg_path;
                            if ( ( arg_doc_path
                                   && strcmp( rb_path->name,
                                              arg_doc_path->name ) )
                                 || !arg_doc_path )
                            {
                                RB_Directory_Insert_RB_Path( arg_rb_directory,
                                                             rb_path );
                                RB_Fill_Directory( arg_rb_directory, rb_path,
                                                   arg_doc_path );
                            }
                            else
                            {
                                RB_Say( "skipping %s\n", SAY_INFO,
                                        rb_path->name );
                            }
                        }
                    }
                }
            }
            else
            {
                /* Not a file and also not a directory */
            }
        }
    }
    closedir( a_dirstream );
}

RB_Free_RB_Directory

[ Top ] [ Directory ] [ Functions ]

FUNCTION

Free all the memory use by the RB_Directory structure.

SYNOPSIS

void RB_Free_RB_Directory(
    struct RB_Directory *arg_directory )

INPUTS

SOURCE

{
    struct RB_Filename *rb_filename;
    struct RB_Filename *rb_filename2;
    struct RB_Path     *rb_path;
    struct RB_Path     *rb_path2;

    /* TODO  Not complete... check for leaks. */
    rb_filename = arg_directory->first;

    while ( rb_filename )
    {
        rb_filename2 = rb_filename;
        rb_filename = rb_filename->next;
        RB_Free_RB_Filename( rb_filename2 );
    }

    rb_path = arg_directory->first_path;

    while ( rb_path )
    {
        rb_path2 = rb_path;
        rb_path = rb_path->next;
        RB_Free_RB_Path( rb_path2 );
    }

    free( arg_directory );
}

RB_Get_FileName

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Get_PathName -- extract the file name

SYNOPSIS

char               *RB_Get_FileName(
    char *arg_fullpath )

FUNCTION

Given a full path to a file, that is a filename, or a filename prefixed with a pathname, return the filename. So

      "./filename"           returns "filename"
      "/home/et/filename"    returns "filename"
      "filename"             return  "filename"

INPUTS

arg_fullpath -- a full path to a file, with or without a path.

RESULT

0 -- The full path did not contain a filename pointer to the filename -- otherwise.

NOTES

You are responsible for deallocating it.

SOURCE

{
    int                 n;
    int                 i;
    int                 found;
    char               *result = 0;

    assert( arg_fullpath );

    n = strlen( arg_fullpath );

    /* Try and find a path character ( ':' or '/' ) */
    for ( found = FALSE, i = 0; i < n; ++i )
    {
        if ( RB_Is_PathCharacter( arg_fullpath[i] ) )
        {
            found = TRUE;
            break;
        }
    }

    if ( !found )
    {
        /* The full path does not contain a pathname,
         * so we can return the arg_fullpath as
         * the filename.
         */
        result = RB_StrDup( arg_fullpath );
    }
    else
    {
        /* The full path does contain a pathname,
         * strip this and return the remainder
         */

        for ( i = n - 1; i > 0; --i )
        {
            if ( RB_Is_PathCharacter( arg_fullpath[i] ) )
            {
                assert( i < ( n - 1 ) );
                result = RB_StrDup( &( arg_fullpath[i + 1] ) );
                break;
            }
        }
    }

    return result;
}

RB_Get_PathName

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Get_PathName -- extract the path name

SYNOPSIS

char               *RB_Get_PathName(
    char *arg_fullpath )

FUNCTION

Given a full path to a file, that is a filename, or a filename prefixed with a pathname, return the pathname. So

      "./filename"           returns "./"
      "/home/et/filename"    returns "/home/et/"
      "filename"             return  ""

INPUTS

arg_fullpath -- a full path to a file, with or without a path.

RESULT

0 -- The full path did not contain a path pointer to the pathname -- otherwise.

NOTES

You are responsible for deallocating it.

SOURCE

{
    int                 n;
    int                 i;
    int                 found;
    char               *result = 0;

    assert( arg_fullpath );

    n = strlen( arg_fullpath );

    /* Try and find a path character ( ':' or '/' ) */
    for ( found = FALSE, i = 0; i < n; ++i )
    {
        if ( RB_Is_PathCharacter( arg_fullpath[i] ) )
        {
            found = TRUE;
            break;
        }
    }

    if ( found )
    {
        /* Copy the whole file name and then
           replace the character after the 
           first path character found
           counting from the back with a '\0'
         */
        result = RB_StrDup( arg_fullpath );

        for ( i = n - 1; i > 0; --i )
        {
            if ( RB_Is_PathCharacter( result[i] ) )
            {
                assert( i < ( n - 1 ) );
                result[i + 1] = '\0';
                break;
            }
        }
    }

    return result;
}

RB_Get_RB_Directory

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Get_RB_Directory -- get a RB_Directory structure

FUNCTION

Returns a RB_Directory structure to the give directory, specified by the path. This structure can then be uses to walk through all the files in the directory and it's subdirectories.

SYNOPSIS

struct RB_Directory *RB_Get_RB_Directory(
    char *arg_rootpath_name,
    char *arg_docroot_name )

INPUTS

arg_rootpath -- the name a the directory to get,

                   a nul terminated string.

arg_docroot_name -- the name of the directory the documentation

                       file are stored in.  This directory is
                       skipped while scanning for sourcefiles.
                       It can be NULL.

RESULT

A freshly allocated RB_Directory filled with source files.

SOURCE

{
    struct RB_Directory *rb_directory;
    struct RB_Path     *doc_path = NULL;

    rb_directory =
        ( struct RB_Directory * ) malloc( sizeof( struct RB_Directory ) );
    rb_directory->first = 0;
    rb_directory->last = 0;
    rb_directory->first_path = RB_Get_RB_Path( arg_rootpath_name );

    if ( arg_docroot_name )
    {
        doc_path = RB_Get_RB_Path( arg_docroot_name );
    }

    RB_Fill_Directory( rb_directory, rb_directory->first_path, doc_path );
    if ( ( RB_Number_Of_Filenames( rb_directory ) > 0 ) &&
         ( RB_Number_Of_Paths( rb_directory ) > 0 ) )
    {
        RB_SortDirectory( rb_directory );
    }
    else
    {

        RB_Panic( "No files found! (Or all were filtered out)\n" );
    }
    return rb_directory;
}

RB_Get_RB_SingleFileDirectory

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Get_RB_SingleFileDirectory -- get a RB_Directory structure

SYNOPSIS

struct RB_Directory *RB_Get_RB_SingleFileDirectory(
    char *arg_fullpath )

FUNCTION

Returns a RB_Directory structure to the give directory, specified by the path that contains only a single file. This is used for the --singlefile option.

INPUT

RESULT

a freshly allocated RB_Directory that contains only a single file.

SOURCE

{
    struct RB_Directory *rb_directory;
    struct RB_Path     *path;
    char               *pathname = NULL;
    char               *filename = NULL;

    assert( arg_fullpath );

    pathname = RB_Get_PathName( arg_fullpath );
    filename = RB_Get_FileName( arg_fullpath );

    if ( pathname )
    {
        path = RB_Get_RB_Path( pathname );
    }
    else
    {
        /* no directory was specified so we use
         * the current directory
         */
        path = RB_Get_RB_Path( "./" );
    }

    rb_directory =
        ( struct RB_Directory * ) malloc( sizeof( struct RB_Directory ) );
    rb_directory->first = 0;
    rb_directory->last = 0;

    rb_directory->first_path = path;

    RB_Directory_Insert_RB_Filename( rb_directory,
                                     RB_Get_RB_Filename( filename, path ) );

    return rb_directory;
}

RB_Is_PathCharacter

[ Top ] [ Directory ] [ Functions ]

FUNCTION

Test if a character is part of the group of characters that you would normally find in a path.

SYNOPSIS

static int RB_Is_PathCharacter(
    int c )

INPUTS

c -- the character to be tested.

RESULT

TRUE -- it is a path character. FALSE -- it is not.

SOURCE

{
    return ( ( c == ':' ) || ( c == '/' ) );
}

RB_Is_Source_File

[ Top ] [ Directory ] [ Functions ]

NAME

RB_Is_Source_File -- Is a file a sourcefile?

SYNOPSIS

int RB_Is_Source_File(
    struct RB_Path *path,
    char *filename )

FUNCTION

This functions examines the content of a file to see whether or not it is a sourcefile.

Currently it checks if there are no nul characters in the first 8191 characters of the file.

SOURCE

{
    int                 is_source = 1;

    if ( RB_Not_Accepted( filename ) )
    {
        /* File needs to be skipped based on it's name */
        is_source = 0;
    }
    else
    {
        unsigned int        size = 0;

        /* Compute the length of the filename including
           the path. */
        size += strlen( path->name );
        size += 1;
        size += strlen( filename );
        if ( size < RB_CBUFFERSIZE )
        {
            FILE               *file;

            /* We use the content_buffer buffer temporarily to
               store the filename. */
            content_buffer[0] = '\0';
            strcat( content_buffer, path->name );
            strcat( content_buffer, filename );
            if ( ( file = fopen( content_buffer, "rb" ) ) )
            {
                int                 no_read;
                no_read =
                    fread( content_buffer, sizeof( char ), RB_CBUFFERSIZE,
                           file );
                if ( no_read > 10 )
                {
                    char               *c;

                    for ( c = content_buffer; no_read; --no_read, c++ )
                    {
                        if ( *c == 0 )
                        {
                            is_source = 0;
                            break;
                        }
                    }
                }
                else
                {
                    /* A file with only 9 characters can not
                       contain any source plus documentation. */
                    is_source = 0;
                }
                fclose( file );
            }
            else
            {
                /* The file could not be opened.   */
                is_source = 0;
            }
        }
        else
        {
            /* The filename is longer than 8191 characters,
               that's way too long... so we skip it. */
            is_source = 0;
        }
    }
    return is_source;
}

RB_Not_Accepted

[ Top ] [ Directory ] [ Functions ]

FUNCTION

Test if a file should be skipped, because it does not match a pattern in "accept files:"

This test is done based on the wildcard expressions specified in configuration.accept_files.

SYNOPSIS

int RB_Not_Accepted(
    char *filename )

INPUTS

SOURCE

{
    unsigned int        i;
    int                 skip = FALSE;

    skip = RB_To_Be_Skipped( filename );

    if ( !skip && configuration.accept_files.number > 0 )
    {
        skip = TRUE;
        for ( i = 0; i < configuration.accept_files.number; ++i )
        {
            if ( RB_Match( filename, configuration.accept_files.names[i] ) )
            {
                RB_Say( "accept >%s< with >%s<\n", SAY_INFO, filename,
                        configuration.accept_files.names[i] );
                skip = FALSE;
                break;
            }
        }
    }
    return skip;
}

RB_To_Be_Skipped

[ Top ] [ Directory ] [ Functions ]

FUNCTION

Test if a file should not be included in the list of source files that are scanned for documentation.

This test is done based on the wildcard expressions specified in configuration.ignore_files.

SYNOPSIS

int RB_To_Be_Skipped(
    char *filename )

INPUTS

SOURCE

{
    unsigned int        i;
    int                 skip = FALSE;

    for ( i = 0; i < configuration.ignore_files.number; ++i )
    {
        if ( RB_Match( filename, configuration.ignore_files.names[i] ) )
        {
            skip = TRUE;
            break;
        }
    }
    return skip;
}