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/Document
25 * This module contains functions to manipulate the central data
26 * structure (RB_Document) that contains information about the
27 * source files, and documentation files, and headers.
29 * The name is a bit confusing because it sort of implies that
30 * it contains the documentation extracted from the sourcefiles.
32 * For each run a RB_Document structure is created, it is filled
33 * by the analyser and directory module and then used by the
34 * generator module to create the documentation.
35 * MODIFICATION HISTORY
36 * * ????-??-?? Frans Slothouber V1.0
37 * * 2003-02-03 Frans Slothouber Refactoring
38 * * 2003-10-30 David White Removed unistd.h for Borland
46 #include <sys/types.h>
48 #if defined (RB_BCC) || defined( RB_MSVC )
50 #include <unistd.h> /* Not used for Borland */
57 #include "directory.h"
62 #include "generator.h"
72 /****f* Document/RB_Document_Add_Part
74 * Add a new part to the document.
77 void RB_Document_Add_Part(
78 struct RB_Document *document,
79 struct RB_Part *part )
82 * o document -- the document the part is to be added to.
83 * o part -- the part to be added
87 part->next = document->parts;
88 document->parts = part;
94 /* TODO Documentation */
95 void RB_Free_RB_Document_Parts(
96 struct RB_Document *document )
98 if ( document->parts )
100 struct RB_Part *a_part = NULL;
101 struct RB_Part *a_part2 = NULL;
103 for ( a_part = document->parts; a_part; a_part = a_part2 )
105 a_part2 = a_part->next;
106 RB_Free_RB_Part( a_part );
109 document->parts = NULL;
113 /* TODO Documentation */
114 void RB_Free_RB_Document(
115 struct RB_Document *document )
117 RB_Free_RB_Document_Parts( document );
118 if ( document->headers )
122 for ( i = 0; i < document->no_headers; ++i )
124 RB_Free_Header( document->headers[i] );
127 free( document->headers );
132 /****f* Document/RB_Document_Create_Parts
134 * Create all the parts of a document based on the sourcefiles in
135 * the source tree. This creates a new RB_Part for each file in
138 * o document -- the document for which the parts are generated.
142 void RB_Document_Create_Parts(
143 struct RB_Document *document )
145 struct RB_Filename *i_file = NULL;
148 assert( document->srctree );
150 for ( i_file = document->srctree->first; i_file; i_file = i_file->next )
152 struct RB_Part *rbpart;
154 rbpart = RB_Get_RB_Part( );
155 RB_Part_Add_Source( rbpart, i_file );
156 RB_Document_Add_Part( document, rbpart );
163 /****f* Document/RB_Fill_Header_Filename
165 * Fill the file_name attribute of all headers based either on the
166 * part or the singledoc name. The file_name tells in which file
167 * the documentation for the header is to be stored.
170 void RB_Fill_Header_Filename(
171 struct RB_Document *document )
176 struct RB_Part *i_part;
178 RB_Say( "Computing file_name attribute for all headers.\n", SAY_DEBUG );
179 for ( i_part = document->parts; i_part; i_part = i_part->next )
181 struct RB_header *i_header;
183 for ( i_header = i_part->headers;
184 i_header; i_header = i_header->next )
186 if ( document->actions.do_singledoc )
188 i_header->file_name = document->singledoc_name;
190 else if ( document->actions.do_multidoc )
192 i_header->file_name = RB_Get_FullDocname( i_part->filename );
194 else if ( document->actions.do_singlefile )
196 i_header->file_name = document->singledoc_name;
209 /****f* Document/RB_Document_Determine_DocFilePaths
211 * Determine the path of each of the documentation files based on
212 * the path of the source file and the documentation root path and
213 * the source root path.
216 void RB_Document_Determine_DocFilePaths(
217 struct RB_Document *document )
220 * srcpath = ./test/mysrc/sub1/sub2
221 * srcroot = ./test/mysrc/
222 * docroot = ./test/mydoc/
224 * docpath = ./test/mydoc/sub1/sub2
228 struct RB_Path *path;
233 assert( document->srctree );
234 assert( document->srcroot );
235 assert( document->docroot );
237 docroot_length = strlen( document->docroot->name );
238 srcroot_length = strlen( document->srcroot->name );
240 for ( path = document->srctree->first_path; path; path = path->next )
247 length = strlen( name );
248 assert( length >= srcroot_length );
249 tail = name + srcroot_length;
250 new_name = calloc( docroot_length +
251 ( length - srcroot_length ) + 1, sizeof( char ) );
253 strcat( new_name, document->docroot->name );
254 if ( document->actions.do_no_subdirectories )
256 /* No subdirectory */
260 strcat( new_name, tail );
262 path->docname = new_name;
269 /****f* Document/RB_Document_Create_DocFilePaths
271 * This function creates the whole document directory
272 * tree. It tests if the directories exist and if they
273 * do not the directory is created.
276 void RB_Document_Create_DocFilePaths(
277 struct RB_Document *document )
280 * o document -- the document for which the tree is created.
284 struct RB_Path *path;
286 for ( path = document->srctree->first_path; path; path = path->next )
288 char *pathname = NULL;
291 RB_Say( "Trying to create directory %s\n", SAY_INFO, path->docname );
292 /* Don't want to modify the docname in the path
293 structure. So we make a copy that we later
296 pathname = RB_StrDup( path->docname );
297 for ( c2 = pathname + 1; /* We skip the leading '/' */
304 *c2 = '\0'; /* Replace the '/' with a '\0'. */
305 /* We now have one of the paths leading up to the
306 total path. Test if it exists. */
307 if ( stat( pathname, &dirstat ) == 0 )
311 else if ( ( strlen( pathname ) == 2 ) &&
312 ( utf8_isalpha( pathname[0] ) ) &&
313 ( pathname[1] == ':' ) )
315 /* Is is a drive indicator, ( A: B: C: etc )
316 * stat fails on this, but we should not
317 * create either, so we do nothing.
324 #if defined(__MINGW32__) || defined( RB_MSVC )
325 result = mkdir( pathname );
327 result = mkdir( pathname, 0770 );
331 /* Path was created. */
336 RB_Panic( "Can't create directory %s\n", pathname );
339 /* Put the '/' back in it's place. */
350 /* TODO Documentation */
354 * Compare two header types for sorting.
362 int RB_CompareHeaders(
366 struct RB_header *header_1 = h1;
367 struct RB_header *header_2 = h2;
369 // Check for priorities
370 if ( header_1->htype->priority > header_2->htype->priority )
372 // Header 1 has higher priority
375 else if ( header_1->htype->priority < header_2->htype->priority )
377 // Header 2 has higher priority
382 // Priorities are equal
383 // Check if we sort on full name or just the function name
384 if ( course_of_action.do_sectionnameonly )
386 // Do not include parent name in sorting if they are not displayed
387 return RB_Str_Case_Cmp( header_1->function_name,
388 header_2->function_name );
392 // Sort on full name ( module/function )
393 return RB_Str_Case_Cmp( header_1->name, header_2->name );
400 /* TODO Documentation */
401 void RB_Document_Sort_Headers(
402 struct RB_Document *document )
404 struct RB_Part *i_part;
405 unsigned long part_count = 0;
407 RB_Say( "Sorting headers per part (file)\n", SAY_INFO );
408 for ( i_part = document->parts; i_part; i_part = i_part->next )
410 struct RB_header *i_header;
412 /* Count the number of headers */
413 for ( part_count = 0, i_header = i_part->headers;
414 i_header; i_header = i_header->next )
422 struct RB_header **temp_headers =
423 calloc( part_count, sizeof( struct RB_header * ) );
426 i_header = i_part->headers;
427 for ( i = 0; i < part_count; ++i )
430 temp_headers[i] = i_header;
431 i_header = i_header->next;
433 RB_QuickSort( ( void ** ) temp_headers, 0, part_count - 1,
435 i_part->headers = temp_headers[0];
436 i_part->headers->next = NULL;
437 i_header = temp_headers[0];
438 for ( i = 1; i < part_count; ++i )
441 i_header->next = temp_headers[i];
442 i_header = i_header->next;
444 temp_headers[part_count - 1]->next = NULL;
445 free( temp_headers );
448 RB_Say( "Sorting all headers\n", SAY_INFO );
449 RB_QuickSort( ( void ** ) document->headers, 0, document->no_headers - 1,
454 /****f* Document/RB_Document_Collect_Headers
456 * Create a table of pointers to all headers. This is done to
457 * have easy access to all heades without having to scan all
460 * o document -- the document for which the table is created.
462 * o document->headers
463 * o document->no_headers
467 void RB_Document_Collect_Headers(
468 struct RB_Document *document )
470 struct RB_Part *i_part;
471 struct RB_header **headers; /* Pointer to an array of pointers RB_headers. */
472 unsigned long count = 0;
473 unsigned long part_count = 0;
476 RB_Say( "Collecting all headers in a single table\n", SAY_INFO );
477 for ( i_part = document->parts; i_part; i_part = i_part->next )
479 struct RB_header *i_header;
481 /* Count the number of headers */
482 for ( part_count = 0, i_header = i_part->headers;
483 i_header; i_header = i_header->next )
487 /* Compute the total count */
491 ( struct RB_header ** ) calloc( count, sizeof( struct RB_header * ) );
492 for ( i_part = document->parts; i_part; i_part = i_part->next )
494 struct RB_header *i_header;
496 for ( i_header = i_part->headers;
497 i_header; i_header = i_header->next )
499 headers[i] = i_header;
503 document->headers = headers;
504 document->no_headers = count;
509 /* TODO Documentation */
511 struct RB_header *RB_Document_Check_For_Duplicate(
512 struct RB_Document *arg_document,
513 struct RB_header *hdr )
515 struct RB_Part *i_part;
517 for ( i_part = arg_document->parts; i_part; i_part = i_part->next )
519 struct RB_header *i_header;
521 for ( i_header = i_part->headers; i_header;
522 i_header = i_header->next )
526 if ( hdr == i_header )
529 for ( i = 0; i < hdr->no_names; i++ )
530 if ( strcmp( hdr->names[i], i_header->name ) == 0 )
538 /* TODO Documentation
539 If A is called qqqq/ffff and B is called ffff/zzzz then A is the
543 void RB_Document_Link_Headers(
544 struct RB_Document *document )
548 struct RB_header *parent;
549 struct RB_header *child;
553 RB_Say( "Linking all %d headers\n", SAY_INFO, document->no_headers );
554 for ( i = 0; i < document->no_headers; i++ )
556 parent = ( document->headers )[i];
557 parent_name = parent->function_name;
558 for ( j = 0; j < document->no_headers; j++ )
562 child = ( document->headers )[j];
563 child_name = child->module_name;
564 if ( strcmp( child_name, parent_name ) == 0 )
566 child->parent = parent;
574 void RB_Document_Split_Parts(
575 struct RB_Document *document )
577 struct RB_Part *i_part = NULL;
578 struct RB_Part **new_parts = NULL;
579 int new_number_of_parts = 0;
583 /* split eacht part in several parts. One for each header
584 * in the original part.
586 for ( i_part = document->parts; i_part; i_part = i_part->next )
588 struct RB_header *i_header;
590 for ( i_header = i_part->headers;
591 i_header; i_header = i_header->next )
593 ++new_number_of_parts;
597 new_parts = calloc( new_number_of_parts, sizeof( struct RB_Part * ) );
601 /* Create new parts */
603 RB_Say( "Splitting parts based on headers.\n", SAY_DEBUG );
604 for ( i_part = document->parts; i_part; i_part = i_part->next )
606 struct RB_header *i_header;
607 struct RB_header *i_next_header;
609 for ( i_header = i_part->headers;
610 i_header; i_header = i_next_header )
612 struct RB_Part *new_part;
614 i_next_header = i_header->next;
616 RB_Say( "Creating new part.\n", SAY_DEBUG );
617 new_part = RB_Get_RB_Part( );
618 RB_Part_Add_Source( new_part,
619 RB_Copy_RB_Filename( RB_Part_Get_Source
621 /* remove header from i_part and add to new_part.
623 RB_Part_Add_Header( new_part, i_header );
624 assert( n < new_number_of_parts );
625 new_parts[n] = new_part;
628 i_part->headers = NULL;
629 i_part->last_header = NULL;
631 /* Remove old part from document */
632 RB_Free_RB_Document_Parts( document );
633 /* Add new parts to document */
634 for ( i = 0; i < n; ++i )
636 RB_Document_Add_Part( document, new_parts[i] );
638 /* clean-up temp array */
643 RB_Panic( "Out of memory! RB_Document_Split_Parts()" );
647 /* TODO Documentation */
648 void RB_Document_Determine_DocFileNames(
649 struct RB_Document *document )
651 struct RB_Filename *filename;
652 unsigned int length = 0;
656 struct RB_Part *part;
658 assert( document->actions.do_multidoc );
660 for ( part = document->parts; part; part = part->next )
663 filename = part->filename;
664 /* turn mysource.c into mysource_c.html
665 First find the total length. */
666 length = strlen( filename->name );
667 /* add one for the '.' */
670 if ( document->actions.do_one_file_per_header )
672 struct RB_header *i_header = part->headers;
675 /* add the name of the header to the filename */
676 /* We make this twice as long because some of the
677 * characters in the file are escaped to 2 hexadecimal
680 length += 2 * strlen( i_header->name );
683 length += RB_Get_Len_Extension( document->extension );
684 /* plus one for the '\0' */
686 name = ( char * ) calloc( length, sizeof( char ) );
688 strcat( name, filename->name );
689 for ( c = name; *c != '\0'; c++ )
697 if ( document->actions.do_one_file_per_header )
700 struct RB_header *i_header = part->headers;
703 /* add the name of the header to the filename */
704 for ( i = 0; i < strlen( i_header->name ); ++i )
706 if ( utf8_isalnum( i_header->name[i] ) )
708 sprintf( c, "%c", i_header->name[i] );
713 sprintf( c, "%2X", i_header->name[i] );
719 RB_Add_Extension( document->extension, name );
721 RB_Say( "Filename for part is %s\n", SAY_DEBUG, name );
722 part->filename->docname = name;
726 /****f* Document/RB_Open_SingleDocumentation
728 * Open the file that will contain the documentation in
729 * case we create a single document.
732 FILE *RB_Open_SingleDocumentation(
733 struct RB_Document *document )
741 static char *default_name = "singledoc";
745 if ( document->singledoc_name )
747 size += strlen( document->singledoc_name );
751 size += strlen( default_name );
753 size++; /* and the '\0'; */
754 size += RB_Get_Len_Extension( document->extension );
756 name = ( char * ) calloc( size, sizeof( char ) );
758 if ( document->singledoc_name )
760 strcat( name, document->singledoc_name );
764 strcat( name, default_name );
766 RB_Add_Extension( document->extension, name );
768 file = fopen( name, "w" );
775 RB_Panic( "Can't open %s\n", name );
783 /****f* Document/RB_Get_RB_Document
785 * Allocate and initialize an RB_Document structure.
788 struct RB_Document *RB_Get_RB_Document(
792 * An initialized document structure.
796 struct RB_Document *document = 0;
798 ( struct RB_Document * ) malloc( sizeof( struct RB_Document ) );
801 document->cur_part = NULL;
802 document->parts = NULL;
803 document->links = NULL;
804 document->headers = NULL;
805 document->doctype = UNKNOWN;
806 document->actions = No_Actions();
807 document->srctree = NULL;
808 document->srcroot = NULL;
809 document->docroot = NULL;
810 document->singledoc_name = NULL;
811 document->no_headers = 0;
812 document->charset = NULL;
813 document->extension = NULL;
814 document->first_section_level = 1;
815 document->doctype_name = NULL;
816 document->doctype_location = NULL;
820 RB_Panic( "out of memory" );