Bug Summary

File:src/gnu/usr.bin/texinfo/util/install-info.c
Warning:line 1329, column 35
Access to field 'entry_sections' results in a dereference of a null pointer (loaded from variable 'entries_to_add')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name install-info.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/texinfo/obj/util -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -I . -I /usr/src/gnu/usr.bin/texinfo/util -I .. -I /usr/src/gnu/usr.bin/texinfo/lib -I ../intl -D LOCALEDIR="/usr/share/locale" -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/usr.bin/texinfo/obj/util -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/gnu/usr.bin/texinfo/util/install-info.c
1/* install-info -- create Info directory entry(ies) for an Info file.
2 $Id: install-info.c,v 1.9 2015/11/14 23:06:06 deraadt Exp $
3
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
5 Foundation, 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 of the License, or
10 (at your option) 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
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
20
21#include "system.h"
22#include <getopt.h>
23
24static char *progname = "install-info";
25
26struct spec_entry;
27struct spec_section;
28
29struct line_data *findlines (char *data, int size, int *nlinesp);
30void insert_entry_here (struct spec_entry *entry, int line_number,
31 struct line_data *dir_lines, int n_entries);
32int compare_section_names (const void *s1, const void *s2);
33int compare_entries_text (const void *e1, const void *e2);
34
35/* Data structures. */
36
37
38/* Record info about a single line from a file as read into core. */
39struct line_data
40{
41 /* The start of the line. */
42 char *start;
43 /* The number of characters in the line,
44 excluding the terminating newline. */
45 int size;
46 /* Vector containing pointers to the entries to add before this line.
47 The vector is null-terminated. */
48 struct spec_entry **add_entries_before;
49 /* 1 means output any needed new sections before this line. */
50 int add_sections_before;
51 /* 1 means don't output this line. */
52 int delete;
53};
54
55
56/* This is used for a list of the specified menu section names
57 in which entries should be added. */
58struct spec_section
59{
60 struct spec_section *next;
61 char *name;
62 /* 1 means we have not yet found an existing section with this name
63 in the dir file--so we will need to add a new section. */
64 int missing;
65};
66
67
68/* This is used for a list of the entries specified to be added. */
69struct spec_entry
70{
71 struct spec_entry *next;
72 char *text;
73 int text_len;
74 /* A pointer to the list of sections to which this entry should be
75 added. */
76 struct spec_section *entry_sections;
77 /* A pointer to a section that is beyond the end of the chain whose
78 head is pointed to by entry_sections. */
79 struct spec_section *entry_sections_tail;
80};
81
82
83/* This is used for a list of nodes found by parsing the dir file. */
84struct node
85{
86 struct node *next;
87 /* The node name. */
88 char *name;
89 /* The line number of the line where the node starts.
90 This is the line that contains control-underscore. */
91 int start_line;
92 /* The line number of the line where the node ends,
93 which is the end of the file or where the next line starts. */
94 int end_line;
95 /* Start of first line in this node's menu
96 (the line after the * Menu: line). */
97 char *menu_start;
98 /* The start of the chain of sections in this node's menu. */
99 struct menu_section *sections;
100 /* The last menu section in the chain. */
101 struct menu_section *last_section;
102};
103
104
105/* This is used for a list of sections found in a node's menu.
106 Each struct node has such a list in the sections field. */
107struct menu_section
108{
109 struct menu_section *next;
110 char *name;
111 /* Line number of start of section. */
112 int start_line;
113 /* Line number of end of section. */
114 int end_line;
115};
116
117/* This table defines all the long-named options, says whether they
118 use an argument, and maps them into equivalent single-letter options. */
119
120struct option longopts[] =
121{
122 { "delete", no_argument0, NULL((void *)0), 'r' },
123 { "dir-file", required_argument1, NULL((void *)0), 'd' },
124 { "entry", required_argument1, NULL((void *)0), 'e' },
125 { "help", no_argument0, NULL((void *)0), 'h' },
126 { "infodir", required_argument1, NULL((void *)0), 'D' },
127 { "info-dir", required_argument1, NULL((void *)0), 'D' },
128 { "info-file", required_argument1, NULL((void *)0), 'i' },
129 { "item", required_argument1, NULL((void *)0), 'e' },
130 { "quiet", no_argument0, NULL((void *)0), 'q' },
131 { "remove", no_argument0, NULL((void *)0), 'r' },
132 { "section", required_argument1, NULL((void *)0), 's' },
133 { "version", no_argument0, NULL((void *)0), 'V' },
134 { 0 }
135};
136
137/* Error message functions. */
138
139/* Print error message. S1 is printf control string, S2 and S3 args for it. */
140
141/* VARARGS1 */
142void
143error (const char *s1, const char *s2, const char *s3)
144{
145 fprintf (stderr(&__sF[2]), "%s: ", progname);
146 fprintf (stderr(&__sF[2]), s1, s2, s3);
147 putc ('\n', stderr)(!__isthreaded ? __sputc('\n', (&__sF[2])) : (putc)('\n',
(&__sF[2])))
;
148}
149
150/* VARARGS1 */
151void
152warning (const char *s1, const char *s2, const char *s3)
153{
154 fprintf (stderr(&__sF[2]), _("%s: warning: ")((const char *) ("%s: warning: ")), progname);
155 fprintf (stderr(&__sF[2]), s1, s2, s3);
156 putc ('\n', stderr)(!__isthreaded ? __sputc('\n', (&__sF[2])) : (putc)('\n',
(&__sF[2])))
;
157}
158
159/* Print error message and exit. */
160
161void
162fatal (const char *s1, const char *s2, const char *s3)
163{
164 error (s1, s2, s3);
165 xexit (1);
166}
167
168/* Return a newly-allocated string
169 whose contents concatenate those of S1, S2, S3. */
170char *
171concat (const char *s1, const char *s2, const char *s3)
172{
173 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
174 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
175
176 strcpy (result, s1);
177 strcpy (result + len1, s2);
178 strcpy (result + len1 + len2, s3);
179 *(result + len1 + len2 + len3) = 0;
180
181 return result;
182}
183
184/* Return a string containing SIZE characters
185 copied from starting at STRING. */
186
187char *
188copy_string (const char *string, int size)
189{
190 int i;
191 char *copy = (char *) xmalloc (size + 1);
192 for (i = 0; i < size; i++)
193 copy[i] = string[i];
194 copy[size] = 0;
195 return copy;
196}
197
198/* Print fatal error message based on errno, with file name NAME. */
199
200void
201pfatal_with_name (const char *name)
202{
203 char *s = concat ("", strerror (errno(*__errno())), _(" for %s")((const char *) (" for %s")));
204 fatal (s, name, 0);
205}
206
207/* Compare the menu item names in LINE1 (line length LEN1)
208 and LINE2 (line length LEN2). Return 1 if the item name
209 in LINE1 is less, 0 otherwise. */
210
211static int
212menu_line_lessp (char *line1, int len1, char *line2, int len2)
213{
214 int minlen = (len1 < len2 ? len1 : len2);
215 int i;
216
217 for (i = 0; i < minlen; i++)
218 {
219 /* If one item name is a prefix of the other,
220 the former one is less. */
221 if (line1[i] == ':' && line2[i] != ':')
222 return 1;
223 if (line2[i] == ':' && line1[i] != ':')
224 return 0;
225 /* If they both continue and differ, one is less. */
226 if (line1[i] < line2[i])
227 return 1;
228 if (line1[i] > line2[i])
229 return 0;
230 }
231 /* With a properly formatted dir file,
232 we can only get here if the item names are equal. */
233 return 0;
234}
235
236/* Compare the menu item names in LINE1 (line length LEN1)
237 and LINE2 (line length LEN2). Return 1 if the item names are equal,
238 0 otherwise. */
239
240static int
241menu_line_equal (char *line1, int len1, char *line2, int len2)
242{
243 int minlen = (len1 < len2 ? len1 : len2);
244 int i;
245
246 for (i = 0; i < minlen; i++)
247 {
248 /* If both item names end here, they are equal. */
249 if (line1[i] == ':' && line2[i] == ':')
250 return 1;
251 /* If they both continue and differ, one is less. */
252 if (line1[i] != line2[i])
253 return 0;
254 }
255 /* With a properly formatted dir file,
256 we can only get here if the item names are equal. */
257 return 1;
258}
259
260
261/* Given the full text of a menu entry, null terminated,
262 return just the menu item name (copied). */
263
264char *
265extract_menu_item_name (char *item_text)
266{
267 char *p;
268
269 if (*item_text == '*')
270 item_text++;
271 while (*item_text == ' ')
272 item_text++;
273
274 p = item_text;
275 while (*p && *p != ':') p++;
276 return copy_string (item_text, p - item_text);
277}
278
279/* Given the full text of a menu entry, terminated by null or newline,
280 return just the menu item file (copied). */
281
282char *
283extract_menu_file_name (char *item_text)
284{
285 char *p = item_text;
286
287 /* If we have text that looks like * ITEM: (FILE)NODE...,
288 extract just FILE. Otherwise return "(none)". */
289
290 if (*p == '*')
291 p++;
292 while (*p == ' ')
293 p++;
294
295 /* Skip to and past the colon. */
296 while (*p && *p != '\n' && *p != ':') p++;
297 if (*p == ':') p++;
298
299 /* Skip past the open-paren. */
300 while (1)
301 {
302 if (*p == '(')
303 break;
304 else if (*p == ' ' || *p == '\t')
305 p++;
306 else
307 return "(none)";
308 }
309 p++;
310
311 item_text = p;
312
313 /* File name ends just before the close-paren. */
314 while (*p && *p != '\n' && *p != ')') p++;
315 if (*p != ')')
316 return "(none)";
317
318 return copy_string (item_text, p - item_text);
319}
320
321
322
323/* Return FNAME with any [.info][.gz] suffix removed. */
324
325static char *
326strip_info_suffix (char *fname)
327{
328 char *ret = xstrdup (fname);
329 unsigned len = strlen (ret);
330
331 if (len > 3 && FILENAME_CMPstrcmp (ret + len - 3, ".gz") == 0)
332 {
333 len -= 3;
334 ret[len] = 0;
335 }
336 else if (len > 4 && FILENAME_CMPstrcmp (ret + len - 4, ".bz2") == 0)
337 {
338 len -= 4;
339 ret[len] = 0;
340 }
341
342 if (len > 5 && FILENAME_CMPstrcmp (ret + len - 5, ".info") == 0)
343 {
344 len -= 5;
345 ret[len] = 0;
346 }
347 else if (len > 4 && FILENAME_CMPstrcmp (ret + len - 4, ".inf") == 0)
348 {
349 len -= 4;
350 ret[len] = 0;
351 }
352#ifdef __MSDOS__
353 else if (len > 4 && (FILENAME_CMPstrcmp (ret + len - 4, ".inz") == 0
354 || FILENAME_CMPstrcmp (ret + len - 4, ".igz") == 0))
355 {
356 len -= 4;
357 ret[len] = 0;
358 }
359#endif /* __MSDOS__ */
360
361 return ret;
362}
363
364
365/* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
366 can also be followed by `.gz', `.info.gz', or `.info' (and then
367 TERM_CHAR) and still match. */
368
369static int
370menu_item_equal (const char *item, char term_char, const char *name)
371{
372 int ret;
373 const char *item_basename = item;
374 unsigned name_len = strlen (name);
375
376 /* We must compare the basename in ITEM, since we are passed the
377 basename of the original info file. Otherwise, a new entry like
378 "lilypond/lilypond" won't match "lilypond".
379
380 Actually, it seems to me that we should really compare the whole
381 name, and not just the basename. Couldn't there be dir1/foo.info
382 and dir2/foo.info? Also, it seems like we should be using the
383 filename from the new dir entries, not the filename on the command
384 line. Not worrying about those things right now, though. --karl,
385 26mar04. */
386 while (*item_basename && !IS_SLASH (*item_basename)((*item_basename) == '/')
387 && *item_basename != term_char)
388 item_basename++;
389 if (! *item_basename || *item_basename == term_char)
390 item_basename = item; /* no /, use original */
391 else
392 item_basename++; /* have /, move past it */
393
394 /* First, ITEM must actually match NAME (usually it won't). */
395 ret = strncasecmp (item_basename, name, name_len) == 0;
396 if (ret)
397 {
398 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
399 ITEM. The various suffixes should never actually appear in the
400 dir file, but sometimes people put them in. */
401 static char *suffixes[]
402 = { "", ".info.gz", ".info", ".inf", ".gz",
403#ifdef __MSDOS__
404 ".inz", ".igz",
405#endif
406 NULL((void *)0) };
407 unsigned i;
408 ret = 0;
409 for (i = 0; !ret && suffixes[i]; i++)
410 {
411 char *suffix = suffixes[i];
412 unsigned suffix_len = strlen (suffix);
413 ret = strncasecmp (item_basename + name_len, suffix, suffix_len) == 0
414 && item_basename[name_len + suffix_len] == term_char;
415 }
416 }
417
418 return ret;
419}
420
421
422
423void
424suggest_asking_for_help (void)
425{
426 fprintf (stderr(&__sF[2]), _("\tTry `%s --help' for a complete list of options.\n")((const char *) ("\tTry `%s --help' for a complete list of options.\n"
))
,
427 progname);
428 xexit (1);
429}
430
431void
432print_help (void)
433{
434 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
435\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
436Install or delete dir entries from INFO-FILE in the Info directory file\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
437DIR-FILE.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
438\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
439Options:\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
440 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
441 don't insert any new entries.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
442 --dir-file=NAME specify file name of Info directory file.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
443 This is equivalent to using the DIR-FILE argument.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
444 --entry=TEXT insert TEXT as an Info directory entry.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
445 TEXT should have the form of an Info menu item line\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
446 plus zero or more extra lines starting with whitespace.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
447 If you specify more than one entry, they are all added.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
448 If you don't specify any entries, they are determined\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
449 from information in the Info file itself.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
450 --help display this help and exit.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
451 --info-file=FILE specify Info file to install in the directory.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
452 This is equivalent to using the INFO-FILE argument.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
453 --info-dir=DIR same as --dir-file=DIR/dir.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
454 --item=TEXT same as --entry TEXT.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
455 An Info directory entry is actually a menu item.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
456 --quiet suppress warnings.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
457 --remove same as --delete.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
458 --section=SEC put this file's entries in section SEC of the directory.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
459 If you specify more than one section, all the entries\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
460 are added in each of the sections.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
461 If you don't specify any sections, they are determined\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
462 from information in the Info file itself.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
463 --version display version information and exit.\n\((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
464")((const char *) ("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\nInstall or delete dir entries from INFO-FILE in the Info directory file\nDIR-FILE.\n\nOptions:\n --delete delete existing entries for INFO-FILE from DIR-FILE;\n don't insert any new entries.\n --dir-file=NAME specify file name of Info directory file.\n This is equivalent to using the DIR-FILE argument.\n --entry=TEXT insert TEXT as an Info directory entry.\n TEXT should have the form of an Info menu item line\n plus zero or more extra lines starting with whitespace.\n If you specify more than one entry, they are all added.\n If you don't specify any entries, they are determined\n from information in the Info file itself.\n --help display this help and exit.\n --info-file=FILE specify Info file to install in the directory.\n This is equivalent to using the INFO-FILE argument.\n --info-dir=DIR same as --dir-file=DIR/dir.\n --item=TEXT same as --entry TEXT.\n An Info directory entry is actually a menu item.\n --quiet suppress warnings.\n --remove same as --delete.\n --section=SEC put this file's entries in section SEC of the directory.\n If you specify more than one section, all the entries\n are added in each of the sections.\n If you don't specify any sections, they are determined\n from information in the Info file itself.\n --version display version information and exit.\n"
))
, progname);
465
466 puts (_("\n\((const char *) ("\nEmail bug reports to bug-texinfo@gnu.org,\ngeneral questions and discussion to help-texinfo@gnu.org.\nTexinfo home page: http://www.gnu.org/software/texinfo/"
))
467Email bug reports to bug-texinfo@gnu.org,\n\((const char *) ("\nEmail bug reports to bug-texinfo@gnu.org,\ngeneral questions and discussion to help-texinfo@gnu.org.\nTexinfo home page: http://www.gnu.org/software/texinfo/"
))
468general questions and discussion to help-texinfo@gnu.org.\n\((const char *) ("\nEmail bug reports to bug-texinfo@gnu.org,\ngeneral questions and discussion to help-texinfo@gnu.org.\nTexinfo home page: http://www.gnu.org/software/texinfo/"
))
469Texinfo home page: http://www.gnu.org/software/texinfo/")((const char *) ("\nEmail bug reports to bug-texinfo@gnu.org,\ngeneral questions and discussion to help-texinfo@gnu.org.\nTexinfo home page: http://www.gnu.org/software/texinfo/"
))
);
470}
471
472
473/* If DIRFILE does not exist, create a minimal one (or abort). If it
474 already exists, do nothing. */
475
476void
477ensure_dirfile_exists (char *dirfile)
478{
479 int desc = open (dirfile, O_RDONLY0x0000);
480 if (desc < 0 && errno(*__errno()) == ENOENT2)
481 {
482 FILE *f;
483 char *readerr = strerror (errno(*__errno()));
484 close (desc);
485 f = fopen (dirfile, "w");
486 if (f)
487 {
488 fprintf (f, _("This is the file .../info/dir, which contains the\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
489topmost node of the Info hierarchy, called (dir)Top.\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
490The first time you invoke Info you start off looking at this node.\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
491\x1f\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
492%s\tThis is the top of the INFO tree\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
493\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
494 This (the Directory node) gives a menu of major topics.\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
495 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
496 \"h\" gives a primer for first-timers,\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
497 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
498\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
499 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
500 to select it.\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
501\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
502%s\n\((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
503")((const char *) ("This is the file .../info/dir, which contains the\ntopmost node of the Info hierarchy, called (dir)Top.\nThe first time you invoke Info you start off looking at this node.\n\x1f\n%s\tThis is the top of the INFO tree\n\n This (the Directory node) gives a menu of major topics.\n Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n \"h\" gives a primer for first-timers,\n \"mEmacs<Return>\" visits the Emacs manual, etc.\n\n In Emacs, you can click mouse button 2 on a menu item or cross reference\n to select it.\n\n%s\n"
))
, "File: dir,\tNode: Top", /* These keywords must not be translated. */
504 "* Menu:"
505);
506 if (fclose (f) < 0)
507 pfatal_with_name (dirfile);
508 }
509 else
510 {
511 /* Didn't exist, but couldn't open for writing. */
512 fprintf (stderr(&__sF[2]),
513 _("%s: could not read (%s) and could not create (%s)\n")((const char *) ("%s: could not read (%s) and could not create (%s)\n"
))
,
514 dirfile, readerr, strerror (errno(*__errno())));
515 xexit (1);
516 }
517 }
518 else
519 close (desc); /* It already existed, so fine. */
520}
521
522/* Open FILENAME and return the resulting stream pointer. If it doesn't
523 exist, try FILENAME.gz. If that doesn't exist either, call
524 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
525 non-NULL. If still no luck, fatal error.
526
527 If we do open it, return the actual name of the file opened in
528 OPENED_FILENAME and the compress program to use to (de)compress it in
529 COMPRESSION_PROGRAM. The compression program is determined by the
530 magic number, not the filename. */
531
532FILE *
533open_possibly_compressed_file (char *filename,
534 void (*create_callback) (char *),
535 char **opened_filename, char **compression_program, int *is_pipe)
536{
537 char *local_opened_filename, *local_compression_program;
538 int nread;
539 char data[4];
540 FILE *f;
541
542 /* We let them pass NULL if they don't want this info, but it's easier
543 to always determine it. */
544 if (!opened_filename)
545 opened_filename = &local_opened_filename;
546
547 *opened_filename = filename;
548 f = fopen (*opened_filename, FOPEN_RBIN"r");
549 if (!f)
550 {
551 *opened_filename = concat (filename, ".gz", "");
552 f = fopen (*opened_filename, FOPEN_RBIN"r");
553 if (!f)
554 {
555 free (*opened_filename);
556 *opened_filename = concat (filename, ".bz2", "");
557 f = fopen (*opened_filename, FOPEN_RBIN"r");
558 }
559
560#ifdef __MSDOS__
561 if (!f)
562 {
563 free (*opened_filename);
564 *opened_filename = concat (filename, ".igz", "");
565 f = fopen (*opened_filename, FOPEN_RBIN"r");
566 }
567 if (!f)
568 {
569 free (*opened_filename);
570 *opened_filename = concat (filename, ".inz", "");
571 f = fopen (*opened_filename, FOPEN_RBIN"r");
572 }
573#endif
574 if (!f)
575 {
576 if (create_callback)
577 { /* That didn't work either. Create the file if we can. */
578 (*create_callback) (filename);
579
580 /* And try opening it again. */
581 free (*opened_filename);
582 *opened_filename = filename;
583 f = fopen (*opened_filename, FOPEN_RBIN"r");
584 if (!f)
585 pfatal_with_name (filename);
586 }
587 else
588 pfatal_with_name (filename);
589 }
590 }
591
592 /* Read first few bytes of file rather than relying on the filename.
593 If the file is shorter than this it can't be usable anyway. */
594 nread = fread (data, sizeof (data), 1, f);
595 if (nread != 1)
596 {
597 /* Empty files don't set errno, so we get something like
598 "install-info: No error for foo", which is confusing. */
599 if (nread == 0)
600 fatal (_("%s: empty file")((const char *) ("%s: empty file")), *opened_filename, 0);
601 pfatal_with_name (*opened_filename);
602 }
603
604 if (!compression_program)
605 compression_program = &local_compression_program;
606
607 if (data[0] == '\x1f' && data[1] == '\x8b')
608#if STRIP_DOT_EXE0
609 /* An explicit .exe yields a better diagnostics from popen below
610 if they don't have gzip installed. */
611 *compression_program = "gzip.exe";
612#else
613 *compression_program = "gzip";
614#endif
615 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == 'h')
616#ifndef STRIP_DOT_EXE0
617 *compression_program = "bzip2.exe";
618#else
619 *compression_program = "bzip2";
620#endif
621 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == '0')
622#ifndef STRIP_DOT_EXE0
623 *compression_program = "bzip.exe";
624#else
625 *compression_program = "bzip";
626#endif
627 else
628 *compression_program = NULL((void *)0);
629
630 if (*compression_program)
631 { /* It's compressed, so fclose the file and then open a pipe. */
632 char *command = concat (*compression_program," -cd <", *opened_filename);
633 if (fclose (f) < 0)
634 pfatal_with_name (*opened_filename);
635 f = popen (command, "r");
636 if (f)
637 *is_pipe = 1;
638 else
639 pfatal_with_name (command);
640 }
641 else
642 { /* It's a plain file, seek back over the magic bytes. */
643 if (fseek (f, 0, 0) < 0)
644 pfatal_with_name (*opened_filename);
645#if O_BINARY0
646 /* Since this is a text file, and we opened it in binary mode,
647 switch back to text mode. */
648 f = freopen (*opened_filename, "r", f);
649#endif
650 *is_pipe = 0;
651 }
652
653 return f;
654}
655
656/* Read all of file FILENAME into memory and return the address of the
657 data. Store the size of the data into SIZEP. If need be, uncompress
658 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
659 the actual file name that was opened into OPENED_FILENAME (if it is
660 non-NULL), and the companion compression program (if any, else NULL)
661 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
662 a fatal error. */
663
664char *
665readfile (char *filename, int *sizep,
666 void (*create_callback) (char *), char **opened_filename,
667 char **compression_program)
668{
669 char *real_name;
670 FILE *f;
671 int pipe_p;
672 int filled = 0;
673 int data_size = 8192;
674 char *data = xmalloc (data_size);
675
676 /* If they passed the space for the file name to return, use it. */
677 f = open_possibly_compressed_file (filename, create_callback,
678 opened_filename ? opened_filename
679 : &real_name,
680 compression_program, &pipe_p);
681
682 for (;;)
683 {
684 int nread = fread (data + filled, 1, data_size - filled, f);
685 if (nread < 0)
686 pfatal_with_name (real_name);
687 if (nread == 0)
688 break;
689
690 filled += nread;
691 if (filled == data_size)
692 {
693 data_size += 65536;
694 data = xrealloc (data, data_size);
695 }
696 }
697
698 /* We'll end up wasting space if we're not passing the filename back
699 and it is not just FILENAME, but so what. */
700 /* We need to close the stream, since on some systems the pipe created
701 by popen is simulated by a temporary file which only gets removed
702 inside pclose. */
703 if (pipe_p)
704 pclose (f);
705 else
706 fclose (f);
707
708 *sizep = filled;
709 return data;
710}
711
712/* Output the old dir file, interpolating the new sections
713 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
714 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
715 we'll write dir.gz on output. */
716
717static void
718output_dirfile (char *dirfile, int dir_nlines, struct line_data *dir_lines,
719 int n_entries_to_add, struct spec_entry *entries_to_add,
720 struct spec_section *input_sections, char *compression_program)
721{
722 int i;
723 FILE *output;
724
725 if (compression_program)
726 {
727 char *command = concat (compression_program, ">", dirfile);
728 output = popen (command, "w");
729 }
730 else
731 output = fopen (dirfile, "w");
732
733 if (!output)
734 {
735 perror (dirfile);
736 xexit (1);
737 }
738
739 for (i = 0; i <= dir_nlines; i++)
740 {
741 int j;
742
743 /* If we decided to output some new entries before this line,
744 output them now. */
745 if (dir_lines[i].add_entries_before)
746 for (j = 0; j < n_entries_to_add; j++)
747 {
748 struct spec_entry *this = dir_lines[i].add_entries_before[j];
749 if (this == 0)
750 break;
751 fputs (this->text, output);
752 }
753 /* If we decided to add some sections here
754 because there are no such sections in the file,
755 output them now. */
756 if (dir_lines[i].add_sections_before)
757 {
758 struct spec_section *spec;
759 struct spec_section **sections;
760 int n_sections = 0;
761 struct spec_entry *entry;
762 struct spec_entry **entries;
763 int n_entries = 0;
764
765 /* Count the sections and allocate a vector for all of them. */
766 for (spec = input_sections; spec; spec = spec->next)
767 n_sections++;
768 sections = ((struct spec_section **)
769 xmalloc (n_sections * sizeof (struct spec_section *)));
770
771 /* Fill the vector SECTIONS with pointers to all the sections,
772 and sort them. */
773 j = 0;
774 for (spec = input_sections; spec; spec = spec->next)
775 sections[j++] = spec;
776 qsort (sections, n_sections, sizeof (struct spec_section *),
777 compare_section_names);
778
779 /* Count the entries and allocate a vector for all of them. */
780 for (entry = entries_to_add; entry; entry = entry->next)
781 n_entries++;
782 entries = ((struct spec_entry **)
783 xmalloc (n_entries * sizeof (struct spec_entry *)));
784
785 /* Fill the vector ENTRIES with pointers to all the sections,
786 and sort them. */
787 j = 0;
788 for (entry = entries_to_add; entry; entry = entry->next)
789 entries[j++] = entry;
790 qsort (entries, n_entries, sizeof (struct spec_entry *),
791 compare_entries_text);
792
793 /* Generate the new sections in alphabetical order. In each
794 new section, output all of the entries that belong to that
795 section, in alphabetical order. */
796 for (j = 0; j < n_sections; j++)
797 {
798 spec = sections[j];
799 if (spec->missing)
800 {
801 int k;
802
803 putc ('\n', output)(!__isthreaded ? __sputc('\n', output) : (putc)('\n', output)
)
;
804 fputs (spec->name, output);
805 putc ('\n', output)(!__isthreaded ? __sputc('\n', output) : (putc)('\n', output)
)
;
806 for (k = 0; k < n_entries; k++)
807 {
808 struct spec_section *spec1;
809 /* Did they at all want this entry to be put into
810 this section? */
811 entry = entries[k];
812 for (spec1 = entry->entry_sections;
813 spec1 && spec1 != entry->entry_sections_tail;
814 spec1 = spec1->next)
815 {
816 if (!strcmp (spec1->name, spec->name))
817 break;
818 }
819 if (spec1 && spec1 != entry->entry_sections_tail)
820 fputs (entry->text, output);
821 }
822 }
823 }
824
825 free (entries);
826 free (sections);
827 }
828
829 /* Output the original dir lines unless marked for deletion. */
830 if (i < dir_nlines && !dir_lines[i].delete)
831 {
832 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
833 putc ('\n', output)(!__isthreaded ? __sputc('\n', output) : (putc)('\n', output)
)
;
834 }
835 }
836
837 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
838 On those systems, the compressor actually gets run inside pclose,
839 so we must call pclose. */
840 if (compression_program)
841 pclose (output);
842 else
843 fclose (output);
844}
845
846/* Parse the input to find the section names and the entry names it
847 specifies. Return the number of entries to add from this file. */
848int
849parse_input (const struct line_data *lines, int nlines,
850 struct spec_section **sections, struct spec_entry **entries)
851{
852 int n_entries = 0;
853 int prefix_length = strlen ("INFO-DIR-SECTION ");
854 struct spec_section *head = *sections, *tail = NULL((void *)0);
855 int reset_tail = 0;
856 char *start_of_this_entry = 0;
857 int ignore_sections = *sections != 0;
858 int ignore_entries = *entries != 0;
859
860 int i;
861
862 if (ignore_sections && ignore_entries)
863 return 0;
864
865 /* Loop here processing lines from the input file. Each
866 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
867 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
868 list, and all its entries inherit the chain of SECTION entries
869 defined by the last group of INFO-DIR-SECTION entries we have
870 seen until that point. */
871 for (i = 0; i < nlines; i++)
872 {
873 if (!ignore_sections
874 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
875 {
876 struct spec_section *next
877 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
878 next->name = copy_string (lines[i].start + prefix_length,
879 lines[i].size - prefix_length);
880 next->next = *sections;
881 next->missing = 1;
882 if (reset_tail)
883 {
884 tail = *sections;
885 reset_tail = 0;
886 }
887 *sections = next;
888 head = *sections;
889 }
890 /* If entries were specified explicitly with command options,
891 ignore the entries in the input file. */
892 else if (!ignore_entries)
893 {
894 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
895 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
896 {
897 if (!*sections)
898 {
899 /* We found an entry, but didn't yet see any sections
900 specified. Default to section "Miscellaneous". */
901 *sections = (struct spec_section *)
902 xmalloc (sizeof (struct spec_section));
903 (*sections)->name = "Miscellaneous";
904 (*sections)->next = 0;
905 (*sections)->missing = 1;
906 head = *sections;
907 }
908 /* Next time we see INFO-DIR-SECTION, we will reset the
909 tail pointer. */
910 reset_tail = 1;
911
912 if (start_of_this_entry != 0)
913 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY")((const char *) ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"
))
, 0, 0);
914 start_of_this_entry = lines[i + 1].start;
915 }
916 else if (start_of_this_entry)
917 {
918 if ((!strncmp ("* ", lines[i].start, 2)
919 && lines[i].start > start_of_this_entry)
920 || (!strncmp ("END-INFO-DIR-ENTRY",
921 lines[i].start, lines[i].size)
922 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
923 {
924 /* We found an end of this entry. Allocate another
925 entry, fill its data, and add it to the linked
926 list. */
927 struct spec_entry *next
928 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
929 next->text
930 = copy_string (start_of_this_entry,
931 lines[i].start - start_of_this_entry);
932 next->text_len = lines[i].start - start_of_this_entry;
933 next->entry_sections = head;
934 next->entry_sections_tail = tail;
935 next->next = *entries;
936 *entries = next;
937 n_entries++;
938 if (!strncmp ("END-INFO-DIR-ENTRY",
939 lines[i].start, lines[i].size)
940 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
941 start_of_this_entry = 0;
942 else
943 start_of_this_entry = lines[i].start;
944 }
945 else if (!strncmp ("END-INFO-DIR-ENTRY",
946 lines[i].start, lines[i].size)
947 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
948 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY")((const char *) ("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"
))
, 0, 0);
949 }
950 }
951 }
952 if (start_of_this_entry != 0)
953 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY")((const char *) ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"
))
,
954 0, 0);
955
956 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
957 and plug the names of all the sections we found into every
958 element of the ENTRIES list. */
959 if (ignore_entries && *entries)
960 {
961 struct spec_entry *entry;
962
963 for (entry = *entries; entry; entry = entry->next)
964 {
965 entry->entry_sections = head;
966 entry->entry_sections_tail = tail;
967 }
968 }
969
970 return n_entries;
971}
972
973/* Parse the dir file whose basename is BASE_NAME. Find all the
974 nodes, and their menus, and the sections of their menus. */
975int
976parse_dir_file (struct line_data *lines, int nlines, struct node **nodes,
977 const char *base_name)
978{
979 int node_header_flag = 0;
980 int something_deleted = 0;
981 int i;
982
983 *nodes = 0;
984 for (i = 0; i < nlines; i++)
985 {
986 /* Parse node header lines. */
987 if (node_header_flag)
988 {
989 int j, end;
990 for (j = 0; j < lines[i].size; j++)
991 /* Find the node name and store it in the `struct node'. */
992 if (!strncmp ("Node:", lines[i].start + j, 5))
993 {
994 char *line = lines[i].start;
995 /* Find the start of the node name. */
996 j += 5;
997 while (line[j] == ' ' || line[j] == '\t')
998 j++;
999 /* Find the end of the node name. */
1000 end = j;
1001 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
1002 && line[end] != '\t')
1003 end++;
1004 (*nodes)->name = copy_string (line + j, end - j);
1005 }
1006 node_header_flag = 0;
1007 }
1008
1009 /* Notice the start of a node. */
1010 if (*lines[i].start == 037)
1011 {
1012 struct node *next = (struct node *) xmalloc (sizeof (struct node));
1013
1014 next->next = *nodes;
1015 next->name = NULL((void *)0);
1016 next->start_line = i;
1017 next->end_line = 0;
1018 next->menu_start = NULL((void *)0);
1019 next->sections = NULL((void *)0);
1020 next->last_section = NULL((void *)0);
1021
1022 if (*nodes != 0)
1023 (*nodes)->end_line = i;
1024 /* Fill in the end of the last menu section
1025 of the previous node. */
1026 if (*nodes != 0 && (*nodes)->last_section != 0)
1027 (*nodes)->last_section->end_line = i;
1028
1029 *nodes = next;
1030
1031 /* The following line is the header of this node;
1032 parse it. */
1033 node_header_flag = 1;
1034 }
1035
1036 /* Notice the lines that start menus. */
1037 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
1038 (*nodes)->menu_start = lines[i + 1].start;
1039
1040 /* Notice sections in menus. */
1041 if (*nodes != 0
1042 && (*nodes)->menu_start != 0
1043 && *lines[i].start != '\n'
1044 && *lines[i].start != '*'
1045 && *lines[i].start != ' '
1046 && *lines[i].start != '\t')
1047 {
1048 /* Add this menu section to the node's list.
1049 This list grows in forward order. */
1050 struct menu_section *next
1051 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1052
1053 next->start_line = i + 1;
1054 next->next = 0;
1055 next->end_line = 0;
1056 next->name = copy_string (lines[i].start, lines[i].size);
1057 if ((*nodes)->sections)
1058 {
1059 (*nodes)->last_section->next = next;
1060 (*nodes)->last_section->end_line = i;
1061 }
1062 else
1063 (*nodes)->sections = next;
1064 (*nodes)->last_section = next;
1065 }
1066
1067 /* Check for an existing entry that should be deleted.
1068 Delete all entries which specify this file name. */
1069 if (*lines[i].start == '*')
1070 {
1071 char *q;
1072 char *p = lines[i].start;
1073
1074 p++; /* skip * */
1075 while (*p == ' ') p++; /* ignore following spaces */
1076 q = p; /* remember this, it's the beginning of the menu item. */
1077
1078 /* Read menu item. */
1079 while (*p != 0 && *p != ':')
1080 p++;
1081 p++; /* skip : */
1082
1083 if (*p == ':')
1084 { /* XEmacs-style entry, as in * Mew::Messaging. */
1085 if (menu_item_equal (q, ':', base_name))
1086 {
1087 lines[i].delete = 1;
1088 something_deleted = 1;
1089 }
1090 }
1091 else
1092 { /* Emacs-style entry, as in * Emacs: (emacs). */
1093 while (*p == ' ') p++; /* skip spaces after : */
1094 if (*p == '(') /* if at parenthesized (FILENAME) */
1095 {
1096 p++;
1097 if (menu_item_equal (p, ')', base_name))
1098 {
1099 lines[i].delete = 1;
1100 something_deleted = 1;
1101 }
1102 }
1103 }
1104 }
1105
1106 /* Treat lines that start with whitespace
1107 as continuations; if we are deleting an entry,
1108 delete all its continuations as well. */
1109 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1110 {
1111 lines[i].delete = lines[i - 1].delete;
1112 }
1113 }
1114
1115 /* Finish the info about the end of the last node. */
1116 if (*nodes != 0)
1117 {
1118 (*nodes)->end_line = nlines;
1119 if ((*nodes)->last_section != 0)
1120 (*nodes)->last_section->end_line = nlines;
1121 }
1122
1123 return something_deleted;
1124}
1125
1126int
1127main (int argc, char **argv)
1128{
1129 char *opened_dirfilename;
1130 char *compression_program;
1131 char *infile_sans_info;
1132 char *infile = 0, *dirfile = 0;
1133
1134 /* Record the text of the Info file, as a sequence of characters
1135 and as a sequence of lines. */
1136 char *input_data = NULL((void *)0);
1137 int input_size = 0;
1138 struct line_data *input_lines = NULL((void *)0);
1139 int input_nlines = 0;
1140
1141 /* Record here the specified section names and directory entries. */
1142 struct spec_section *input_sections = NULL((void *)0);
1143 struct spec_entry *entries_to_add = NULL((void *)0);
1144 int n_entries_to_add = 0;
1145
1146 /* Record the old text of the dir file, as plain characters,
1147 as lines, and as nodes. */
1148 char *dir_data;
1149 int dir_size;
1150 int dir_nlines;
1151 struct line_data *dir_lines;
1152 struct node *dir_nodes;
1153
1154 /* Nonzero means --delete was specified (just delete existing entries). */
1155 int delete_flag = 0;
1156 int something_deleted = 0;
1157 /* Nonzero means -q was specified. */
1158 int quiet_flag = 0;
1159
1160 int i;
1161
1162#ifdef HAVE_SETLOCALE1
1163 /* Set locale via LC_ALL. */
1164 setlocale (LC_ALL0, "");
1165#endif
1166
1167 if (pledge ("stdio rpath wpath cpath proc exec", NULL((void *)0)) == -1)
1
Assuming the condition is false
2
Taking false branch
1168 pfatal_with_name ("pledge");
1169
1170 /* Set the text message domain. */
1171 bindtextdomain (PACKAGE, LOCALEDIR)((const char *) ("/usr/share/locale"));
1172 textdomain (PACKAGE)((const char *) ("texinfo"));
1173
1174 while (1)
3
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
1175 {
1176 int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
1177
1178 if (opt == EOF(-1))
4
Assuming the condition is false
5
Taking false branch
10
Assuming the condition is true
11
Taking true branch
1179 break;
12
Execution continues on line 1280
1180
1181 switch (opt)
6
Control jumps to 'case 68:' at line 1201
1182 {
1183 case 0:
1184 /* If getopt returns 0, then it has already processed a
1185 long-named option. We should do nothing. */
1186 break;
1187
1188 case 1:
1189 abort ();
1190
1191 case 'd':
1192 if (dirfile)
1193 {
1194 fprintf (stderr(&__sF[2]), _("%s: already have dir file: %s\n")((const char *) ("%s: already have dir file: %s\n")),
1195 progname, dirfile);
1196 suggest_asking_for_help ();
1197 }
1198 dirfile = optarg;
1199 break;
1200
1201 case 'D':
1202 if (dirfile
6.1
'dirfile' is null
)
7
Taking false branch
1203 {
1204 fprintf (stderr(&__sF[2]), _("%s: already have dir file: %s\n")((const char *) ("%s: already have dir file: %s\n")),
1205 progname, dirfile);
1206 suggest_asking_for_help ();
1207 }
1208 dirfile = concat (optarg, "", "/dir");
1209 break;
8
Execution continues on line 1174
1210
1211 case 'e':
1212 {
1213 struct spec_entry *next
1214 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1215 int olen = strlen (optarg);
1216 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
1217 {
1218 optarg = concat (optarg, "\n", "");
1219 olen++;
1220 }
1221 next->text = optarg;
1222 next->text_len = olen;
1223 next->entry_sections = NULL((void *)0);
1224 next->entry_sections_tail = NULL((void *)0);
1225 next->next = entries_to_add;
1226 entries_to_add = next;
1227 n_entries_to_add++;
1228 }
1229 break;
1230
1231 case 'h':
1232 case 'H':
1233 print_help ();
1234 xexit (0);
1235
1236 case 'i':
1237 if (infile)
1238 {
1239 fprintf (stderr(&__sF[2]), _("%s: Specify the Info file only once.\n")((const char *) ("%s: Specify the Info file only once.\n")),
1240 progname);
1241 suggest_asking_for_help ();
1242 }
1243 infile = optarg;
1244 break;
1245
1246 case 'q':
1247 quiet_flag = 1;
1248 break;
1249
1250 case 'r':
1251 delete_flag = 1;
1252 break;
1253
1254 case 's':
1255 {
1256 struct spec_section *next
1257 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1258 next->name = optarg;
1259 next->next = input_sections;
1260 next->missing = 1;
1261 input_sections = next;
1262 }
1263 break;
1264
1265 case 'V':
1266 printf ("install-info (GNU %s) %s\n", PACKAGE"texinfo", VERSION"4.8");
1267 puts ("");
1268 puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
1269 printf (_("There is NO warranty. You may redistribute this software\n\((const char *) ("There is NO warranty. You may redistribute this software\nunder the terms of the GNU General Public License.\nFor more information about these matters, see the files named COPYING.\n"
))
1270under the terms of the GNU General Public License.\n\((const char *) ("There is NO warranty. You may redistribute this software\nunder the terms of the GNU General Public License.\nFor more information about these matters, see the files named COPYING.\n"
))
1271For more information about these matters, see the files named COPYING.\n")((const char *) ("There is NO warranty. You may redistribute this software\nunder the terms of the GNU General Public License.\nFor more information about these matters, see the files named COPYING.\n"
))
);
1272 xexit (0);
1273
1274 default:
1275 suggest_asking_for_help ();
1276 }
1277 }
1278
1279 /* Interpret the non-option arguments as file names. */
1280 for (; optind < argc; ++optind)
13
Assuming 'optind' is < 'argc'
14
Loop condition is true. Entering loop body
16
Assuming 'optind' is >= 'argc'
17
Loop condition is false. Execution continues on line 1290
1281 {
1282 if (infile
14.1
'infile' is equal to null
== 0)
15
Taking true branch
1283 infile = argv[optind];
1284 else if (dirfile == 0)
1285 dirfile = argv[optind];
1286 else
1287 error (_("excess command line argument `%s'")((const char *) ("excess command line argument `%s'")), argv[optind], 0);
1288 }
1289
1290 if (!infile)
18
Assuming 'infile' is non-null
19
Taking false branch
1291 fatal (_("No input file specified; try --help for more information.")((const char *) ("No input file specified; try --help for more information."
))
,
1292 0, 0);
1293 if (!dirfile
19.1
'dirfile' is non-null
)
20
Taking false branch
1294 fatal (_("No dir file specified; try --help for more information.")((const char *) ("No dir file specified; try --help for more information."
))
, 0, 0);
1295
1296 /* Read the Info file and parse it into lines, unless we're deleting. */
1297 if (!delete_flag
20.1
'delete_flag' is 0
)
21
Taking true branch
1298 {
1299 input_data = readfile (infile, &input_size, NULL((void *)0), NULL((void *)0), NULL((void *)0));
1300 input_lines = findlines (input_data, input_size, &input_nlines);
1301 }
1302
1303 i = parse_input (input_lines, input_nlines,
22
Value assigned to 'entries_to_add'
1304 &input_sections, &entries_to_add);
1305 if (i > n_entries_to_add)
23
Assuming 'i' is > 'n_entries_to_add'
24
Taking true branch
1306 n_entries_to_add = i;
1307
1308 if (!delete_flag
24.1
'delete_flag' is 0
)
25
Taking true branch
1309 {
1310 if (entries_to_add == 0)
26
Assuming 'entries_to_add' is equal to null
27
Taking true branch
1311 { /* No need to abort here, the original info file may not
1312 have the requisite Texinfo commands. This is not
1313 something an installer should have to correct (it's a
1314 problem for the maintainer), and there's no need to cause
1315 subsequent parts of `make install' to fail. */
1316 warning (_("no info dir entry in `%s'")((const char *) ("no info dir entry in `%s'")), infile, 0);
1317 xexit (0);
1318 }
1319
1320 /* If the entries came from the command-line arguments, their
1321 entry_sections pointers are not yet set. Walk the chain of
1322 the entries and for each entry update entry_sections to point
1323 to the head of the list of sections where this entry should
1324 be put. Note that all the entries specified on the command
1325 line get put into ALL the sections we've got, either from the
1326 Info file, or (under --section) from the command line,
1327 because in the loop below every entry inherits the entire
1328 chain of sections. */
1329 if (n_entries_to_add
27.1
'n_entries_to_add' is > 0
> 0 && entries_to_add->entry_sections == NULL((void *)0))
28
Access to field 'entry_sections' results in a dereference of a null pointer (loaded from variable 'entries_to_add')
1330 {
1331 struct spec_entry *ep;
1332
1333 /* If we got no sections, default to "Miscellaneous". */
1334 if (input_sections == NULL((void *)0))
1335 {
1336 input_sections = (struct spec_section *)
1337 xmalloc (sizeof (struct spec_section));
1338 input_sections->name = "Miscellaneous";
1339 input_sections->next = NULL((void *)0);
1340 input_sections->missing = 1;
1341 }
1342 for (ep = entries_to_add; ep; ep = ep->next)
1343 ep->entry_sections = input_sections;
1344 }
1345 }
1346
1347 /* Now read in the Info dir file. */
1348 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
1349 &opened_dirfilename, &compression_program);
1350 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
1351
1352 /* We will be comparing the entries in the dir file against the
1353 current filename, so need to strip off any directory prefix and/or
1354 [.info][.gz] suffix. */
1355 {
1356 char *infile_basename = infile + strlen (infile);
1357
1358 if (HAVE_DRIVE (infile)(0))
1359 infile += 2; /* get past the drive spec X: */
1360
1361 while (infile_basename > infile && !IS_SLASH (infile_basename[-1])((infile_basename[-1]) == '/'))
1362 infile_basename--;
1363
1364 infile_sans_info = strip_info_suffix (infile_basename);
1365 }
1366
1367 something_deleted
1368 = parse_dir_file (dir_lines, dir_nlines, &dir_nodes, infile_sans_info);
1369
1370 /* Decide where to add the new entries (unless --delete was used).
1371 Find the menu sections to add them in.
1372 In each section, find the proper alphabetical place to add
1373 each of the entries. */
1374 if (!delete_flag)
1375 {
1376 struct node *node;
1377 struct menu_section *section;
1378 struct spec_section *spec;
1379
1380 for (node = dir_nodes; node; node = node->next)
1381 for (section = node->sections; section; section = section->next)
1382 {
1383 for (i = section->end_line; i > section->start_line; i--)
1384 if (dir_lines[i - 1].size != 0)
1385 break;
1386 section->end_line = i;
1387
1388 for (spec = input_sections; spec; spec = spec->next)
1389 if (!strcmp (spec->name, section->name))
1390 break;
1391 if (spec)
1392 {
1393 int add_at_line = section->end_line;
1394 struct spec_entry *entry;
1395 /* Say we have found at least one section with this name,
1396 so we need not add such a section. */
1397 spec->missing = 0;
1398 /* For each entry, find the right place in this section
1399 to add it. */
1400 for (entry = entries_to_add; entry; entry = entry->next)
1401 {
1402 /* Did they at all want this entry to be put into
1403 this section? */
1404 for (spec = entry->entry_sections;
1405 spec && spec != entry->entry_sections_tail;
1406 spec = spec->next)
1407 {
1408 if (!strcmp (spec->name, section->name))
1409 break;
1410 }
1411 if (!spec || spec == entry->entry_sections_tail)
1412 continue;
1413
1414 /* Subtract one because dir_lines is zero-based,
1415 but the `end_line' and `start_line' members are
1416 one-based. */
1417 for (i = section->end_line - 1;
1418 i >= section->start_line - 1; i--)
1419 {
1420 /* If an entry exists with the same name,
1421 and was not marked for deletion
1422 (which means it is for some other file),
1423 we are in trouble. */
1424 if (dir_lines[i].start[0] == '*'
1425 && menu_line_equal (entry->text, entry->text_len,
1426 dir_lines[i].start,
1427 dir_lines[i].size)
1428 && !dir_lines[i].delete)
1429 fatal (_("menu item `%s' already exists, for file `%s'")((const char *) ("menu item `%s' already exists, for file `%s'"
))
,
1430 extract_menu_item_name (entry->text),
1431 extract_menu_file_name (dir_lines[i].start));
1432 if (dir_lines[i].start[0] == '*'
1433 && menu_line_lessp (entry->text, entry->text_len,
1434 dir_lines[i].start,
1435 dir_lines[i].size))
1436 add_at_line = i;
1437 }
1438 insert_entry_here (entry, add_at_line,
1439 dir_lines, n_entries_to_add);
1440 }
1441 }
1442 }
1443
1444 /* Mark the end of the Top node as the place to add any
1445 new sections that are needed. */
1446 for (node = dir_nodes; node; node = node->next)
1447 if (node->name && strcmp (node->name, "Top") == 0)
1448 dir_lines[node->end_line].add_sections_before = 1;
1449 }
1450
1451 if (delete_flag && !something_deleted && !quiet_flag)
1452 warning (_("no entries found for `%s'; nothing deleted")((const char *) ("no entries found for `%s'; nothing deleted"
))
, infile, 0);
1453
1454 output_dirfile (opened_dirfilename, dir_nlines, dir_lines, n_entries_to_add,
1455 entries_to_add, input_sections, compression_program);
1456
1457 xexit (0);
1458 return 0; /* Avoid bogus warnings. */
1459}
1460
1461/* Divide the text at DATA (of SIZE bytes) into lines.
1462 Return a vector of struct line_data describing the lines.
1463 Store the length of that vector into *NLINESP. */
1464
1465struct line_data *
1466findlines (char *data, int size, int *nlinesp)
1467{
1468 int i;
1469 int lineflag = 1;
1470 int lines_allocated = 511;
1471 int filled = 0;
1472 struct line_data *lines
1473 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
1474
1475 for (i = 0; i < size; i++)
1476 {
1477 if (lineflag)
1478 {
1479 if (filled == lines_allocated)
1480 {
1481 /* try to keep things somewhat page-aligned */
1482 lines_allocated = ((lines_allocated + 1) * 2) - 1;
1483 lines = xrealloc (lines, (lines_allocated + 1)
1484 * sizeof (struct line_data));
1485 }
1486 lines[filled].start = &data[i];
1487 lines[filled].add_entries_before = 0;
1488 lines[filled].add_sections_before = 0;
1489 lines[filled].delete = 0;
1490 if (filled > 0)
1491 lines[filled - 1].size
1492 = lines[filled].start - lines[filled - 1].start - 1;
1493 filled++;
1494 }
1495 lineflag = (data[i] == '\n');
1496 }
1497 if (filled > 0)
1498 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
1499
1500 /* Do not leave garbage in the last element. */
1501 lines[filled].start = NULL((void *)0);
1502 lines[filled].add_entries_before = NULL((void *)0);
1503 lines[filled].add_sections_before = 0;
1504 lines[filled].delete = 0;
1505 lines[filled].size = 0;
1506
1507 *nlinesp = filled;
1508 return lines;
1509}
1510
1511/* This is the comparison function for qsort for a vector of pointers to
1512 struct spec_section. (Have to use const void * as the parameter type
1513 to avoid incompatible-with-qsort warnings.)
1514 Compare the section names. */
1515
1516int
1517compare_section_names (const void *p1, const void *p2)
1518{
1519 struct spec_section **sec1 = (struct spec_section **) p1;
1520 struct spec_section **sec2 = (struct spec_section **) p2;
1521 char *name1 = (*sec1)->name;
1522 char *name2 = (*sec2)->name;
1523 return strcmp (name1, name2);
1524}
1525
1526/* This is the comparison function for qsort
1527 for a vector of pointers to struct spec_entry.
1528 Compare the entries' text. */
1529
1530int
1531compare_entries_text (const void *p1, const void *p2)
1532{
1533 struct spec_entry **entry1 = (struct spec_entry **) p1;
1534 struct spec_entry **entry2 = (struct spec_entry **) p2;
1535 char *text1 = (*entry1)->text;
1536 char *text2 = (*entry2)->text;
1537 char *colon1 = strchr (text1, ':');
1538 char *colon2 = strchr (text2, ':');
1539 int len1, len2;
1540
1541 if (!colon1)
1542 len1 = strlen (text1);
1543 else
1544 len1 = colon1 - text1;
1545 if (!colon2)
1546 len2 = strlen (text2);
1547 else
1548 len2 = colon2 - text2;
1549 return strncmp (text1, text2, len1 <= len2 ? len1 : len2);
1550}
1551
1552/* Insert ENTRY into the add_entries_before vector
1553 for line number LINE_NUMBER of the dir file.
1554 DIR_LINES and N_ENTRIES carry information from like-named variables
1555 in main. */
1556
1557void
1558insert_entry_here (struct spec_entry *entry, int line_number,
1559 struct line_data *dir_lines, int n_entries)
1560{
1561 int i, j;
1562
1563 if (dir_lines[line_number].add_entries_before == 0)
1564 {
1565 dir_lines[line_number].add_entries_before
1566 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1567 for (i = 0; i < n_entries; i++)
1568 dir_lines[line_number].add_entries_before[i] = 0;
1569 }
1570
1571 /* Find the place where this entry belongs. If there are already
1572 several entries to add before LINE_NUMBER, make sure they are in
1573 alphabetical order. */
1574 for (i = 0; i < n_entries; i++)
1575 if (dir_lines[line_number].add_entries_before[i] == 0
1576 || menu_line_lessp (entry->text, strlen (entry->text),
1577 dir_lines[line_number].add_entries_before[i]->text,
1578 strlen (dir_lines[line_number].add_entries_before[i]->text)))
1579 break;
1580
1581 if (i == n_entries)
1582 abort ();
1583
1584 /* If we need to plug ENTRY into the middle of the
1585 ADD_ENTRIES_BEFORE array, move the entries which should be output
1586 after this one down one notch, before adding a new one. */
1587 if (dir_lines[line_number].add_entries_before[i] != 0)
1588 for (j = n_entries - 1; j > i; j--)
1589 dir_lines[line_number].add_entries_before[j]
1590 = dir_lines[line_number].add_entries_before[j - 1];
1591
1592 dir_lines[line_number].add_entries_before[i] = entry;
1593}