source: trunk/essentials/sys-apps/texinfo/makeinfo/index.c

Last change on this file was 2617, checked in by bird, 19 years ago

GNU Texinfo 4.8

File size: 28.8 KB
Line 
1/* index.c -- indexing for Texinfo.
2 $Id: index.c,v 1.17 2004/11/30 02:03:23 karl Exp $
3
4 Copyright (C) 1998, 1999, 2002, 2003, 2004 Free Software Foundation,
5 Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "system.h"
22#include "files.h"
23#include "footnote.h"
24#include "html.h"
25#include "index.h"
26#include "lang.h"
27#include "macro.h"
28#include "sectioning.h"
29#include "toc.h"
30#include "xml.h"
31
32INDEX_ALIST **name_index_alist = NULL;
33
34/* An array of pointers. Each one is for a different index. The
35 "synindex" command changes which array slot is pointed to by a
36 given "index". */
37INDEX_ELT **the_indices = NULL;
38
39/* The number of defined indices. */
40int defined_indices = 0;
41
42/* This is the order of the index. */
43int index_counter = 0;
44
45/* Stuff for defining commands on the fly. */
46COMMAND **user_command_array = NULL;
47int user_command_array_len = 0;
48
49/* How to compare index entries for sorting. May be set to strcoll. */
50int (*index_compare_fn) (const char *a, const char *b) = strcasecmp;
51
52/* Function to compare index entries for sorting. (Calls
53 `index_compare_fn' above.) */
54int index_element_compare (const void *element1, const void *element2);
55
56
57/* Find which element in the known list of indices has this name.
58 Returns -1 if NAME isn't found. */
59static int
60find_index_offset (char *name)
61{
62 int i;
63 for (i = 0; i < defined_indices; i++)
64 if (name_index_alist[i] && STREQ (name, name_index_alist[i]->name))
65 return i;
66 return -1;
67}
68
69/* Return a pointer to the entry of (name . index) for this name.
70 Return NULL if the index doesn't exist. */
71static INDEX_ALIST *
72find_index (char *name)
73{
74 int offset = find_index_offset (name);
75 if (offset > -1)
76 return name_index_alist[offset];
77 else
78 return NULL;
79}
80
81
82/* User-defined commands, which happens only from user-defined indexes.
83 Used to initialize the builtin indices, too. */
84static void
85define_user_command (char *name, COMMAND_FUNCTION (*proc), int needs_braces_p)
86{
87 int slot = user_command_array_len;
88 user_command_array_len++;
89
90 if (!user_command_array)
91 user_command_array = xmalloc (1 * sizeof (COMMAND *));
92
93 user_command_array = xrealloc (user_command_array,
94 (1 + user_command_array_len) * sizeof (COMMAND *));
95
96 user_command_array[slot] = xmalloc (sizeof (COMMAND));
97 user_command_array[slot]->name = xstrdup (name);
98 user_command_array[slot]->proc = proc;
99 user_command_array[slot]->argument_in_braces = needs_braces_p;
100}
101
102
103/* Please release me, let me go... */
104static void
105free_index (INDEX_ELT *index)
106{
107 INDEX_ELT *temp;
108
109 while ((temp = index))
110 {
111 free (temp->entry);
112 free (temp->entry_text);
113 /* Do not free the node, because we already freed the tag table,
114 which freed all the node names. */
115 /* free (temp->node); */
116 index = index->next;
117 free (temp);
118 }
119}
120
121/* Flush an index by name. This will delete the list of entries that
122 would be written by a @printindex command for this index. */
123static void
124undefindex (char *name)
125{
126 int i;
127 int which = find_index_offset (name);
128
129 /* The index might have already been freed if this was the target of
130 an @synindex. */
131 if (which < 0 || !name_index_alist[which])
132 return;
133
134 i = name_index_alist[which]->read_index;
135
136 free_index (the_indices[i]);
137 the_indices[i] = NULL;
138
139 free (name_index_alist[which]->name);
140 free (name_index_alist[which]);
141 name_index_alist[which] = NULL;
142}
143
144
145/* Add the arguments to the current index command to the index NAME. */
146static void
147index_add_arg (char *name)
148{
149 int which;
150 char *index_entry;
151 INDEX_ALIST *tem;
152
153 tem = find_index (name);
154
155 which = tem ? tem->write_index : -1;
156
157 if (macro_expansion_output_stream && !executing_string)
158 append_to_expansion_output (input_text_offset + 1);
159
160 get_rest_of_line (0, &index_entry);
161 ignore_blank_line ();
162
163 if (macro_expansion_output_stream && !executing_string)
164 {
165 char *index_line = xmalloc (strlen (index_entry) + 2);
166 sprintf (index_line, "%s\n", index_entry);
167 me_execute_string_keep_state (index_line, NULL);
168 free (index_line);
169 }
170
171 if (which < 0)
172 {
173 line_error (_("Unknown index `%s'"), name);
174 free (index_entry);
175 }
176 else
177 {
178 INDEX_ELT *new = xmalloc (sizeof (INDEX_ELT));
179
180 index_counter++;
181
182 /* Get output line number updated before doing anything. */
183 if (!html && !xml)
184 flush_output ();
185
186 new->next = the_indices[which];
187 new->entry = NULL;
188 new->entry_text = index_entry;
189 /* Since footnotes are handled at the very end of the document,
190 node name in the non-split HTML outputs always show the last
191 node. We artificially make it ``Footnotes''. */
192 if (html && !splitting && already_outputting_pending_notes)
193 new->node = xstrdup (_("Footnotes"));
194 else
195 new->node = current_node ? current_node : xstrdup ("");
196 if (!html && !xml && no_headers)
197 {
198 new->section = current_sectioning_number ();
199 if (strlen (new->section) == 0)
200 new->section_name = current_sectioning_name ();
201 else
202 new->section_name = "";
203 }
204 else
205 {
206 new->section = NULL;
207 new->section_name = NULL;
208 }
209 new->code = tem->code;
210 new->defining_line = line_number - 1;
211 new->output_line = no_headers ? output_line_number : node_line_number;
212 /* We need to make a copy since input_filename may point to
213 something that goes away, for example, inside a macro.
214 (see the findexerr test). */
215 new->defining_file = xstrdup (input_filename);
216
217 if (html && splitting)
218 {
219 if (current_output_filename && *current_output_filename)
220 new->output_file = filename_part (current_output_filename);
221 else
222 new->output_file = xstrdup ("");
223 }
224 else
225 new->output_file = NULL;
226
227 new->entry_number = index_counter;
228 the_indices[which] = new;
229
230#if 0
231 /* The index breaks if there are colons in the entry.
232 -- This is true, but it's too painful to force changing index
233 entries to use `colon', and too confusing for users. The real
234 fix is to change Info support to support arbitrary characters
235 in node names, and we're not ready to do that. --karl,
236 19mar02. */
237 if (strchr (new->entry_text, ':'))
238 warning (_("Info cannot handle `:' in index entry `%s'"),
239 new->entry_text);
240#endif
241
242 if (html)
243 {
244 /* Anchor. */
245 int removed_empty_elt = 0;
246
247 /* We must put the anchor outside the <dl> and <ul> blocks. */
248 if (rollback_empty_tag ("dl"))
249 removed_empty_elt = 1;
250 else if (rollback_empty_tag ("ul"))
251 removed_empty_elt = 2;
252
253 add_word ("<a name=\"index-");
254 add_escaped_anchor_name (index_entry, 0);
255 add_word_args ("-%d\"></a>", index_counter);
256
257 if (removed_empty_elt == 1)
258 add_html_block_elt_args ("\n<dl>");
259 else if (removed_empty_elt == 2)
260 add_html_block_elt_args ("\n<ul>");
261 }
262 }
263
264 if (xml)
265 xml_insert_indexterm (index_entry, name);
266}
267
268/* The function which user defined index commands call. */
269static void
270gen_index (void)
271{
272 char *name = xstrdup (command);
273 if (strlen (name) >= strlen ("index"))
274 name[strlen (name) - strlen ("index")] = 0;
275 index_add_arg (name);
276 free (name);
277}
278
279
280/* Define an index known as NAME. We assign the slot number.
281 If CODE is nonzero, make this a code index. */
282static void
283defindex (char *name, int code)
284{
285 int i, slot;
286
287 /* If it already exists, flush it. */
288 undefindex (name);
289
290 /* Try to find an empty slot. */
291 slot = -1;
292 for (i = 0; i < defined_indices; i++)
293 if (!name_index_alist[i])
294 {
295 slot = i;
296 break;
297 }
298
299 if (slot < 0)
300 { /* No such luck. Make space for another index. */
301 slot = defined_indices;
302 defined_indices++;
303
304 name_index_alist = (INDEX_ALIST **)
305 xrealloc (name_index_alist, (1 + defined_indices)
306 * sizeof (INDEX_ALIST *));
307 the_indices = (INDEX_ELT **)
308 xrealloc (the_indices, (1 + defined_indices) * sizeof (INDEX_ELT *));
309 }
310
311 /* We have a slot. Start assigning. */
312 name_index_alist[slot] = xmalloc (sizeof (INDEX_ALIST));
313 name_index_alist[slot]->name = xstrdup (name);
314 name_index_alist[slot]->read_index = slot;
315 name_index_alist[slot]->write_index = slot;
316 name_index_alist[slot]->code = code;
317
318 the_indices[slot] = NULL;
319}
320
321/* Define an index NAME, implicitly @code if CODE is nonzero. */
322static void
323top_defindex (char *name, int code)
324{
325 char *temp;
326
327 temp = xmalloc (1 + strlen (name) + strlen ("index"));
328 sprintf (temp, "%sindex", name);
329 define_user_command (temp, gen_index, 0);
330 defindex (name, code);
331 free (temp);
332}
333
334
335/* Set up predefined indices. */
336void
337init_indices (void)
338{
339 int i;
340
341 /* Create the default data structures. */
342
343 /* Initialize data space. */
344 if (!the_indices)
345 {
346 the_indices = xmalloc ((1 + defined_indices) * sizeof (INDEX_ELT *));
347 the_indices[defined_indices] = NULL;
348
349 name_index_alist = xmalloc ((1 + defined_indices)
350 * sizeof (INDEX_ALIST *));
351 name_index_alist[defined_indices] = NULL;
352 }
353
354 /* If there were existing indices, get rid of them now. */
355 for (i = 0; i < defined_indices; i++)
356 {
357 if (name_index_alist[i])
358 { /* Suppose we're called with two input files, and the first
359 does a @synindex pg cp. Then, when we get here to start
360 the second file, the "pg" element won't get freed by
361 undefindex (because it's pointing to "cp"). So free it
362 here; otherwise, when we try to define the pg index again
363 just below, it will still point to cp. */
364 undefindex (name_index_alist[i]->name);
365
366 /* undefindex sets all this to null in some cases. */
367 if (name_index_alist[i])
368 {
369 free (name_index_alist[i]->name);
370 free (name_index_alist[i]);
371 name_index_alist[i] = NULL;
372 }
373 }
374 }
375
376 /* Add the default indices. */
377 top_defindex ("cp", 0); /* cp is the only non-code index. */
378 top_defindex ("fn", 1);
379 top_defindex ("ky", 1);
380 top_defindex ("pg", 1);
381 top_defindex ("tp", 1);
382 top_defindex ("vr", 1);
383}
384
385/* Given an index name, return the offset in the_indices of this index,
386 or -1 if there is no such index. */
387static int
388translate_index (char *name)
389{
390 INDEX_ALIST *which = find_index (name);
391
392 if (which)
393 return which->read_index;
394 else
395 return -1;
396}
397
398/* Return the index list which belongs to NAME. */
399INDEX_ELT *
400index_list (char *name)
401{
402 int which = translate_index (name);
403 if (which < 0)
404 return (INDEX_ELT *) -1;
405 else
406 return the_indices[which];
407}
408
409/* Define a new index command. Arg is name of index. */
410static void
411gen_defindex (int code)
412{
413 char *name;
414 get_rest_of_line (0, &name);
415
416 if (find_index (name))
417 {
418 line_error (_("Index `%s' already exists"), name);
419 }
420 else
421 {
422 char *temp = xmalloc (strlen (name) + sizeof ("index"));
423 sprintf (temp, "%sindex", name);
424 define_user_command (temp, gen_index, 0);
425 defindex (name, code);
426 free (temp);
427 }
428
429 free (name);
430}
431
432void
433cm_defindex (void)
434{
435 gen_defindex (0);
436}
437
438void
439cm_defcodeindex (void)
440{
441 gen_defindex (1);
442}
443
444/* Expects 2 args, on the same line. Both are index abbreviations.
445 Make the first one be a synonym for the second one, i.e. make the
446 first one have the same index as the second one. */
447void
448cm_synindex (void)
449{
450 int source, target;
451 char *abbrev1, *abbrev2;
452
453 skip_whitespace ();
454 get_until_in_line (0, " ", &abbrev1);
455 target = find_index_offset (abbrev1);
456 skip_whitespace ();
457 get_until_in_line (0, " ", &abbrev2);
458 source = find_index_offset (abbrev2);
459 if (source < 0 || target < 0)
460 {
461 line_error (_("Unknown index `%s' and/or `%s' in @synindex"),
462 abbrev1, abbrev2);
463 }
464 else
465 {
466 if (xml && !docbook)
467 xml_synindex (abbrev1, abbrev2);
468 else
469 name_index_alist[target]->write_index
470 = name_index_alist[source]->write_index;
471 }
472
473 free (abbrev1);
474 free (abbrev2);
475}
476
477void
478cm_pindex (void) /* Pinhead index. */
479{
480 index_add_arg ("pg");
481}
482
483void
484cm_vindex (void) /* Variable index. */
485{
486 index_add_arg ("vr");
487}
488
489void
490cm_kindex (void) /* Key index. */
491{
492 index_add_arg ("ky");
493}
494
495void
496cm_cindex (void) /* Concept index. */
497{
498 index_add_arg ("cp");
499}
500
501void
502cm_findex (void) /* Function index. */
503{
504 index_add_arg ("fn");
505}
506
507void
508cm_tindex (void) /* Data Type index. */
509{
510 index_add_arg ("tp");
511}
512
513int
514index_element_compare (const void *element1, const void *element2)
515{
516 INDEX_ELT **elt1 = (INDEX_ELT **) element1;
517 INDEX_ELT **elt2 = (INDEX_ELT **) element2;
518
519 return index_compare_fn ((*elt1)->entry, (*elt2)->entry);
520}
521
522/* Force all index entries to be unique. */
523static void
524make_index_entries_unique (INDEX_ELT **array, int count)
525{
526 int i, j;
527 INDEX_ELT **copy;
528 int counter = 1;
529
530 copy = xmalloc ((1 + count) * sizeof (INDEX_ELT *));
531
532 for (i = 0, j = 0; i < count; i++)
533 {
534 if (i == (count - 1)
535 || array[i]->node != array[i + 1]->node
536 || !STREQ (array[i]->entry, array[i + 1]->entry))
537 copy[j++] = array[i];
538 else
539 {
540 free (array[i]->entry);
541 free (array[i]->entry_text);
542 free (array[i]);
543 }
544 }
545 copy[j] = NULL;
546
547 /* Now COPY contains only unique entries. Duplicated entries in the
548 original array have been freed. Replace the current array with
549 the copy, fixing the NEXT pointers. */
550 for (i = 0; copy[i]; i++)
551 {
552 copy[i]->next = copy[i + 1];
553
554 /* Fix entry names which are the same. They point to different nodes,
555 so we make the entry name unique. */
556 if (copy[i+1]
557 && STREQ (copy[i]->entry, copy[i + 1]->entry)
558 && !html)
559 {
560 char *new_entry_name;
561
562 new_entry_name = xmalloc (10 + strlen (copy[i]->entry));
563 sprintf (new_entry_name, "%s <%d>", copy[i]->entry, counter);
564 free (copy[i]->entry);
565 copy[i]->entry = new_entry_name;
566 counter++;
567 }
568 else
569 counter = 1;
570
571 array[i] = copy[i];
572 }
573 array[i] = NULL;
574
575 /* Free the storage used only by COPY. */
576 free (copy);
577}
578
579
580/* Sort the index passed in INDEX, returning an array of pointers to
581 elements. The array is terminated with a NULL pointer. */
582
583static INDEX_ELT **
584sort_index (INDEX_ELT *index)
585{
586 INDEX_ELT **array;
587 INDEX_ELT *temp;
588 int count = 0;
589 int save_line_number = line_number;
590 char *save_input_filename = input_filename;
591 int save_html = html;
592
593 /* Pretend we are in non-HTML mode, for the purpose of getting the
594 expanded index entry that lacks any markup and other HTML escape
595 characters which could produce a wrong sort order. */
596 /* fixme: html: this still causes some markup, such as non-ASCII
597 characters @AE{} etc., to sort incorrectly. */
598 html = 0;
599
600 for (temp = index, count = 0; temp; temp = temp->next, count++)
601 ;
602 /* We have the length, now we can allocate an array. */
603 array = xmalloc ((count + 1) * sizeof (INDEX_ELT *));
604
605 for (temp = index, count = 0; temp; temp = temp->next, count++)
606 {
607 /* Allocate new memory for the return array, since parts of the
608 original INDEX get freed. Otherwise, if the document calls
609 @printindex twice on the same index, with duplicate entries,
610 we'll have garbage the second time. There are cleaner ways to
611 deal, but this will suffice for now. */
612 array[count] = xmalloc (sizeof (INDEX_ELT));
613 *(array[count]) = *(temp); /* struct assignment, hope it's ok */
614
615 /* Adjust next pointers to use the new memory. */
616 if (count > 0)
617 array[count-1]->next = array[count];
618
619 /* Set line number and input filename to the source line for this
620 index entry, as this expansion finds any errors. */
621 line_number = array[count]->defining_line;
622 input_filename = array[count]->defining_file;
623
624 /* If this particular entry should be printed as a "code" index,
625 then expand it as @code{entry}, i.e., as in fixed-width font. */
626 array[count]->entry = expansion (temp->entry_text, array[count]->code);
627 }
628 array[count] = NULL; /* terminate the array. */
629
630 line_number = save_line_number;
631 input_filename = save_input_filename;
632 html = save_html;
633
634#ifdef HAVE_STRCOLL
635 /* This is not perfect. We should set (then restore) the locale to the
636 documentlanguage, so strcoll operates according to the document's
637 locale, not the user's. For now, I'm just going to assume that
638 those few new documents which use @documentlanguage will be
639 processed in the appropriate locale. In any case, don't use
640 strcoll in the C (aka POSIX) locale, that is the ASCII ordering. */
641 if (language_code != en)
642 {
643 char *lang_env = getenv ("LANG");
644 if (lang_env && !STREQ (lang_env, "C") && !STREQ (lang_env, "POSIX"))
645 index_compare_fn = strcoll;
646 }
647#endif /* HAVE_STRCOLL */
648
649 /* Sort the array. */
650 qsort (array, count, sizeof (INDEX_ELT *), index_element_compare);
651
652 /* Remove duplicate entries. */
653 make_index_entries_unique (array, count);
654
655 /* Replace the original index with the sorted one, in case the
656 document wants to print it again. If the index wasn't empty. */
657 if (index)
658 *index = **array;
659
660 return array;
661}
662
663static void
664insert_index_output_line_no (int line_number, int output_line_number_len)
665{
666 int last_column;
667 int str_size = output_line_number_len + strlen (_("(line )"))
668 + sizeof (NULL);
669 char *out_line_no_str = (char *) xmalloc (str_size + 1);
670
671 /* Do not translate ``(line NNN)'' below for !no_headers case (Info output),
672 because it's something like the ``* Menu'' strings. For plaintext output
673 it should be translated though. */
674 sprintf (out_line_no_str,
675 no_headers ? _("(line %*d)") : "(line %*d)",
676 output_line_number_len, line_number);
677
678 {
679 int i = output_paragraph_offset;
680 while (0 < i && output_paragraph[i-1] != '\n')
681 i--;
682 last_column = output_paragraph_offset - i;
683 }
684
685 if (last_column + strlen (out_line_no_str) > fill_column)
686 {
687 insert ('\n');
688 last_column = 0;
689 }
690
691 while (last_column + strlen (out_line_no_str) < fill_column)
692 {
693 insert (' ');
694 last_column++;
695 }
696
697 insert_string (out_line_no_str);
698 insert ('\n');
699
700 free (out_line_no_str);
701}
702
703/* Nonzero means that we are in the middle of printing an index. */
704int printing_index = 0;
705
706/* Takes one arg, a short name of an index to print.
707 Outputs a menu of the sorted elements of the index. */
708void
709cm_printindex (void)
710{
711 char *index_name;
712 get_rest_of_line (0, &index_name);
713
714 /* get_rest_of_line increments the line number by one,
715 so to make warnings/errors point to the correct line,
716 we decrement the line_number again. */
717 if (!handling_delayed_writes)
718 line_number--;
719
720 if (xml && !docbook)
721 {
722 xml_insert_element (PRINTINDEX, START);
723 insert_string (index_name);
724 xml_insert_element (PRINTINDEX, END);
725 }
726 else if (!handling_delayed_writes)
727 {
728 int command_len = sizeof ("@ ") + strlen (command) + strlen (index_name);
729 char *index_command = xmalloc (command_len + 1);
730
731 close_paragraph ();
732 if (docbook)
733 xml_begin_index ();
734
735 sprintf (index_command, "@%s %s", command, index_name);
736 register_delayed_write (index_command);
737 free (index_command);
738 }
739 else
740 {
741 int item;
742 INDEX_ELT *index;
743 INDEX_ELT *last_index = 0;
744 INDEX_ELT **array;
745 unsigned line_length;
746 char *line;
747 int saved_inhibit_paragraph_indentation = inhibit_paragraph_indentation;
748 int saved_filling_enabled = filling_enabled;
749 int saved_line_number = line_number;
750 char *saved_input_filename = input_filename;
751 unsigned output_line_number_len;
752
753 index = index_list (index_name);
754 if (index == (INDEX_ELT *)-1)
755 {
756 line_error (_("Unknown index `%s' in @printindex"), index_name);
757 free (index_name);
758 return;
759 }
760
761 /* Do this before sorting, so execute_string is in the good environment */
762 if (xml && docbook)
763 xml_begin_index ();
764
765 /* Do this before sorting, so execute_string in index_element_compare
766 will give the same results as when we actually print. */
767 printing_index = 1;
768 filling_enabled = 0;
769 inhibit_paragraph_indentation = 1;
770 xml_sort_index = 1;
771 array = sort_index (index);
772 xml_sort_index = 0;
773 close_paragraph ();
774 if (html)
775 add_html_block_elt_args ("<ul class=\"index-%s\" compact>",
776 index_name);
777 else if (!no_headers && !docbook)
778 { /* Info. Add magic cookie for info readers (to treat this
779 menu differently), and the usual start-of-menu. */
780 add_char ('\0');
781 add_word ("\010[index");
782 add_char ('\0');
783 add_word ("\010]\n");
784 add_word ("* Menu:\n\n");
785 }
786
787 me_inhibit_expansion++;
788
789 /* This will probably be enough. */
790 line_length = 100;
791 line = xmalloc (line_length);
792
793 {
794 char *max_output_line_number = (char *) xmalloc (25 * sizeof (char));
795
796 if (no_headers)
797 sprintf (max_output_line_number, "%d", output_line_number);
798 else
799 {
800 INDEX_ELT *tmp_entry = index;
801 unsigned tmp = 0;
802 for (tmp_entry = index; tmp_entry; tmp_entry = tmp_entry->next)
803 tmp = tmp_entry->output_line > tmp ? tmp_entry->output_line : tmp;
804 sprintf (max_output_line_number, "%d", tmp);
805 }
806
807 output_line_number_len = strlen (max_output_line_number);
808 free (max_output_line_number);
809 }
810
811 for (item = 0; (index = array[item]); item++)
812 {
813 /* A pathological document might have an index entry outside of any
814 node. Don't crash; try using the section name instead. */
815 char *index_node = index->node;
816
817 line_number = index->defining_line;
818 input_filename = index->defining_file;
819
820 if ((!index_node || !*index_node) && html)
821 index_node = toc_find_section_of_node (index_node);
822
823 if (!index_node || !*index_node)
824 {
825 line_error (_("Entry for index `%s' outside of any node"),
826 index_name);
827 if (html || !no_headers)
828 index_node = (char *) _("(outside of any node)");
829 }
830
831 if (html)
832 {
833 /* For HTML, we need to expand and HTML-escape the
834 original entry text, at the same time. Consider
835 @cindex J@"urgen. We want J&uuml;urgen. We can't
836 expand and then escape since we'll end up with
837 J&amp;uuml;rgen. We can't escape and then expand
838 because then `expansion' will see J@&quot;urgen, and
839 @&quot;urgen is not a command. */
840 char *html_entry =
841 maybe_escaped_expansion (index->entry_text, index->code, 1);
842
843 add_html_block_elt_args ("\n<li><a href=\"%s#index-",
844 (splitting && index->output_file) ? index->output_file : "");
845 add_escaped_anchor_name (index->entry_text, 0);
846 add_word_args ("-%d\">%s</a>: ", index->entry_number,
847 html_entry);
848 free (html_entry);
849
850 add_word ("<a href=\"");
851 if (index->node && *index->node)
852 {
853 /* Ensure any non-macros in the node name are expanded. */
854 char *expanded_index;
855
856 in_fixed_width_font++;
857 expanded_index = expansion (index_node, 0);
858 in_fixed_width_font--;
859 add_anchor_name (expanded_index, 1);
860 expanded_index = escape_string (expanded_index);
861 add_word_args ("\">%s</a>", expanded_index);
862 free (expanded_index);
863 }
864 else if (STREQ (index_node, _("(outside of any node)")))
865 {
866 add_anchor_name (index_node, 1);
867 add_word_args ("\">%s</a>", index_node);
868 }
869 else
870 /* If we use the section instead of the (missing) node, then
871 index_node already includes all we need except the #. */
872 add_word_args ("#%s</a>", index_node);
873
874 add_html_block_elt ("</li>");
875 }
876 else if (xml && docbook)
877 {
878 /* In the DocBook case, the expanded index entry is not
879 good for us, since it was expanded for non-DocBook mode
880 inside sort_index. So we send the original entry text
881 to be used with execute_string. */
882 xml_insert_indexentry (index->entry_text, index_node);
883 }
884 else
885 {
886 unsigned new_length = strlen (index->entry);
887
888 if (new_length < 50) /* minimum length used below */
889 new_length = 50;
890 new_length += strlen (index_node) + 7; /* * : .\n\0 */
891
892 if (new_length > line_length)
893 {
894 line_length = new_length;
895 line = xrealloc (line, line_length);
896 }
897 /* Print the entry, nicely formatted. We've already
898 expanded any commands in index->entry, including any
899 implicit @code. Thus, can't call execute_string, since
900 @@ has turned into @. */
901 if (!no_headers)
902 {
903 sprintf (line, "* %-37s ", index->entry);
904 line[2 + strlen (index->entry)] = ':';
905 insert_string (line);
906 /* Make sure any non-macros in the node name are expanded. */
907 in_fixed_width_font++;
908 execute_string ("%s. ", index_node);
909 insert_index_output_line_no (index->output_line,
910 output_line_number_len);
911 in_fixed_width_font--;
912 }
913 else
914 {
915 /* With --no-headers, the @node lines are gone, so
916 there's little sense in referring to them in the
917 index. Instead, output the number or name of the
918 section that corresponds to that node. */
919 sprintf (line, "%-*s ", number_sections ? 46 : 1, index->entry);
920 line[strlen (index->entry)] = ':';
921 insert_string (line);
922
923 if (strlen (index->section) > 0)
924 { /* We got your number. */
925 insert_string ((char *) _("See "));
926 insert_string (index->section);
927 }
928 else
929 { /* Sigh, index in an @unnumbered. :-\ */
930 insert_string ("\n ");
931 insert_string ((char *) _("See "));
932 insert_string ("``");
933 insert_string (expansion (index->section_name, 0));
934 insert_string ("''");
935 }
936
937 insert_string (". ");
938 insert_index_output_line_no (index->output_line,
939 output_line_number_len);
940 }
941 }
942
943 /* Prevent `output_paragraph' from growing to the size of the
944 whole index. */
945 flush_output ();
946 last_index = index;
947 }
948
949 free (line);
950
951 me_inhibit_expansion--;
952 printing_index = 0;
953
954 close_single_paragraph ();
955 filling_enabled = saved_filling_enabled;
956 inhibit_paragraph_indentation = saved_inhibit_paragraph_indentation;
957 input_filename = saved_input_filename;
958 line_number = saved_line_number;
959
960 if (html)
961 add_html_block_elt ("</ul>");
962 else if (xml && docbook)
963 xml_end_index ();
964 }
965
966 free (index_name);
967 /* Re-increment the line number, because get_rest_of_line
968 left us looking at the next line after the command. */
969 line_number++;
970}
Note: See TracBrowser for help on using the repository browser.