Configuration

[ Top ] [ ROBODoc ] [ Modules ]

FUNCTION

Functions to access the ROBODoc configuration and configuration file (robodoc.rc) or the file specified with the --rc option.

The robodoc.rc file consists of a number of blocks. Each block starts with a line of the form

     <block name>:

This is followed by a number of lines of data. Each line starts with at least one space followed by the actual data.

This module parses this data and stores it in the global configuration.

NOTES

Is missing a lot of documentation.

You can not use RB_Say() in this module since the --tell flag won't be parsed until after this module has finished.


add_keywords_to_hash_table

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Initalize hash table and add all keywords from configuration.keywords to the hash table

SOURCE

void add_keywords_to_hash_table(
    void )
{
    unsigned int        i;

    /* If nothing to add, exit */
    if ( !configuration.keywords.number )
        return;

    /* Make some allocations */
    allocate_keywords_hash_table(  );

    /* Add keywords to hash table */
    for ( i = 0; i < configuration.keywords.number; i++ )
    {
        add_to_keywords_hash_table( configuration.keywords.names[i] );
    }
}

add_to_keywords_hash_table

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Add a keyword to the hash table

SYNOPSIS

void add_to_keywords_hash_table(
    char *keyword )

INPUTS

keyword -- The keyword string

SOURCE

{
    struct keywords_hash_s *tmp, **curr;
    unsigned long       hash;

    /* Allocate space for new entry in hash table */
    tmp = RB_malloc( sizeof( struct keywords_hash_s ) );
    /* and initialise it */
    tmp->keyword = keyword;
    tmp->next = NULL;

    /* Calculate hash value */
    hash = Hash_Keyword( keyword, strlen( keyword ) );

    /* Seek to last element in hash table row */
    for ( curr = &( keywords_hash[hash] ); *curr;
          curr = &( ( *curr )->next ) );

    /* Insert entry into hash table */
    *curr = tmp;
}

allocate_keywords_hash_table

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Allocates space for the keyword hash table.

The size of the table depends on the number of keywords rounded up to the next power of two.

SYNOPSIS

void allocate_keywords_hash_table(
    void )

SOURCE

{
    unsigned int        i;

    /* Calculate hash table size (powers of two) */
    for ( keywords_hash_mask = 2;
          keywords_hash_mask < configuration.keywords.number;
          keywords_hash_mask <<= 1 );
    keywords_hash_mask -= 1;

    /* Allocate space for hash table */
    keywords_hash = RB_malloc( ( keywords_hash_mask + 1 ) *
                               sizeof( struct keywords_hash_s * ) );

    /* Zero out all rows */
    for ( i = 0; i <= keywords_hash_mask; i++ )
    {
        keywords_hash[i] = NULL;
    }
}

c_keywords

[ Top ] [ Configuration ] [ Variables ]

FUNCTION

The default C keywords.

SOURCE

static char        *c_keywords[] = {

    /* ANSI C Keywords */
    "auto",
    "break",
    "case",
    "char",
    "const",
    "continue",
    "default",
    "do",
    "double",
    "else",
    "enum",
    "extern",
    "float",
    "for",
    "goto",
    "if",
    "int",
    "long",
    "register",
    "return",
    "short",
    "signed",
    "sizeof",
    "static",
    "struct",
    "switch",
    "typedef",
    "union",
    "unsigned",
    "void",
    "volatile",
    "while",

    /* Some preprocessor directives */
    "#include",
    "#define",
    "#undef",
    "#if",
    "#else",
    "#elif",
    "#endif",
    "#ifdef",
    "#ifndef",
    "#pragma",

    NULL,                       /* don't delete, so we can count how many there are... */
};

/* C comments */
#define C_LINE_COMMENT        "//"
#define C_BLOCK_COMMENT_START "/*"
#define C_BLOCK_COMMENT_END   "*/"

configuration

[ Top ] [ Configuration ] [ Variables ]

FUNCTION

This global stores all the configuration parameters specified on the command line and in the robodoc.rc file.

SOURCE

struct RB_Configuration configuration;

default_item_names

[ Top ] [ Configuration ] [ Variables ]

FUNCTION

Defines the names of items that ROBODoc recognized as items by default if none are specified in the robodoc.rc file.

SOURCE

static char        *default_item_names[] = {
    "SOURCE",                   /* source code inclusion */
    "NAME",                     /* Item name + short description */
    "COPYRIGHT",                /* who own the copyright : "(c) <year>-<year> by <company/person>" */
    "SYNOPSIS", "USAGE",        /* how to use it */
    "FUNCTION", "DESCRIPTION", "PURPOSE",       /* what does it */
    "AUTHOR",                   /* who wrote it */
    "CREATION DATE",            /* when did the work start */
    "MODIFICATION HISTORY", "HISTORY",  /* who done what changes when */
    "INPUTS", "ARGUMENTS", "OPTIONS", "PARAMETERS", "SWITCHES", /* what can we feed into it */
    "OUTPUT", "SIDE EFFECTS",   /* what output will be made */
    "RESULT", "RETURN VALUE",   /* what do we get returned */
    "EXAMPLE",                  /* a clear example of the items use */
    "NOTES",                    /* any annotations */
    "DIAGNOSTICS",              /* diagnostical output */
    "WARNINGS", "ERRORS",       /* warning & error-messages */
    "BUGS",                     /* known bugs */
    "TODO", "IDEAS",            /* what to implement next & ideas */
    "PORTABILITY",              /* where does it come from, where will it work */
    "SEE ALSO",                 /* references */
    "METHODS", "NEW METHODS",   /* oop methods */
    "ATTRIBUTES", "NEW ATTRIBUTES",     /* oop attributes */
    "TAGS",                     /* tagitem description */
    "COMMANDS",                 /* command description */
    "DERIVED FROM",             /* oop super class */
    "DERIVED BY",               /* oop sub class */
    "USES", "CHILDREN",         /* what modules are used by this one */
    "USED BY", "PARENTS",       /* which modules do use this */
    NULL,                       /* don't delete, so we can count how many there are... */
};

Find_Keyword

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Find a keyword in the hash table

SYNOPSIS

char               *Find_Keyword(
    char *keyword,
    int len )

INPUTS

RETURN VALUE

SOURCE

{
    unsigned long       hash;
    struct keywords_hash_s *curr;

    /* Calculate hash value */
    hash = Hash_Keyword( keyword, len );

    /* Seek through hash table row */
    for ( curr = keywords_hash[hash]; curr; curr = curr->next )
    {
        /* Check for keyword in row element */
        if ( !strncmp( keyword, curr->keyword, len ) )
        {
            /* Found it! */
            return curr->keyword;
        }
    }

    /* Keyword not found */
    return NULL;
}

Find_Parameter_Char

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Checks for the existence of a given configuration parameter (Character match)

SOURCE

char               *Find_Parameter_Char(
    struct Parameters *params,
    char param )
{
    unsigned int        i;

    for ( i = 0; i < params->number; i++ )
    {
        if ( params->names[i][0] == param )
        {
            /* found it */
            return params->names[i];
        }
    }

    /* parameter not found */
    return NULL;
}

Find_Parameter_Exact

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Checks for the existence of a given configuration parameter (exact string match)

SOURCE

char               *Find_Parameter_Exact(
    struct Parameters *params,
    char *paramname )
{
    unsigned int        i;

    /* we are looking for an exact match */
    for ( i = 0; i < params->number; i++ )
    {
        if ( !strcmp( params->names[i], paramname ) )
        {
            /* found it */
            return params->names[i];
        }
    }

    /* parameter not found */
    return NULL;
}

Find_Parameter_Partial

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Checks for the existence of a given configuration parameter (partial string match)

SOURCE

char               *Find_Parameter_Partial(
    struct Parameters *params,
    char *paramname )
{
    unsigned int        i;

    /* we are looking for a not exact match */
    for ( i = 0; i < params->number; i++ )
    {
        if ( !strncmp
             ( params->names[i], paramname, strlen( params->names[i] ) ) )
        {
            /* found it */
            return params->names[i];
        }
    }

    /* parameter not found */
    return NULL;
}

GetParameters

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Parse a line of text and store the individual words in a Parameters structure. Words are seperated by spaces, the exception are words surrounded by quotes. So:

      aap noot mies "back to the future"

contains four words.

INPUTS

SOURCE

static void GetParameters(
    char *line,
    struct Parameters *parameters )
{
    int                 i;
    int                 n = strlen( line );

    /* Remove any spaces at the end of the line */
    for ( i = n - 1; i >= 0 && utf8_isspace( line[i] ); --i )
    {
        line[i] = '\0';
    }

    assert( i > 0 );            /* If i <= 0 then the line was empty
                                   and that cannot be, because this
                                   is supposed to be a parameter */

    /* Skip any white space at the begin of the line. */
    n = strlen( line );
    for ( i = 0; i < n && utf8_isspace( line[i] ); ++i )
    {
        /* Empty */
    }
    line += i;

    n = strlen( line );
    for ( i = 0; i < n; /* empty */  )
    {
        char               *name = line;

        if ( line[i] == '"' )
        {
            /* It is quoted string, fetch everything until
             * the next quote */
            ++name;             /* skip the double quote */
            for ( ++i; ( i < n ) && ( line[i] != '"' ); ++i )
            {
                /* empty */
            }
            if ( i == n )
            {
                RB_Panic( "Missing quote in your .rc file in line:\n  %s\n",
                          line );
            }
            else
            {
#if defined(__APPLE__)
                /* hacked because of error when compiling on Mac OS X */
                assert( line[i] == 34 );
#else
                assert( line[i] == '"' );
#endif
                line[i] = '\0';
                AddParameter( name, parameters );
            }
        }
        else
        {
            /* a single word, find the next space */
            for ( ; ( i < n ) && !utf8_isspace( line[i] ); ++i )
            {
                /* empty */
            }
            if ( i < n )
            {
                line[i] = '\0';
            }
            AddParameter( name, parameters );
        }
        /* Is there anything left? */
        if ( i < n )
        {
            /* skip any spaces until the next parameter */
            ++i;                /* first skip the nul character */
            line += i;
            n = strlen( line );
            for ( i = 0; ( i < n ) && utf8_isspace( line[i] ); ++i )
            {
                /* empty */
            }
            line += i;
            n = strlen( line );
            i = 0;
        }
    }
}

Hash_Keyword

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Calculate the hash value for a string

The hash value is a 32 bit integer based on the hash function written by Bob Jenkins. It is then reduced by an AND operation to the actual size of the hash table.

SYNOPSIS

unsigned long Hash_Keyword(
    char *key,
    unsigned long keylen )

INPUTS

RETURN VALUE

The hash value for the keyword.

SOURCE

{
    unsigned long       bkt, i, j, k;

    bkt = 0xfeedbeef;
    i = j = 0x9e3779b9;
    k = keylen;

    while ( k >= 12 )
    {
        i += ( key[0] + ( ( unsigned ) key[1] << 8 )
               + ( ( unsigned ) key[2] << 16 )
               + ( ( unsigned ) key[3] << 24 ) );
        j += ( key[4] + ( ( unsigned ) key[5] << 8 )
               + ( ( unsigned ) key[6] << 16 )
               + ( ( unsigned ) key[7] << 24 ) );
        bkt += ( key[8] + ( ( unsigned ) key[9] << 8 )
                 + ( ( unsigned ) key[10] << 16 )
                 + ( ( unsigned ) key[11] << 24 ) );

        HASH_MIX( i, j, bkt );

        key += 12;
        k -= 12;
    }

    bkt += keylen;

    switch ( k )
    {
    case 11:
        bkt += ( ( unsigned ) key[10] << 24 );
    case 10:
        bkt += ( ( unsigned ) key[9] << 16 );
    case 9:
        bkt += ( ( unsigned ) key[8] << 8 );
    case 8:
        j += ( ( unsigned ) key[7] << 24 );
    case 7:
        j += ( ( unsigned ) key[6] << 16 );
    case 6:
        j += ( ( unsigned ) key[5] << 8 );
    case 5:
        j += key[4];
    case 4:
        i += ( ( unsigned ) key[3] << 24 );
    case 3:
        i += ( ( unsigned ) key[2] << 16 );
    case 2:
        i += ( ( unsigned ) key[1] << 8 );
    case 1:
        i += key[0];
    }

    HASH_MIX( i, j, bkt );

    return ( bkt & keywords_hash_mask );
}

HASH_MIX

[ Top ] [ Hash_Keyword ] [ Functions ]

FUNCTION

Helper macro for the function Hash_Keyword( )

SOURCE

#define HASH_MIX(a,b,c)             \
{                                   \
  a -= b; a -= c; a ^= ( c >> 13 ); \
  b -= c; b -= a; b ^= ( a << 8 );  \
  c -= a; c -= b; c ^= ( b >> 13 ); \
  a -= b; a -= c; a ^= ( c >> 12 ); \
  b -= c; b -= a; b ^= ( a << 16 ); \
  c -= a; c -= b; c ^= ( b >> 5 );  \
  a -= b; a -= c; a ^= ( c >> 3 );  \
  b -= c; b -= a; b ^= ( a << 10 ); \
  c -= a; c -= b; c ^= ( b >> 15 ); \
}

Install_C_Syntax

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Install default C keywords and comments

SOURCE

void Install_C_Syntax(
    void )
{
    unsigned int        i;

    /* Check if we can install our default C keywords */
    if ( !configuration.keywords.number )
    {
        for ( i = 0; c_keywords[i]; i++ )
        {
            AddParameter( c_keywords[i], &( configuration.keywords ) );
        }

        /* Make keywords hash table (if necessarry) */
        add_keywords_to_hash_table(  );
    }

    /* Make sure that C line comment is present */
    if ( Find_Parameter_Exact
         ( &( configuration.source_line_comments ), C_LINE_COMMENT ) == NULL )
    {
        AddParameter( C_LINE_COMMENT,
                      &( configuration.source_line_comments ) );
    }


    /* Make sure that C block comment start is present */
    if ( Find_Parameter_Exact
         ( &( configuration.remark_begin_markers ),
           C_BLOCK_COMMENT_START ) == NULL )
    {
        AddParameter( C_BLOCK_COMMENT_START,
                      &( configuration.remark_begin_markers ) );
    }

    /* Make sure that C block comment end is present */
    if ( Find_Parameter_Exact
         ( &( configuration.remark_end_markers ),
           C_BLOCK_COMMENT_END ) == NULL )
    {
        AddParameter( C_BLOCK_COMMENT_END,
                      &( configuration.remark_end_markers ) );
    }
}

keywords_hash

[ Top ] [ Configuration ] [ Variables ]

FUNCTION

This is the hash table for the keywords. See keywords_hash_s.

SOURCE

static struct keywords_hash_s **keywords_hash;

keywords_hash_mask

[ Top ] [ Configuration ] [ Variables ]

FUNCTION

Mask for keyword hash function. This mask reduces the hash value for the actual hash table size. Also the size of the hash table can be derived from this mask:

     hash table size = keywords_hash_mask + 1

SOURCE

static unsigned int keywords_hash_mask;

ReadConfiguration

[ Top ] [ Configuration ] [ Functions ]

FUNCTION

Read the robodoc configuration file, and create a RB_Configuration structure.

SYNOPSIS

char               *ReadConfiguration(
    unsigned int argc,
    char **argv,
    char *filename )

INPUTS

RESULT

An initialized configuration (a global).

SOURCE

{
    FILE               *f = NULL;
    char               *path = NULL;

    if ( filename )
    {
        path = Get_rc( filename );
        if ( path )
        {
            f = fopen( path, "r" );
        }
        if ( !f )
        {
            /* It should open as the user claimed it exists somewhere */
            RB_Panic( "Can't open %s\n", filename );
        }
    }
    else
    {
        /* Try the default rc file */
        path = Get_rc( "robodoc.rc" );
        if ( path )
        {
            f = fopen( path, "r" );
        }
    }

    AllocOptions( argc, argv );
    Alloc_Parameters( &( configuration.items ), 10 );
    Alloc_Parameters( &( configuration.ignore_items ), 10 );
    Alloc_Parameters( &( configuration.source_items ), 10 );
    Alloc_Parameters( &( configuration.preformatted_items ), 10 );
    Alloc_Parameters( &( configuration.format_items ), 10 );
    Alloc_Parameters( &( configuration.item_order ), 10 );

    Alloc_Parameters( &( configuration.custom_headertypes ), 10 );
    Alloc_Parameters( &( configuration.ignore_files ), 10 );
    Alloc_Parameters( &( configuration.accept_files ), 10 );
    Alloc_Parameters( &( configuration.header_markers ), 10 );
    Alloc_Parameters( &( configuration.remark_markers ), 10 );
    Alloc_Parameters( &( configuration.end_markers ), 10 );
    Alloc_Parameters( &( configuration.remark_begin_markers ), 10 );
    Alloc_Parameters( &( configuration.remark_end_markers ), 10 );
    Alloc_Parameters( &( configuration.keywords ), 10 );
    Alloc_Parameters( &( configuration.source_line_comments ), 10 );
    Alloc_Parameters( &( configuration.header_ignore_chars ), 10 );
    Alloc_Parameters( &( configuration.header_separate_chars ), 10 );

    if ( f )
    {
        SecondScan( f );
        fclose( f );
    }
    else
    {
        /* No .rc file found.  That's OK */
    }
    ComplementItemNames(  );
    ComplementHeaderMarkers(  );
    Complement_Remark_Markers(  );
    Install_Custom_HeaderTypes(  );

    /* Make keywords hash table (if necessarry) */
    add_keywords_to_hash_table(  );

    assert( configuration.items.number );

    return path;
}