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 * This module contains functions to manipulate links.
26 * Links are derived from headers. They are used to create
27 * links in the documentation between a word and the part of
28 * the documentation that explains something about that word.
29 * (For instance a function name or variable name).
30 * In addition to the links derived from the headers links are
31 * also derived from the names of all the sourcefiles.
32 * MODIFICATION HISTORY
33 * ????-??-?? Frans Slothouber V1.0
34 * 2003-02-03 Frans Slothouber Refactoring
36 * $Header: /cvsroot/robodoc/robo/Source/links.c,v 1.43 2007/07/10 19:13:52 gumpu Exp $
58 /* TODO Documentation */
59 unsigned int link_index_size = 0;
60 struct RB_link **link_index = NULL;
61 struct RB_link **case_sensitive_link_index = NULL;
66 static struct RB_link *RB_Alloc_Link( char *label_name, char *object_name,
69 /* TODO Documentation */
70 int link_cmp( void *l1, void *l2 )
72 struct RB_link *link1 = l1;
73 struct RB_link *link2 = l2;
75 return RB_Str_Case_Cmp( link1->object_name, link2->object_name );
79 int case_sensitive_link_cmp( void *l1, void *l2 )
81 struct RB_link *link1 = l1;
82 struct RB_link *link2 = l2;
84 return strcmp( link1->object_name, link2->object_name );
87 char * function_name( char * full_name )
89 char * name = strchr( full_name, '/' );
91 if( name ) return name + 1;
92 else return full_name;
95 /****f* Links/RB_CollectLinks
97 * Convert header information into link information.
98 * RB_header -> RB_link conversion
102 RB_CollectLinks( struct RB_Document *document,
103 struct RB_header **headers,
104 unsigned long count )
108 * * headers -- the array with headers.
109 * * count -- number of headers in the array
111 * * link_index -- an array with links
112 * * link_index_size -- the number of links in the array.
119 struct RB_Part *i_part;
121 for ( i = j = 0; i < count; ++i )
123 j += headers[i]->no_names - 1;
126 link_index_size = count + j;
128 if ( ( document->actions.do_multidoc ) &&
129 ! ( document->actions.do_one_file_per_header )
132 for ( i_part = document->parts; i_part; i_part = i_part->next )
134 if ( i_part->headers )
142 ( struct RB_link ** ) calloc( link_index_size,
143 sizeof( struct RB_link ** ) );
144 case_sensitive_link_index =
145 ( struct RB_link ** ) calloc( link_index_size,
146 sizeof( struct RB_link ** ) );
148 for ( i = j = 0; i < count; ++i )
150 struct RB_link *link;
151 struct RB_header *header;
154 assert( header->unique_name );
155 assert( header->file_name );
156 for( k = 0; k < header->no_names; j++, k++ )
158 link = RB_Alloc_Link( header->unique_name,
159 header->function_name,
161 link->htype = header->htype;
162 link->is_internal = header->is_internal;
163 link_index[j] = link;
164 case_sensitive_link_index[j] = link;
168 /* If we are in multidoc mode, we also create links
169 * for all the source files.
172 if ( ( document->actions.do_multidoc ) &&
173 /* but not for one file per header multidocs */
174 ! ( document->actions.do_one_file_per_header )
177 for ( i_part = document->parts; i_part; i_part = i_part->next )
179 if ( i_part->headers )
181 struct RB_link *link;
184 RB_Alloc_Link( "robo_top_of_doc", i_part->filename->name,
185 RB_Get_FullDocname( i_part->filename ) );
186 i_part->filename->link = link;
187 link->htype = RB_FindHeaderType( HT_SOURCEHEADERTYPE );
188 link_index[j] = link;
189 case_sensitive_link_index[j] = link;
194 i_part->filename->link = NULL;
199 /* Sort all the links so we can use a binary search */
200 RB_QuickSort( (void **)link_index, 0, link_index_size - 1, link_cmp );
201 RB_QuickSort( (void **)case_sensitive_link_index, 0, link_index_size - 1, case_sensitive_link_cmp );
207 /****f* Links/RB_Free_Links
209 * Deallocate all the memory used to store the links.
212 void RB_Free_Links( void )
218 * Should use RB_Free_Link instead of doing
219 * everything by it self.
223 struct RB_link *cur_link;
226 for ( i = 0; i < link_index_size; ++i )
228 cur_link = link_index[i];
229 free( cur_link->object_name );
230 free( cur_link->label_name );
231 free( cur_link->file_name );
239 /* TODO Documentation */
241 int RB_Number_Of_Links( struct RB_HeaderType* header_type, char* file_name, int internal )
243 struct RB_link *cur_link;
247 for ( i = 0; i < link_index_size; ++i )
249 cur_link = link_index[i];
250 if ( RB_CompareHeaderTypes( cur_link->htype, header_type ) &&
251 ( ( cur_link->is_internal && internal ) ||
252 ( !cur_link->is_internal && !internal ) ) )
256 if ( strcmp( file_name, cur_link->file_name ) == 0 )
270 /****f* Links/Find_Link [3.0h]
272 * Find_Link -- try to match word with a link
274 * Searches for the given word in the list of links and
275 * headers. There are three passes (or four, when the C option
276 * is selected). Each pass uses a different definition of "word":
277 * o In the first pass it is any thing that ends with a 'space', a '.'
279 * o In the second pass it is any string that consists of alpha
280 * numerics, '_', ':', '.', or '-'.
281 * o In the third pass (for C) it is any string that consists
282 * of alpha numerics or '_'.
287 Find_Link( char *word_begin,
293 * o word_begin - pointer to a word (a string).
294 * o object_name - pointer to a pointer to a string
295 * o file_name - pointer to a pointer to a string
297 * label_name & file_name are modified
299 * o object_name -- points to the object if a match was found,
301 * o file_name -- points to the file name if a match was found,
303 * o label_name -- points to the labelname if a match was found,
304 * o TRUE -- a match was found.
305 * o FALSE -- no match was found.
307 * This is a rather sensitive algorithm. Don't mess with it
313 char *cur_char = NULL, old_char;
314 int low_index, high_index, cur_index, state, pass;
315 unsigned int length = 0;
317 for ( pass = 0; pass < 3; pass++ )
323 for ( cur_char = word_begin;
324 ( *cur_char == '_' ) || utf8_isalnum( *cur_char ) || utf8_ispunct( *cur_char );
330 for ( cur_char = word_begin;
331 utf8_isalnum( *cur_char ) || ( *cur_char == '_' ) ||
332 ( *cur_char == '-' ) || ( *cur_char == '.' ) ||
333 ( *cur_char == ':' ); cur_char++ );
338 for ( cur_char = word_begin;
339 utf8_isalnum( *cur_char ) || ( *cur_char == '_');
345 if ( ( ( *( cur_char - 1 ) ) == ',' ) || ( ( *( cur_char - 1 ) ) == '.' ) )
350 old_char = *cur_char;
352 * End the word with a '\0'
354 if ( strlen( word_begin ) == length )
356 /* Do not test the same word over and over. If
357 * the current string and the string of the previous
358 * pass are the same length, they are the same. */
360 /* RB_Say ("Skipping (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */
364 length = strlen( word_begin );
365 /* RB_Say ("Testing (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */
367 * Search case sensitive for a link
369 for ( cur_index = 0, low_index = 0, high_index =
370 link_index_size - 1; high_index >= low_index; )
372 cur_index = ( high_index - low_index ) / 2 + low_index;
373 state = strcmp( word_begin, case_sensitive_link_index[cur_index]->object_name );
376 high_index = cur_index - 1;
378 else if ( state == 0 )
380 *object_name = case_sensitive_link_index[cur_index]->object_name;
381 *label_name = case_sensitive_link_index[cur_index]->label_name;
382 *file_name = case_sensitive_link_index[cur_index]->file_name;
383 RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG,
384 word_begin, *object_name, *file_name );
385 *cur_char = old_char;
388 else if ( state > 0 )
390 low_index = cur_index + 1;
395 * Search case insensitive for a link.
396 * But only when the user asks for this.
398 if ( course_of_action.do_ignore_case_when_linking )
401 for ( cur_index = 0, low_index = 0, high_index =
402 link_index_size - 1; high_index >= low_index; )
404 cur_index = ( high_index - low_index ) / 2 + low_index;
405 state = RB_Str_Case_Cmp( word_begin, link_index[cur_index]->object_name );
408 high_index = cur_index - 1;
410 else if ( state == 0 )
412 *object_name = link_index[cur_index]->object_name;
413 *label_name = link_index[cur_index]->label_name;
414 *file_name = link_index[cur_index]->file_name;
415 RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG,
416 word_begin, *object_name, *file_name );
417 *cur_char = old_char;
420 else if ( state > 0 )
422 low_index = cur_index + 1;
427 *cur_char = old_char;
438 /****f* Links/RB_Alloc_Link [2.01]
440 * RB_Alloc_Link -- oop
442 * allocate struct + strings
445 static struct RB_link *
446 RB_Alloc_Link( char *label_name, char *object_name, char *file_name )
449 * char *label_name -- strings to copy into the link
452 * struct RB_link * -- ready-to-use
456 * RB_StrDup(), RB_Free_Link()
461 struct RB_link *new_link;
463 assert( object_name );
465 RB_Say( "Allocating a link (%s %s %s)\n", SAY_DEBUG, object_name, label_name, file_name );
466 new_link = malloc( sizeof( struct RB_link ) );
467 memset( new_link, 0, sizeof( struct RB_link ) );
469 new_link->file_name = RB_StrDup( file_name );
470 new_link->object_name = RB_StrDup( object_name );
471 new_link->label_name = label_name ? RB_StrDup( label_name ) : NULL;
477 /****f* Links/RB_Free_Link
479 * RB_Free_Link -- oop
481 * free struct + strings
484 void RB_Free_Link( struct RB_link *arg_link )
487 * struct RB_link *link
491 * RB_Alloc_Link(), RB_Close_The_Shop()
498 if ( arg_link->label_name )
500 free( arg_link->label_name );
502 if ( arg_link->file_name )
504 free( arg_link->file_name );