2 Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen,
3 Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
4 Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
6 This file is part of ROBODoc
8 ROBODoc is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 /****h* ROBODoc/Analyser
27 * Analyser -- Functions to scan source and collect headers
29 * This module provides the functions to scan a sourcefile and
30 * collect all the headers.
33 * $Id: analyser.c,v 1.73 2007/07/10 19:13:51 gumpu Exp $
46 #include "headertypes.h"
54 #include "roboconfig.h"
61 struct RB_Document *document,
62 struct RB_header *header );
63 static int Find_Header_Name(
66 static struct RB_header *Grab_Header(
68 struct RB_Document *arg_document );
69 static char *Function_Name(
71 static char *Module_Name(
73 static int Find_End_Marker(
75 struct RB_header *new_header );
76 struct RB_HeaderType *AnalyseHeaderType(
79 static struct RB_HeaderType *RB_Find_Marker(
82 int reuse_previous_line );
83 static int Analyse_Items(
84 struct RB_header *arg_header );
85 static int Is_ListItem_Start(
89 /****f* Analyser/Is_Pipe_Marker
93 * Check for "pipe" markers e.g. "|html ".
96 static char *Is_Pipe_Marker(
101 * Pointer to the data to be piped to document or in case no pointers
108 char *s = cur_char + 1;
111 if ( *cur_char == '|' && *s )
113 if ( strncmp( "html ", s, 5 ) == 0 )
118 else if ( strncmp( "latex ", s, 6 ) == 0 )
123 else if ( strncmp( "rtf ", s, 4 ) == 0 )
128 else if ( strncmp( "dbxml ", s, 6 ) == 0 )
130 *pipe_mode = XMLDOCBOOK;
133 else if ( strncmp( "ascii ", s, 6 ) == 0 )
140 return ( char * ) NULL;
146 /****f* Analyser/Is_Tool
149 static char *Is_Tool(
151 enum ItemLineKind *itemkind,
155 * Checks for tool start and end markers
159 char *s = cur_char + 1;
161 if ( *cur_char == '|' && *s )
163 // Check if tool starts or ends
164 if ( !strncmp( "tool ", s, 5 ) )
168 *itemkind = ITEM_LINE_TOOL_END;
173 *itemkind = ITEM_LINE_TOOL_START;
179 // Check if DOT starts or ends
180 if ( !strncmp( "dot ", s, 4 ) )
184 *itemkind = ITEM_LINE_DOT_END;
189 *itemkind = ITEM_LINE_DOT_START;
195 // Check for DOT file includes
196 else if ( !strncmp( "dotfile ", s, 8 ) && !*tool_active )
198 *itemkind = ITEM_LINE_DOT_FILE;
201 // Check for exec items
202 else if ( !strncmp( "exec ", s, 5 ) && !*tool_active )
204 *itemkind = ITEM_LINE_EXEC;
214 /****f* Analyser/RB_Analyse_Document
217 * Scan all the sourcefiles of all parts of a document for
218 * headers. Store these headers in each part (RB_Part).
221 void RB_Analyse_Document(
222 struct RB_Document *arg_document )
225 * o document -- document to be analysed.
227 * Each part will contain the headers that were found in the
228 * sourcefile of the part.
232 struct RB_Part *a_part;
233 struct RB_Filename *a_filename;
236 for ( a_part = arg_document->parts; a_part; a_part = a_part->next )
238 struct RB_header *new_header = NULL;
240 a_filename = a_part->filename;
241 RB_Say( "analysing %s\n", SAY_DEBUG, Get_Fullname( a_filename ) );
242 RB_SetCurrentFile( Get_Fullname( a_filename ) );
244 RB_Header_Lock_Reset( );
245 filehandle = RB_Open_Source( a_part );
248 for ( new_header = Grab_Header( filehandle, arg_document );
250 new_header = Grab_Header( filehandle, arg_document ) )
252 if ( ToBeAdded( arg_document, new_header ) )
254 /* The Add is required before the
255 * Analyse because Add sets the owner of the header
256 * which is needed for error messages.
258 RB_Part_Add_Header( a_part, new_header );
259 Analyse_Items( new_header );
263 RB_Free_Header( new_header );
266 fclose( filehandle );
273 /****f* Analyser/Check_Header_Start
275 * Sometimes a user makes a spelling mistake in the name of the first item.
276 * ROBODoc then ignores all the lines leading up to the second item,
277 * (which is the first item ROBODoc recognized). This function
278 * checks for this condition and gives the user a warning.
281 static void Check_Header_Start(
282 struct RB_header *arg_header,
286 * * arg_header -- the header to be checked.
287 * * first -- the line on which the first item was found
289 * A warning is given if the condition occured.
297 for ( i = 0; i < first_item; ++i )
299 char *c = arg_header->lines[i];
301 c = RB_Skip_Whitespace( c );
302 if ( RB_Has_Remark_Marker( c ) )
304 c = RB_Skip_Remark_Marker( c );
307 if ( !utf8_isspace( *c ) )
309 RB_Warning_Full( Get_Fullname
310 ( arg_header->owner->filename ),
311 arg_header->line_number,
312 "Header \"%s\" contains text before the fist item, "
313 "this might be caused by a misspelled item name.\n",
326 /****f* Analyser/Is_Empty_Line
328 * Check if line is empty. This assumes that
329 * Copy_Lines_To_Item has been run on the item.
332 static int Is_Empty_Line(
336 * * line -- the string to be analysed.
340 line = RB_Skip_Whitespace( line );
341 return ( *line == '\0' );
347 /****f* Analyser/Get_Indent
349 * Determine the indentation of a line by counting
350 * the number of spaces at the begining of the line.
353 static int Get_Indent(
365 for ( i = 0; line[i] && utf8_isspace( line[i] ); ++i )
375 /****f* Analyser/Is_ListItem_Start
377 * Test if a line starts with something that indicates a list item.
378 * List items start with '*', '-', or 'o'.
381 static int Is_ListItem_Start(
388 * * TRUE -- it did start with one of those characters
389 * * FALSE -- it did not.
394 int cur_indent = Get_Indent( arg_line );
396 if ( cur_indent == arg_indent )
398 /* TODO Think there is a function for this */
399 for ( ; *c && utf8_isspace( *c ); ++c )
403 if ( *c && ( strlen( c ) >= 3 ) )
405 if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) )
413 /* The line is indented so it must be
414 * the start of a pre block */
423 /****f* Analyser/Is_List_Item_Continuation
425 * Is it like the second line in something like:
426 * * this is a list item
430 static int Is_List_Item_Continuation(
435 * * arg_line -- the current line
436 * * indent -- the indent of the current item.
439 * * FALSE -- it is not.
443 int this_indent = Get_Indent( arg_line );
445 return ( this_indent > indent );
452 /****f* Analyser/Is_End_of_List
461 static int Is_End_of_List(
465 int this_indent = Get_Indent( arg_line );
467 return ( this_indent <= indent );
474 /****f* Analyser/Is_Start_List
483 static int Is_Start_List(
487 int this_indent = Get_Indent( arg_line );
488 char *c = strrchr( arg_line, ':' );
490 if ( ( this_indent == indent ) && c )
494 if ( !utf8_isspace( *c ) )
507 /****f* Analyser/Remove_List_Char
511 * * arg_item -- the item to be analysed.
516 static void Remove_List_Char(
517 struct RB_Item *arg_item,
520 char *c = arg_item->lines[start_index]->line;
522 for ( ; *c && utf8_isspace( *c ); ++c )
525 if ( *c && ( strlen( c ) >= 3 ) )
527 if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) )
529 char *temp = arg_item->lines[start_index]->line;
532 arg_item->lines[start_index]->line = RB_StrDup( temp + 2 );
540 /****f* Analyser/Analyse_ListBody
545 static int Analyse_ListBody(
546 struct RB_Item *arg_item,
551 * * arg_item -- the item to be analysed.
559 for ( ; i < arg_item->no_lines; i++ )
561 char *line = arg_item->lines[i]->line;
563 if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) ||
564 ( arg_item->lines[i]->kind == ITEM_LINE_END ) )
566 if ( Is_ListItem_Start( line, arg_indent ) )
568 arg_item->lines[i]->format |= RBILA_END_LIST_ITEM;
569 arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
570 Remove_List_Char( arg_item, i );
572 else if ( Is_List_Item_Continuation( line, arg_indent ) )
578 /* Must be the end of the list */
579 arg_item->lines[i]->format |= RBILA_END_LIST_ITEM;
580 arg_item->lines[i]->format |= RBILA_END_LIST;
590 /****f* Analyser/Analyse_List
592 * Parse the item text to see if there are any lists.
593 * A list is either case I:
598 * some text: <-- begin of a list
599 * o bla bla <-- list item
600 * bla bla bla <-- continuation of list item.
601 * o bla bla <-- list item
603 * bla bla <-- this can also be the end of a list.
606 static void Analyse_List(
607 struct RB_Item *arg_item,
611 * * arg_item -- the item to be parsed.
612 * * indent -- the indent of this item.
614 * * arg_item -- the itemlines will contain formatting information
615 * for all the lists that were found.
619 if ( arg_item->no_lines >= 1 )
622 char *line = arg_item->lines[i]->line;
625 if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
626 Is_ListItem_Start( line, indent ) )
628 /* Case I, the is a list item right after the item name */
629 arg_item->lines[i]->format |= RBILA_BEGIN_LIST;
630 arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
631 Remove_List_Char( arg_item, i );
632 /* Now try to find the end of the list */
633 i = Analyse_ListBody( arg_item, 1, indent );
636 /* Now search for case II cases */
637 for ( ; i < arg_item->no_lines; i++ )
639 line = arg_item->lines[i]->line;
640 if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
641 Is_Start_List( line, indent ) )
644 if ( i < arg_item->no_lines )
646 line = arg_item->lines[i]->line;
647 if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) &&
648 Is_ListItem_Start( line, indent ) )
650 arg_item->lines[i]->format |= RBILA_BEGIN_LIST;
651 arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM;
652 Remove_List_Char( arg_item, i );
654 i = Analyse_ListBody( arg_item, i, indent );
657 /* One list might be immediately followed
658 * by another. In this case we have to
659 * analyse the last line again. */
660 line = arg_item->lines[i]->line;
661 if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN )
662 && Is_Start_List( line, indent ) )
676 // If (unused(this_function)) { delete(this_function) }
678 /****f* Analyser/Dump_Item
680 * Print debug information.
682 static void Dump_Item(
683 struct RB_Item *arg_item )
686 * * arg_item -- the item to be pretty-printed.
692 /* preformatted blocks */
693 for ( i = 0; i < arg_item->no_lines; i++ )
695 char *line = arg_item->lines[i]->line;
696 int format = arg_item->lines[i]->format;
698 printf( "%04d ", i );
699 printf( ( format & RBILA_END_PARAGRAPH ) ? "p" : " " );
700 printf( ( format & RBILA_BEGIN_PARAGRAPH ) ? "P" : " " );
701 printf( ( format & RBILA_END_PRE ) ? "e" : " " );
702 printf( ( format & RBILA_BEGIN_PRE ) ? "E" : " " );
703 printf( ( format & RBILA_END_LIST ) ? "l" : " " );
704 printf( ( format & RBILA_BEGIN_LIST ) ? "L" : " " );
705 printf( ( format & RBILA_END_LIST_ITEM ) ? "i" : " " );
706 printf( ( format & RBILA_BEGIN_LIST_ITEM ) ? "I" : " " );
707 printf( " (%s)\n", line );
714 /****f* Analyser/Preformat_All
719 static void Preformat_All(
720 struct RB_Item *arg_item,
724 * * arg_item -- the item to be pre-formatted.
725 * * source -- is it a source item ?
730 int preformatted = FALSE;
733 if ( arg_item->no_lines > 0 )
736 /* Skip any pipe stuff */
738 ( i < arg_item->no_lines )
739 && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
744 line = arg_item->lines[i]->line;
745 if ( ( arg_item->lines[i]->kind == ITEM_LINE_RAW ) ||
746 ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) )
748 arg_item->lines[i]->format |=
749 RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 );
752 for ( ++i; i < arg_item->no_lines; i++ )
754 if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE )
756 /* Temporarily end the preformatting to allow
757 * the piping to happen
759 arg_item->lines[i]->format |=
760 RBILA_END_PRE | ( source ? RBILA_END_SOURCE : 0 );
761 /* Find the end of the pipe stuff */
762 for ( ; ( i < arg_item->no_lines ) &&
763 ( arg_item->lines[i]->kind == ITEM_LINE_PIPE );
767 /* Every item ends with an ITEM_LINE_END, so: */
768 assert( i < arg_item->no_lines );
769 /* And re-enable preformatting */
770 arg_item->lines[i]->format |=
771 RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 );
774 if ( arg_item->lines[i]->kind == ITEM_LINE_END )
776 /* If the last line ends with a begin_pre remove
777 * it, otherwise a begin and end pre will be
778 * generated, in the wrong order, on the same line in the output.
780 if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) {
781 arg_item->lines[i]->format &= ~( RBILA_BEGIN_PRE );
783 arg_item->lines[i]->format |= RBILA_END_PRE;
785 arg_item->lines[i]->format |= ( source ? RBILA_END_SOURCE : 0 );
805 /****f* Analyser/Analyse_Preformatted
807 * Analyse preformatted text ... (TODO)
810 static void Analyse_Preformatted(
811 struct RB_Item *arg_item,
815 * * arg_item -- the item to be analysed.
823 int preformatted = FALSE;
826 /* preformatted blocks */
827 if ( arg_item->no_lines > 0 )
830 /* Skip any pipe stuff */
832 ( i < arg_item->no_lines )
833 && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
838 line = arg_item->lines[i]->line;
841 && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) )
845 if ( ( in_list ) && ( arg_item->lines[i]->format & RBILA_END_LIST ) )
850 for ( ++i; i < arg_item->no_lines; i++ )
852 if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE )
856 arg_item->lines[i]->format |= RBILA_END_PRE;
858 for ( ; ( i < arg_item->no_lines ) &&
859 ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
862 /* Every item ends with an ITEM_LINE_END, so: */
863 assert( i < arg_item->no_lines );
866 arg_item->lines[i]->format |= RBILA_BEGIN_PRE;
870 line = arg_item->lines[i]->line;
871 new_indent = Get_Indent( line );
874 && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) )
879 && ( arg_item->lines[i]->format & RBILA_END_LIST ) )
886 if ( ( new_indent > indent ) && !preformatted )
889 arg_item->lines[i]->format |= RBILA_BEGIN_PRE;
891 else if ( ( new_indent <= indent ) && preformatted )
893 preformatted = FALSE;
894 arg_item->lines[i]->format |= RBILA_END_PRE;
903 /* We are in a list, do nothing */
911 /****f* Analyser/Analyse_Paragraphs
913 * Analyse paragraphs... (TODO)
916 static void Analyse_Paragraphs(
917 struct RB_Item *arg_item )
920 * * arg_item -- the item to be analysed.
928 int is_empty = FALSE;
929 int prev_is_empty = FALSE;
932 ( i < arg_item->no_lines )
933 && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i )
937 assert( i < arg_item->no_lines );
939 if ( ( arg_item->lines[i]->format == 0 ) )
941 arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH;
944 for ( ; i < arg_item->no_lines; i++ )
946 char *line = arg_item->lines[i]->line;
948 prev_is_empty = is_empty;
949 is_empty = Is_Empty_Line( line );
950 if ( arg_item->lines[i]->format & RBILA_BEGIN_LIST )
954 if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE )
958 if ( arg_item->lines[i]->format & RBILA_END_LIST )
962 if ( arg_item->lines[i]->format & RBILA_END_PRE )
968 if ( ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) ||
969 ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) ||
973 arg_item->lines[i]->format |= RBILA_END_PARAGRAPH;
978 if ( ( arg_item->lines[i]->format & RBILA_END_LIST ) ||
979 ( arg_item->lines[i]->format & RBILA_END_PRE ) ||
980 ( !is_empty && prev_is_empty && !in_list && !in_pre ) )
983 arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH;
989 arg_item->lines[arg_item->no_lines - 1]->format |=
997 /****f* Analyser/Analyse_Indentation
999 * Figure out how text is indented.
1002 static int Analyse_Indentation(
1003 struct RB_Item *arg_item )
1006 * * arg_item -- the item to be analysed.
1013 assert( arg_item->no_lines > 0 );
1015 for ( i = 0; i < arg_item->no_lines; ++i )
1017 if ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN )
1019 char *line = arg_item->lines[i]->line;
1021 if ( Is_Empty_Line( line ) )
1028 indent = Get_Indent( line );
1033 assert( indent >= 0 );
1039 /****f* Analyser/Analyse_Item_Format
1041 * Try to determine the formatting of an item.
1042 * An empty line generates a new paragraph
1043 * Things that are indented more that the rest of the text
1045 * Things that start with a '*' or '-' create list items
1046 * unless they are indented more that the rest of the text.
1049 static void Analyse_Item_Format(
1050 struct RB_Item *arg_item )
1053 * * arg_item -- the item to be analysed.
1057 // If item is not empty
1058 if ( arg_item->no_lines )
1060 // If it is a SOURCE item
1061 if ( Works_Like_SourceItem( arg_item->type ) )
1063 // Preformat it like a SOURCE item
1064 Preformat_All( arg_item, TRUE );
1066 // Check if we have to analyse this item
1067 else if ( ( course_of_action.do_nopre
1068 || Is_Format_Item( arg_item->type ) )
1069 && !Is_Preformatted_Item( arg_item->type ) )
1072 int indent = Analyse_Indentation( arg_item );
1074 Analyse_List( arg_item, indent );
1075 Analyse_Preformatted( arg_item, indent );
1076 Analyse_Paragraphs( arg_item );
1078 // If none of above, preformat item
1082 Preformat_All( arg_item, FALSE );
1096 static int Trim_Empty_Item_Begin_Lines(
1097 struct RB_header *arg_header,
1098 struct RB_Item *arg_item,
1104 if ( Works_Like_SourceItem( arg_item->type ) )
1106 /* We skip the first line after the source item, if
1107 * it an remark end marker -- such as '*)'
1109 c = arg_header->lines[current_index];
1110 if ( RB_Is_Remark_End_Marker( c ) )
1112 c = RB_Skip_Remark_End_Marker( c );
1113 c = RB_Skip_Whitespace( c );
1116 c = arg_header->lines[current_index];
1117 RB_Warning( "text following a remark end marker:\n%s\n", c );
1123 if ( current_index > arg_item->end_index )
1131 c = arg_header->lines[current_index];
1132 c = RB_Skip_Whitespace( c );
1133 if ( RB_Has_Remark_Marker( c ) )
1135 c = RB_Skip_Remark_Marker( c );
1137 c = RB_Skip_Whitespace( c );
1143 while ( ( *c == '\0' ) && ( current_index < arg_item->end_index ) );
1146 return current_index;
1151 static int Trim_Empty_Item_End_Lines(
1152 struct RB_header *arg_header,
1153 struct RB_Item *arg_item,
1158 if ( Works_Like_SourceItem( arg_item->type ) )
1160 c = arg_header->lines[current_index];
1161 if ( RB_Is_Remark_Begin_Marker( c ) )
1163 c = RB_Skip_Remark_Begin_Marker( c );
1164 c = RB_Skip_Whitespace( c );
1167 c = arg_header->lines[current_index];
1168 RB_Warning( "text following a remark begin marker:\n%s\n",
1177 c = arg_header->lines[current_index];
1178 c = RB_Skip_Whitespace( c );
1179 if ( RB_Has_Remark_Marker( c ) )
1181 c = RB_Skip_Remark_Marker( c );
1183 c = RB_Skip_Whitespace( c );
1189 while ( ( *c == '\0' ) && ( current_index > arg_item->begin_index ) );
1191 return current_index;
1196 static void Trim_Empty_Item_Lines(
1197 struct RB_header *arg_header,
1198 struct RB_Item *arg_item )
1200 arg_item->no_lines = arg_item->end_index - arg_item->begin_index + 1;
1201 if ( arg_item->no_lines <= 1 )
1204 arg_item->no_lines = 0;
1210 /* trim all empty lines at the begin of an item */
1212 /* we skip the first line because that contains the item name.
1214 current_index = arg_item->begin_index + 1;
1216 Trim_Empty_Item_Begin_Lines( arg_header, arg_item,
1219 /* Is there anything left? */
1220 if ( current_index <= arg_item->end_index )
1222 arg_item->begin_index = current_index;
1224 /* trim all the empty lines at the end of an item */
1225 current_index = arg_item->end_index;
1227 Trim_Empty_Item_End_Lines( arg_header, arg_item,
1229 if ( current_index >= arg_item->begin_index )
1231 arg_item->end_index = current_index;
1232 arg_item->no_lines =
1233 arg_item->end_index - arg_item->begin_index + 1;
1238 arg_item->no_lines = 0;
1244 arg_item->no_lines = 0;
1252 /* TODO This routine is way too long */
1254 static void Copy_Lines_To_Item(
1255 struct RB_header *arg_header,
1256 struct RB_Item *arg_item )
1259 printf( "%d\n%d\n%s\n%s\n",
1260 arg_item->begin_index,
1261 arg_item->end_index,
1262 arg_header->lines[arg_item->begin_index],
1263 arg_header->lines[arg_item->end_index] );
1266 Trim_Empty_Item_Lines( arg_header, arg_item );
1268 if ( arg_item->no_lines > 0 )
1272 struct RB_Item_Line *itemline = NULL;
1273 int tool_active = 0; // Shows wether we are inside a tool body
1275 /* Allocate enough memory for all the lines, plus one
1278 ++arg_item->no_lines;
1280 calloc( arg_item->no_lines, sizeof( struct RB_Item_Line * ) );
1281 if ( !arg_item->lines )
1283 RB_Panic( "Out of memory! %s\n", "Copy_Lines_To_Item" );
1286 /* And create an RB_Item_Line for each of them, and add
1287 * those to the RB_Item
1289 for ( i = 0; i < arg_item->no_lines - 1; ++i )
1292 arg_header->lines[arg_item->begin_index + i];
1293 /* TODO should be a Create_ItemLine() */
1294 itemline = malloc( sizeof( struct RB_Item_Line ) );
1297 RB_Panic( "Out of memory! %s (2)\n", "Copy_Lines_To_Item" );
1301 c = RB_Skip_Whitespace( c );
1302 // Lines with remark marker
1303 if ( RB_Has_Remark_Marker( c )
1304 && !Works_Like_SourceItem( arg_item->type ) )
1308 enum ItemLineKind item_kind;
1310 c = RB_Skip_Remark_Marker( c );
1311 c2 = RB_Skip_Whitespace( c );
1314 // Check wether a tool starts or ends
1315 if ( ( c3 = Is_Tool( c2, &item_kind, &tool_active ) ) )
1317 itemline->kind = item_kind;
1320 // If we have an active tool, copy the body lines
1321 else if ( tool_active )
1323 itemline->kind = ITEM_LINE_TOOL_BODY;
1324 c++; // Skip space after the remark marker
1327 else if ( ( c3 = Is_Pipe_Marker( c2, &pipe_mode ) ) )
1329 itemline->kind = ITEM_LINE_PIPE;
1330 itemline->pipe_mode = pipe_mode;
1336 itemline->kind = ITEM_LINE_PLAIN;
1339 // Empty lines with remark markers and active tool
1340 else if ( tool_active )
1342 itemline->kind = ITEM_LINE_TOOL_BODY;
1344 // Plain empty lines with remark markers...
1347 itemline->kind = ITEM_LINE_PLAIN;
1352 itemline->kind = ITEM_LINE_RAW;
1353 /* The is raw code, so we do not want to have the
1354 * whitespace stripped of
1356 c = arg_header->lines[arg_item->begin_index + i];
1360 if ( ( !Works_Like_SourceItem( arg_item->type ) &&
1361 ( itemline->kind != ITEM_LINE_RAW ) ) ||
1362 Works_Like_SourceItem( arg_item->type ) )
1364 itemline->line = RB_StrDup( c );
1365 itemline->format = 0;
1366 arg_item->lines[j] = itemline;
1371 /* We dump the RAW item lines if we are not in a
1380 /* And one empty line to mark the end of an item and
1381 * to be able to store some additional formatting actions
1383 itemline = malloc( sizeof( struct RB_Item_Line ) );
1386 RB_Panic( "Out of memory! %s (3)\n", "Copy_Lines_To_Item" );
1389 itemline->kind = ITEM_LINE_END;
1390 itemline->line = RB_StrDup( "" );
1391 itemline->format = 0;
1392 arg_item->lines[j] = itemline;
1394 /* Store the real number of lines we copied */
1395 assert( arg_item->no_lines >= ( j + 1 ) );
1396 arg_item->no_lines = j + 1;
1400 arg_item->no_lines = 0;
1401 free( arg_item->lines );
1402 arg_item->lines = NULL;
1407 arg_item->no_lines = 0;
1408 arg_item->lines = NULL;
1413 /****f* Analyser/RB_Analyse_Items
1415 * Locate the items in the header and create RB_Item structures for
1419 static int Analyse_Items(
1420 struct RB_header *arg_header )
1426 enum ItemType item_type = NO_ITEM;
1427 struct RB_Item *new_item;
1428 struct RB_Item *cur_item;
1430 RB_Item_Lock_Reset( );
1432 /* find the first item */
1433 for ( line_nr = 0; line_nr < arg_header->no_lines; ++line_nr )
1435 item_type = RB_Is_ItemName( arg_header->lines[line_nr] );
1436 if ( item_type != NO_ITEM )
1442 /* and all the others */
1443 while ( ( item_type != NO_ITEM ) && ( line_nr < arg_header->no_lines ) )
1445 new_item = RB_Create_Item( item_type );
1446 new_item->begin_index = line_nr;
1448 /* Add the item to the end of the list of items. */
1449 if ( arg_header->items )
1451 for ( cur_item = arg_header->items; cur_item->next;
1452 cur_item = cur_item->next )
1456 cur_item->next = new_item;
1460 arg_header->items = new_item;
1462 /* Find the next item */
1463 for ( ++line_nr; line_nr < arg_header->no_lines; ++line_nr )
1465 item_type = RB_Is_ItemName( arg_header->lines[line_nr] );
1466 if ( item_type != NO_ITEM )
1472 /* This points to the last line in the item */
1473 new_item->end_index = line_nr - 1;
1475 assert( new_item->end_index >= new_item->begin_index );
1477 /* Now analyse and copy the lines */
1478 Copy_Lines_To_Item( arg_header, new_item );
1479 Analyse_Item_Format( new_item );
1480 /* Handy for debugging wiki formatting
1481 * Dump_Item( new_item );
1492 /****f* Analyser/ToBeAdded
1494 * Test whether or not a header needs to be added to the
1495 * list of headers. This implements the options
1501 static int ToBeAdded(
1502 struct RB_Document *document,
1503 struct RB_header *header )
1506 * o document -- a document (to determine the options)
1507 * o header -- a header
1509 * TRUE -- Add header
1510 * FALSE -- Don't add header
1516 if ( header->is_internal )
1518 if ( ( document->actions.do_include_internal ) ||
1519 ( document->actions.do_internal_only ) )
1530 if ( document->actions.do_internal_only )
1546 /****f* Analyser/Grab_Header
1548 * Grab a header from a source file, that is scan a source file
1549 * until the start of a header is found. Then search for the end
1550 * of a header and store all the lines in between.
1553 static struct RB_header *Grab_Header(
1555 struct RB_Document *arg_document )
1558 * o sourcehandle -- an opened source file.
1560 * o sourcehandle -- will point to the line following the end marker.
1562 * 0 if no header was found, or a pointer to a new header otherwise.
1566 struct RB_header *new_header = NULL;
1567 int is_internal = 0;
1568 struct RB_HeaderType *header_type = NULL;
1569 int good_header = FALSE;
1574 good_header = FALSE;
1575 header_type = RB_Find_Marker( sourcehandle, &is_internal, reuse );
1579 struct RB_header *duplicate_header = NULL;
1580 long previous_line = 0;
1582 new_header = RB_Alloc_Header( );
1583 new_header->htype = header_type;
1584 new_header->is_internal = is_internal;
1586 if ( Find_Header_Name( sourcehandle, new_header ) )
1588 new_header->line_number = line_number;
1589 RB_Say( "found header [line %5d]: \"%s\"\n", SAY_DEBUG,
1590 line_number, new_header->name );
1592 RB_Document_Check_For_Duplicate( arg_document,
1594 if ( duplicate_header )
1596 /* Duplicate headers do not crash the program so
1597 * we accept them. But we do warn the user.
1600 ( "A header with the name \"%s\" already exists.\n See %s(%d)\n",
1602 Get_Fullname( duplicate_header->owner->filename ),
1603 duplicate_header->line_number );
1606 if ( ( new_header->function_name =
1607 Function_Name( new_header->name ) ) == NULL )
1609 RB_Warning( "Can't determine the \"function\" name.\n" );
1610 RB_Free_Header( new_header );
1615 if ( ( new_header->module_name =
1616 Module_Name( new_header->name ) ) == NULL )
1619 ( "Can't determine the \"module\" name.\n" );
1620 RB_Free_Header( new_header );
1625 previous_line = line_number;
1626 if ( Find_End_Marker( sourcehandle, new_header ) ==
1630 ( "found header on line %d with name \"%s\"\n"
1631 " but I can't find the end marker\n",
1632 previous_line, new_header->name );
1633 /* Reuse the current line while finding the next
1634 * Marking using RB_Find_Marker()
1637 RB_Free_Header( new_header );
1642 RB_Say( "found end header [line %5d]:\n",
1643 SAY_DEBUG, line_number );
1644 /* Good header found, we can stop */
1652 RB_Warning( "found header marker but no name\n" );
1653 RB_Free_Header( new_header );
1659 /* end of the file */
1663 while ( !good_header );
1671 /****f* Analyser/Module_Name
1673 * Get the module name from the header name. The header name will be
1676 * module/functionname.
1680 static char *Module_Name(
1684 * o header_name -- a pointer to a nul terminated string.
1686 * Pointer to the modulename. You're responsible for freeing it.
1696 assert( header_name );
1698 for ( cur_char = header_name; *cur_char && *cur_char != '/'; ++cur_char );
1703 name = RB_StrDup( header_name );
1713 /****f* Analyser/Function_Name
1715 * A header name is consists of two parts. The module name and
1716 * the function name. This returns a pointer to the function name.
1717 * The name "function name" is a bit obsolete. It is really the name
1718 * of any of objects that can be documented; classes, methods,
1719 * variables, functions, projects, etc.
1722 static char *Function_Name(
1732 if ( ( cur_char = header_name ) != NULL )
1734 for ( ; *cur_char != '\0'; ++cur_char )
1736 if ( '/' == *cur_char )
1749 return RB_StrDup( name );
1757 /*** Function_Name ***/
1760 /****f* Analyser/RB_Find_Marker
1762 * RB_Find_Marker -- Search for header marker in document.
1764 * Read document file line by line, and search each line for
1765 * any of the headers defined in the array header_markers (OR
1766 * if using the -rh switch, robo_head)
1769 static struct RB_HeaderType *RB_Find_Marker(
1772 int reuse_previous_line )
1775 * document - pointer to the file to be searched.
1776 * the gobal buffer line_buffer.
1778 * o document will point to the line after the line with
1779 * the header marker.
1780 * o is_internal will be TRUE if the header is an internal
1785 * Bad use of feof(), fgets().
1793 struct RB_HeaderType *header_type = 0;
1797 while ( !feof( document ) && !found )
1799 if ( reuse_previous_line )
1801 /* reuse line in the line_buffer */
1802 reuse_previous_line = FALSE;
1806 RB_FreeLineBuffer( );
1807 myLine = RB_ReadWholeLine( document, line_buffer, &readChars );
1809 if ( !feof( document ) )
1812 found = RB_Is_Begin_Marker( myLine, &cur_char );
1815 header_type = AnalyseHeaderType( &cur_char, is_internal );
1816 RB_Say( "found header marker of type %s\n", SAY_DEBUG,
1817 header_type->indexName );
1825 /******** END RB_Find_Marker ******/
1828 /****f* Analyser/AnalyseHeaderType
1830 * Determine the type of the header.
1833 struct RB_HeaderType *AnalyseHeaderType(
1838 * o cur_char -- pointer to the header type character
1840 * o is_internal -- indicates if it is an internal header or not.*
1841 * o cur_char -- points to the header type character
1843 * o pointer to a RB_HeaderType
1847 struct RB_HeaderType *headertype = 0;
1849 *is_internal = RB_IsInternalHeader( **cur_char );
1853 /* Skip the character */
1856 headertype = RB_FindHeaderType( **cur_char );
1859 RB_Panic( "Undefined headertype (%c)\n", **cur_char );
1869 /****f* Analyser/Find_End_Marker
1871 * Scan and store all lines from a source file until
1872 * an end marker is found.
1875 static int Find_End_Marker(
1877 struct RB_header *new_header )
1880 * o document -- a pointer to an opened source file.
1882 * o new_header -- the lines of source code will be added
1885 * o TRUE -- an end marker was found.
1886 * o FALSE -- no end marker was found while scanning the
1892 unsigned int no_lines = 0;
1893 unsigned int max_no_lines = 10;
1894 char **lines = NULL;
1895 char **new_lines = NULL;
1898 lines = ( char ** ) calloc( max_no_lines, sizeof( char * ) );
1901 RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" );
1904 while ( !feof( document ) )
1906 RB_FreeLineBuffer( );
1907 myLine = RB_ReadWholeLine( document, line_buffer, &readChars );
1908 ++line_number; /* global linecounter, koessi */
1909 if ( RB_Is_Begin_Marker( myLine, &dummy ) )
1911 /* Bad... found a begin marker but was expecting to
1912 find an end marker. Panic... */
1916 else if ( RB_Is_End_Marker( myLine ) )
1918 RB_Say( "Found end marker \"%s\"", SAY_DEBUG, myLine );
1927 line = RB_StrDup( myLine );
1930 assert( line[n - 1] == '\n' );
1933 lines[no_lines] = line;
1935 if ( no_lines == max_no_lines )
1938 new_lines = realloc( lines, max_no_lines * sizeof( char * ) );
1942 RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" );
1950 new_header->no_lines = no_lines;
1951 new_header->lines = lines;
1960 /* TODO Documentation */
1961 static void Remove_Trailing_Asterics(
1964 int i = strlen( line ) - 1;
1966 for ( ; ( i > 0 ) && utf8_isspace( line[i] ); i-- )
1970 for ( ; ( i > 0 ) && ( line[i] == '*' ); i-- )
1977 /****if* Utilities/RB_WordWithSpacesLen
1980 static int RB_WordWithSpacesLen(
1984 * get the amount of bytes until next separator character or ignore character
1987 * char *str -- the line
1989 * int -- length of the next word or 0
1991 * RB_Find_Header_Name()
1998 for ( len = 0; ( ( c = *str ) != '\0' ) && ( c != '\n' ); ++str, ++len )
2000 // Look for header truncating characters
2001 if ( Find_Parameter_Char( &( configuration.header_separate_chars ),
2004 Find_Parameter_Char( &( configuration.header_ignore_chars ),
2007 // and exit loop if any found
2011 /* Don't count any of the trailing spaces. */
2015 for ( ; utf8_isspace( *str ); --len, --str )
2023 /*** RB_WordWithSpacesLen ***/
2026 /* TODO Documentation */
2027 static int Find_Header_Name(
2029 struct RB_header *hdr )
2031 char *cur_char = myLine;
2032 char **names = NULL;
2035 Remove_Trailing_Asterics( cur_char );
2036 skip_while( *cur_char != '*' );
2037 skip_while( !utf8_isspace( *cur_char ) );
2038 skip_while( utf8_isspace( *cur_char ) );
2041 int length = RB_WordWithSpacesLen( cur_char );
2045 names = realloc( names, ( ++num ) * sizeof *names );
2049 RB_Panic( "Out of memory! %s()\n", "Find_Header_Name" );
2052 names[num - 1] = RB_StrDupLen( cur_char, length );
2053 /* printf("%c adding name = %s\n", num > 1 ? ' ' : '*', names[ num - 1 ] ); */
2055 if ( Find_Parameter_Char( &( configuration.header_separate_chars ),
2058 for ( cur_char++; utf8_isspace( *cur_char ); cur_char++ );
2059 /* End of line reach, but comma encountered, more headernames follow on next line */
2060 if ( *cur_char == 0 )
2063 RB_FreeLineBuffer( );
2064 myLine = RB_ReadWholeLine( fh, line_buffer, &readChars );
2066 for ( cur_char = myLine; *cur_char && !utf8_isalpha( *cur_char );
2072 hdr->no_names = num;
2073 hdr->name = num ? names[0] : NULL;
2077 /***** Find_Header_Name *****/