Analyser

[ Top ] [ ROBODoc ] [ Modules ]

NAME

Analyser -- Functions to scan source and collect headers

FUNCTION

This module provides the functions to scan a sourcefile and collect all the headers.


Analyse_Indentation

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Figure out how text is indented.

SYNPOPSIS

static int Analyse_Indentation(
    struct RB_Item *arg_item )

INPUTS

SOURCE

{
    int                 i;
    int                 indent = -1;

    assert( arg_item->no_lines > 0 );

    for ( i = 0; i < arg_item->no_lines; ++i )
    {
        if ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN )
        {
            char               *line = arg_item->lines[i]->line;

            if ( Is_Empty_Line( line ) )
            {
                /* Empty */
                indent = 0;
            }
            else
            {
                indent = Get_Indent( line );
                break;
            }
        }
    }
    assert( indent >= 0 );
    return indent;
}

Analyse_Item_Format

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Try to determine the formatting of an item. An empty line generates a new paragraph Things that are indented more that the rest of the text are preformatted. Things that start with a '*' or '-' create list items unless they are indented more that the rest of the text.

SYNPOPSIS

static void Analyse_Item_Format(
    struct RB_Item *arg_item )

INPUTS

SOURCE

{
    /* If item is not empty */
    if ( arg_item->no_lines )
    {
        /* If it is a SOURCE item */
        if ( Works_Like_SourceItem( arg_item->type ) )
        {
            /* Preformat it like a SOURCE item */
            Preformat_All( arg_item, TRUE );
        }
        /* Check if we have to analyse this item */
        else if ( ( course_of_action.do_nopre
                    || Is_Format_Item( arg_item->type ) )
                  && !Is_Preformatted_Item( arg_item->type ) )
        {
            /* analyse item */
            int                 indent = Analyse_Indentation( arg_item );

            Analyse_List( arg_item, indent );
            Analyse_Preformatted( arg_item, indent );
            Analyse_Paragraphs( arg_item );
        }
        /* If none of above, preformat item */
        else
        {
            /* Preformat it */
            Preformat_All( arg_item, FALSE );
        }
    }
    /* Item is empty */
    else
    {
        /* Do nothing */
    }
}

Analyse_List

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Parse the item text to see if there are any lists. A list is either case I:

      ITEMNAME
         o bla bla
         o bla bla

or case II:

      some text:     <-- begin of a list
      o bla bla      <-- list item
        bla bla bla  <-- continuation of list item.
      o bla bla      <-- list item
                     <-- end of a list 
      bla bla        <-- this can also be the end of a list.

SYNPOPSIS

static void Analyse_List(
    struct RB_Item *arg_item,
    int indent )

INPUTS

OUTPUT

SOURCE

{
    if ( arg_item->no_lines >= 1 )
    {
        int                 i = 0;
        char               *line = arg_item->lines[i]->line;

        /* Case I */
        if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
             Is_ListItem_Start( line, indent ) )
        {
            /* Case I, the is a list item right after the item name */
            arg_item->lines[i]->format |= RBILA_BEGIN_LIST;
            arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
            Remove_List_Char( arg_item, i );
            /* Now try to find the end of the list */
            i = Analyse_ListBody( arg_item, 1, indent );
        }

        /* Now search for case II cases */
        for ( ; i < arg_item->no_lines; i++ )
        {
            line = arg_item->lines[i]->line;
            if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
                 Is_Start_List( line, indent ) )
            {
                ++i;
                if ( i < arg_item->no_lines )
                {
                    line = arg_item->lines[i]->line;
                    if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
                         Is_ListItem_Start( line, indent ) )
                    {
                        arg_item->lines[i]->format |= RBILA_BEGIN_LIST;
                        arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
                        Remove_List_Char( arg_item, i );
                        ++i;
                        i = Analyse_ListBody( arg_item, i, indent );


                        /* One list might be immediately followed
                         * by another. In this case we have to
                         * analyse the last line again. */
                        line = arg_item->lines[i]->line;
                        if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN )
                             && Is_Start_List( line, indent ) )
                        {
                            --i;
                        }

                    }
                }
            }
        }
    }
}

Analyse_ListBody

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Analyse... (TODO)

SYNPOPSIS

static int Analyse_ListBody(
    struct RB_Item *arg_item,
    int start_index,
    int arg_indent )

INPUTS

SOURCE

{
    int                 i = start_index;

    for ( ; i < arg_item->no_lines; i++ )
    {
        char               *line = arg_item->lines[i]->line;

        if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) ||
             ( arg_item->lines[i]->kind == ITEM_LINE_END ) )
        {
            if ( Is_ListItem_Start( line, arg_indent ) )
            {
                arg_item->lines[i]->format |= RBILA_END_LIST_ITEM;
                arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
                Remove_List_Char( arg_item, i );
            }
            else if ( Is_List_Item_Continuation( line, arg_indent ) )
            {
                /* Nothing */
            }
            else
            {
                /* Must be the end of the list */
                arg_item->lines[i]->format |= RBILA_END_LIST_ITEM;
                arg_item->lines[i]->format |= RBILA_END_LIST;
                break;
            }
        }
    }
    return i;
}

Analyse_Paragraphs

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Analyse paragraphs... (TODO)

SYNPOPSIS

static void Analyse_Paragraphs(
    struct RB_Item *arg_item )

INPUTS

SOURCE

{
    int                 i;
    int                 in_par = FALSE;
    int                 in_list = FALSE;
    int                 in_pre = FALSE;
    int                 is_empty = FALSE;
    int                 prev_is_empty = FALSE;

    for ( i = 0;
          ( i < arg_item->no_lines )
          && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
    {
        /* Empty */
    }
    assert( i < arg_item->no_lines );

    if ( ( arg_item->lines[i]->format == 0 ) )
    {
        arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH;
        in_par = TRUE;
    }
    for ( ; i < arg_item->no_lines; i++ )
    {
        char               *line = arg_item->lines[i]->line;

        prev_is_empty = is_empty;
        is_empty = Is_Empty_Line( line );
        if ( arg_item->lines[i]->format & RBILA_BEGIN_LIST )
        {
            in_list = TRUE;
        }
        if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE )
        {
            in_pre = TRUE;
        }
        if ( arg_item->lines[i]->format & RBILA_END_LIST )
        {
            in_list = FALSE;
        }
        if ( arg_item->lines[i]->format & RBILA_END_PRE )
        {
            in_pre = FALSE;
        }
        if ( in_par )
        {
            if ( ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) ||
                 ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) ||
                 is_empty )
            {
                in_par = FALSE;
                arg_item->lines[i]->format |= RBILA_END_PARAGRAPH;
            }
        }
        else
        {
            if ( ( arg_item->lines[i]->format & RBILA_END_LIST ) ||
                 ( arg_item->lines[i]->format & RBILA_END_PRE ) ||
                 ( !is_empty && prev_is_empty && !in_list && !in_pre ) )
            {
                in_par = TRUE;
                arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH;
            }
        }
    }
    if ( in_par )
    {
        arg_item->lines[arg_item->no_lines - 1]->format |=
            RBILA_END_PARAGRAPH;
    }
}

Analyse_Preformatted

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Analyse preformatted text ... (TODO)

SYNPOPSIS

static void Analyse_Preformatted(
    struct RB_Item *arg_item,
    int indent )

INPUTS

SOURCE

{
    int                 i;
    int                 in_list = FALSE;
    int                 new_indent = -1;
    int                 preformatted = FALSE;
    char               *line = NULL;

    /* preformatted blocks */
    if ( arg_item->no_lines > 0 )
    {
        i = 0;
        /* Skip any pipe stuff */
        for ( ;
              ( i < arg_item->no_lines )
              && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
        {
            /* Empty */
        }

        line = arg_item->lines[i]->line;

        if ( ( !in_list )
             && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) )
        {
            in_list = TRUE;
        }
        if ( ( in_list ) && ( arg_item->lines[i]->format & RBILA_END_LIST ) )
        {
            in_list = FALSE;
        }

        for ( ++i; i < arg_item->no_lines; i++ )
        {
            if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE )
            {
                if ( preformatted )
                {
                    arg_item->lines[i]->format |= RBILA_END_PRE;
                }
                for ( ; ( i < arg_item->no_lines ) &&
                      ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
                {               /* Empty */
                };
                /* Every item ends with an ITEM_LINE_END, so: */
                assert( i < arg_item->no_lines );
                if ( preformatted )
                {
                    arg_item->lines[i]->format |= RBILA_BEGIN_PRE;
                }
            }

            line = arg_item->lines[i]->line;
            new_indent = Get_Indent( line );

            if ( ( !in_list )
                 && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) )
            {
                in_list = TRUE;
            }
            if ( ( in_list )
                 && ( arg_item->lines[i]->format & RBILA_END_LIST ) )
            {
                in_list = FALSE;
            }

            if ( !in_list )
            {
                if ( ( new_indent > indent ) && !preformatted )
                {
                    preformatted = TRUE;
                    arg_item->lines[i]->format |= RBILA_BEGIN_PRE;
                }
                else if ( ( new_indent <= indent ) && preformatted )
                {
                    preformatted = FALSE;
                    arg_item->lines[i]->format |= RBILA_END_PRE;
                }
                else
                {
                    /* An empty line */
                }
            }
            else
            {
                /* We are in a list, do nothing */
            }
        }
    }
}

AnalyseHeaderType

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Determine the type of the header.

SYNOPSIS

struct RB_HeaderType *AnalyseHeaderType(
    char **cur_char,
    int *is_internal )

INPUTS

OUTPUT

RESULT

SOURCE

{
    struct RB_HeaderType *headertype = 0;

    *is_internal = RB_IsInternalHeader( **cur_char );

    if ( *is_internal )
    {
        /* Skip the character */
        ++( *cur_char );
    }
    headertype = RB_FindHeaderType( **cur_char );
    if ( !headertype )
    {
        RB_Panic( "Undefined headertype (%c)\n", **cur_char );
    }

    return headertype;
}

Find_End_Marker

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Scan and store all lines from a source file until an end marker is found.

SYNOPSIS

static int Find_End_Marker(
    FILE *document,
    struct RB_header *new_header )

INPUTS

OUTPUT

RESULT

SOURCE

{
    int                 found = FALSE;
    unsigned int        no_lines = 0;
    unsigned int        max_no_lines = 10;
    struct RB_header_lines *lines = NULL;
    char               *dummy;

    lines = malloc( max_no_lines * sizeof( struct RB_header_lines ) );
    if ( lines == NULL )
    {
        RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" );
    }

    while ( !feof( document ) )
    {
        RB_FreeLineBuffer(  );
        myLine = RB_ReadWholeLine( document, line_buffer, &readChars );
        ++line_number;          /* global linecounter, koessi */
        if ( RB_Is_Begin_Marker( myLine, &dummy ) )
        {
            /* Bad... found a begin marker but was expecting to
               find an end marker.  Panic... */
            found = FALSE;
            return found;
        }
        else if ( RB_Is_End_Marker( myLine ) )
        {
            RB_Say( "Found end marker \"%s\"", SAY_DEBUG, myLine );
            found = TRUE;
            break;
        }
        else
        {
            unsigned int        n;
            char               *line;

            line = RB_StrDup( myLine );
            n = strlen( line );
            assert( n > 0 );
            assert( line[n - 1] == '\n' );
            /* Strip CR */
            line[n - 1] = '\0';
            /* Copy the line itself */
            lines[no_lines].line = line;
            /* and also save the original source line number */
            lines[no_lines].line_number = line_number;
            ++no_lines;
            if ( no_lines == max_no_lines )
            {
                max_no_lines *= 2;
                lines =
                    realloc( lines,
                             max_no_lines *
                             sizeof( struct RB_header_lines ) );

                if ( lines == NULL )
                {
                    RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" );
                }
            }
        }
    }

    new_header->no_lines = no_lines;
    new_header->lines = lines;

    return found;
}

Function_Name

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

A header name is consists of two parts. The module name and the function name. This returns a pointer to the function name. The name "function name" is a bit obsolete. It is really the name of any of objects that can be documented; classes, methods, variables, functions, projects, etc.

SYNOPSIS

static char        *Function_Name(
    char *header_name )

SOURCE

{
    char               *cur_char;
    char               *name;

    name = NULL;
    if ( ( cur_char = header_name ) != NULL )
    {
        for ( ; *cur_char != '\0'; ++cur_char )
        {
            if ( '/' == *cur_char )
            {
                ++cur_char;
                if ( *cur_char )
                {
                    name = cur_char;
                    break;
                }
            }
        }
    }
    if ( name )
    {
        return RB_StrDup( name );
    }
    else
    {
        return ( name );
    }
}

Get_Indent

[ Top ] [ Analyser ] [ Functions ]

SYNOPSIS

static int Get_Indent(
    char *line )

INPUTS

RESULT

The indentation.

SOURCE

{
    int                 i;

    for ( i = 0; line[i] && utf8_isspace( line[i] ); ++i )
    {
        /* empty */
    }
    return i;
}

Grab_Header

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Grab a header from a source file, that is scan a source file until the start of a header is found. Then search for the end of a header and store all the lines in between.

SYNPOPSIS

static struct RB_header *Grab_Header(
    FILE *sourcehandle,
    struct RB_Document *arg_document )

INPUTS

OUTPUT

RESULT

0 if no header was found, or a pointer to a new header otherwise.

SOURCE

{
    struct RB_header   *new_header = NULL;
    int                 is_internal = 0;
    struct RB_HeaderType *header_type = NULL;
    int                 good_header = FALSE;
    int                 reuse = FALSE;

    do
    {
        good_header = FALSE;
        header_type = RB_Find_Marker( sourcehandle, &is_internal, reuse );
        reuse = FALSE;
        if ( header_type )
        {
            struct RB_header   *duplicate_header = NULL;
            long                previous_line = 0;

            new_header = RB_Alloc_Header(  );
            new_header->htype = header_type;
            new_header->is_internal = is_internal;

            if ( Find_Header_Name( sourcehandle, new_header ) )
            {
                new_header->line_number = line_number;
                RB_Say( "found header [line %5d]: \"%s\"\n", SAY_DEBUG,
                        line_number, new_header->name );
                duplicate_header =
                    RB_Document_Check_For_Duplicate( arg_document,
                                                     new_header );
                if ( duplicate_header )
                {
                    /* Duplicate headers do not crash the program so
                     * we accept them.  But we do warn the user.
                     */
                    RB_Warning
                        ( "A header with the name \"%s\" already exists.\n  See %s(%d)\n",
                          new_header->name,
                          Get_Fullname( duplicate_header->owner->filename ),
                          duplicate_header->line_number );
                }

                if ( ( new_header->function_name =
                       Function_Name( new_header->name ) ) == NULL )
                {
                    RB_Warning( "Can't determine the \"function\" name.\n" );
                    RB_Free_Header( new_header );
                    new_header = NULL;
                }
                else
                {
                    if ( ( new_header->module_name =
                           Module_Name( new_header->name ) ) == NULL )
                    {
                        RB_Warning
                            ( "Can't determine the \"module\" name.\n" );
                        RB_Free_Header( new_header );
                        new_header = NULL;
                    }
                    else
                    {
                        previous_line = line_number;
                        if ( Find_End_Marker( sourcehandle, new_header ) ==
                             0 )
                        {
                            RB_Warning
                                ( "found header on line %d with name \"%s\"\n"
                                  "  but I can't find the end marker\n",
                                  previous_line, new_header->name );
                            /* Reuse the current line while finding the next
                             * Marking using RB_Find_Marker()
                             */
                            reuse = TRUE;
                            RB_Free_Header( new_header );
                            new_header = NULL;
                        }
                        else
                        {
                            RB_Say( "found end header [line %5d]:\n",
                                    SAY_DEBUG, line_number );
                            /* Good header found, we can stop */
                            good_header = TRUE;
                        }
                    }
                }
            }
            else
            {
                RB_Warning( "found header marker but no name\n" );
                RB_Free_Header( new_header );
                new_header = NULL;
            }
        }
        else
        {
            /* end of the file */
            good_header = TRUE;
        }
    }
    while ( !good_header );
    return new_header;
}

Is_Empty_Line

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Check if line is empty. This assumes that Copy_Lines_To_Item has been run on the item.

SYNOPSIS

static int Is_Empty_Line(
    char *line )

INPUTS

SOURCE

{
    line = RB_Skip_Whitespace( line );
    return ( *line == '\0' );
}

Is_List_Item_Continuation

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Is it like the second line in something like:

     * this is a list item
       that continues 

SYNPOPSIS

static int Is_List_Item_Continuation(
    char *arg_line,
    int indent )

INPUTS

RESULT

SOURCE

{
    int                 this_indent = Get_Indent( arg_line );

    return ( this_indent > indent );
}

Is_ListItem_Start

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Test if a line starts with something that indicates a list item. List items start with '*', '-', or 'o'.

SYNPOPSIS

static int Is_ListItem_Start(
    char *arg_line,
    int arg_indent )

INPUTS

RESULT

SOURCE

{
    char               *c = arg_line;
    int                 cur_indent = Get_Indent( arg_line );

    if ( cur_indent == arg_indent )
    {
        /* TODO  Think there is a function for this */
        for ( ; *c && utf8_isspace( *c ); ++c )
        {                       /* empty */
        };

        if ( *c && ( strlen( c ) >= 3 ) )
        {
            if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) )
            {
                return TRUE;
            }
        }
    }
    else
    {
        /* The line is indented so it must be
         * the start of a pre block  */
    }

    return FALSE;
}

Is_Pipe_Marker

[ Top ] [ Analyser ] [ Functions ]

NAME

Is_Pipe_Marker

FUNCTION

Check for "pipe" markers e.g. "|html ".

SYNOPSIS

static char        *Is_Pipe_Marker(
    char *cur_char,
    int *pipe_mode )

RESULT

Pointer to the data to be piped to document or in case no pointers are found.

SEE ALSO

RB_Check_Pipe

SOURCE

{
    char               *short = cur_char + 1;

    *pipe_mode = -1;
    if ( *cur_char == '|' && *short )
    {
        if ( strncmp( "html ", short, 5 ) == 0 )
        {
            *pipe_mode = HTML;
            return ( short + 5 );
        }
        else if ( strncmp( "latex ", short, 6 ) == 0 )
        {
            *pipe_mode = LATEX;
            return ( short + 6 );
        }
        else if ( strncmp( "rtf ", short, 4 ) == 0 )
        {
            *pipe_mode = RTF;
            return ( short + 4 );
        }
        else if ( strncmp( "dbxml ", short, 6 ) == 0 )
        {
            *pipe_mode = XMLDOCBOOK;
            return ( short + 6 );
        }
        else if ( strncmp( "ascii ", short, 6 ) == 0 )
        {
            *pipe_mode = ASCII;
            return ( short + 6 );
        }
    }

    return ( char * ) NULL;
}

Is_Start_List

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Check... (TODO)

INPUTS

SOURCE

static int Is_Start_List(
    char *arg_line,
    int indent )
{
    int                 this_indent = Get_Indent( arg_line );
    char               *c = strrchr( arg_line, ':' );

    if ( ( this_indent == indent ) && c )
    {
        for ( ++c; *c; ++c )
        {
            if ( !utf8_isspace( *c ) )
            {
                return FALSE;
            }
        }
        return TRUE;
    }
    return FALSE;
}

Is_Tool

[ Top ] [ Analyser ] [ Functions ]

SYNOPSIS

static char        *Is_Tool(
    char *cur_char,
    enum ItemLineKind *itemkind,
    int *tool_active )

FUNCTION

Checks for tool start and end markers

SOURCE

{
    char               *short = cur_char + 1;

    if ( *cur_char == '|' && *short )
    {
        /* Check if tool starts or ends */
        if ( !strncmp( "tool ", short, 5 ) )
        {
            if ( *tool_active )
            {
                *itemkind = ITEM_LINE_TOOL_END;
                *tool_active = 0;
            }
            else
            {
                *itemkind = ITEM_LINE_TOOL_START;
                *tool_active = 1;
            }

            return ( short + 5 );
        }
        /* Check if DOT starts or ends */
        if ( !strncmp( "dot ", short, 4 ) )
        {
            if ( *tool_active )
            {
                *itemkind = ITEM_LINE_DOT_END;
                *tool_active = 0;
            }
            else
            {
                *itemkind = ITEM_LINE_DOT_START;
                *tool_active = 1;
            }

            return ( short + 4 );
        }
        /* Check for DOT file includes */
        else if ( !strncmp( "dotfile ", short, 8 ) && !*tool_active )
        {
            *itemkind = ITEM_LINE_DOT_FILE;
            return ( short + 8 );
        }
        /* Check for exec items */
        else if ( !strncmp( "exec ", short, 5 ) && !*tool_active )
        {
            *itemkind = ITEM_LINE_EXEC;
            return ( short + 5 );
        }
    }

    return NULL;
}

Module_Name

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Get the module name from the header name. The header name will be something like

     module/functionname.

SYNPOPSIS

static char        *Module_Name(
    char *header_name )

INPUTS

RESULT

Pointer to the modulename. You're responsible for freeing it.

SEE ALSO

Function_Name()

SOURCE

{
    char               *cur_char;
    char                c;
    char               *name = NULL;

    assert( header_name );

    for ( cur_char = header_name; *cur_char && *cur_char != '/'; ++cur_char );
    if ( *cur_char )
    {
        c = *cur_char;
        *cur_char = '\0';
        name = RB_StrDup( header_name );
        *cur_char = c;
    }
    return name;
}

Preformat_All

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Process... (TODO)

SYNPOPSIS

static void Preformat_All(
    struct RB_Item *arg_item,
    int source )

INPUTS

SOURCE

{
    int                 i;
    int                 preformatted = FALSE;
    char               *line = NULL;

    if ( arg_item->no_lines > 0 )
    {
        i = 0;
        /* Skip any pipe stuff */
        for ( ;
              ( i < arg_item->no_lines )
              && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
        {
            /* Empty */
        }

        line = arg_item->lines[i]->line;
        if ( ( arg_item->lines[i]->kind == ITEM_LINE_RAW ) ||
             ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) )
        {
            arg_item->lines[i]->format |=
                RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 );
            preformatted = TRUE;

            for ( ++i; i < arg_item->no_lines; i++ )
            {
                if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE )
                {
                    /* Temporarily end the preformatting to allow
                     * the piping to happen
                     */
                    arg_item->lines[i]->format |=
                        RBILA_END_PRE | ( source ? RBILA_END_SOURCE : 0 );
                    /* Find the end of the pipe stuff */
                    for ( ; ( i < arg_item->no_lines ) &&
                          ( arg_item->lines[i]->kind == ITEM_LINE_PIPE );
                          ++i )
                    {           /* Empty */
                    };
                    /* Every item ends with an ITEM_LINE_END, so: */
                    assert( i < arg_item->no_lines );
                    /* And re-enable preformatting */
                    arg_item->lines[i]->format |=
                        RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 );
                }

                if ( arg_item->lines[i]->kind == ITEM_LINE_END )
                {
                    /* If the last line ends with a begin_pre remove
                     * it, otherwise a begin and end pre will be
                     * generated, in the wrong order, on the same line in the output.
                     */
                    if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE )
                    {
                        arg_item->lines[i]->format &= ~( RBILA_BEGIN_PRE );
                    }
                    else
                    {
                        arg_item->lines[i]->format |= RBILA_END_PRE;
                    }
                    arg_item->lines[i]->format |=
                        ( source ? RBILA_END_SOURCE : 0 );
                }
            }
        }
    }
}

RB_Analyse_Document

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Scan all the sourcefiles of all parts of a document for headers. Store these headers in each part (RB_Part).

SYNOPSIS

void RB_Analyse_Document(
    struct RB_Document *arg_document )

INPUTS

RESULT

Each part will contain the headers that were found in the sourcefile of the part.

SOURCE

{
    struct RB_Part     *a_part;
    struct RB_Filename *a_filename;
    FILE               *filehandle;

    for ( a_part = arg_document->parts; a_part; a_part = a_part->next )
    {
        struct RB_header   *new_header = NULL;

        a_filename = a_part->filename;
        RB_Say( "analysing %s\n", SAY_DEBUG, Get_Fullname( a_filename ) );
        RB_SetCurrentFile( Get_Fullname( a_filename ) );

        RB_Header_Lock_Reset(  );
        filehandle = RB_Open_Source( a_part );
        line_number = 0;

        for ( new_header = Grab_Header( filehandle, arg_document );
              new_header;
              new_header = Grab_Header( filehandle, arg_document ) )
        {
            if ( ToBeAdded( arg_document, new_header ) )
            {
                /* The Add is required before the 
                 * Analyse because Add sets the owner of the header
                 * which is needed for error messages.
                 */
                RB_Part_Add_Header( a_part, new_header );
                Analyse_Items( new_header );
            }
            else
            {
                RB_Free_Header( new_header );
            }
        }
        fclose( filehandle );
    }
}

RB_Analyse_Items

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Locate the items in the header and create RB_Item structures for them.

SYNPOPSIS

static int Analyse_Items(
    struct RB_header *arg_header )

SOURCE

{
    int                 line_nr;
    enum ItemType       item_type = NO_ITEM;
    struct RB_Item     *new_item;
    struct RB_Item     *cur_item;
    /*RZ variables for source comment adding */
    int isSource=0;
    struct RB_Item *use_item = NULL;
    unsigned int marker;
    char *cur_mchar = NULL;
    char *cur_char = NULL;
    int length;

    RB_Item_Lock_Reset(  );

    /* find the first item */
    for ( line_nr = 0; line_nr < arg_header->no_lines; ++line_nr )
    {
        item_type = RB_Is_ItemName( arg_header->lines[line_nr].line );
        if ( item_type != NO_ITEM )
        {
            break;
        }
    }

    /* and all the others */
    while ( ( item_type != NO_ITEM ) && ( line_nr < arg_header->no_lines ) )
    {
        new_item = RB_Create_Item( item_type );
        new_item->begin_index = line_nr;
        /*RZ add source comments to this item */
        if (use_source_comments) {
            if (strcmp(configuration.items.names[item_type],use_source_comments)==0) {
                use_item = new_item;
            } else {
                isSource = !strcmp(configuration.items.names[item_type],"SOURCE");
            }
        }
        /* Add the item to the end of the list of items. */
        if ( arg_header->items )
        {
            for ( cur_item = arg_header->items; cur_item->next;
                    cur_item = cur_item->next )
            {
                /* Empty */
            }
            cur_item->next = new_item;
        }
        else
        {
            arg_header->items = new_item;
        }
        /* Find the next item */
        for ( ++line_nr; line_nr < arg_header->no_lines; ++line_nr )
        {
            /*RZ add comment line to item */
            if (isSource) {
                cur_char = RB_Skip_Whitespace (arg_header->lines[line_nr].line);
                for (marker = 0; marker < configuration.source_line_comments.number;
                        marker++) {
                    cur_mchar = configuration.source_line_comments.names[marker];
                    length = strlen(cur_mchar);
                    if (strncmp(cur_char,cur_mchar,length) == 0) {
                        /* create item if not already existing */
                        if (use_item == NULL) {
                            item_type = RB_Get_Item_Type (use_source_comments);
                            if ( item_type != NO_ITEM ) {
                                use_item = RB_Create_Item( item_type );
                                use_item->no_lines = 0;
                                /* Add the item to the end of the list of items. */
                                if ( arg_header->items ) {
                                    for ( cur_item = arg_header->items; cur_item->next;
                                            cur_item = cur_item->next ) {
                                        /* Empty */
                                    }
                                    cur_item->next = use_item;
                                } else {
                                    arg_header->items = use_item;
                                }
                            }
                        }
                        Add_Lines_To_Item( use_item, &cur_char[length]);
                    }
                }
            }
            item_type = RB_Is_ItemName( arg_header->lines[line_nr].line );
            if ( item_type != NO_ITEM )
            {
                break;
            }
        }

        /* This points to the last line in the item */
        new_item->end_index = line_nr - 1;

        assert( new_item->end_index >= new_item->begin_index );

        /* Now analyse and copy the lines */
        Copy_Lines_To_Item( arg_header, new_item );
        Analyse_Item_Format( new_item );
        /* Handy for debugging wiki formatting 
         *   Dump_Item( new_item );
         */
    }
    /*RZ*/
    if (use_item) {
        Analyse_Item_Format( use_item );
    }
    return 0;
}

RB_Find_Marker

[ Top ] [ Analyser ] [ Functions ]

NAME

RB_Find_Marker -- Search for header marker in document.

FUNCTION

Read document file line by line, and search each line for any of the headers defined in the array header_markers (OR if using the -rh switch, robo_head)

SYNOPSIS

static struct RB_HeaderType *RB_Find_Marker(
    FILE *document,
    int *is_internal,
    int reuse_previous_line )

INPUTS

document - pointer to the file to be searched. the gobal buffer line_buffer.

OUTPUT

RESULT

BUGS

Bad use of feof(), fgets().

SEE ALSO

Find_End_Marker

SOURCE

{
    int                 found;
    char               *cur_char;
    struct RB_HeaderType *header_type = 0;

    cur_char = NULL;
    found = FALSE;
    while ( !feof( document ) && !found )
    {
        if ( reuse_previous_line )
        {
            /* reuse line in the line_buffer */
            reuse_previous_line = FALSE;
        }
        else
        {
            RB_FreeLineBuffer(  );
            myLine = RB_ReadWholeLine( document, line_buffer, &readChars );
        }
        if ( !feof( document ) )
        {
            line_number++;
            found = RB_Is_Begin_Marker( myLine, &cur_char );
            if ( found )
            {
                header_type = AnalyseHeaderType( &cur_char, is_internal );
                RB_Say( "found header marker of type %s\n", SAY_DEBUG,
                        header_type->indexName );
            }
        }
    }

    return header_type;
}

Remove_List_Char

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Remove... (TODO)

INPUTS

SOURCE

static void Remove_List_Char(
    struct RB_Item *arg_item,
    int start_index )
{
    char               *c = arg_item->lines[start_index]->line;

    for ( ; *c && utf8_isspace( *c ); ++c )
    {                           /* empty */
    };
    if ( *c && ( strlen( c ) >= 3 ) )
    {
        if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) )
        {
            char               *temp = arg_item->lines[start_index]->line;

            *c = ' ';
            arg_item->lines[start_index]->line = RB_StrDup( temp + 2 );
            free( temp );
        }
    }
}

ToBeAdded

[ Top ] [ Analyser ] [ Functions ]

FUNCTION

Test whether or not a header needs to be added to the list of headers. This implements the options

      --internal 

and

      --internalonly

SYNPOPSIS

static int ToBeAdded(
    struct RB_Document *document,
    struct RB_header *header )

INPUTS

RESULT

TRUE -- Add header FALSE -- Don't add header

SOURCE

{
    int                 add = FALSE;

    if ( header->is_internal )
    {
        if ( ( document->actions.do_include_internal ) ||
             ( document->actions.do_internal_only ) )
        {
            add = TRUE;
        }
        else
        {
            add = FALSE;
        }
    }
    else
    {
        if ( document->actions.do_internal_only )
        {
            add = FALSE;
        }
        else
        {
            add = TRUE;
        }
    }
    return add;
}