/****h* ROBODoc/Headers * FUNCTION * This module contains a set of variables that define how headers * start and how they end in various programming languages. * NOTES * Added C++/ACM header option (David White) * Enables documentation only comments (//!) to be extracted from C++ * and ACM files, rather than all comments. ****** */ #include #include #include #include #include "robodoc.h" #include "headers.h" #include "globals.h" #include "roboconfig.h" #include "util.h" /* This limits the total number of possible markers. */ /* TODO should be an enum */ #define NO_MARKER_LOCKED 100000 #define NO_MARKER 100002 static int locked_header_marker = NO_MARKER_LOCKED; static int locked_end_marker = NO_MARKER_LOCKED; static int locked_remark_marker = NO_MARKER_LOCKED; /****v* Headers/header_markers * NAME * header_markers -- strings that mark the begin of a header. * FUNCTION * These specify what robodoc recognizes as the beginning * NOTE * The numbers at the beginning of the lines make it easier * to keep them in sync with the src_constants * of a header. * SOURCE */ char *header_markers[] = { "/****", /* 0 C, C++ */ "//!****", /* 1 C++, ACM */ "//****", /* 2 C++ */ "(****", /* 3 Pascal, Modula-2, B52 */ "{****", /* 4 Pascal */ ";;!****", /* 5 Aspen Plus */ ";****", /* 6 M68K assembler */ "****", /* 7 M68K assembler */ "C ****", /* 8 Fortran */ "REM ****", /* 9 BASIC */ "%****", /* 10 LaTeX, TeX, Postscript */ "#****", /* 11 Tcl/Tk */ " ****", /* 12 COBOL */ "--****", /* 13 Occam */ "", /* 15 HTML & XML */ "--->", /* 16 HTML */ ( char * ) NULL, /* 17 GNU Assembler */ ( char * ) NULL, /* 18 FORTRAN 90 !! */ ( char * ) NULL, /* 19 FORTRAN 90 ! */ ( char * ) NULL, /* 20 VB */ ( char * ) NULL, /* 21 Aspen Plus */ ( char * ) NULL /* 22 Forth */ }; /****/ /****v* Headers/robo_end [3.0h] * NAME * robo_end[] -- the distinct robodoc end marker - * alternative to using end_markers * FUNCTION * This is an alternative to using end_markers - sometimes ROBODOC * confuses asterisks commonly used in comments as an end marker. To * use this footer instead of end_markers use the -rh switch. * NOTE * Added by David Druffner. * SOURCE */ char *robo_end[] = { "/*ROBODOC_END*", "*ROBODOC_END*", NULL }; /****/ /***f* Headers/RB_Is_Begin_Marker * FUNCTION * Scan a line and see if any of the begin-of-a-header-markers * defined in header_markers can be found. * SYNOPSIS */ int RB_Is_Begin_Marker( char *cur_line, char **type ) /* * INPUTS * cur_line -- line to be searched. * OUTPUT * type -- the kind of header * RESULT * TRUE -- a begin header was found * FALSE -- no begin header was found. * SOURCE */ { int found = FALSE; unsigned int marker = NO_MARKER; /* for the assert */ char *cur_mchar = NULL; char *cur_char = NULL; if ( !( course_of_action.do_robo_head ) && ( ( ( course_of_action.do_lockheader ) && ( locked_header_marker == NO_MARKER_LOCKED ) ) || !( course_of_action.do_lockheader ) ) ) { for ( marker = 0; ( marker < configuration.header_markers.number ) && !found; marker++ ) { cur_mchar = configuration.header_markers.names[marker]; for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line ); *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) { if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) found = FALSE; } if ( *cur_mchar != '\0' ) { /* It is not a complete match */ found = FALSE; } } } else if ( ( course_of_action.do_lockheader ) && ( locked_header_marker != NO_MARKER_LOCKED ) ) { cur_mchar = configuration.header_markers.names[locked_header_marker]; for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line ); *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) { if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) { found = FALSE; } if ( *cur_mchar != '\0' ) { /* It is not a complete match */ found = FALSE; } } } else { assert( 0 ); } if ( found && cur_char ) { *type = cur_char; ++cur_char; if ( *cur_char == '*' ) { ++cur_char; found = utf8_isspace( *cur_char ); } else if ( *( cur_char + 1 ) == '*' ) { ++cur_char; ++cur_char; found = utf8_isspace( *cur_char ); } else { found = FALSE; } if ( found ) { found = FALSE; /* It should contain some non * characters. */ for ( ; *cur_char; ++cur_char ) { if ( utf8_isalnum( *cur_char ) ) { found = TRUE; } } } } if ( found && ( course_of_action.do_lockheader ) && ( locked_header_marker == NO_MARKER_LOCKED ) ) { assert( marker != NO_MARKER ); locked_header_marker = marker - 1; RB_Say( "header marker locked on %s\n", SAY_INFO, configuration.header_markers.names[locked_header_marker] ); } return found; } /******/ /* Generic function to skip a remark begin or end marker */ static char *RB_Skip_Remark_XXX_Marker( char *cur_line, struct Parameters *parameters ) { char *cur_char; char *space_pos; unsigned int marker; int found = FALSE; cur_char = RB_Skip_Whitespace( cur_line ); space_pos = strchr( cur_char, ' ' ); /* Replace the first space on the line with a '\0' * this makes the comparison with the remark markers * much easier. */ if ( space_pos ) { *space_pos = '\0'; } for ( marker = 0; ( marker < parameters->number ) && !found; marker++ ) { found = ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 ); } assert( found ); if ( space_pos ) { *space_pos = ' '; return space_pos; } else { return cur_char + strlen( parameters->names[marker - 1] ); } } /* Generic function to see if there is a remark begin or end marker */ static int RB_Is_Remark_XXX_Marker( char *cur_line, struct Parameters *parameters ) { char *cur_char; char *space_pos; unsigned int marker; int found = FALSE; cur_char = RB_Skip_Whitespace( cur_line ); space_pos = strchr( cur_char, ' ' ); /* Replace the first space on the line with a '\0' * this makes the comparison with the remark markers * much easier. */ if ( space_pos ) { *space_pos = '\0'; } for ( marker = 0; ( marker < parameters->number ) && !found; marker++ ) { found = ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 ); } if ( space_pos ) { *space_pos = ' '; } return found; } /* TODO Documentation */ int RB_Is_Remark_End_Marker( char *cur_line ) { return RB_Is_Remark_XXX_Marker( cur_line, &( configuration.remark_end_markers ) ); } /* TODO Documentation */ int RB_Is_Remark_Begin_Marker( char *cur_line ) { return RB_Is_Remark_XXX_Marker( cur_line, &( configuration.remark_begin_markers ) ); } char *RB_Skip_Remark_Begin_Marker( char *cur_line ) { return RB_Skip_Remark_XXX_Marker( cur_line, &( configuration. remark_begin_markers ) ); } char *RB_Skip_Remark_End_Marker( char *cur_line ) { return RB_Skip_Remark_XXX_Marker( cur_line, &( configuration.remark_end_markers ) ); } /****f* Headers/RB_Is_End_Marker * FUNCTION * Scan a line and see if any of the end of a header markers * defined in header_markers can be found. * SYNOPSIS */ int RB_Is_End_Marker( char *cur_line ) /* * INPUTS * cur_line -- line to be searched. * OUTPUT * none * RESULT * TRUE -- an end header was found * FALSE -- none was found. * SOURCE */ { int found = FALSE; unsigned int marker = NO_MARKER; /* For the assert */ char *cur_mchar; char *cur_char; if ( !( course_of_action.do_robo_head ) && ( ( ( course_of_action.do_lockheader ) && ( locked_end_marker == NO_MARKER_LOCKED ) ) || !( course_of_action.do_lockheader ) ) ) { for ( marker = 0; ( marker < configuration.end_markers.number ) && !found; marker++ ) { cur_mchar = configuration.end_markers.names[marker]; cur_char = RB_Skip_Whitespace( cur_line ); if ( *cur_char ) { for ( found = TRUE; *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) { if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) { found = FALSE; } } } } } else if ( ( course_of_action.do_lockheader ) && ( locked_end_marker != NO_MARKER_LOCKED ) ) { cur_mchar = configuration.end_markers.names[locked_end_marker]; cur_char = RB_Skip_Whitespace( cur_line ); if ( *cur_char ) { for ( found = TRUE; *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) { if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) { found = FALSE; } } } } else { assert( 0 ); } /* Locking on end markers does not work at the moment, * because there can be more than one end marker for * a given language. TODO */ #if 0 if ( found && ( course_of_action.do_LOCKHEADER ) && ( locked_end_marker == NO_MARKER_LOCKED ) ) { assert( marker != NO_MARKER ); locked_end_marker = marker - 1; RB_Say( "end marker locked on %s\n", SAY_INFO, end_markers[locked_end_marker] ); } #endif return found; } /*****/ /****f* Headers/RB_Has_Remark_Marker * FUNCTION * Check if a line starts with a remark marker. This function * assumes that the remark marker starts on the first character of * the line. * SYNOPSIS */ int RB_Has_Remark_Marker( char *lline_buffer ) /* * INPUTS * o lline_buffer -- the line of text. * RESULT * o TRUE -- it starts with a remark marker * o FALSE -- it does not. * SOURCE */ { unsigned int marker = 0; unsigned int marker_found = configuration.remark_markers.number; int found = FALSE; char *space_pos = NULL; space_pos = strchr( lline_buffer, ' ' ); /* Replace the first space on the line with a '\0' * this makes the comparison with the remark markers * much easier. */ if ( space_pos ) { *space_pos = '\0'; } if ( ( ( course_of_action.do_lockheader ) && ( locked_remark_marker == NO_MARKER_LOCKED ) ) || !( course_of_action.do_lockheader ) ) { for ( marker = 0; marker < configuration.remark_markers.number; marker++ ) { if ( RB_Str_Case_Cmp ( lline_buffer, configuration.remark_markers.names[marker] ) == 0 ) { marker_found = marker; found = TRUE; } } } else { if ( RB_Str_Case_Cmp ( lline_buffer, configuration.remark_markers.names[locked_remark_marker] ) == 0 ) { marker_found = marker; found = TRUE; } } if ( found && ( locked_remark_marker == NO_MARKER_LOCKED ) && ( course_of_action.do_lockheader ) ) { assert( marker_found < configuration.remark_markers.number ); locked_remark_marker = marker_found; RB_Say( "remark marker locked on %s\n", SAY_INFO, configuration.remark_markers.names[locked_remark_marker] ); } /* Restore the space we replaced with a '\0' */ if ( space_pos ) { *space_pos = ' '; } return found; } /******/ /****f* Headers/RB_Skip_Remark_Marker [2.0e] * NAME * RB_Skip_Remark_Marker * SYNOPSIS */ char *RB_Skip_Remark_Marker( char *lline_buffer ) /* * FUNCTION * Scan and search for a recognized remark marker; skip past the * marker to the body of the text * SOURCE */ { unsigned int marker, found; char *cur_char, *cur_mchar; found = FALSE; cur_char = NULL; for ( marker = 0; ( marker < configuration.remark_markers.number ) && !found; marker++ ) { cur_mchar = configuration.remark_markers.names[marker]; for ( found = TRUE, cur_char = lline_buffer; *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) { if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) { found = FALSE; } } } return ( cur_char ); } /**************/ /* TODO Documentation */ void RB_Header_Lock_Reset( void ) { locked_header_marker = NO_MARKER_LOCKED; locked_end_marker = NO_MARKER_LOCKED; } void RB_Item_Lock_Reset( void ) { locked_remark_marker = NO_MARKER_LOCKED; }