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/>.
23 /****h* ROBODoc/Headers
25 * This module contains a set of variables that define how headers
26 * start and how they end in various programming languages.
28 * Added C++/ACM header option (David White)
29 * Enables documentation only comments (//!) to be extracted from C++
30 * and ACM files, rather than all comments.
41 #include "roboconfig.h"
44 /* This limits the total number of possible markers. */
45 /* TODO should be an enum */
46 #define NO_MARKER_LOCKED 100000
47 #define NO_MARKER 100002
49 static int locked_header_marker = NO_MARKER_LOCKED;
50 static int locked_end_marker = NO_MARKER_LOCKED;
51 static int locked_remark_marker = NO_MARKER_LOCKED;
53 /****v* Headers/header_markers
55 * header_markers -- strings that mark the begin of a header.
57 * These specify what robodoc recognizes as the beginning
59 * The numbers at the beginning of the lines make it easier
60 * to keep them in sync with the src_constants
65 char *header_markers[] = {
66 "/****", /* 0 C, C++ */
67 "//!****", /* 1 C++, ACM */
69 "(****", /* 3 Pascal, Modula-2, B52 */
70 "{****", /* 4 Pascal */
71 ";;!****", /* 5 Aspen Plus */
72 ";****", /* 6 M68K assembler */
73 "****", /* 7 M68K assembler */
74 "C ****", /* 8 Fortran */
75 "REM ****", /* 9 BASIC */
76 "%****", /* 10 LaTeX, TeX, Postscript */
77 "#****", /* 11 Tcl/Tk */
78 " ****", /* 12 COBOL */
79 "--****", /* 13 Occam */
80 "<!--****", /* 14 HTML Code */
81 "<!---****", /* 15 HTML Code, the three-dashed comment
82 * tells the [server] pre-processor not
83 * to send that comment with the HTML
85 "|****", /* 16 GNU Assembler */
86 "!****", /* 17 FORTRAN 90 */
87 "!!****", /* 18 FORTRAN 90 */
88 "$!****", /* 19 DCL */
89 "'****", /* 20 VB, LotusScript */
90 ".****", /* 21 DB/C */
91 "\\ ****", /* 22 Forth */
92 "<!-- ****", /* 23 XML */
98 /****v* Headers/robo_header
100 * robo_header -- the distinct robodoc header -
101 * alternative to using header_markers
103 * This is an alternative to using header_markers - sometimes
104 * ROBODOC confuses asterisks commonly used in comments as a header.
105 * To use this header instead of header_markers use the -rh switch.
107 * Added by David Druffner. OBSOLETE
111 char *robo_header = "/*ROBODOC*"; /* TODO Remove */
116 /****v* Headers/remark_markers [3.0h]
120 * These specify what robodoc recognizes as a comment marker.
122 * (1) All the markers that start with one or more spaces are
123 * never recognized, and should be removed.
124 * (2) The numbers at the beginning of the lines make it easier
125 * to keep them in sync with the src_remark_constants
129 char *remark_markers[] = {
131 " *", /* 0 C, C++, Pascal, Modula-2 */
132 "//!", /* 1 C++, ACM *//* MUST CHECK BEFORE C++ */
134 "*", /* 3 C, C++, M68K assembler, Pascal, Modula-2 */
135 ";;!", /* 4 Aspen Plus *//* MUST CHECK BEFORE M68K */
136 ";*", /* 5 M68K assembler */
137 ";", /* 6 M68K assembler */
140 "%", /* 9 LaTeX, TeX, Postscript */
144 "|", /* 13 GNU Assembler */
145 "!!", /* 14 FORTRAN 90 */
146 "!", /* 15 FORTRAN 90 */
157 /****v* Headers/end_markers [3.0h]
159 * end_markers -- strings that mark the end of a header.
161 * These specify what robodoc recognizes as the end of a
162 * documentation header. In most cases this will be
163 * "***" or " ***". If the header contains a SOURCE item
164 * then the end of the source has to be marked, which
165 * is when the other strings in this array are used.
167 * The numbers at the beginning of the lines make it easier
168 * to find a special index-number.
172 char *end_markers[] = {
173 "/***", /* 0 C, C++ */
174 "//!***", /* 1 C++, ACM *//* Must check before C++ */
176 " ***", /* 3 C, C++, Pascal, Modula-2 */
177 "{***", /* 4 Pascal */
178 "(***", /* 5 Pascal, Modula-2, B52 */
179 ";;!***", /* 6 Aspen Plus *//* Must check before M68K */
180 ";***", /* 7 M68K assembler */
181 "***", /* 8 M68K assembler */
182 "C ***", /* 9 Fortran */
183 "REM ***", /* 10 BASIC */
184 "%***", /* 11 LaTeX, TeX, Postscript */
185 "#***", /* 12 Tcl/Tk */
186 " ***", /* 13 COBOL */
187 "--***", /* 14 Occam */
188 "<!--***", /* 15 HTML */
189 "<!---***", /* 16 HTML */
190 "|***", /* 17 GNU Assembler */
191 "!!***", /* 18 FORTRAN 90 */
192 "!***", /* 19 FORTRAN 90 */
193 "$!***", /* 20 DCL */
194 "'***", /* 21 VB, LotusScript */
195 ".***", /* 22 DB/C */
196 "\\ ***", /* 23 Forth */
197 "<!-- ***", /* 24 XML */
203 /****v* Headers/end_remark_markers
205 * end_remark_markers -- strings that mark the end of a comment.
207 * The numbers at the beginning of the lines make it easier
208 * to keep them in sync with the end_remark_constants
212 char *end_remark_markers[] = {
214 ( char * ) NULL, /* 1 C++, ACM */
215 ( char * ) NULL, /* 2 C++ */
216 ( char * ) NULL, /* 3 C, C++, Pascal, Modula-2 */
217 "***}", /* 5 Pascal */
218 "***)", /* 6 Pascal, Modula-2, B52 */
219 ( char * ) NULL, /* 7 M68K assembler */
220 ( char * ) NULL, /* 8 M68K assembler */
221 ( char * ) NULL, /* 9 Fortran */
222 ( char * ) NULL, /* 10 BASIC */
223 ( char * ) NULL, /* 11 LaTeX, TeX, Postscript */
224 ( char * ) NULL, /* 12 Tcl/Tk */
225 ( char * ) NULL, /* 13 COBOL */
226 ( char * ) NULL, /* 14 Occam */
227 "-->", /* 15 HTML & XML */
228 "--->", /* 16 HTML */
229 ( char * ) NULL, /* 17 GNU Assembler */
230 ( char * ) NULL, /* 18 FORTRAN 90 !! */
231 ( char * ) NULL, /* 19 FORTRAN 90 ! */
232 ( char * ) NULL, /* 20 VB */
233 ( char * ) NULL, /* 21 Aspen Plus */
234 ( char * ) NULL /* 22 Forth */
240 /****v* Headers/robo_end [3.0h]
242 * robo_end[] -- the distinct robodoc end marker -
243 * alternative to using end_markers
245 * This is an alternative to using end_markers - sometimes ROBODOC
246 * confuses asterisks commonly used in comments as an end marker. To
247 * use this footer instead of end_markers use the -rh switch.
249 * Added by David Druffner.
253 char *robo_end[] = { "/*ROBODOC_END*", "*ROBODOC_END*", NULL };
258 /***f* Headers/RB_Is_Begin_Marker
260 * Scan a line and see if any of the begin-of-a-header-markers
261 * defined in header_markers can be found.
264 int RB_Is_Begin_Marker(
269 * cur_line -- line to be searched.
271 * type -- the kind of header
273 * TRUE -- a begin header was found
274 * FALSE -- no begin header was found.
279 unsigned int marker = NO_MARKER; /* for the assert */
280 char *cur_mchar = NULL;
281 char *cur_char = NULL;
283 if ( !( course_of_action.do_robo_head )
285 ( ( ( course_of_action.do_lockheader ) &&
286 ( locked_header_marker == NO_MARKER_LOCKED ) )
287 || !( course_of_action.do_lockheader ) ) )
290 ( marker < configuration.header_markers.number ) && !found;
293 cur_mchar = configuration.header_markers.names[marker];
294 for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line );
295 *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ )
297 if ( tolower( *cur_mchar ) != tolower( *cur_char ) )
300 if ( *cur_mchar != '\0' )
302 /* It is not a complete match */
307 else if ( ( course_of_action.do_lockheader ) &&
308 ( locked_header_marker != NO_MARKER_LOCKED ) )
310 cur_mchar = configuration.header_markers.names[locked_header_marker];
311 for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line );
312 *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ )
314 if ( tolower( *cur_mchar ) != tolower( *cur_char ) )
318 if ( *cur_mchar != '\0' )
320 /* It is not a complete match */
331 if ( found && cur_char )
335 if ( *cur_char == '*' )
338 found = utf8_isspace( *cur_char );
340 else if ( *( cur_char + 1 ) == '*' )
344 found = utf8_isspace( *cur_char );
353 /* It should contain some non * characters. */
354 for ( ; *cur_char; ++cur_char )
356 if ( utf8_isalnum( *cur_char ) )
365 ( course_of_action.do_lockheader ) &&
366 ( locked_header_marker == NO_MARKER_LOCKED ) )
368 assert( marker != NO_MARKER );
369 locked_header_marker = marker - 1;
370 RB_Say( "header marker locked on %s\n", SAY_INFO,
371 configuration.header_markers.names[locked_header_marker] );
379 /* Generic function to skip a remark begin or end marker */
381 static char *RB_Skip_Remark_XXX_Marker(
383 struct Parameters *parameters )
390 cur_char = RB_Skip_Whitespace( cur_line );
391 space_pos = strchr( cur_char, ' ' );
392 /* Replace the first space on the line with a '\0'
393 * this makes the comparison with the remark markers
401 for ( marker = 0; ( marker < parameters->number ) && !found; marker++ )
404 ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 );
416 return cur_char + strlen( parameters->names[marker - 1] );
421 /* Generic function to see if there is a remark begin or end marker */
423 static int RB_Is_Remark_XXX_Marker(
425 struct Parameters *parameters )
432 cur_char = RB_Skip_Whitespace( cur_line );
433 space_pos = strchr( cur_char, ' ' );
434 /* Replace the first space on the line with a '\0'
435 * this makes the comparison with the remark markers
443 for ( marker = 0; ( marker < parameters->number ) && !found; marker++ )
446 ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 );
458 /* TODO Documentation */
459 int RB_Is_Remark_End_Marker(
462 return RB_Is_Remark_XXX_Marker( cur_line,
463 &( configuration.remark_end_markers ) );
466 /* TODO Documentation */
467 int RB_Is_Remark_Begin_Marker(
470 return RB_Is_Remark_XXX_Marker( cur_line,
471 &( configuration.remark_begin_markers ) );
474 char *RB_Skip_Remark_Begin_Marker(
477 return RB_Skip_Remark_XXX_Marker( cur_line,
479 remark_begin_markers ) );
482 char *RB_Skip_Remark_End_Marker(
485 return RB_Skip_Remark_XXX_Marker( cur_line,
486 &( configuration.remark_end_markers ) );
490 /****f* Headers/RB_Is_End_Marker
492 * Scan a line and see if any of the end of a header markers
493 * defined in header_markers can be found.
496 int RB_Is_End_Marker(
500 * cur_line -- line to be searched.
504 * TRUE -- an end header was found
505 * FALSE -- none was found.
510 unsigned int marker = NO_MARKER; /* For the assert */
514 if ( !( course_of_action.do_robo_head )
516 ( ( ( course_of_action.do_lockheader ) &&
517 ( locked_end_marker == NO_MARKER_LOCKED ) )
518 || !( course_of_action.do_lockheader ) ) )
521 ( marker < configuration.end_markers.number ) && !found;
524 cur_mchar = configuration.end_markers.names[marker];
525 cur_char = RB_Skip_Whitespace( cur_line );
529 *cur_mchar && *cur_char && found;
530 cur_mchar++, cur_char++ )
532 if ( tolower( *cur_mchar ) != tolower( *cur_char ) )
540 else if ( ( course_of_action.do_lockheader ) &&
541 ( locked_end_marker != NO_MARKER_LOCKED ) )
543 cur_mchar = configuration.end_markers.names[locked_end_marker];
544 cur_char = RB_Skip_Whitespace( cur_line );
548 *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ )
550 if ( tolower( *cur_mchar ) != tolower( *cur_char ) )
562 /* Locking on end markers does not work at the moment,
563 * because there can be more than one end marker for
564 * a given language. TODO
568 ( course_of_action.do_LOCKHEADER ) &&
569 ( locked_end_marker == NO_MARKER_LOCKED ) )
571 assert( marker != NO_MARKER );
572 locked_end_marker = marker - 1;
573 RB_Say( "end marker locked on %s\n", SAY_INFO,
574 end_markers[locked_end_marker] );
583 /****f* Headers/RB_Has_Remark_Marker
585 * Check if a line starts with a remark marker. This function
586 * assumes that the remark marker starts on the first character of
590 int RB_Has_Remark_Marker(
594 * o lline_buffer -- the line of text.
596 * o TRUE -- it starts with a remark marker
597 * o FALSE -- it does not.
601 unsigned int marker = 0;
602 unsigned int marker_found = configuration.remark_markers.number;
604 char *space_pos = NULL;
606 space_pos = strchr( lline_buffer, ' ' );
608 /* Replace the first space on the line with a '\0'
609 * this makes the comparison with the remark markers
617 if ( ( ( course_of_action.do_lockheader ) &&
618 ( locked_remark_marker == NO_MARKER_LOCKED ) )
619 || !( course_of_action.do_lockheader ) )
621 for ( marker = 0; marker < configuration.remark_markers.number;
626 configuration.remark_markers.names[marker] ) == 0 )
628 marker_found = marker;
637 configuration.remark_markers.names[locked_remark_marker] ) ==
640 marker_found = marker;
646 ( locked_remark_marker == NO_MARKER_LOCKED )
647 && ( course_of_action.do_lockheader ) )
649 assert( marker_found < configuration.remark_markers.number );
650 locked_remark_marker = marker_found;
651 RB_Say( "remark marker locked on %s\n", SAY_INFO,
652 configuration.remark_markers.names[locked_remark_marker] );
655 /* Restore the space we replaced with a '\0' */
667 /****f* Headers/RB_Skip_Remark_Marker [2.0e]
669 * RB_Skip_Remark_Marker
672 char *RB_Skip_Remark_Marker(
676 * Scan and search for a recognized remark marker; skip past the
677 * marker to the body of the text
681 unsigned int marker, found;
682 char *cur_char, *cur_mchar;
687 ( marker < configuration.remark_markers.number ) && !found;
690 cur_mchar = configuration.remark_markers.names[marker];
691 for ( found = TRUE, cur_char = lline_buffer;
692 *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ )
694 if ( tolower( *cur_mchar ) != tolower( *cur_char ) )
708 /* TODO Documentation */
709 void RB_Header_Lock_Reset(
712 locked_header_marker = NO_MARKER_LOCKED;
713 locked_end_marker = NO_MARKER_LOCKED;
716 void RB_Item_Lock_Reset(
719 locked_remark_marker = NO_MARKER_LOCKED;