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