1 /* Copyright 2010-2019 Free Software Foundation, Inc.
2 
3    This program is free software: you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation, either version 3 of the License, or
6    (at your option) any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
15 
16 #include <config.h>
17 #include <string.h>
18 #include <stdio.h>
19 
20 #include "parser.h"
21 #include "indices.h"
22 
23 INDEX **index_names = 0;
24 int number_of_indices = 0;
25 int space_for_indices = 0;
26 
27 typedef struct {
28     enum command_id cmd;
29     INDEX *idx;
30 } CMD_TO_IDX;
31 
32 /* Array mapping Texinfo commands to index data structures. */
33 static CMD_TO_IDX *cmd_to_idx = 0;
34 static size_t num_index_commands = 0;
35 static size_t cmd_to_idx_space = 0;
36 
37 static void
associate_command_to_index(enum command_id cmd,INDEX * idx)38 associate_command_to_index (enum command_id cmd, INDEX *idx)
39 {
40   if (num_index_commands == cmd_to_idx_space)
41     {
42       cmd_to_idx = realloc (cmd_to_idx,
43                             sizeof (CMD_TO_IDX) * (cmd_to_idx_space += 10));
44       if (!cmd_to_idx)
45         fatal ("no index for command");
46     }
47 
48   cmd_to_idx[num_index_commands].cmd = cmd;
49   cmd_to_idx[num_index_commands++].idx = idx;
50 }
51 
52 /* Get the index associated with CMD. */
53 INDEX *
index_of_command(enum command_id cmd)54 index_of_command (enum command_id cmd)
55 {
56   int i;
57 
58   for (i = 0; i < num_index_commands; i++)
59     {
60       if (cmd_to_idx[i].cmd == cmd)
61         return cmd_to_idx[i].idx;
62     }
63   return 0;
64 }
65 
66 
67 /* Save a new Texinfo command with the name CMDNAME and record that it
68    creates index entries in IDX. */
69 static void
add_index_command(char * cmdname,INDEX * idx)70 add_index_command (char *cmdname, INDEX *idx)
71 {
72   enum command_id new = add_texinfo_command (cmdname);
73   user_defined_command_data[new & ~USER_COMMAND_BIT].flags
74     = CF_line | CF_index_entry_command;
75   user_defined_command_data[new & ~USER_COMMAND_BIT].data = LINE_line;
76   associate_command_to_index (new, idx);
77 }
78 
79 static INDEX *
add_index_internal(char * name,int in_code)80 add_index_internal (char *name, int in_code)
81 {
82   INDEX *idx = malloc (sizeof (INDEX));
83 
84   memset (idx, 0, sizeof *idx);
85   idx->name = name;
86   idx->prefix = name;
87   idx->in_code = in_code;
88   if (number_of_indices == space_for_indices)
89     {
90       space_for_indices += 5;
91       index_names = realloc (index_names, (space_for_indices + 1)
92                              * sizeof (INDEX *));
93     }
94   index_names[number_of_indices++] = idx;
95   index_names[number_of_indices] = 0;
96   return idx;
97 }
98 
99 /* NAME is the name of an index, e.g. "cp" */
100 INDEX *
index_by_name(char * name)101 index_by_name (char *name)
102 {
103   int i;
104 
105   for (i = 0; i < number_of_indices; i++)
106     {
107       if (!strcmp (index_names[i]->name, name))
108         return index_names[i];
109     }
110   return 0;
111 }
112 
113 
114 /* Add a user defined index with the name NAME */
115 void
add_index(char * name,int in_code)116 add_index (char *name, int in_code)
117 {
118   INDEX *idx;
119   char *cmdname;
120 
121   idx = add_index_internal (name, in_code);
122 
123   /* For example, "rq" -> "rqindex". */
124   asprintf (&cmdname, "%s%s", name, "index");
125   add_index_command (cmdname, idx);
126   free (cmdname);
127 }
128 
129 static void
wipe_index(INDEX * idx)130 wipe_index (INDEX *idx)
131 {
132   int i;
133   INDEX_ENTRY *ie;
134   for (i = 0; i < idx->index_number; i++)
135     {
136       ie = &idx->index_entries[i];
137       /* Destroy element if it is not in the main tree */
138       if (ie->content && !ie->content->parent)
139         destroy_element (ie->content);
140     }
141   free (idx->name);
142   free (idx->index_entries);
143 }
144 
145 void
wipe_indices(void)146 wipe_indices (void)
147 {
148   int i;
149   for (i = 0; i < number_of_indices; i++)
150     {
151       wipe_index (index_names[i]);
152       free (index_names[i]);
153     }
154   number_of_indices = 0;
155   return;
156 }
157 
158 void
init_index_commands(void)159 init_index_commands (void)
160 {
161   INDEX *idx;
162 
163   struct def { char *name; int in_code; }
164   *p, default_indices[] = {
165     "cp", 0, /* concepts */
166     "fn", 1, /* functions */
167     "vr", 1, /* variables */
168     "ky", 1, /* keystrokes */
169     "pg", 1, /* programs */
170     "tp", 1, /* types */
171     0, 0
172   };
173   int i, j;
174 
175   char name[] = "?index";
176   char name2[] = "??index";
177 
178 #define MAX (10 * 2)
179 
180 #define X(command) CM_##command, CM_##command##x
181   struct def_cmds { char *name; enum command_id id[MAX]; }
182     def_command_indices[] = {
183       "fn",
184 
185       {X(deffn),
186        X(deftypefn),
187        X(deftypeop),
188        X(defop),
189        X(defun),
190        X(defmac),
191        X(defspec),
192        X(deftypefun),
193        X(defmethod),
194        X(deftypemethod),
195       },
196 
197       "vr",
198 
199       {X(defvr),
200        X(deftypevr),
201        X(defcv),
202        X(deftypecv),
203        X(defvar),
204        X(defivar),
205        X(defopt),
206        X(deftypevar),
207        X(deftypeivar),
208       },
209 
210       "tp",
211 
212       {X(deftp),}
213     };
214 #undef X
215 
216   number_of_indices = 0;
217   num_index_commands = 0;
218 
219   for (p = default_indices; p->name; p++)
220     {
221       /* Both @cindex and @cpindex are added. */
222       idx = add_index_internal (strdup (p->name), p->in_code);
223 
224       *name = p->name[0];
225       add_index_command (name, idx); /* @cindex */
226 
227       name2[0] = p->name[0];
228       name2[1] = p->name[1];
229       add_index_command (name2, idx); /* @cpindex */
230     }
231 
232   associate_command_to_index (CM_vtable, index_by_name ("vr"));
233   associate_command_to_index (CM_ftable, index_by_name ("fn"));
234 
235   for (i = 0;
236        i < sizeof (def_command_indices) / sizeof (def_command_indices[0]);
237        i++)
238     {
239       enum command_id cmd;
240       idx = index_by_name (def_command_indices[i].name);
241       if (idx)
242         {
243           for (j = 0; j < MAX; j++)
244             {
245               cmd = def_command_indices[i].id[j];
246               if (cmd)
247                 associate_command_to_index (cmd, idx);
248             }
249         }
250     }
251 #undef MAX
252 }
253 
254 
255 /* A reference to an index entry, in the "index_entry" extra key of
256    an element.  index->index_entries[entry] is the referred-to index
257    entry.  Not actually used in api.c (element_to_perl_hash). */
258 typedef struct {
259     INDEX *index;
260     int entry;
261 } INDEX_ENTRY_REF;
262 
263 
264 /* INDEX_TYPE_COMMAND is used to determine which index to enter the entry in.
265    INDEX_AT_COMMAND is the Texinfo @-command defining the index entry.
266    CONTENT is an element whose contents represent the text of the
267    index entry.  CURRENT is the element in the main body of the manual that
268    the index entry refers to.
269 
270    CONTENT_NORMALIZED would be "the index entry content, independent
271    of the current language." */
272 void
enter_index_entry(enum command_id index_type_command,enum command_id index_at_command,ELEMENT * current,ELEMENT * content)273 enter_index_entry (enum command_id index_type_command,
274                    enum command_id index_at_command,
275                    ELEMENT *current, ELEMENT *content)
276 {
277   INDEX *idx;
278   INDEX_ENTRY *entry;
279   KEY_PAIR *k;
280 
281   idx = index_of_command (index_type_command);
282   if (idx->index_number == idx->index_space)
283     {
284       idx->index_entries = realloc (idx->index_entries,
285                              sizeof (INDEX_ENTRY) * (idx->index_space += 20));
286       if (!idx->index_entries)
287         fatal ("realloc failed");
288     }
289   entry = &idx->index_entries[idx->index_number++];
290   memset (entry, 0, sizeof (INDEX_ENTRY));
291 
292   entry->index_name = idx->name;
293   entry->index_at_command = index_at_command;
294   entry->index_type_command = index_type_command;
295   entry->index_prefix = idx->prefix;
296   entry->content = content;
297   entry->command = current;
298   entry->number = idx->index_number;
299 
300   k = lookup_extra (current, "sortas");
301   if (k)
302     entry->sortas = (char *) k->value;
303 
304   if (current_region ())
305     entry->region = current_region ();
306   else
307     entry->node = current_node;
308 
309   entry->number = idx->index_number;
310 
311 #if 0
312   /* This reference is not used in api.c when the Perl tree is output. */
313   {
314   INDEX_ENTRY_REF *ier;
315   ier = malloc (sizeof (INDEX_ENTRY_REF));
316   ier->index = idx;
317   ier->entry = idx->index_number - 1;
318 
319   add_extra_index_entry (current, "index_entry", ier);
320   }
321 #endif
322 
323   if (!current_region () && !current_node && !current_section)
324     line_warn ("entry for index `%s' outside of any node", idx->name);
325 }
326 
327 
328 INDEX *
ultimate_index(INDEX * index)329 ultimate_index (INDEX *index)
330 {
331   while (index->merged_in)
332     index = index->merged_in;
333   return index;
334 }
335