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, function_name(header->names[k]),
160 link->htype = header->htype;
161 link->is_internal = header->is_internal;
162 link_index[j] = link;
163 case_sensitive_link_index[j] = link;
167 /* If we are in multidoc mode, we also create links
168 * for all the source files.
171 if ( ( document->actions.do_multidoc ) &&
172 /* but not for one file per header multidocs */
173 ! ( document->actions.do_one_file_per_header )
176 for ( i_part = document->parts; i_part; i_part = i_part->next )
178 if ( i_part->headers )
180 struct RB_link *link;
183 RB_Alloc_Link( "robo_top_of_doc", i_part->filename->name,
184 RB_Get_FullDocname( i_part->filename ) );
185 i_part->filename->link = link;
186 link->htype = RB_FindHeaderType( HT_SOURCEHEADERTYPE );
187 link_index[j] = link;
188 case_sensitive_link_index[j] = link;
193 i_part->filename->link = NULL;
198 /* Sort all the links so we can use a binary search */
199 RB_QuickSort( (void **)link_index, 0, link_index_size - 1, link_cmp );
200 RB_QuickSort( (void **)case_sensitive_link_index, 0, link_index_size - 1, case_sensitive_link_cmp );
206 /****f* Links/RB_Free_Links
208 * Deallocate all the memory used to store the links.
211 void RB_Free_Links( void )
217 * Should use RB_Free_Link instead of doing
218 * everything by it self.
222 struct RB_link *cur_link;
225 for ( i = 0; i < link_index_size; ++i )
227 cur_link = link_index[i];
228 free( cur_link->object_name );
229 free( cur_link->label_name );
230 free( cur_link->file_name );
238 /* TODO Documentation */
240 int RB_Number_Of_Links( struct RB_HeaderType* header_type, char* file_name, int internal )
242 struct RB_link *cur_link;
246 for ( i = 0; i < link_index_size; ++i )
248 cur_link = link_index[i];
249 if ( RB_CompareHeaderTypes( cur_link->htype, header_type ) &&
250 ( ( cur_link->is_internal && internal ) ||
251 ( !cur_link->is_internal && !internal ) ) )
255 if ( strcmp( file_name, cur_link->file_name ) == 0 )
269 /****f* Links/Find_Link [3.0h]
271 * Find_Link -- try to match word with a link
273 * Searches for the given word in the list of links and
274 * headers. There are three passes (or four, when the C option
275 * is selected). Each pass uses a different definition of "word":
276 * o In the first pass it is any thing that ends with a 'space', a '.'
278 * o In the second pass it is any string that consists of alpha
279 * numerics, '_', ':', '.', or '-'.
280 * o In the third pass (for C) it is any string that consists
281 * of alpha numerics or '_'.
286 Find_Link( char *word_begin,
292 * o word_begin - pointer to a word (a string).
293 * o object_name - pointer to a pointer to a string
294 * o file_name - pointer to a pointer to a string
296 * label_name & file_name are modified
298 * o object_name -- points to the object if a match was found,
300 * o file_name -- points to the file name if a match was found,
302 * o label_name -- points to the labelname if a match was found,
303 * o TRUE -- a match was found.
304 * o FALSE -- no match was found.
306 * This is a rather sensitive algorithm. Don't mess with it
312 char *cur_char = NULL, old_char;
313 int low_index, high_index, cur_index, state, pass;
314 unsigned int length = 0;
316 for ( pass = 0; pass < 3; pass++ )
322 for ( cur_char = word_begin;
323 ( *cur_char == '_' ) || utf8_isalnum( *cur_char ) || utf8_ispunct( *cur_char );
329 for ( cur_char = word_begin;
330 utf8_isalnum( *cur_char ) || ( *cur_char == '_' ) ||
331 ( *cur_char == '-' ) || ( *cur_char == '.' ) ||
332 ( *cur_char == ':' ); cur_char++ );
337 for ( cur_char = word_begin;
338 utf8_isalnum( *cur_char ) || ( *cur_char == '_');
344 if ( ( ( *( cur_char - 1 ) ) == ',' ) || ( ( *( cur_char - 1 ) ) == '.' ) )
349 old_char = *cur_char;
351 * End the word with a '\0'
353 if ( strlen( word_begin ) == length )
355 /* Do not test the same word over and over. If
356 * the current string and the string of the previous
357 * pass are the same length, they are the same. */
359 /* RB_Say ("Skipping (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */
363 length = strlen( word_begin );
364 /* RB_Say ("Testing (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */
366 * Search case sensitive for a link
368 for ( cur_index = 0, low_index = 0, high_index =
369 link_index_size - 1; high_index >= low_index; )
371 cur_index = ( high_index - low_index ) / 2 + low_index;
372 state = strcmp( word_begin, case_sensitive_link_index[cur_index]->object_name );
375 high_index = cur_index - 1;
377 else if ( state == 0 )
379 *object_name = case_sensitive_link_index[cur_index]->object_name;
380 *label_name = case_sensitive_link_index[cur_index]->label_name;
381 *file_name = case_sensitive_link_index[cur_index]->file_name;
382 RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG,
383 word_begin, *object_name, *file_name );
384 *cur_char = old_char;
387 else if ( state > 0 )
389 low_index = cur_index + 1;
394 * Search case insensitive for a link.
395 * But only when the user asks for this.
397 if ( course_of_action.do_ignore_case_when_linking )
400 for ( cur_index = 0, low_index = 0, high_index =
401 link_index_size - 1; high_index >= low_index; )
403 cur_index = ( high_index - low_index ) / 2 + low_index;
404 state = RB_Str_Case_Cmp( word_begin, link_index[cur_index]->object_name );
407 high_index = cur_index - 1;
409 else if ( state == 0 )
411 *object_name = link_index[cur_index]->object_name;
412 *label_name = link_index[cur_index]->label_name;
413 *file_name = link_index[cur_index]->file_name;
414 RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG,
415 word_begin, *object_name, *file_name );
416 *cur_char = old_char;
419 else if ( state > 0 )
421 low_index = cur_index + 1;
426 *cur_char = old_char;
437 /****f* Links/RB_Alloc_Link [2.01]
439 * RB_Alloc_Link -- oop
441 * allocate struct + strings
444 static struct RB_link *
445 RB_Alloc_Link( char *label_name, char *object_name, char *file_name )
448 * char *label_name -- strings to copy into the link
451 * struct RB_link * -- ready-to-use
455 * RB_StrDup(), RB_Free_Link()
460 struct RB_link *new_link;
462 assert( object_name );
463 assert( label_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 = RB_StrDup( label_name );
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 );