// vi: spell ff=unix /****h* ROBODoc/Generator * FUNCTION * This contains routines to generate the documentation from the * headers collected from the source code. It contains * functionality common for all document types (HTML, RTF etc). * The specifics are handled in the modules for each of the several * document types. * * The behaviour of many of the functions in this module are * modified by the global output_mode. * * The general call sequence is as follows: * RB_Generate_Documentation * +> RB_Generate_SingleDoc * +> RB_Generate_Part * +> Generate_Header * +> Generate_Item_Line * +> Generate_Char * BUGS * o Confusing use of doctype and output mode. * NOTES * Might be a good idea to replace all the switch statements with * function pointers. * So instead of: * switch (output_mode) * { * case HTML: * RB_HTML_Generate_Doc_Start(dest_doc, src_name, name, toc); * break; * case LATEX: * RB_LaTeX_Generate_Doc_Start(dest_doc, src_name, name, toc); * break; * case RTF: * RB_RTF_Generate_Doc_Start(dest_doc, src_name, name, toc); * break; * case ASCII: * RB_ASCII_Generate_Doc_Start(dest_doc, src_name, name, toc); * break; * case TROFF: * RB_TROFF_Generate_Doc_Start(dest_doc, src_name, name, toc); * break; * default: * break; * } * we will have * (*rb_generate_doc_start)(dest_doc, src_name, name, toc); * * were the function pointers are initialized at program start based * on the output mode. ******* * $Id: generator.c,v 1.105 2007/05/10 09:45:27 thuffir Exp $ */ #include #include #include #include #include #include "globals.h" #include "robodoc.h" #include "headers.h" #include "items.h" #include "util.h" #include "links.h" #include "generator.h" #include "document.h" #include "part.h" #include "file.h" #include "roboconfig.h" /* Generators */ #include "html_generator.h" #include "latex_generator.h" #include "xmldocbook_generator.h" #include "rtf_generator.h" #include "troff_generator.h" #include "ascii_generator.h" #include "test_generator.h" /* TODO This should not be here.... */ #include "analyser.h" #ifdef DMALLOC #include #endif /* Module functions */ // static void RB_Generate_Empty_Item( FILE * dest_doc ); static void Generate_Item_Line( FILE *dest_doc, char *line, int item_type, char *docname, struct RB_header *fnames ); void Generate_Char( FILE *dest_doc, int cur_char ); static void Generate_Index( struct RB_Document *document ); static void Generate_Header( FILE *f, struct RB_Document *document, struct RB_header *header, char *docname ); static void Generate_Begin_Paragraph( FILE *dest_doc ); static void Generate_End_Paragraph( FILE *dest_doc ); static void Format_Line( FILE *dest_doc, long format ); static void Generate_Begin_Preformatted( FILE *dest_doc, int source ); static void Generate_End_Preformatted( FILE *dest_doc ); static void Generate_Begin_List_Item( FILE *dest_doc ); static void Generate_End_List_Item( FILE *dest_doc ); static void Generate_Begin_List( FILE *dest_doc ); static void Generate_End_List( FILE *dest_doc ); static void Pipe_Line( FILE *dest_doc, char *arg_line ); static char piping = FALSE; /* TODO Documentation */ void RB_Generate_False_Link( FILE *dest_doc, char *name ) { switch ( output_mode ) { case TEST: RB_TEST_Generate_False_Link( dest_doc, name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_False_Link( dest_doc, name ); break; case HTML: RB_HTML_Generate_False_Link( dest_doc, name ); break; case LATEX: RB_LaTeX_Generate_False_Link( dest_doc, name ); break; case RTF: RB_RTF_Generate_False_Link( dest_doc, name ); break; case ASCII: RB_ASCII_Generate_False_Link( dest_doc, name ); break; case TROFF: RB_TROFF_Generate_False_Link( dest_doc, name ); break; case UNKNOWN: default: assert( 0 ); } } /****f* Generator/RB_Generate_Item_Begin * FUNCTION * Generate the begin of an item. This should switch to some * preformatted output mode, similar to HTML's
.
 * SYNOPSIS
 */
void RB_Generate_Item_Begin(
    FILE *dest_doc,
    char *name )
/*
 * INPUTS
 *   dest_doc -- file to be written to
 *   output_mode -- global with the current output mode
 * SOURCE
 */
{
    switch ( output_mode )
    {
    case TEST:
        RB_TEST_Generate_Item_Begin( dest_doc );
        break;
    case XMLDOCBOOK:
        RB_XMLDB_Generate_Item_Begin( dest_doc );
        break;
    case HTML:
        RB_HTML_Generate_Item_Begin( dest_doc, name );
        break;
    case LATEX:
        RB_LaTeX_Generate_Item_Begin( dest_doc );
        break;
    case RTF:
        RB_RTF_Generate_Item_Begin( dest_doc );
        break;
    case ASCII:
        RB_ASCII_Generate_Item_Begin( dest_doc );
        break;
    case TROFF:
        /* nothing */
        break;
    case UNKNOWN:
    default:
        assert( 0 );
    }
}

/******/


/****f* Generator/Generate_Label
 * FUNCTION
 *   Generate a label that can be used for a link.
 *   For instance in HTML this is 
 * SYNOPSIS
 */
void Generate_Label(
    FILE *dest_doc,
    char *name )
/*
 * INPUTS
 *   * dest_doc -- file to be written to
 *   * name -- the label's name.
 *   * output_mode -- global with the current output mode
 * SOURCE
 */
{
    switch ( output_mode )
    {
    case TEST:
        RB_TEST_Generate_Label( dest_doc, name );
        break;
    case XMLDOCBOOK:
        RB_XMLDB_Generate_Label( dest_doc, name );
        break;
    case HTML:
        RB_HTML_Generate_Label( dest_doc, name );
        break;
    case LATEX:
        /* lowtexx 21.09.2005 11:33 */
        RB_LaTeX_Generate_Label( dest_doc, name );
        break;
    case RTF:
        RB_RTF_Generate_Label( dest_doc, name );
        break;
    case ASCII:
        /* Doesn't apply */
        break;
    case TROFF:
        /* Doesn't apply */
        break;
    case UNKNOWN:
    default:
        assert( 0 );
    }
}

/******/


/****f* Generator/RB_Generate_Item_End
 * FUNCTION
 *   Generate the end of an item.  This should switch back from the
 *   preformatted mode.  So in HTML it generates the 
of a
 *   
pair. * INPUTS * * dest_doc -- file to be written to * * output_mode -- global with the current output mode * SOURCE */ void RB_Generate_Item_End( FILE *dest_doc, char *name ) { switch ( output_mode ) { case TEST: RB_TEST_Generate_Item_End( dest_doc ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Item_End( dest_doc ); break; case HTML: RB_HTML_Generate_Item_End( dest_doc, name ); break; case LATEX: if ( piping == TRUE ) { fprintf( dest_doc, "\\begin{verbatim}\n" ); piping = FALSE; } RB_LaTeX_Generate_Item_End( dest_doc ); break; case RTF: RB_RTF_Generate_Item_End( dest_doc ); break; case ASCII: RB_ASCII_Generate_Item_End( dest_doc ); break; case TROFF: /* Doesn't apply */ break; case UNKNOWN: default: assert( 0 ); } } /****/ /****f Generator/RB_Get_Len_Extension * FUNCTION * Compute the length of the filename extension for * the current document type. ***** */ size_t RB_Get_Len_Extension( char *extension ) { size_t size = 0; size = strlen( extension ); if ( *extension != '.' ) size++; return size; } /****f* Generator/RB_Add_Extension * FUNCTION * Add an extension to the filename base based on on the current * output mode. * INPUTS * * doctype -- output mode * * name -- the name of the file without extension and with * enough room left to add the extension. * OUTPUT * name -- the name of the file including the extension. * SOURCE */ void RB_Add_Extension( char *extension, char *name ) { if ( *extension != '.' ) strcat( name, "." ); strcat( name, extension ); } /******/ /*x**f Generator/RB_Default_Len_Extension * FUNCTION * Returns default extension for * the current document type. ***** */ char *RB_Get_Default_Extension( T_RB_DocType doctype ) { char *extension = NULL; switch ( doctype ) { case TEST: extension = RB_TEST_Get_Default_Extension( ); break; case XMLDOCBOOK: extension = RB_XMLDB_Get_Default_Extension( ); break; case HTML: extension = RB_HTML_Get_Default_Extension( ); break; case LATEX: extension = RB_LaTeX_Get_Default_Extension( ); break; case RTF: extension = RB_RTF_Get_Default_Extension( ); break; case ASCII: extension = RB_ASCII_Get_Default_Extension( ); break; case TROFF: extension = RB_TROFF_Get_Default_Extension( ); break; case UNKNOWN: default: assert( 0 ); } return extension; } /****f* Generator/RB_Generate_BeginSection * FUNCTION * Generate a section of level depth in the current output mode. * This is used for the --sections option. Where each header is * placed in a section based on the header hierarchy. * INPUTS * * dest_doc -- the destination file. * * doctype -- document type * * depth -- the level of the section * * name -- the name of the section * * header -- pointer to the header structure * * output_mode -- global with the current output mode. * SOURCE */ void RB_Generate_BeginSection( FILE *dest_doc, int depth, char *name, struct RB_header *header ) { switch ( output_mode ) { case TEST: RB_TEST_Generate_BeginSection( dest_doc, depth, name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_BeginSection( dest_doc, depth, name ); break; case HTML: RB_HTML_Generate_BeginSection( dest_doc, depth, name, header ); break; case LATEX: RB_LaTeX_Generate_BeginSection( dest_doc, depth, name, header ); break; case RTF: RB_RTF_Generate_BeginSection( dest_doc, depth, name ); break; case TROFF: /* RB_TROFF_Generate_BeginSection( dest_doc, depth, name ); */ break; case ASCII: RB_ASCII_Generate_BeginSection( dest_doc, depth, name, header ); break; case UNKNOWN: default: assert( 0 ); } } /*******/ /****f* Generator/RB_Generate_EndSection * FUNCTION * Generate the end of a section base on the current output mode. * The functions is used for the --section option. * It closes a section in the current output mode. * INPUTS * * dest_doc -- the destination file. * * doctype -- * * depth -- the level of the section * * name -- the name of the section * * output_mode -- global with the current output mode. * SOURCE */ void RB_Generate_EndSection( FILE *dest_doc, int depth, char *name ) { switch ( output_mode ) { case TEST: RB_TEST_Generate_EndSection( dest_doc, depth, name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_EndSection( dest_doc, depth, name ); break; case HTML: RB_HTML_Generate_EndSection( dest_doc, depth, name ); break; case LATEX: RB_LaTeX_Generate_EndSection( dest_doc, depth, name ); break; case RTF: RB_RTF_Generate_EndSection( dest_doc, depth, name ); break; case TROFF: /* doesn't apply */ break; case ASCII: RB_HTML_Generate_EndSection( dest_doc, depth, name ); break; case UNKNOWN: default: assert( 0 ); } } /******/ /****f* Generator/RB_Generate_Index_Entry * FUNCTION * Generate an entry for an auto generated index. This works only * for output modes that support this, LaTeX for instance. This * has nothting to do with the master index. * SYNOPSIS */ void RB_Generate_Index_Entry( FILE *dest_doc, T_RB_DocType doctype, struct RB_header *header ) /* * INPUTS * * dest_doc -- the destination file. * * header -- pointer to the header the index entry is for. * * output_mode -- global with the current output mode. * SOURCE */ { switch ( doctype ) { case TEST: /* TODO */ break; case XMLDOCBOOK: /* TODO */ break; case HTML: /* TODO */ break; case LATEX: RB_LaTeX_Generate_Index_Entry( dest_doc, header ); break; case RTF: /* TODO */ break; case ASCII: /* No index available */ break; case TROFF: /* No index available */ break; case UNKNOWN: default: assert( 0 ); } } /*******/ /****f* Generator/RB_Generate_TOC_2 * FUNCTION * Create a Table of Contents based on the headers found in * _all_ source files. There is also a function to create * a table of contents based on the headers found in a single * source file RB_Generate_TOC_1 * SYNOPSIS */ void RB_Generate_TOC_2( FILE *dest_doc, struct RB_header **headers, int count, struct RB_Part *owner, char *dest_name ) /* * INPUTS * * dest_doc -- the destination file. * * headers -- an array of pointers to all the headers. * * count -- the number of pointers in the array. * * output_mode -- global with the current output mode. * * owner -- The owner of the TOC. Only the headers that are owned * by this owner are included in the TOC. Can be NULL, * in which case all headers are included. * SOURCE */ { switch ( output_mode ) { case TEST: break; case TROFF: break; case XMLDOCBOOK: break; case HTML: RB_HTML_Generate_TOC_2( dest_doc, headers, count, owner, dest_name ); break; case LATEX: /* LaTeX has it's own mechanism for creating * a table of content */ break; case RTF: RB_RTF_Generate_TOC_2( dest_doc, headers, count ); break; case ASCII: /* TODO: No TOC in ASCII mode */ break; case UNKNOWN: default: assert( 0 ); } } /******/ /****f* Generator/RB_Generate_Doc_Start * NAME * RB_Generate_Doc_Start -- Generate document header. * SYNOPSIS */ void RB_Generate_Doc_Start( struct RB_Document *document, FILE *dest_doc, char *src_name, char *title, char toc, char *dest_name, char *charset ) /* * FUNCTION * Generates for depending on the output_mode the text that * will be at the start of a document. * Including the table of contents. * INPUTS * o dest_doc - pointer to the file to which the output will * be written. * o src_name - the name of the source file or directory. * o name - the name of this file. * o output_mode - global variable that indicates the output * mode. * o toc - generate table of contens * SEE ALSO * RB_Generate_Doc_End * SOURCE */ { switch ( output_mode ) { case TEST: RB_TEST_Generate_Doc_Start( dest_doc, src_name, title, toc ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Doc_Start( document, dest_doc, charset ); break; case HTML: RB_HTML_Generate_Doc_Start( dest_doc, src_name, title, dest_name, charset ); break; case LATEX: RB_LaTeX_Generate_Doc_Start( dest_doc, src_name, title, charset ); break; case RTF: RB_RTF_Generate_Doc_Start( dest_doc, src_name, title, toc ); break; case ASCII: RB_ASCII_Generate_Doc_Start( dest_doc, src_name, title, toc ); break; case TROFF: /* */ ; break; case UNKNOWN: default: ; } } /***************/ /****f* Generator/RB_Generate_Doc_End * NAME * RB_Generate_Doc_End -- generate document trailer. * SYNOPSIS */ void RB_Generate_Doc_End( FILE *dest_doc, char *name, char *src_name ) /* * FUNCTION * Generates for depending on the output_mode the text that * will be at the end of a document. * INPUTS * o dest_doc - pointer to the file to which the output will * be written. * o name - the name of this file. * o output_mode - global variable that indicates the output * mode. * NOTES * Doesn't do anything with its arguments, but that might * change in the future. * BUGS * SOURCE */ { switch ( output_mode ) { case TEST: RB_TEST_Generate_Doc_End( dest_doc, name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Doc_End( dest_doc, name ); break; case HTML: RB_HTML_Generate_Doc_End( dest_doc, name, src_name ); break; case LATEX: RB_LaTeX_Generate_Doc_End( dest_doc, name ); break; case RTF: RB_RTF_Generate_Doc_End( dest_doc, name ); break; case TROFF: break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /************/ /****f* Generator/RB_Generate_Header_Start [3.0h] * NAME * RB_Generate_Header_Start -- generate header start text. * SYNOPSIS */ FILE *RB_Generate_Header_Start( FILE *dest_doc, struct RB_header *cur_header ) /* * FUNCTION * Generates depending on the output_mode the text that * will be at the end of each header. * INPUTS * o dest_doc - pointer to the file to which the output will * be written. * o cur_header - pointer to a RB_header structure. * SEE ALSO * RB_Generate_Header_End * SOURCE */ { switch ( output_mode ) { case TEST: RB_TEST_Generate_Header_Start( dest_doc, cur_header ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Header_Start( dest_doc, cur_header ); break; case HTML: RB_HTML_Generate_Header_Start( dest_doc, cur_header ); break; case LATEX: RB_LaTeX_Generate_Header_Start( dest_doc, cur_header ); break; case RTF: RB_RTF_Generate_Header_Start( dest_doc, cur_header ); break; case ASCII: RB_ASCII_Generate_Header_Start( dest_doc, cur_header ); break; case TROFF: dest_doc = RB_TROFF_Generate_Header_Start( dest_doc, cur_header ); break; case UNKNOWN: default: assert( 0 ); } return dest_doc; } /******/ /****f* Generator/RB_Generate_Header_End [3.0h] * NAME * RB_Generate_Header_End * SYNOPSIS */ void RB_Generate_Header_End( FILE *dest_doc, struct RB_header *cur_header ) /* * FUNCTION * Generates for depending on the output_mode the text that * will be at the end of a header. * This function is used if the option --section is _not_ * used. * INPUTS * o dest_doc - pointer to the file to which the output will * be written. * o cur_header - pointer to a RB_header structure. * SEE ALSO * RB_Generate_Header_Start, RB_Generate_EndSection, * RB_Generate_BeginSection * SOURCE */ { switch ( output_mode ) { /* switch by *koessi */ case TEST: RB_TEST_Generate_Header_End( dest_doc, cur_header ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Header_End( dest_doc, cur_header ); break; case HTML: RB_HTML_Generate_Header_End( dest_doc, cur_header ); break; case LATEX: RB_LaTeX_Generate_Header_End( dest_doc, cur_header ); break; case RTF: RB_RTF_Generate_Header_End( dest_doc, cur_header ); break; case ASCII: RB_ASCII_Generate_Header_End( dest_doc, cur_header ); break; case TROFF: RB_TROFF_Generate_Header_End( dest_doc, cur_header ); break; case UNKNOWN: default: break; } } /*****/ /****f* Generator/Generate_Item_Name [2.01] * NAME * Generate_Item_Name -- fast&easy * SYNOPSIS */ void Generate_Item_Name( FILE *dest_doc, int item_type ) /* * FUNCTION * write the item's name to the doc * INPUTS * o FILE* dest_doc -- destination file * o int item_type -- the type of item * AUTHOR * Koessi * NOTES * uses globals: output_mode * SOURCE */ { char *name = configuration.items.names[item_type]; switch ( output_mode ) { case TEST: RB_TEST_Generate_Item_Name( dest_doc, name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Item_Name( dest_doc, name ); break; case HTML: RB_HTML_Generate_Item_Name( dest_doc, name ); break; case LATEX: RB_LaTeX_Generate_Item_Name( dest_doc, name ); break; case RTF: RB_RTF_Generate_Item_Name( dest_doc, name ); break; case ASCII: RB_ASCII_Generate_Item_Name( dest_doc, name ); break; case TROFF: RB_TROFF_Generate_Item_Name( dest_doc, name, item_type ); break; break; case UNKNOWN: default: assert( 0 ); } } /*********/ void Generate_Begin_Content( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_Begin_Content( dest_doc ); break; default: break; } } void Generate_End_Content( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_End_Content( dest_doc ); break; default: break; } } void Generate_Begin_Navigation( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_Begin_Navigation( dest_doc ); break; default: break; } } void Generate_End_Navigation( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_End_Navigation( dest_doc ); break; default: break; } } void Generate_IndexMenu( FILE *dest_doc, char *filename, struct RB_Document *document ) { switch ( output_mode ) { case HTML: RB_HTML_Generate_IndexMenu( dest_doc, filename, document, NULL ); break; default: break; } } void Generate_Begin_Extra( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_Begin_Extra( dest_doc ); break; default: break; } } void Generate_End_Extra( FILE *dest_doc ) { switch ( output_mode ) { case HTML: HTML_Generate_End_Extra( dest_doc ); break; default: break; } } /* TODO Documentation */ void RB_Generate_Nav_Bar( struct RB_Document *document, FILE *current_doc, struct RB_header *current_header ) { switch ( output_mode ) { case TEST: break; case XMLDOCBOOK: break; case HTML: if ( course_of_action.do_one_file_per_header ) { /* Nothing */ } else { RB_HTML_Generate_Nav_Bar( document, current_doc, current_header ); } break; case LATEX: break; case RTF: break; case ASCII: break; case TROFF: break; case UNKNOWN: default: /* Bug */ assert( 0 ); } } /* TODO Documentation */ int RB_HTML_Extra( FILE *dest_doc, int item_type, char *cur_char, char prev_char ) { int res = -1; switch ( output_mode ) { case TEST: break; case XMLDOCBOOK: break; case HTML: res = RB_HTML_Generate_Extra( dest_doc, item_type, cur_char, prev_char ); break; case LATEX: /* TODO */ break; case RTF: /* TODO */ break; case ASCII: /* TODO */ break; case TROFF: res = RB_TROFF_Generate_Extra( dest_doc, item_type, cur_char ); break; break; case UNKNOWN: default: /* Bug */ assert( 0 ); } return res; } /****f* Generator/RB_Name_Headers * FUNCTION * Give all headers a unique name. This makes sure that if * two headers have the same name linking to one of the headers * still works. * SYNOPSIS */ void RB_Name_Headers( struct RB_header **headers, long count ) /* * SOURCE */ #define MAX_UNIQUE_ID_LENGTH 80 { int i; char id[MAX_UNIQUE_ID_LENGTH + 1]; RB_Say( "Assigning headers a unique name.\n", SAY_DEBUG ); for ( i = 0; i < count; ++i ) { struct RB_header *header; header = headers[i]; sprintf( id, "robo%d", i ); header->unique_name = RB_StrDup( id ); } } /******/ /****f* Generator/RB_Sort_Items * FUNCTION * Sort the items in all the headers according to the order * specified in the 'item order' block in the robodoc.rc * file. * SYNOPSIS */ static void RB_Sort_Items( struct RB_header **headers, long header_count ) /* * SOURCE */ { int n_order = configuration.item_order.number; if ( n_order ) { int i = 0; int j = 0; int max_number_of_items = 0; struct RB_Item **items = NULL; struct RB_Item **items_sorted = NULL; RB_Say( "Sorting items in %d headers.\n", SAY_DEBUG, header_count ); /* Compute the maximum number of items in any given header */ for ( j = 0; j < header_count; ++j ) { struct RB_header *header; struct RB_Item *item; int item_count = 0; header = headers[j]; for ( item = header->items; item; item = item->next ) { ++item_count; } if ( item_count > max_number_of_items ) { max_number_of_items = item_count; } } /* Allocate an array for the items, this makes it easier to * sort. */ RB_Say( "Largest header has %d items.\n", SAY_DEBUG, max_number_of_items ); if ( max_number_of_items == 0 ) { /* No items in any of the headers, do nothing */ } else { items = calloc( max_number_of_items, sizeof( struct RB_Item * ) ); items_sorted = calloc( max_number_of_items, sizeof( struct RB_Item * ) ); /* Sort items */ for ( j = 0; j < header_count; ++j ) { struct RB_header *header = NULL; struct RB_Item *item = NULL; int item_index = 0; int sorted_item_index = 0; int item_count = 0; header = headers[j]; /* Copy item pointers to array */ for ( item = header->items; item; item = item->next, ++item_index ) { items[item_index] = item; items_sorted[item_index] = item; }; item_count = item_index; if ( item_count == 0 ) { /* No items in this header, do nothing. */ } else { assert( item_count <= max_number_of_items ); /* First copy the items in the order that is defined in * item_order[] to sorted_items[] */ sorted_item_index = 0; for ( i = 0; i < n_order; ++i ) { for ( item_index = 0; item_index < item_count; ++item_index ) { if ( items[item_index] ) { if ( strcmp ( configuration.items. names[items[item_index]->type], configuration.item_order.names[i] ) == 0 ) { /* copy to items_sorted */ items_sorted[sorted_item_index] = items[item_index]; ++sorted_item_index; items[item_index] = NULL; } } } } /* Then copy the remaining items to items_sorted[] */ for ( item_index = 0; item_index < item_count; ++item_index ) { if ( items[item_index] ) { /* copy to items_sorted */ items_sorted[sorted_item_index] = items[item_index]; ++sorted_item_index; items[item_index] = NULL; } } assert( sorted_item_index == item_count ); /* Now copy the items in items_sorted[] back into the linked list in * the header */ if ( item_count > 1 ) { /* Chain all the items */ for ( item_index = 0; item_index < item_count - 1; ++item_index ) { items_sorted[item_index]->next = items_sorted[item_index + 1]; } } assert( item_count > 0 ); items_sorted[item_count - 1]->next = NULL; /* now link the first item to the header. */ header->items = items_sorted[0]; } } free( items_sorted ); free( items ); } } RB_Say( "Done sorting items in %d headers.\n", SAY_DEBUG, header_count ); } /*******/ /****f* Generator/RB_Generate_Documentation * FUNCTION * Generate the documentation for all the information contained in a * RB_Document structure. * SYNOPSIS */ void RB_Generate_Documentation( struct RB_Document *document ) /* * INPUTS * document -- pointer to the RB_Document structure. * SOURCE */ { RB_SetCurrentFile( NULL ); if ( document->actions.do_singledoc ) { RB_Generate_SingleDoc( document ); } else if ( document->actions.do_multidoc ) { RB_Generate_MultiDoc( document ); } else if ( document->actions.do_singlefile ) { RB_Generate_SingleDoc( document ); } } /*****/ /****f* Generator/RB_Generate_MultiDoc * FUNCTION * Create documentation by creating a file for each * individual source file that was scanned. * SYNOPSIS */ void RB_Generate_MultiDoc( struct RB_Document *document ) /* * INPUTS * document -- pointer to the RB_Document structure. * SOURCE */ { struct RB_Part *i_part; FILE *document_file = NULL; RB_Document_Determine_DocFilePaths( document ); RB_Document_Create_DocFilePaths( document ); if ( document->actions.do_one_file_per_header ) { RB_Document_Split_Parts( document ); } RB_Document_Determine_DocFileNames( document ); RB_Document_Collect_Headers( document ); if ( document->actions.do_nosort ) { /* Nothing */ } else { RB_Document_Sort_Headers( document ); } RB_Document_Link_Headers( document ); RB_Fill_Header_Filename( document ); RB_Name_Headers( document->headers, document->no_headers ); RB_Sort_Items( document->headers, document->no_headers ); RB_CollectLinks( document, document->headers, document->no_headers ); if ( output_mode == HTML ) { RB_Create_CSS( document ); } for ( i_part = document->parts; i_part != NULL; i_part = i_part->next ) { char *srcname = Get_Fullname( i_part->filename ); char *docname = RB_Get_FullDocname( i_part->filename ); /* Nothing found in this part, do not generate it */ if ( i_part->headers == 0 ) continue; if ( output_mode != TROFF ) { document_file = RB_Open_Documentation( i_part ); RB_Generate_Doc_Start( document, document_file, srcname, srcname, 1, docname, document->charset ); Generate_Begin_Navigation( document_file ); if ( document->actions.do_one_file_per_header ) { RB_HTML_Generate_Nav_Bar_One_File_Per_Header( document, document_file, i_part-> headers ); } else { Generate_IndexMenu( document_file, docname, document ); } Generate_End_Navigation( document_file ); Generate_Begin_Content( document_file ); if ( ( document->actions.do_toc ) && document->no_headers ) { RB_Generate_TOC_2( document_file, document->headers, document->no_headers, i_part, docname ); } RB_Generate_Part( document_file, document, i_part ); Generate_End_Content( document_file ); RB_Generate_Doc_End( document_file, docname, srcname ); fclose( document_file ); } else { RB_Generate_Part( document_file, document, i_part ); } } if ( document->actions.do_index ) { Generate_Index( document ); } RB_Free_Links( ); } /*****/ /****f* Generator/RB_Generate_SingleDoc * FUNCTION * Create documentation by creating a single file for all individual * source file that were scanned. * * This function is called when the option --singledoc is used. * Based on whether the option --sections is used this function then * calls RB_Generate_Sections or RB_Generate_Part * SYNOPSIS */ void RB_Generate_SingleDoc( struct RB_Document *document ) /* * INPUTS * document -- pointer to the RB_Document structure. * SOURCE */ { FILE *document_file; struct RB_Part *i_part; RB_Document_Collect_Headers( document ); if ( document->actions.do_nosort ) { /* Nothing */ } else { RB_Document_Sort_Headers( document ); } RB_Document_Link_Headers( document ); RB_Fill_Header_Filename( document ); RB_Name_Headers( document->headers, document->no_headers ); RB_Sort_Items( document->headers, document->no_headers ); RB_CollectLinks( document, document->headers, document->no_headers ); for ( i_part = document->parts; i_part != NULL; i_part = i_part->next ) { RB_Set_FullDocname( i_part->filename, document->singledoc_name ); } if ( output_mode == HTML ) { RB_Create_CSS( document ); } document_file = RB_Open_SingleDocumentation( document ); assert( document->parts->filename->name ); RB_Generate_Doc_Start( document, document_file, document->srcroot->name, document->singledoc_name, 1, document->singledoc_name, document->charset ); if ( ( document->actions.do_toc ) && document->no_headers ) { RB_Generate_TOC_2( document_file, document->headers, document->no_headers, NULL, document->parts->filename->name ); } if ( document->actions.do_sections ) { RB_Generate_Sections( document_file, document ); } else { for ( i_part = document->parts; i_part != NULL; i_part = i_part->next ) { RB_Generate_Part( document_file, document, i_part ); } } RB_Generate_Doc_End( document_file, "singledoc", document->srcroot->name ); fclose( document_file ); RB_Free_Links( ); } /******/ /****f* Generator/RB_Generate_Sections * FUNCTION * Creates the documentation for all headers found in all source * files. The order in which they are generated depends on the * header hierarchy. First the top level header's documentation * is generated then, the documentation for all it's childern, then * the next top level header's documentation is generated. * This is a recursive proces. * The idea is to create something like: * 1. Parentheader1 * 1.1 Child1 * 1.2 Child2 * 1.2.1 Child's child1 * 2. Parentheader2 * etc * SYNOPSIS */ void RB_Generate_Sections( FILE *document_file, struct RB_Document *document ) /* * INPUTS * o document_file -- destination file. * o document -- pointer to the RB_Document structure. * SOURCE */ { unsigned long i; int depth = 1; struct RB_header *header; depth = document->first_section_level; RB_Say( "Generating Sections\n", SAY_INFO ); for ( i = 0; i < document->no_headers; ++i ) { header = ( document->headers )[i]; if ( header->parent ) { /* This will be in one of the subsections */ } else { RB_Generate_Section( document_file, header, document, depth ); } } } /******/ /****f* Generator/RB_Generate_Section * FUNCTION * Generate the documentation for a header and all * its childern. * INPUTS * o document_file -- destination file * o parent -- the parent of the header for which the documentation * is to be generated. * o document -- pointer to the RB_Document structure. * o depth -- level of sectioning ( 1 1.1 1.1.1 etc) * SYNOPSIS */ void RB_Generate_Section( FILE *document_file, struct RB_header *parent, struct RB_Document *document, int depth ) /* * NOTE * This is a recursive function. * SEE ALSO * RB_Generate_Sections * SOURCE */ { unsigned long i; struct RB_header *header; char *headername; // We pass either modulename/name or just the name if ( course_of_action.do_sectionnameonly ) { headername = parent->function_name; } else { headername = parent->name; } switch ( output_mode ) { case XMLDOCBOOK: { RB_Generate_BeginSection( document_file, depth, headername, parent ); /* Docbook output does not like the labels to be * generated before the
part */ Generate_Label( document_file, parent->unique_name ); Generate_Label( document_file, parent->name ); } break; /* lowtexx 21.09.2005 11:37 */ case LATEX: { RB_Generate_BeginSection( document_file, depth, headername, parent ); /* We have to start section before labeling in latex */ Generate_Label( document_file, parent->unique_name ); Generate_Label( document_file, parent->name ); } break; /* --- */ default: { Generate_Label( document_file, parent->unique_name ); Generate_Label( document_file, parent->name ); RB_Generate_BeginSection( document_file, depth, headername, parent ); } break; } RB_Generate_Nav_Bar( document, document_file, parent ); RB_Generate_Index_Entry( document_file, document->doctype, parent ); Generate_Header( document_file, document, parent, "dummy" ); for ( i = 0; i < document->no_headers; ++i ) { header = ( document->headers )[i]; if ( header->parent == parent ) { RB_Generate_Section( document_file, header, document, depth + 1 ); } else { /* Leeg */ } } RB_Generate_EndSection( document_file, depth, parent->name ); } /******/ /****f* Generator/RB_Generate_Part * FUNCTION * Generate the documention for all the headers found in a single * source file. * SYNOPSIS */ void RB_Generate_Part( FILE *document_file, struct RB_Document *document, struct RB_Part *part ) /* * INPUTS * * document_file -- The file were it stored. * * document -- All the documentation. * * part -- pointer to a RB_Part that contains all the headers found * in a single source file. * SOURCE */ { struct RB_header *i_header; char *docname = NULL; char *srcname = Get_Fullname( part->filename ); RB_Say( "generating documentation for file \"%s\"\n", SAY_INFO, srcname ); if ( document->actions.do_singledoc ) { docname = document->singledoc_name; } else if ( document->actions.do_multidoc ) { docname = RB_Get_FullDocname( part->filename ); } else if ( document->actions.do_singlefile ) { docname = document->singledoc_name; } else { assert( 0 ); } if ( output_mode == TROFF ) { RB_TROFF_Set_Param( document->compress, document->section ); } for ( i_header = part->headers; i_header; i_header = i_header->next ) { RB_Say( "generating documentation for header \"%s\"\n", SAY_INFO, i_header->name ); document_file = RB_Generate_Header_Start( document_file, i_header ); RB_Generate_Nav_Bar( document, document_file, i_header ); RB_Generate_Index_Entry( document_file, document->doctype, i_header ); Generate_Header( document_file, document, i_header, docname ); RB_Generate_Header_End( document_file, i_header ); } } /******/ /****f* Generator/RB_Get_DOT_Type * FUNCTION * Returns the type of the DOT file for the given output mode * SOURCE */ char *RB_Get_DOT_Type( void ) { switch ( output_mode ) { case HTML: return DOT_HTML_TYPE; break; case LATEX: return DOT_LATEX_TYPE; break; default: break; } return NULL; } /******/ /****f* Generator/RB_Generate_DOT_Image_Link * FUNCTION * Generates the image link for the created dot graphics * SOURCE */ void RB_Generate_DOT_Image_Link( FILE *f, int dot_nr, char *dot_type ) { switch ( output_mode ) { case HTML: fprintf( f, "\n", DOT_GRAPH_NAME, dot_nr, dot_type ); break; case LATEX: { char str[TEMP_BUF_SIZE]; // First we need to convert graph to PDF // (maybe the user is using pdflatex) #if defined(RB_MSVC) sprintf( str, "%s %s%d.%s", EPSTOPDF_NAME, DOT_GRAPH_NAME, dot_nr, dot_type ); #else snprintf( str, sizeof( str ), "%s %s%d.%s", EPSTOPDF_NAME, DOT_GRAPH_NAME, dot_nr, dot_type ); #endif system( str ); fprintf( f, "\\includegraphics{%s%d}\n", DOT_GRAPH_NAME, dot_nr ); } break; default: break; } } /******/ /****f* Generator/Generate_Item * SYNOPSIS */ static void Generate_Item( FILE *f, struct RB_Document *document, struct RB_header *header, struct RB_Item *cur_item, char *docname ) /* * FUNCTION * Generate the documentation for a single item. * SOURCE */ { static int dot_nr = 1; int line_nr; char *dot_type = NULL; FILE *tool = NULL; // Pipe handler to the tool we use enum ItemType item_type = cur_item->type; char *name = configuration.items.names[item_type]; Generate_Item_Name( f, item_type ); RB_Generate_Item_Begin( f, name ); for ( line_nr = 0; line_nr < cur_item->no_lines; ++line_nr ) { struct RB_Item_Line *item_line = cur_item->lines[line_nr]; char *line = item_line->line; // Plain item lines if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_PLAIN ) ) { Format_Line( f, item_line->format ); Generate_Item_Line( f, line, item_type, docname, header ); } // Last line else if ( item_line->kind == ITEM_LINE_END ) { Format_Line( f, item_line->format ); } // Normal Pipes else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_PIPE ) ) { Format_Line( f, item_line->format ); if ( item_line->pipe_mode == output_mode ) { Pipe_Line( f, line ); } } // Tool start else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_TOOL_START ) ) { Format_Line( f, item_line->format ); // Change to docdir RB_Change_To_Docdir( document ); // Open pipe to tool tool = Open_Pipe( line ); // Get back to working dir RB_Change_Back_To_CWD( ); } // Tool (or DOT) body else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_TOOL_BODY ) ) { if ( tool != NULL ) { fprintf( tool, "%s\n", line ); } } // Tool end else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_TOOL_END ) ) { // Close pipe Close_Pipe( tool ); tool = NULL; } // DOT start else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_DOT_START ) ) { Format_Line( f, item_line->format ); // Get DOT file type dot_type = RB_Get_DOT_Type( ); if ( dot_type ) { char pipe_str[TEMP_BUF_SIZE]; // Change to docdir RB_Change_To_Docdir( document ); #if defined(RB_MSVC) sprintf( pipe_str, "%s -T%s -o%s%d.%s", dot_name, dot_type, DOT_GRAPH_NAME, dot_nr, dot_type ); #else snprintf( pipe_str, sizeof( pipe_str ), "%s -T%s -o%s%d.%s", dot_name, dot_type, DOT_GRAPH_NAME, dot_nr, dot_type ); #endif tool = Open_Pipe( pipe_str ); } } // DOT end else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_DOT_END ) ) { if ( tool ) { // Close pipe Close_Pipe( tool ); tool = NULL; // Generate link to image RB_Generate_DOT_Image_Link( f, dot_nr, dot_type ); // Get back to working dir RB_Change_Back_To_CWD( ); // Increment dot file number dot_nr++; } } // DOT file include else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_DOT_FILE ) ) { Format_Line( f, item_line->format ); // Get DOT file type dot_type = RB_Get_DOT_Type( ); if ( dot_type ) { char str[TEMP_BUF_SIZE]; // Change to docdir RB_Change_To_Docdir( document ); #if defined(RB_MSVC) sprintf( str, "%s -T%s \"%s/%s\" -o%s%d.%s", dot_name, dot_type, RB_Get_Saved_CWD( ), line, DOT_GRAPH_NAME, dot_nr, dot_type ); #else snprintf( str, sizeof( str ), "%s -T%s \"%s/%s\" -o%s%d.%s", dot_name, dot_type, RB_Get_Saved_CWD( ), line, DOT_GRAPH_NAME, dot_nr, dot_type ); #endif system( str ); // Generate link to image RB_Generate_DOT_Image_Link( f, dot_nr, dot_type ); // Get back to working dir RB_Change_Back_To_CWD( ); // Increment dot file number dot_nr++; } } // Exec item else if ( !Works_Like_SourceItem( item_type ) && ( item_line->kind == ITEM_LINE_EXEC ) ) { Format_Line( f, item_line->format ); // Change to docdir RB_Change_To_Docdir( document ); // Execute line system( line ); // Get back to working dir RB_Change_Back_To_CWD( ); } // Source lines else if ( Works_Like_SourceItem( item_type ) ) { Format_Line( f, item_line->format ); Generate_Item_Line( f, line, item_type, docname, header ); } else { /* This item line is ignored */ } } RB_Generate_Item_End( f, name ); } /******/ /****f* Generator/Generate_Header * FUNCTION * Generate the documentation for all the items found in * a header except for any items specified in * configuration.ignore_items. * SYNOPSIS */ static void Generate_Header( FILE *f, struct RB_Document *document, struct RB_header *header, char *docname ) /* * INPUTS * * f -- destination file * * header -- header to be searched. * * srcname -- name of the source file the header was found in. * * document -- name of the documentation file. * BUGS * This skips the first item body if the first item name was * not correctly spelled. * SOURCE */ { struct RB_Item *cur_item; for ( cur_item = header->items; cur_item; cur_item = cur_item->next ) { enum ItemType item_type = cur_item->type; char *name = configuration.items.names[item_type]; if ( Is_Ignore_Item( name ) ) { /* User does not want this item */ } else if ( Works_Like_SourceItem( item_type ) && ( course_of_action.do_nosource ) ) { /* User does not want source items */ } else { Generate_Item( f, document, header, cur_item, docname ); } } } /******/ static void Pipe_Line( FILE *dest_doc, char *arg_line ) { char *cur_char = arg_line; for ( ; *cur_char && ( *cur_char == ' ' || *cur_char == '\t' ); cur_char++ ) { fputc( *cur_char, dest_doc ); } fprintf( dest_doc, "%s%s", cur_char, ( output_mode == RTF ? "\\line" : "\n" ) ); } static void Format_Line( FILE *dest_doc, long format ) { if ( format & RBILA_END_LIST_ITEM ) { Generate_End_List_Item( dest_doc ); } if ( format & RBILA_END_LIST ) { Generate_End_List( dest_doc ); } if ( format & RBILA_END_PRE ) { Generate_End_Preformatted( dest_doc ); } if ( format & RBILA_BEGIN_PARAGRAPH ) { Generate_Begin_Paragraph( dest_doc ); } if ( format & RBILA_END_PARAGRAPH ) { Generate_End_Paragraph( dest_doc ); } if ( format & RBILA_BEGIN_PRE ) { Generate_Begin_Preformatted( dest_doc, ( format & RBILA_BEGIN_SOURCE ) ); } if ( format & RBILA_BEGIN_LIST ) { Generate_Begin_List( dest_doc ); } if ( format & RBILA_BEGIN_LIST_ITEM ) { Generate_Begin_List_Item( dest_doc ); } } static void Generate_Begin_List_Item( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_Begin_List_Item( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_Begin_List_Item( dest_doc ); break; case HTML: HTML_Generate_Begin_List_Item( dest_doc ); break; case LATEX: LaTeX_Generate_Begin_List_Item( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_Begin_List_Item( dest_doc ); break; break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } static void Generate_End_List_Item( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_End_List_Item( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_End_List_Item( dest_doc ); break; case HTML: HTML_Generate_End_List_Item( dest_doc ); break; case LATEX: LaTeX_Generate_End_List_Item( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_End_List_Item( dest_doc ); break; break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } static void Generate_Begin_List( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_Begin_List( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_Begin_List( dest_doc ); break; case HTML: HTML_Generate_Begin_List( dest_doc ); break; case LATEX: LaTeX_Generate_Begin_List( dest_doc ); break; case RTF: case TROFF: case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /* TODO FS Document */ static void Generate_End_List( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_End_List( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_End_List( dest_doc ); break; case HTML: HTML_Generate_End_List( dest_doc ); break; case LATEX: LaTeX_Generate_End_List( dest_doc ); break; case RTF: case TROFF: case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /* TODO FS Document */ static void Generate_Begin_Preformatted( FILE *dest_doc, int source ) { switch ( output_mode ) { case TEST: TEST_Generate_Begin_Preformatted( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_Begin_Preformatted( dest_doc ); break; case HTML: HTML_Generate_Begin_Preformatted( dest_doc, source ); break; case LATEX: LaTeX_Generate_Begin_Preformatted( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_Begin_Preformatted( dest_doc ); break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /* TODO FS Document */ static void Generate_End_Preformatted( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_End_Preformatted( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_End_Preformatted( dest_doc ); break; case HTML: HTML_Generate_End_Preformatted( dest_doc ); break; case LATEX: LaTeX_Generate_End_Preformatted( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_End_Preformatted( dest_doc ); break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /* TODO FS Document */ static void Generate_End_Paragraph( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_End_Paragraph( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_End_Paragraph( dest_doc ); break; case HTML: HTML_Generate_End_Paragraph( dest_doc ); break; case LATEX: LaTeX_Generate_End_Paragraph( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_End_Paragraph( dest_doc ); break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } /* TODO FS Document */ static void Generate_Begin_Paragraph( FILE *dest_doc ) { switch ( output_mode ) { case TEST: TEST_Generate_Begin_Paragraph( dest_doc ); break; case XMLDOCBOOK: XMLDB_Generate_Begin_Paragraph( dest_doc ); break; case HTML: HTML_Generate_Begin_Paragraph( dest_doc ); break; case LATEX: LaTeX_Generate_Begin_Paragraph( dest_doc ); break; case RTF: break; case TROFF: TROFF_Generate_Begin_Paragraph( dest_doc ); break; case ASCII: break; case UNKNOWN: default: assert( 0 ); } } #if 0 /*x**f* Generator/RB_Generate_Empty_Item * FUNCTION * Generate documentation for an item with an empty body. * INPUTS * dest_doc -- destination file. **** * TODO Documentation */ static void RB_Generate_Empty_Item( FILE *dest_doc ) { switch ( output_mode ) { case TEST: break; case XMLDOCBOOK: break; case HTML: RB_HTML_Generate_Empty_Item( dest_doc ); break; case LATEX: RB_LaTeX_Generate_Empty_Item( dest_doc ); break; case RTF: RB_RTF_Generate_Empty_Item( dest_doc ); break; case TROFF: break; case ASCII: RB_ASCII_Generate_Empty_Item( dest_doc ); break; case UNKNOWN: default: assert( 0 ); } } #endif static void Generate_Item_Line( FILE *dest_doc, char *line, int item_type, char *docname, struct RB_header *fnames ) { char *cur_char = line; char *object_name = NULL; char *label_name = NULL; char *file_name = NULL; enum EIL_State { SKIP_ALPHANUM, SKIP_SPACE, SEARCH_LINK_START_WORD, SEARCH_LINK } state = SKIP_SPACE; for ( ; *cur_char; cur_char++ ) { char c = *cur_char; /* This is a little statemachine to switch searching for * links on and off. A link can be found for a word * or for a word combined with some punctuation * characters. A word is a string of alpha numeric * characters (including a '_'), say FunctionAA_10_B * All other characters are punctuation characters. * We do not want links to start in the middle of a word, * but they can start after or on a punctuation character. * So for a link can start at * Foo_bar::SnaFu * ^ ^^^ * | ||| * */ /* Move to the next state based on current character. */ switch ( state ) { case SKIP_SPACE: /* In this state we try to skip of a string of space * characters until we find something else. */ { if ( utf8_ispunct( c ) ) { /* we were in the process of skipping spaces, * but now we found a non-space character. * This might be the begin of a link, so * switch to the search link state. */ state = SEARCH_LINK; } else if ( utf8_isalnum( c ) || ( c == '_' ) ) { state = SEARCH_LINK_START_WORD; } else { /* Links can only start with a none space character, * so if the current charater is a space, we skip it. */ } break; } case SKIP_ALPHANUM: /* In this state we skipping a string of alpha * numeric charaters after that the first * character in this string did not result in a * link. */ { if ( utf8_isspace( c ) ) { /* We found the end of the string, so we go * back to the space skipping state */ state = SKIP_SPACE; } else if ( utf8_ispunct( c ) && ( c != '_' ) ) { /* We found a puntuation character, this end * the string of alpha numeric character, but * can be the begin of a new link, so we * switch to the seach link state. */ state = SEARCH_LINK; } else { /* We stay in this state */ } } break; case SEARCH_LINK_START_WORD: /* In this state we are at the start of a string * of alpha numeric characters. */ { if ( utf8_isalnum( c ) || ( c == '_' ) ) { /* We are not at the second character of * a string of alpha numeric characters, * we can stop searching for links, as a * link can only start at the begin of * such a string. */ state = SKIP_ALPHANUM; } else if ( utf8_ispunct( c ) && ( c != '_' ) ) { state = SEARCH_LINK; } else if ( utf8_isspace( c ) ) { state = SKIP_SPACE; } else { state = SKIP_SPACE; } } break; case SEARCH_LINK: { /* In this state we search for links. We stop * searching if we encounter a space because this * marks end of the word, */ if ( utf8_isalnum( c ) || ( c == '_' ) ) { /* We are at the start of a word. */ state = SEARCH_LINK_START_WORD; } else if ( utf8_isspace( c ) ) { state = SKIP_SPACE; } else { /* We stay in this state */ } } break; default: assert( 0 ); break; } if ( ( ( state == SEARCH_LINK ) || ( state == SEARCH_LINK_START_WORD ) ) && Find_Link( cur_char, &object_name, &label_name, &file_name ) ) { /* We found a link, so we can stop searching for one * for now. */ state = SKIP_SPACE; if ( object_name && fnames->no_names > 0 ) { extern char *function_name( char * ); int i; for ( i = 0; i < fnames->no_names; i++ ) if ( strcmp ( object_name, function_name( fnames->names[i] ) ) == 0 ) break; if ( i < fnames->no_names ) { RB_Generate_False_Link( dest_doc, object_name ); cur_char += strlen( object_name ) - 1; } else { Generate_Link( dest_doc, docname, file_name, label_name, object_name ); cur_char += strlen( object_name ) - 1; } } else { assert( 0 ); } } else { int res = RB_HTML_Extra( dest_doc, item_type, cur_char, ( cur_char == line ) ? 0 : *( cur_char - 1 ) ); if ( res >= 0 ) { cur_char += res; } else { /* convert from signed to unsigned */ unsigned char c2 = *cur_char; Generate_Char( dest_doc, c2 ); } } } /* TODO Move to the RTF_Generator */ switch ( output_mode ) { case RTF: fprintf( dest_doc, "\\line" ); break; case TROFF: RB_TROFF_Start_New_Line( dest_doc ); break; case HTML: // Check for source line comment endings RB_HTML_Generate_Line_Comment_End( dest_doc ); break; case TEST: case ASCII: case LATEX: case XMLDOCBOOK: case UNKNOWN: break; default: break; } /* For all modes we add a newline. */ fputc( '\n', dest_doc ); } /****f* Generator/Generate_Link * FUNCTION * Generate a link to another headers documentation. * SYNOPSIS */ void Generate_Link( FILE *dest_doc, char *docname, char *file_name, char *label_name, char *function_name ) /* * INPUTS * * dest_doc -- the output file * * docname -- the name of the output file * * file_name -- the name of the file that contains the link's body * * label_name -- the label for the link * * function_name -- the name that is shown for the link in the * documentation * SOURCE */ { switch ( output_mode ) { case TEST: RB_TEST_Generate_Link( dest_doc, docname, file_name, label_name, function_name ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Link( dest_doc, docname, file_name, label_name, function_name ); break; case HTML: RB_HTML_Generate_Link( dest_doc, docname, file_name, label_name, function_name, NULL ); break; case RTF: RB_RTF_Generate_Link( dest_doc, docname, file_name, label_name, function_name ); break; case LATEX: RB_LaTeX_Generate_String( dest_doc, function_name ); /* lowtexx 21.09.2005 11:43 */ /* generate a simple link here */ RB_LaTeX_Generate_Link( dest_doc, docname, file_name, label_name, function_name ); break; case UNKNOWN: case ASCII: case TROFF: default: fprintf( dest_doc, "%s", function_name ); } } /******/ /****f* Generator/Generate_Char * FUNCTION * Generate a single character in the current output mode. * The individual generators will make sure that special * characters are escaped. * SYNOPSIS */ void Generate_Char( FILE *dest_doc, int cur_char ) /* * INPUTS * * dest_doc -- destination file. * * cur_char -- character to be generated. ******* */ { switch ( output_mode ) { case TEST: RB_TEST_Generate_Char( dest_doc, cur_char ); break; case XMLDOCBOOK: RB_XMLDB_Generate_Char( dest_doc, cur_char ); break; case HTML: RB_HTML_Generate_Char( dest_doc, cur_char ); break; case LATEX: RB_LaTeX_Generate_Char( dest_doc, cur_char ); break; case RTF: RB_RTF_Generate_Char( dest_doc, cur_char ); break; case TROFF: RB_TROFF_Generate_Char( dest_doc, cur_char ); break; case ASCII: RB_ASCII_Generate_Char( dest_doc, cur_char ); break; case UNKNOWN: default: assert( 0 ); } } /****f* Generator/RB_Get_SubIndex_FileName * FUNCTION * Get the name of the master index file for a specific * header_type. * SYNOPSIS */ char *RB_Get_SubIndex_FileName( char *docroot, char *extension, struct RB_HeaderType *header_type ) /* * INPUTS * * docroot -- the path to the documentation directory. * * extension -- the extension for the file * * header_type -- the header type * RESULT * a pointer to a freshly allocated string. * NOTES * Has too many parameters. * SOURCE */ { size_t l; char *filename; assert( docroot ); l = strlen( docroot ); l += RB_Get_Len_Extension( extension ); l += strlen( docroot ); l += strlen( header_type->fileName ); filename = ( char * ) malloc( l + 2 ); assert( filename ); filename[0] = '\0'; strcat( filename, docroot ); strcat( filename, header_type->fileName ); RB_Add_Extension( extension, filename ); return filename; } /*****/ /****f* Generator/Generate_Index * NAME * Generate_Index -- generate index file based on xref files. * SYNOPSIS */ static void Generate_Index( struct RB_Document *document ) /* * FUNCTION * Create a master index file. It contains pointers to the * documentation generated for each source file, as well as all * "objects" found in the source files. * SOURCE */ { switch ( output_mode ) { case TEST: break; case XMLDOCBOOK: break; case HTML: RB_HTML_Generate_Index( document ); break; case LATEX: /* RB_LaTeX_Generate_Index(dest, source); */ /* Latex has a index by default */ break; case UNKNOWN: case ASCII: case TROFF: case RTF: default: break; } } /*****/