Added options to make Robodoc more customizable.
[robodoc.git] / Source / document.c
1 /*
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.
5
6 This file is part of ROBODoc
7
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.
12
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.
17
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/>.
20
21 */
22
23 /****h* ROBODoc/Document
24  * FUNCTION
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.
28  *
29  *   The name is a bit confusing because it sort of implies that
30  *   it contains the documentation extracted from the sourcefiles.
31  *
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
39  *******
40  */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <ctype.h>
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #if defined (RB_BCC) || defined( RB_MSVC )
49 #else
50 #include <unistd.h>           /* Not used for Borland */
51 #endif
52
53 #include "robodoc.h"
54 #include "document.h"
55 #include "part.h"
56 #include "path.h"
57 #include "directory.h"
58 #include "headers.h"
59 #include "links.h"
60 #include "util.h"
61 #include <string.h>
62 #include "generator.h"
63 #include "file.h"
64 #include "globals.h"
65
66
67 #ifdef DMALLOC
68 #include <dmalloc.h>
69 #endif
70
71
72 /****f* Document/RB_Document_Add_Part
73  * FUNCTION
74  *   Add a new part to the document.
75  * SYNOPSIS
76  */
77 void RB_Document_Add_Part(
78     struct RB_Document *document,
79     struct RB_Part *part )
80 /*
81  * INPUTS
82  *   o document  -- the document the part is to be added to.
83  *   o part      -- the part to be added
84  * SOURCE
85  */
86 {
87     part->next = document->parts;
88     document->parts = part;
89 }
90
91 /*****/
92
93
94 /* TODO Documentation */
95 void RB_Free_RB_Document_Parts(
96     struct RB_Document *document )
97 {
98     if ( document->parts )
99     {
100         struct RB_Part     *a_part = NULL;
101         struct RB_Part     *a_part2 = NULL;
102
103         for ( a_part = document->parts; a_part; a_part = a_part2 )
104         {
105             a_part2 = a_part->next;
106             RB_Free_RB_Part( a_part );
107         }
108     }
109     document->parts = NULL;
110 }
111
112
113 /* TODO Documentation */
114 void RB_Free_RB_Document(
115     struct RB_Document *document )
116 {
117     RB_Free_RB_Document_Parts( document );
118     if ( document->headers )
119     {
120         unsigned long       i;
121
122         for ( i = 0; i < document->no_headers; ++i )
123         {
124             RB_Free_Header( document->headers[i] );
125
126         }
127         free( document->headers );
128     }
129     free( document );
130 }
131
132 /****f* Document/RB_Document_Create_Parts
133  * FUNCTION
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
136  *   the source tree.
137  * INPUTS
138  *    o document -- the document for which the parts are generated.
139  * SOURCE
140  */
141
142 void RB_Document_Create_Parts(
143     struct RB_Document *document )
144 {
145     struct RB_Filename *i_file = NULL;
146
147     assert( document );
148     assert( document->srctree );
149
150     for ( i_file = document->srctree->first; i_file; i_file = i_file->next )
151     {
152         struct RB_Part     *rbpart;
153
154         rbpart = RB_Get_RB_Part(  );
155         RB_Part_Add_Source( rbpart, i_file );
156         RB_Document_Add_Part( document, rbpart );
157     }
158 }
159
160 /*******/
161
162
163 /****f* Document/RB_Fill_Header_Filename
164  * FUNCTION
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.
168  * SYNOPSIS
169  */
170 void RB_Fill_Header_Filename(
171     struct RB_Document *document )
172 /*
173  * SOURCE
174  */
175 {
176     struct RB_Part     *i_part;
177
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 )
180     {
181         struct RB_header   *i_header;
182
183         for ( i_header = i_part->headers;
184               i_header; i_header = i_header->next )
185         {
186             if ( document->actions.do_singledoc )
187             {
188                 i_header->file_name = document->singledoc_name;
189             }
190             else if ( document->actions.do_multidoc )
191             {
192                 i_header->file_name = RB_Get_FullDocname( i_part->filename );
193             }
194             else if ( document->actions.do_singlefile )
195             {
196                 i_header->file_name = document->singledoc_name;
197             }
198             else
199             {
200                 assert( 0 );
201             }
202         }
203     }
204 }
205
206 /******/
207
208
209 /****f* Document/RB_Document_Determine_DocFilePaths
210  * FUNCTION
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.
214  * SYNOPSIS
215  */
216 void RB_Document_Determine_DocFilePaths(
217     struct RB_Document *document )
218 /*
219  * EXAMPLE
220  *   srcpath = ./test/mysrc/sub1/sub2
221  *   srcroot = ./test/mysrc/
222  *   docroot = ./test/mydoc/
223  *     ==>
224  *   docpath = ./test/mydoc/sub1/sub2
225  * SOURCE
226  */
227 {
228     struct RB_Path     *path;
229     int                 docroot_length;
230     int                 srcroot_length;
231     int                 length;
232
233     assert( document->srctree );
234     assert( document->srcroot );
235     assert( document->docroot );
236
237     docroot_length = strlen( document->docroot->name );
238     srcroot_length = strlen( document->srcroot->name );
239
240     for ( path = document->srctree->first_path; path; path = path->next )
241     {
242         char               *name;
243         char               *new_name;
244         char               *tail;
245
246         name = path->name;
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 ) );
252         assert( new_name );
253         strcat( new_name, document->docroot->name );
254         if ( document->actions.do_no_subdirectories )
255         {
256             /* No subdirectory */
257         }
258         else
259         {
260             strcat( new_name, tail );
261         }
262         path->docname = new_name;
263     }
264 }
265
266 /******/
267
268
269 /****f* Document/RB_Document_Create_DocFilePaths
270  * FUNCTION
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.
274  * SYNOPSIS
275  */
276 void RB_Document_Create_DocFilePaths(
277     struct RB_Document *document )
278 /*
279  * INPUTS
280  *   o document -- the document for which the tree is created.
281  * SOURCE
282  */
283 {
284     struct RB_Path     *path;
285
286     for ( path = document->srctree->first_path; path; path = path->next )
287     {
288         char               *pathname = NULL;
289         char               *c2 = NULL;
290
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
294            destroy. */
295
296         pathname = RB_StrDup( path->docname );
297         for ( c2 = pathname + 1;        /* We skip the leading '/' */
298               *c2; ++c2 )
299         {
300             if ( *c2 == '/' )
301             {
302                 struct stat         dirstat;
303
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 )
308                 {
309                     /* Path exists. */
310                 }
311                 else if ( ( strlen( pathname ) == 2 ) &&
312                           ( utf8_isalpha( pathname[0] ) ) &&
313                           ( pathname[1] == ':' ) )
314                 {
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.
318                      */
319                 }
320                 else
321                 {
322                     int                 result;
323
324 #if defined(__MINGW32__) || defined( RB_MSVC )
325                     result = mkdir( pathname );
326 #else
327                     result = mkdir( pathname, 0770 );
328 #endif
329                     if ( result == 0 )
330                     {
331                         /* Path was created. */
332                     }
333                     else
334                     {
335                         perror( NULL );
336                         RB_Panic( "Can't create directory %s\n", pathname );
337                     }
338                 }
339                 /* Put the '/' back in it's place. */
340                 *c2 = '/';
341             }
342         }
343         free( pathname );
344     }
345 }
346
347 /*******/
348
349
350 /* TODO Documentation */
351
352 /*x**f* 
353  * FUNCTION
354  *   Compare two header types for sorting.
355  * RESULT
356  *   -1  h1 <  h2
357  *    0  h1 == h2
358  *    1  h1 >  h2
359  * SOURCE
360  */
361
362 int RB_CompareHeaders(
363     void *h1,
364     void *h2 )
365 {
366     struct RB_header   *header_1 = h1;
367     struct RB_header   *header_2 = h2;
368
369     // Check for priorities
370     if ( header_1->htype->priority > header_2->htype->priority )
371     {
372         // Header 1 has higher priority
373         return -1;
374     }
375     else if ( header_1->htype->priority < header_2->htype->priority )
376     {
377         // Header 2 has higher priority
378         return 1;
379     }
380     else
381     {
382         // Priorities are equal
383         // Check if we sort on full name or just the function name
384         if ( course_of_action.do_sectionnameonly )
385         {
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 );
389         }
390         else
391         {
392             // Sort on full name ( module/function )
393             return RB_Str_Case_Cmp( header_1->name, header_2->name );
394         }
395     }
396 }
397
398 /*****/
399
400 /* TODO Documentation */
401 void RB_Document_Sort_Headers(
402     struct RB_Document *document )
403 {
404     struct RB_Part     *i_part;
405     unsigned long       part_count = 0;
406
407     RB_Say( "Sorting headers per part (file)\n", SAY_INFO );
408     for ( i_part = document->parts; i_part; i_part = i_part->next )
409     {
410         struct RB_header   *i_header;
411
412         /* Count the number of headers */
413         for ( part_count = 0, i_header = i_part->headers;
414               i_header; i_header = i_header->next )
415         {
416             part_count++;
417         }
418
419         if ( part_count )
420         {
421             /* Sort them */
422             struct RB_header  **temp_headers =
423                 calloc( part_count, sizeof( struct RB_header * ) );
424             unsigned int        i = 0;
425
426             i_header = i_part->headers;
427             for ( i = 0; i < part_count; ++i )
428             {
429                 assert( i_header );
430                 temp_headers[i] = i_header;
431                 i_header = i_header->next;
432             }
433             RB_QuickSort( ( void ** ) temp_headers, 0, part_count - 1,
434                           RB_CompareHeaders );
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 )
439             {
440                 assert( i_header );
441                 i_header->next = temp_headers[i];
442                 i_header = i_header->next;
443             }
444             temp_headers[part_count - 1]->next = NULL;
445             free( temp_headers );
446         }
447     }
448     RB_Say( "Sorting all headers\n", SAY_INFO );
449     RB_QuickSort( ( void ** ) document->headers, 0, document->no_headers - 1,
450                   RB_CompareHeaders );
451 }
452
453
454 /****f* Document/RB_Document_Collect_Headers
455  * FUNCTION
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
458  *   RB_Parts.
459  * INPUTS
460  *   o document -- the document for which the table is created.
461  * OUTPUT
462  *   o document->headers
463  *   o document->no_headers
464  * SOURCE
465  */
466
467 void RB_Document_Collect_Headers(
468     struct RB_Document *document )
469 {
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;
474     unsigned long       i = 0;
475
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 )
478     {
479         struct RB_header   *i_header;
480
481         /* Count the number of headers */
482         for ( part_count = 0, i_header = i_part->headers;
483               i_header; i_header = i_header->next )
484         {
485             part_count++;
486         }
487         /* Compute the total count */
488         count += part_count;
489     }
490     headers =
491         ( struct RB_header ** ) calloc( count, sizeof( struct RB_header * ) );
492     for ( i_part = document->parts; i_part; i_part = i_part->next )
493     {
494         struct RB_header   *i_header;
495
496         for ( i_header = i_part->headers;
497               i_header; i_header = i_header->next )
498         {
499             headers[i] = i_header;
500             i++;
501         }
502     }
503     document->headers = headers;
504     document->no_headers = count;
505 }
506
507 /*******/
508
509 /* TODO Documentation */
510
511 struct RB_header   *RB_Document_Check_For_Duplicate(
512     struct RB_Document *arg_document,
513     struct RB_header *hdr )
514 {
515     struct RB_Part     *i_part;
516
517     for ( i_part = arg_document->parts; i_part; i_part = i_part->next )
518     {
519         struct RB_header   *i_header;
520
521         for ( i_header = i_part->headers; i_header;
522               i_header = i_header->next )
523         {
524             int                 i;
525
526             if ( hdr == i_header )
527                 continue;
528
529             for ( i = 0; i < hdr->no_names; i++ )
530                 if ( strcmp( hdr->names[i], i_header->name ) == 0 )
531                     return i_header;
532         }
533     }
534     return NULL;
535 }
536
537
538 /*  TODO Documentation 
539  If A is called   qqqq/ffff and B is called  ffff/zzzz then A is the
540  parent of B
541 */
542
543 void RB_Document_Link_Headers(
544     struct RB_Document *document )
545 {
546     unsigned long       i;
547     unsigned long       j;
548     struct RB_header   *parent;
549     struct RB_header   *child;
550     char               *parent_name;
551     char               *child_name;
552
553     RB_Say( "Linking all %d headers\n", SAY_INFO, document->no_headers );
554     for ( i = 0; i < document->no_headers; i++ )
555     {
556         parent = ( document->headers )[i];
557         parent_name = parent->function_name;
558         for ( j = 0; j < document->no_headers; j++ )
559         {
560             if ( i != j )
561             {
562                 child = ( document->headers )[j];
563                 child_name = child->module_name;
564                 if ( strcmp( child_name, parent_name ) == 0 )
565                 {
566                     child->parent = parent;
567                 }
568             }
569         }
570     }
571 }
572
573
574 void RB_Document_Split_Parts(
575     struct RB_Document *document )
576 {
577     struct RB_Part     *i_part = NULL;
578     struct RB_Part    **new_parts = NULL;
579     int                 new_number_of_parts = 0;
580     int                 n = 0;
581     int                 i;
582
583     /* split eacht part in several parts. One for each header
584      * in the original part.
585      */
586     for ( i_part = document->parts; i_part; i_part = i_part->next )
587     {
588         struct RB_header   *i_header;
589
590         for ( i_header = i_part->headers;
591               i_header; i_header = i_header->next )
592         {
593             ++new_number_of_parts;
594         }
595     }
596
597     new_parts = calloc( new_number_of_parts, sizeof( struct RB_Part * ) );
598
599     if ( new_parts )
600     {
601         /* Create new parts */
602
603         RB_Say( "Splitting parts based on headers.\n", SAY_DEBUG );
604         for ( i_part = document->parts; i_part; i_part = i_part->next )
605         {
606             struct RB_header   *i_header;
607             struct RB_header   *i_next_header;
608
609             for ( i_header = i_part->headers;
610                   i_header; i_header = i_next_header )
611             {
612                 struct RB_Part     *new_part;
613
614                 i_next_header = i_header->next;
615
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
620                                                          ( i_part ) ) );
621                 /* remove header from i_part and add to new_part.
622                  */
623                 RB_Part_Add_Header( new_part, i_header );
624                 assert( n < new_number_of_parts );
625                 new_parts[n] = new_part;
626                 ++n;
627             }
628             i_part->headers = NULL;
629             i_part->last_header = NULL;
630         }
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 )
635         {
636             RB_Document_Add_Part( document, new_parts[i] );
637         }
638         /* clean-up temp array */
639         free( new_parts );
640     }
641     else
642     {
643         RB_Panic( "Out of memory! RB_Document_Split_Parts()" );
644     }
645 }
646
647 /* TODO Documentation */
648 void RB_Document_Determine_DocFileNames(
649     struct RB_Document *document )
650 {
651     struct RB_Filename *filename;
652     unsigned int        length = 0;
653     char               *name;
654     char               *c;
655
656     struct RB_Part     *part;
657
658     assert( document->actions.do_multidoc );
659
660     for ( part = document->parts; part; part = part->next )
661     {
662
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 '.' */
668         ++length;
669
670         if ( document->actions.do_one_file_per_header )
671         {
672             struct RB_header   *i_header = part->headers;
673
674             assert( i_header );
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
678              * digits.
679              */
680             length += 2 * strlen( i_header->name );
681         }
682
683         length += RB_Get_Len_Extension( document->extension );
684         /* plus one for the '\0' */
685         ++length;
686         name = ( char * ) calloc( length, sizeof( char ) );
687         assert( name );
688         strcat( name, filename->name );
689         for ( c = name; *c != '\0'; c++ )
690         {
691             if ( *c == '.' )
692             {
693                 *c = '_';
694             }
695         }
696
697         if ( document->actions.do_one_file_per_header )
698         {
699             unsigned int        i;
700             struct RB_header   *i_header = part->headers;
701
702             assert( i_header );
703             /* add the name of the header to the filename */
704             for ( i = 0; i < strlen( i_header->name ); ++i )
705             {
706                 if ( utf8_isalnum( i_header->name[i] ) )
707                 {
708                     sprintf( c, "%c", i_header->name[i] );
709                     c++;
710                 }
711                 else
712                 {
713                     sprintf( c, "%2X", i_header->name[i] );
714                     c++;
715                     c++;
716                 }
717             }
718         }
719         RB_Add_Extension( document->extension, name );
720
721         RB_Say( "Filename for part is %s\n", SAY_DEBUG, name );
722         part->filename->docname = name;
723     }
724 }
725
726 /****f* Document/RB_Open_SingleDocumentation
727  * FUNCTION
728  *   Open the file that will contain the documentation in
729  *   case we create a single document.
730  * SYNOPSIS
731  */
732 FILE               *RB_Open_SingleDocumentation(
733     struct RB_Document *document )
734 /*
735  * RESULT
736  *   An opened file.
737  * SOURCE
738  */
739 {
740     FILE               *file;
741     static char        *default_name = "singledoc";
742     char               *name = NULL;
743     size_t              size = 0;
744
745     if ( document->singledoc_name )
746     {
747         size += strlen( document->singledoc_name );
748     }
749     else
750     {
751         size += strlen( default_name );
752     }
753     size++;                     /* and the '\0'; */
754     size += RB_Get_Len_Extension( document->extension );
755
756     name = ( char * ) calloc( size, sizeof( char ) );
757     assert( name );
758     if ( document->singledoc_name )
759     {
760         strcat( name, document->singledoc_name );
761     }
762     else
763     {
764         strcat( name, default_name );
765     }
766     RB_Add_Extension( document->extension, name );
767
768     file = fopen( name, "w" );
769     if ( file )
770     {
771         /* File opened  */
772     }
773     else
774     {
775         RB_Panic( "Can't open %s\n", name );
776     }
777     free( name );
778     return file;
779 }
780
781 /****/
782
783 /****f* Document/RB_Get_RB_Document
784  * FUNCTION
785  *   Allocate and initialize an RB_Document structure.
786  * SYNOPSIS
787  */
788 struct RB_Document *RB_Get_RB_Document(
789     void )
790 /*
791  * RESULT
792  *   An initialized document structure.
793  * SOURCE
794  */
795 {
796     struct RB_Document *document = 0;
797     document =
798         ( struct RB_Document * ) malloc( sizeof( struct RB_Document ) );
799     if ( document )
800     {
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;
817     }
818     else
819     {
820         RB_Panic( "out of memory" );
821     }
822     return document;
823 }
824
825 /*******/