2 /* install-info -- create Info directory entry(ies) for an Info file.
3 $Id: install-info.c,v 1.12 2004/04/11 17:56:47 karl Exp $
5 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
25 static char *progname = "install-info";
26 static char *default_section = NULL;
31 struct line_data *findlines (char *data, int size, int *nlinesp);
32 void insert_entry_here (struct spec_entry *entry, int line_number,
33 struct line_data *dir_lines, int n_entries);
34 int compare_section_names (const void *s1, const void *s2);
35 int compare_entries_text (const void *e1, const void *e2);
37 /* Data structures. */
40 /* Record info about a single line from a file as read into core. */
43 /* The start of the line. */
45 /* The number of characters in the line,
46 excluding the terminating newline. */
48 /* Vector containing pointers to the entries to add before this line.
49 The vector is null-terminated. */
50 struct spec_entry **add_entries_before;
51 /* 1 means output any needed new sections before this line. */
52 int add_sections_before;
53 /* 1 means don't output this line. */
58 /* This is used for a list of the specified menu section names
59 in which entries should be added. */
62 struct spec_section *next;
64 /* 1 means we have not yet found an existing section with this name
65 in the dir file--so we will need to add a new section. */
70 /* This is used for a list of the entries specified to be added. */
73 struct spec_entry *next;
76 /* A pointer to the list of sections to which this entry should be
78 struct spec_section *entry_sections;
79 /* A pointer to a section that is beyond the end of the chain whose
80 head is pointed to by entry_sections. */
81 struct spec_section *entry_sections_tail;
85 /* This is used for a list of nodes found by parsing the dir file. */
91 /* The line number of the line where the node starts.
92 This is the line that contains control-underscore. */
94 /* The line number of the line where the node ends,
95 which is the end of the file or where the next line starts. */
97 /* Start of first line in this node's menu
98 (the line after the * Menu: line). */
100 /* The start of the chain of sections in this node's menu. */
101 struct menu_section *sections;
102 /* The last menu section in the chain. */
103 struct menu_section *last_section;
107 /* This is used for a list of sections found in a node's menu.
108 Each struct node has such a list in the sections field. */
111 struct menu_section *next;
113 /* Line number of start of section. */
115 /* Line number of end of section. */
119 /* This table defines all the long-named options, says whether they
120 use an argument, and maps them into equivalent single-letter options. */
122 struct option longopts[] =
124 { "delete", no_argument, NULL, 'r' },
125 { "defentry", required_argument, NULL, 'E' },
126 { "defsection", required_argument, NULL, 'S' },
127 { "dir-file", required_argument, NULL, 'd' },
128 { "entry", required_argument, NULL, 'e' },
129 { "help", no_argument, NULL, 'h' },
130 { "infodir", required_argument, NULL, 'D' },
131 { "info-dir", required_argument, NULL, 'D' },
132 { "info-file", required_argument, NULL, 'i' },
133 { "item", required_argument, NULL, 'e' },
134 { "quiet", no_argument, NULL, 'q' },
135 { "remove", no_argument, NULL, 'r' },
136 { "section", required_argument, NULL, 's' },
137 { "version", no_argument, NULL, 'V' },
141 /* Error message functions. */
143 /* Print error message. S1 is printf control string, S2 and S3 args for it. */
147 error (const char *s1, const char *s2, const char *s3)
149 fprintf (stderr, "%s: ", progname);
150 fprintf (stderr, s1, s2, s3);
156 warning (const char *s1, const char *s2, const char *s3)
158 fprintf (stderr, _("%s: warning: "), progname);
159 fprintf (stderr, s1, s2, s3);
163 /* Print error message and exit. */
166 fatal (const char *s1, const char *s2, const char *s3)
172 /* Return a newly-allocated string
173 whose contents concatenate those of S1, S2, S3. */
175 concat (const char *s1, const char *s2, const char *s3)
177 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
178 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
181 strcpy (result + len1, s2);
182 strcpy (result + len1 + len2, s3);
183 *(result + len1 + len2 + len3) = 0;
188 /* Return a string containing SIZE characters
189 copied from starting at STRING. */
192 copy_string (const char *string, int size)
195 char *copy = (char *) xmalloc (size + 1);
196 for (i = 0; i < size; i++)
202 /* Print fatal error message based on errno, with file name NAME. */
205 pfatal_with_name (const char *name)
207 char *s = concat ("", strerror (errno), _(" for %s"));
211 /* Compare the menu item names in LINE1 (line length LEN1)
212 and LINE2 (line length LEN2). Return 1 if the item name
213 in LINE1 is less, 0 otherwise. */
216 menu_line_lessp (char *line1, int len1, char *line2, int len2)
218 int minlen = (len1 < len2 ? len1 : len2);
221 for (i = 0; i < minlen; i++)
223 /* If one item name is a prefix of the other,
224 the former one is less. */
225 if (line1[i] == ':' && line2[i] != ':')
227 if (line2[i] == ':' && line1[i] != ':')
229 /* If they both continue and differ, one is less. */
230 if (line1[i] < line2[i])
232 if (line1[i] > line2[i])
235 /* With a properly formatted dir file,
236 we can only get here if the item names are equal. */
240 /* Compare the menu item names in LINE1 (line length LEN1)
241 and LINE2 (line length LEN2). Return 1 if the item names are equal,
245 menu_line_equal (char *line1, int len1, char *line2, int len2)
247 int minlen = (len1 < len2 ? len1 : len2);
250 for (i = 0; i < minlen; i++)
252 /* If both item names end here, they are equal. */
253 if (line1[i] == ':' && line2[i] == ':')
255 /* If they both continue and differ, one is less. */
256 if (line1[i] != line2[i])
259 /* With a properly formatted dir file,
260 we can only get here if the item names are equal. */
265 /* Given the full text of a menu entry, null terminated,
266 return just the menu item name (copied). */
269 extract_menu_item_name (char *item_text)
273 if (*item_text == '*')
275 while (*item_text == ' ')
279 while (*p && *p != ':') p++;
280 return copy_string (item_text, p - item_text);
283 /* Given the full text of a menu entry, terminated by null or newline,
284 return just the menu item file (copied). */
287 extract_menu_file_name (char *item_text)
291 /* If we have text that looks like * ITEM: (FILE)NODE...,
292 extract just FILE. Otherwise return "(none)". */
299 /* Skip to and past the colon. */
300 while (*p && *p != '\n' && *p != ':') p++;
303 /* Skip past the open-paren. */
308 else if (*p == ' ' || *p == '\t')
317 /* File name ends just before the close-paren. */
318 while (*p && *p != '\n' && *p != ')') p++;
322 return copy_string (item_text, p - item_text);
327 /* Return FNAME with any [.info][.gz] suffix removed. */
330 strip_info_suffix (char *fname)
332 char *ret = xstrdup (fname);
333 unsigned len = strlen (ret);
335 if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
340 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".bz2") == 0)
346 if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
351 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
357 else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
358 || FILENAME_CMP (ret + len - 4, ".igz") == 0))
363 #endif /* __MSDOS__ */
369 /* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
370 can also be followed by `.gz', `.info.gz', or `.info' (and then
371 TERM_CHAR) and still match. */
374 menu_item_equal (const char *item, char term_char, const char *name)
377 const char *item_basename = item;
378 unsigned name_len = strlen (name);
380 /* We must compare the basename in ITEM, since we are passed the
381 basename of the original info file. Otherwise, a new entry like
382 "lilypond/lilypond" won't match "lilypond".
384 Actually, it seems to me that we should really compare the whole
385 name, and not just the basename. Couldn't there be dir1/foo.info
386 and dir2/foo.info? Also, it seems like we should be using the
387 filename from the new dir entries, not the filename on the command
388 line. Not worrying about those things right now, though. --karl,
390 while (*item_basename && !IS_SLASH (*item_basename)
391 && *item_basename != term_char)
393 if (! *item_basename || *item_basename == term_char)
394 item_basename = item; /* no /, use original */
396 item_basename++; /* have /, move past it */
398 /* First, ITEM must actually match NAME (usually it won't). */
399 ret = strncasecmp (item_basename, name, name_len) == 0;
402 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
403 ITEM. The various suffixes should never actually appear in the
404 dir file, but sometimes people put them in. */
405 static char *suffixes[]
406 = { "", ".info.gz", ".info", ".inf", ".gz",
413 for (i = 0; !ret && suffixes[i]; i++)
415 char *suffix = suffixes[i];
416 unsigned suffix_len = strlen (suffix);
417 ret = strncasecmp (item_basename + name_len, suffix, suffix_len) == 0
418 && item_basename[name_len + suffix_len] == term_char;
428 suggest_asking_for_help (void)
430 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
438 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
440 Install or delete dir entries from INFO-FILE in the Info directory file\n\
444 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
445 don't insert any new entries.\n\
446 --defentry=TEXT like --entry, but only use TEXT if an entry\n\
447 is not present in INFO-FILE.\n\
448 --defsection=TEXT like --section, but only use TEXT if a section\n\
449 is not present in INFO-FILE.\n\
450 --dir-file=NAME specify file name of Info directory file.\n\
451 This is equivalent to using the DIR-FILE argument.\n\
452 --entry=TEXT insert TEXT as an Info directory entry.\n\
453 TEXT should have the form of an Info menu item line\n\
454 plus zero or more extra lines starting with whitespace.\n\
455 If you specify more than one entry, they are all added.\n\
456 If you don't specify any entries, they are determined\n\
457 from information in the Info file itself.\n\
458 --help display this help and exit.\n\
459 --info-file=FILE specify Info file to install in the directory.\n\
460 This is equivalent to using the INFO-FILE argument.\n\
461 --info-dir=DIR same as --dir-file=DIR/dir.\n\
462 --item=TEXT same as --entry TEXT.\n\
463 An Info directory entry is actually a menu item.\n\
464 --quiet suppress warnings.\n\
465 --remove same as --delete.\n\
466 --section=SEC put this file's entries in section SEC of the directory.\n\
467 If you specify more than one section, all the entries\n\
468 are added in each of the sections.\n\
469 If you don't specify any sections, they are determined\n\
470 from information in the Info file itself.\n\
471 --version display version information and exit.\n\
475 Email bug reports to bug-texinfo@gnu.org,\n\
476 general questions and discussion to help-texinfo@gnu.org.\n\
477 Texinfo home page: http://www.gnu.org/software/texinfo/"));
481 /* If DIRFILE does not exist, create a minimal one (or abort). If it
482 already exists, do nothing. */
485 ensure_dirfile_exists (char *dirfile)
487 int desc = open (dirfile, O_RDONLY);
488 if (desc < 0 && errno == ENOENT)
491 char *readerr = strerror (errno);
493 f = fopen (dirfile, "w");
496 fprintf (f, _("This is the file .../info/dir, which contains the\n\
497 topmost node of the Info hierarchy, called (dir)Top.\n\
498 The first time you invoke Info you start off looking at this node.\n\
500 %s\tThis is the top of the INFO tree\n\
502 This (the Directory node) gives a menu of major topics.\n\
503 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
504 \"h\" gives a primer for first-timers,\n\
505 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
507 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
511 "), "File: dir,\tNode: Top", /* These keywords must not be translated. */
515 pfatal_with_name (dirfile);
519 /* Didn't exist, but couldn't open for writing. */
521 _("%s: could not read (%s) and could not create (%s)\n"),
522 dirfile, readerr, strerror (errno));
527 close (desc); /* It already existed, so fine. */
530 /* Open FILENAME and return the resulting stream pointer. If it doesn't
531 exist, try FILENAME.gz. If that doesn't exist either, call
532 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
533 non-NULL. If still no luck, fatal error.
535 If we do open it, return the actual name of the file opened in
536 OPENED_FILENAME and the compress program to use to (de)compress it in
537 COMPRESSION_PROGRAM. The compression program is determined by the
538 magic number, not the filename. */
541 open_possibly_compressed_file (char *filename,
542 void (*create_callback) (char *),
543 char **opened_filename, char **compression_program, int *is_pipe)
545 char *local_opened_filename, *local_compression_program;
550 /* We let them pass NULL if they don't want this info, but it's easier
551 to always determine it. */
552 if (!opened_filename)
553 opened_filename = &local_opened_filename;
555 *opened_filename = filename;
556 f = fopen (*opened_filename, FOPEN_RBIN);
559 *opened_filename = concat (filename, ".gz", "");
560 f = fopen (*opened_filename, FOPEN_RBIN);
563 free (*opened_filename);
564 *opened_filename = concat (filename, ".bz2", "");
565 f = fopen (*opened_filename, FOPEN_RBIN);
571 free (*opened_filename);
572 *opened_filename = concat (filename, ".igz", "");
573 f = fopen (*opened_filename, FOPEN_RBIN);
577 free (*opened_filename);
578 *opened_filename = concat (filename, ".inz", "");
579 f = fopen (*opened_filename, FOPEN_RBIN);
585 { /* That didn't work either. Create the file if we can. */
586 (*create_callback) (filename);
588 /* And try opening it again. */
589 free (*opened_filename);
590 *opened_filename = filename;
591 f = fopen (*opened_filename, FOPEN_RBIN);
593 pfatal_with_name (filename);
596 pfatal_with_name (filename);
600 /* Read first few bytes of file rather than relying on the filename.
601 If the file is shorter than this it can't be usable anyway. */
602 nread = fread (data, sizeof (data), 1, f);
605 /* Empty files don't set errno, so we get something like
606 "install-info: No error for foo", which is confusing. */
608 fatal (_("%s: empty file"), *opened_filename, 0);
609 pfatal_with_name (*opened_filename);
612 if (!compression_program)
613 compression_program = &local_compression_program;
615 if (data[0] == '\x1f' && data[1] == '\x8b')
617 /* An explicit .exe yields a better diagnostics from popen below
618 if they don't have gzip installed. */
619 *compression_program = "gzip.exe";
621 *compression_program = "gzip";
623 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == 'h')
624 #ifndef STRIP_DOT_EXE
625 *compression_program = "bzip2.exe";
627 *compression_program = "bzip2";
629 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == '0')
630 #ifndef STRIP_DOT_EXE
631 *compression_program = "bzip.exe";
633 *compression_program = "bzip";
636 *compression_program = NULL;
638 if (*compression_program)
639 { /* It's compressed, so fclose the file and then open a pipe. */
640 char *command = concat (*compression_program," -cd <", *opened_filename);
642 pfatal_with_name (*opened_filename);
643 f = popen (command, "r");
647 pfatal_with_name (command);
650 { /* It's a plain file, seek back over the magic bytes. */
651 if (fseek (f, 0, 0) < 0)
652 pfatal_with_name (*opened_filename);
654 /* Since this is a text file, and we opened it in binary mode,
655 switch back to text mode. */
656 f = freopen (*opened_filename, "r", f);
664 /* Read all of file FILENAME into memory and return the address of the
665 data. Store the size of the data into SIZEP. If need be, uncompress
666 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
667 the actual file name that was opened into OPENED_FILENAME (if it is
668 non-NULL), and the companion compression program (if any, else NULL)
669 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
673 readfile (char *filename, int *sizep,
674 void (*create_callback) (char *), char **opened_filename,
675 char **compression_program)
681 int data_size = 8192;
682 char *data = xmalloc (data_size);
684 /* If they passed the space for the file name to return, use it. */
685 f = open_possibly_compressed_file (filename, create_callback,
686 opened_filename ? opened_filename
688 compression_program, &pipe_p);
692 int nread = fread (data + filled, 1, data_size - filled, f);
694 pfatal_with_name (real_name);
699 if (filled == data_size)
702 data = xrealloc (data, data_size);
706 /* We'll end up wasting space if we're not passing the filename back
707 and it is not just FILENAME, but so what. */
708 /* We need to close the stream, since on some systems the pipe created
709 by popen is simulated by a temporary file which only gets removed
720 /* Output the old dir file, interpolating the new sections
721 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
722 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
723 we'll write dir.gz on output. */
726 output_dirfile (char *dirfile, int dir_nlines, struct line_data *dir_lines,
727 int n_entries_to_add, struct spec_entry *entries_to_add,
728 struct spec_section *input_sections, char *compression_program)
733 if (compression_program)
735 char *command = concat (compression_program, ">", dirfile);
736 output = popen (command, "w");
739 output = fopen (dirfile, "w");
747 for (i = 0; i <= dir_nlines; i++)
751 /* If we decided to output some new entries before this line,
753 if (dir_lines[i].add_entries_before)
754 for (j = 0; j < n_entries_to_add; j++)
756 struct spec_entry *this = dir_lines[i].add_entries_before[j];
759 fputs (this->text, output);
761 /* If we decided to add some sections here
762 because there are no such sections in the file,
764 if (dir_lines[i].add_sections_before)
766 struct spec_section *spec;
767 struct spec_section **sections;
769 struct spec_entry *entry;
770 struct spec_entry **entries;
773 /* Count the sections and allocate a vector for all of them. */
774 for (spec = input_sections; spec; spec = spec->next)
776 sections = ((struct spec_section **)
777 xmalloc (n_sections * sizeof (struct spec_section *)));
779 /* Fill the vector SECTIONS with pointers to all the sections,
782 for (spec = input_sections; spec; spec = spec->next)
783 sections[j++] = spec;
784 qsort (sections, n_sections, sizeof (struct spec_section *),
785 compare_section_names);
787 /* Count the entries and allocate a vector for all of them. */
788 for (entry = entries_to_add; entry; entry = entry->next)
790 entries = ((struct spec_entry **)
791 xmalloc (n_entries * sizeof (struct spec_entry *)));
793 /* Fill the vector ENTRIES with pointers to all the sections,
796 for (entry = entries_to_add; entry; entry = entry->next)
797 entries[j++] = entry;
798 qsort (entries, n_entries, sizeof (struct spec_entry *),
799 compare_entries_text);
801 /* Generate the new sections in alphabetical order. In each
802 new section, output all of the entries that belong to that
803 section, in alphabetical order. */
804 for (j = 0; j < n_sections; j++)
812 fputs (spec->name, output);
814 for (k = 0; k < n_entries; k++)
816 struct spec_section *spec1;
817 /* Did they at all want this entry to be put into
820 for (spec1 = entry->entry_sections;
821 spec1 && spec1 != entry->entry_sections_tail;
824 if (!strcmp (spec1->name, spec->name))
827 if (spec1 && spec1 != entry->entry_sections_tail)
828 fputs (entry->text, output);
837 /* Output the original dir lines unless marked for deletion. */
838 if (i < dir_nlines && !dir_lines[i].delete)
840 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
845 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
846 On those systems, the compressor actually gets run inside pclose,
847 so we must call pclose. */
848 if (compression_program)
854 /* Parse the input to find the section names and the entry names it
855 specifies. Return the number of entries to add from this file. */
857 parse_input (const struct line_data *lines, int nlines,
858 struct spec_section **sections, struct spec_entry **entries)
861 int prefix_length = strlen ("INFO-DIR-SECTION ");
862 struct spec_section *head = *sections, *tail = NULL;
864 char *start_of_this_entry = 0;
865 int ignore_sections = *sections != 0;
866 int ignore_entries = *entries != 0;
870 if (ignore_sections && ignore_entries)
873 /* Loop here processing lines from the input file. Each
874 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
875 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
876 list, and all its entries inherit the chain of SECTION entries
877 defined by the last group of INFO-DIR-SECTION entries we have
878 seen until that point. */
879 for (i = 0; i < nlines; i++)
882 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
884 struct spec_section *next
885 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
886 next->name = copy_string (lines[i].start + prefix_length,
887 lines[i].size - prefix_length);
888 next->next = *sections;
898 /* If entries were specified explicitly with command options,
899 ignore the entries in the input file. */
900 else if (!ignore_entries)
902 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
903 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
907 /* We found an entry, but didn't yet see any sections
908 specified. Default to section "Miscellaneous". */
909 *sections = (struct spec_section *)
910 xmalloc (sizeof (struct spec_section));
912 default_section ? default_section : "Miscellaneous";
913 (*sections)->next = 0;
914 (*sections)->missing = 1;
917 /* Next time we see INFO-DIR-SECTION, we will reset the
921 if (start_of_this_entry != 0)
922 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"), 0, 0);
923 start_of_this_entry = lines[i + 1].start;
925 else if (start_of_this_entry)
927 if ((!strncmp ("* ", lines[i].start, 2)
928 && lines[i].start > start_of_this_entry)
929 || (!strncmp ("END-INFO-DIR-ENTRY",
930 lines[i].start, lines[i].size)
931 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
933 /* We found an end of this entry. Allocate another
934 entry, fill its data, and add it to the linked
936 struct spec_entry *next
937 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
939 = copy_string (start_of_this_entry,
940 lines[i].start - start_of_this_entry);
941 next->text_len = lines[i].start - start_of_this_entry;
942 next->entry_sections = head;
943 next->entry_sections_tail = tail;
944 next->next = *entries;
947 if (!strncmp ("END-INFO-DIR-ENTRY",
948 lines[i].start, lines[i].size)
949 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
950 start_of_this_entry = 0;
952 start_of_this_entry = lines[i].start;
954 else if (!strncmp ("END-INFO-DIR-ENTRY",
955 lines[i].start, lines[i].size)
956 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
957 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"), 0, 0);
961 if (start_of_this_entry != 0)
962 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"),
965 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
966 and plug the names of all the sections we found into every
967 element of the ENTRIES list. */
968 if (ignore_entries && *entries)
970 struct spec_entry *entry;
972 for (entry = *entries; entry; entry = entry->next)
974 entry->entry_sections = head;
975 entry->entry_sections_tail = tail;
982 /* Parse the dir file whose basename is BASE_NAME. Find all the
983 nodes, and their menus, and the sections of their menus. */
985 parse_dir_file (struct line_data *lines, int nlines, struct node **nodes,
986 const char *base_name)
988 int node_header_flag = 0;
989 int something_deleted = 0;
993 for (i = 0; i < nlines; i++)
995 /* Parse node header lines. */
996 if (node_header_flag)
999 for (j = 0; j < lines[i].size; j++)
1000 /* Find the node name and store it in the `struct node'. */
1001 if (!strncmp ("Node:", lines[i].start + j, 5))
1003 char *line = lines[i].start;
1004 /* Find the start of the node name. */
1006 while (line[j] == ' ' || line[j] == '\t')
1008 /* Find the end of the node name. */
1010 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
1011 && line[end] != '\t')
1013 (*nodes)->name = copy_string (line + j, end - j);
1015 node_header_flag = 0;
1018 /* Notice the start of a node. */
1019 if (*lines[i].start == 037)
1021 struct node *next = (struct node *) xmalloc (sizeof (struct node));
1023 next->next = *nodes;
1025 next->start_line = i;
1027 next->menu_start = NULL;
1028 next->sections = NULL;
1029 next->last_section = NULL;
1032 (*nodes)->end_line = i;
1033 /* Fill in the end of the last menu section
1034 of the previous node. */
1035 if (*nodes != 0 && (*nodes)->last_section != 0)
1036 (*nodes)->last_section->end_line = i;
1040 /* The following line is the header of this node;
1042 node_header_flag = 1;
1045 /* Notice the lines that start menus. */
1046 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
1047 (*nodes)->menu_start = lines[i + 1].start;
1049 /* Notice sections in menus. */
1051 && (*nodes)->menu_start != 0
1052 && *lines[i].start != '\n'
1053 && *lines[i].start != '*'
1054 && *lines[i].start != ' '
1055 && *lines[i].start != '\t')
1057 /* Add this menu section to the node's list.
1058 This list grows in forward order. */
1059 struct menu_section *next
1060 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1062 next->start_line = i + 1;
1065 next->name = copy_string (lines[i].start, lines[i].size);
1066 if ((*nodes)->sections)
1068 (*nodes)->last_section->next = next;
1069 (*nodes)->last_section->end_line = i;
1072 (*nodes)->sections = next;
1073 (*nodes)->last_section = next;
1076 /* Check for an existing entry that should be deleted.
1077 Delete all entries which specify this file name. */
1078 if (*lines[i].start == '*')
1081 char *p = lines[i].start;
1084 while (*p == ' ') p++; /* ignore following spaces */
1085 q = p; /* remember this, it's the beginning of the menu item. */
1087 /* Read menu item. */
1088 while (*p != 0 && *p != ':')
1093 { /* XEmacs-style entry, as in * Mew::Messaging. */
1094 if (menu_item_equal (q, ':', base_name))
1096 lines[i].delete = 1;
1097 something_deleted = 1;
1101 { /* Emacs-style entry, as in * Emacs: (emacs). */
1102 while (*p == ' ') p++; /* skip spaces after : */
1103 if (*p == '(') /* if at parenthesized (FILENAME) */
1106 if (menu_item_equal (p, ')', base_name))
1108 lines[i].delete = 1;
1109 something_deleted = 1;
1115 /* Treat lines that start with whitespace
1116 as continuations; if we are deleting an entry,
1117 delete all its continuations as well. */
1118 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1120 lines[i].delete = lines[i - 1].delete;
1124 /* Finish the info about the end of the last node. */
1127 (*nodes)->end_line = nlines;
1128 if ((*nodes)->last_section != 0)
1129 (*nodes)->last_section->end_line = nlines;
1132 return something_deleted;
1136 main (int argc, char **argv)
1138 char *opened_dirfilename;
1139 char *compression_program;
1140 char *infile_sans_info;
1141 char *infile = 0, *dirfile = 0;
1143 /* Record the text of the Info file, as a sequence of characters
1144 and as a sequence of lines. */
1145 char *input_data = NULL;
1147 struct line_data *input_lines = NULL;
1148 int input_nlines = 0;
1150 /* Record here the specified section names and directory entries. */
1151 struct spec_section *input_sections = NULL;
1152 struct spec_entry *entries_to_add = NULL;
1153 int n_entries_to_add = 0;
1154 struct spec_entry *default_entries_to_add = NULL;
1155 int n_default_entries_to_add = 0;
1157 /* Record the old text of the dir file, as plain characters,
1158 as lines, and as nodes. */
1162 struct line_data *dir_lines;
1163 struct node *dir_nodes;
1165 /* Nonzero means --delete was specified (just delete existing entries). */
1166 int delete_flag = 0;
1167 int something_deleted = 0;
1168 /* Nonzero means -q was specified. */
1173 #ifdef HAVE_SETLOCALE
1174 /* Set locale via LC_ALL. */
1175 setlocale (LC_ALL, "");
1178 /* Set the text message domain. */
1179 bindtextdomain (PACKAGE, LOCALEDIR);
1180 textdomain (PACKAGE);
1184 int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
1192 /* If getopt returns 0, then it has already processed a
1193 long-named option. We should do nothing. */
1202 fprintf (stderr, _("%s: already have dir file: %s\n"),
1204 suggest_asking_for_help ();
1212 fprintf (stderr, _("%s: already have dir file: %s\n"),
1214 suggest_asking_for_help ();
1216 dirfile = concat (optarg, "", "/dir");
1222 struct spec_entry *next
1223 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1224 int olen = strlen (optarg);
1225 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
1227 optarg = concat (optarg, "\n", "");
1230 next->text = optarg;
1231 next->text_len = olen;
1232 next->entry_sections = NULL;
1233 next->entry_sections_tail = NULL;
1236 next->next = entries_to_add;
1237 entries_to_add = next;
1242 next->next = default_entries_to_add;
1243 default_entries_to_add = next;
1244 n_default_entries_to_add++;
1257 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
1259 suggest_asking_for_help ();
1274 struct spec_section *next
1275 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1276 next->name = optarg;
1277 next->next = input_sections;
1279 input_sections = next;
1284 default_section = optarg;
1288 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
1290 puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
1291 printf (_("There is NO warranty. You may redistribute this software\n\
1292 under the terms of the GNU General Public License.\n\
1293 For more information about these matters, see the files named COPYING.\n"));
1297 suggest_asking_for_help ();
1301 /* Interpret the non-option arguments as file names. */
1302 for (; optind < argc; ++optind)
1305 infile = argv[optind];
1306 else if (dirfile == 0)
1307 dirfile = argv[optind];
1309 error (_("excess command line argument `%s'"), argv[optind], 0);
1313 fatal (_("No input file specified; try --help for more information."),
1316 fatal (_("No dir file specified; try --help for more information."), 0, 0);
1318 /* Read the Info file and parse it into lines, unless we're deleting. */
1321 input_data = readfile (infile, &input_size, NULL, NULL, NULL);
1322 input_lines = findlines (input_data, input_size, &input_nlines);
1325 i = parse_input (input_lines, input_nlines,
1326 &input_sections, &entries_to_add);
1327 if (i > n_entries_to_add)
1328 n_entries_to_add = i;
1329 else if (n_entries_to_add == 0)
1331 entries_to_add = default_entries_to_add;
1332 n_entries_to_add = n_default_entries_to_add;
1337 if (entries_to_add == 0)
1338 { /* No need to abort here, the original info file may not
1339 have the requisite Texinfo commands. This is not
1340 something an installer should have to correct (it's a
1341 problem for the maintainer), and there's no need to cause
1342 subsequent parts of `make install' to fail. */
1343 warning (_("no info dir entry in `%s'"), infile, 0);
1347 /* If the entries came from the command-line arguments, their
1348 entry_sections pointers are not yet set. Walk the chain of
1349 the entries and for each entry update entry_sections to point
1350 to the head of the list of sections where this entry should
1351 be put. Note that all the entries specified on the command
1352 line get put into ALL the sections we've got, either from the
1353 Info file, or (under --section) from the command line,
1354 because in the loop below every entry inherits the entire
1355 chain of sections. */
1356 if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
1358 struct spec_entry *ep;
1360 /* If we got no sections, default to "Miscellaneous". */
1361 if (input_sections == NULL)
1363 input_sections = (struct spec_section *)
1364 xmalloc (sizeof (struct spec_section));
1365 input_sections->name =
1366 default_section ? default_section : "Miscellaneous";
1367 input_sections->next = NULL;
1368 input_sections->missing = 1;
1370 for (ep = entries_to_add; ep; ep = ep->next)
1371 ep->entry_sections = input_sections;
1375 /* Now read in the Info dir file. */
1376 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
1377 &opened_dirfilename, &compression_program);
1378 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
1380 /* We will be comparing the entries in the dir file against the
1381 current filename, so need to strip off any directory prefix and/or
1382 [.info][.gz] suffix. */
1384 char *infile_basename = infile + strlen (infile);
1386 if (HAVE_DRIVE (infile))
1387 infile += 2; /* get past the drive spec X: */
1389 while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
1392 infile_sans_info = strip_info_suffix (infile_basename);
1396 = parse_dir_file (dir_lines, dir_nlines, &dir_nodes, infile_sans_info);
1398 /* Decide where to add the new entries (unless --delete was used).
1399 Find the menu sections to add them in.
1400 In each section, find the proper alphabetical place to add
1401 each of the entries. */
1405 struct menu_section *section;
1406 struct spec_section *spec;
1408 for (node = dir_nodes; node; node = node->next)
1409 for (section = node->sections; section; section = section->next)
1411 for (i = section->end_line; i > section->start_line; i--)
1412 if (dir_lines[i - 1].size != 0)
1414 section->end_line = i;
1416 for (spec = input_sections; spec; spec = spec->next)
1417 if (!strcmp (spec->name, section->name))
1421 int add_at_line = section->end_line;
1422 struct spec_entry *entry;
1423 /* Say we have found at least one section with this name,
1424 so we need not add such a section. */
1426 /* For each entry, find the right place in this section
1428 for (entry = entries_to_add; entry; entry = entry->next)
1430 /* Did they at all want this entry to be put into
1432 for (spec = entry->entry_sections;
1433 spec && spec != entry->entry_sections_tail;
1436 if (!strcmp (spec->name, section->name))
1439 if (!spec || spec == entry->entry_sections_tail)
1442 /* Subtract one because dir_lines is zero-based,
1443 but the `end_line' and `start_line' members are
1445 for (i = section->end_line - 1;
1446 i >= section->start_line - 1; i--)
1448 /* If an entry exists with the same name,
1449 and was not marked for deletion
1450 (which means it is for some other file),
1451 we are in trouble. */
1452 if (dir_lines[i].start[0] == '*'
1453 && menu_line_equal (entry->text, entry->text_len,
1456 && !dir_lines[i].delete)
1459 dir_lines[i].delete = 1;
1461 fatal (_("menu item `%s' already exists, for file `%s'"),
1462 extract_menu_item_name (entry->text),
1463 extract_menu_file_name (dir_lines[i].start));
1465 if (dir_lines[i].start[0] == '*'
1466 && menu_line_lessp (entry->text, entry->text_len,
1471 insert_entry_here (entry, add_at_line,
1472 dir_lines, n_entries_to_add);
1477 /* Mark the end of the Top node as the place to add any
1478 new sections that are needed. */
1479 for (node = dir_nodes; node; node = node->next)
1480 if (node->name && strcmp (node->name, "Top") == 0)
1481 dir_lines[node->end_line].add_sections_before = 1;
1484 if (delete_flag && !something_deleted && !quiet_flag)
1485 warning (_("no entries found for `%s'; nothing deleted"), infile, 0);
1487 output_dirfile (opened_dirfilename, dir_nlines, dir_lines, n_entries_to_add,
1488 entries_to_add, input_sections, compression_program);
1491 return 0; /* Avoid bogus warnings. */
1494 /* Divide the text at DATA (of SIZE bytes) into lines.
1495 Return a vector of struct line_data describing the lines.
1496 Store the length of that vector into *NLINESP. */
1499 findlines (char *data, int size, int *nlinesp)
1503 int lines_allocated = 511;
1505 struct line_data *lines
1506 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
1508 for (i = 0; i < size; i++)
1512 if (filled == lines_allocated)
1514 /* try to keep things somewhat page-aligned */
1515 lines_allocated = ((lines_allocated + 1) * 2) - 1;
1516 lines = xrealloc (lines, (lines_allocated + 1)
1517 * sizeof (struct line_data));
1519 lines[filled].start = &data[i];
1520 lines[filled].add_entries_before = 0;
1521 lines[filled].add_sections_before = 0;
1522 lines[filled].delete = 0;
1524 lines[filled - 1].size
1525 = lines[filled].start - lines[filled - 1].start - 1;
1528 lineflag = (data[i] == '\n');
1531 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
1533 /* Do not leave garbage in the last element. */
1534 lines[filled].start = NULL;
1535 lines[filled].add_entries_before = NULL;
1536 lines[filled].add_sections_before = 0;
1537 lines[filled].delete = 0;
1538 lines[filled].size = 0;
1544 /* This is the comparison function for qsort for a vector of pointers to
1545 struct spec_section. (Have to use const void * as the parameter type
1546 to avoid incompatible-with-qsort warnings.)
1547 Compare the section names. */
1550 compare_section_names (const void *p1, const void *p2)
1552 struct spec_section **sec1 = (struct spec_section **) p1;
1553 struct spec_section **sec2 = (struct spec_section **) p2;
1554 char *name1 = (*sec1)->name;
1555 char *name2 = (*sec2)->name;
1556 return strcmp (name1, name2);
1559 /* This is the comparison function for qsort
1560 for a vector of pointers to struct spec_entry.
1561 Compare the entries' text. */
1564 compare_entries_text (const void *p1, const void *p2)
1566 struct spec_entry **entry1 = (struct spec_entry **) p1;
1567 struct spec_entry **entry2 = (struct spec_entry **) p2;
1568 char *text1 = (*entry1)->text;
1569 char *text2 = (*entry2)->text;
1570 char *colon1 = strchr (text1, ':');
1571 char *colon2 = strchr (text2, ':');
1575 len1 = strlen (text1);
1577 len1 = colon1 - text1;
1579 len2 = strlen (text2);
1581 len2 = colon2 - text2;
1582 return strncmp (text1, text2, len1 <= len2 ? len1 : len2);
1585 /* Insert ENTRY into the add_entries_before vector
1586 for line number LINE_NUMBER of the dir file.
1587 DIR_LINES and N_ENTRIES carry information from like-named variables
1591 insert_entry_here (struct spec_entry *entry, int line_number,
1592 struct line_data *dir_lines, int n_entries)
1596 if (dir_lines[line_number].add_entries_before == 0)
1598 dir_lines[line_number].add_entries_before
1599 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1600 for (i = 0; i < n_entries; i++)
1601 dir_lines[line_number].add_entries_before[i] = 0;
1604 /* Find the place where this entry belongs. If there are already
1605 several entries to add before LINE_NUMBER, make sure they are in
1606 alphabetical order. */
1607 for (i = 0; i < n_entries; i++)
1608 if (dir_lines[line_number].add_entries_before[i] == 0
1609 || menu_line_lessp (entry->text, strlen (entry->text),
1610 dir_lines[line_number].add_entries_before[i]->text,
1611 strlen (dir_lines[line_number].add_entries_before[i]->text)))
1617 /* If we need to plug ENTRY into the middle of the
1618 ADD_ENTRIES_BEFORE array, move the entries which should be output
1619 after this one down one notch, before adding a new one. */
1620 if (dir_lines[line_number].add_entries_before[i] != 0)
1621 for (j = n_entries - 1; j > i; j--)
1622 dir_lines[line_number].add_entries_before[j]
1623 = dir_lines[line_number].add_entries_before[j - 1];
1625 dir_lines[line_number].add_entries_before[i] = entry;