1 /* install-info -- create Info directory entry(ies) for an Info file.
2 $Id: install-info.c,v 1.55 2002/03/11 19:55:23 karl Exp $
4 Copyright (C) 1996, 97, 98, 99, 2000, 01, 02 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
23 static char *progname = "install-info";
25 struct line_data *findlines ();
26 void insert_entry_here ();
27 int compare_section_names (), compare_entries_text ();
31 /* Data structures. */
34 /* Record info about a single line from a file as read into core. */
37 /* The start of the line. */
39 /* The number of characters in the line,
40 excluding the terminating newline. */
42 /* Vector containing pointers to the entries to add before this line.
43 The vector is null-terminated. */
44 struct spec_entry **add_entries_before;
45 /* 1 means output any needed new sections before this line. */
46 int add_sections_before;
47 /* 1 means don't output this line. */
52 /* This is used for a list of the specified menu section names
53 in which entries should be added. */
56 struct spec_section *next;
58 /* 1 means we have not yet found an existing section with this name
59 in the dir file--so we will need to add a new section. */
64 /* This is used for a list of the entries specified to be added. */
67 struct spec_entry *next;
70 /* A pointer to the list of sections to which this entry should be
72 struct spec_section *entry_sections;
73 /* A pointer to a section that is beyond the end of the chain whose
74 head is pointed to by entry_sections. */
75 struct spec_section *entry_sections_tail;
79 /* This is used for a list of nodes found by parsing the dir file. */
85 /* The line number of the line where the node starts.
86 This is the line that contains control-underscore. */
88 /* The line number of the line where the node ends,
89 which is the end of the file or where the next line starts. */
91 /* Start of first line in this node's menu
92 (the line after the * Menu: line). */
94 /* The start of the chain of sections in this node's menu. */
95 struct menu_section *sections;
96 /* The last menu section in the chain. */
97 struct menu_section *last_section;
101 /* This is used for a list of sections found in a node's menu.
102 Each struct node has such a list in the sections field. */
105 struct menu_section *next;
107 /* Line number of start of section. */
109 /* Line number of end of section. */
113 /* This table defines all the long-named options, says whether they
114 use an argument, and maps them into equivalent single-letter options. */
116 struct option longopts[] =
118 { "delete", no_argument, NULL, 'r' },
119 { "dir-file", required_argument, NULL, 'd' },
120 { "entry", required_argument, NULL, 'e' },
121 { "help", no_argument, NULL, 'h' },
122 { "info-dir", required_argument, NULL, 'D' },
123 { "info-file", required_argument, NULL, 'i' },
124 { "item", required_argument, NULL, 'e' },
125 { "quiet", no_argument, NULL, 'q' },
126 { "remove", no_argument, NULL, 'r' },
127 { "section", required_argument, NULL, 's' },
128 { "version", no_argument, NULL, 'V' },
132 /* Error message functions. */
134 /* Print error message. S1 is printf control string, S2 and S3 args for it. */
141 fprintf (stderr, "%s: ", progname);
142 fprintf (stderr, s1, s2, s3);
151 fprintf (stderr, _("%s: warning: "), progname);
152 fprintf (stderr, s1, s2, s3);
156 /* Print error message and exit. */
166 /* Memory allocation and string operations. */
168 /* Like malloc but get fatal error if memory is exhausted. */
173 extern void *malloc ();
174 void *result = malloc (size);
176 fatal (_("virtual memory exhausted"), 0, 0);
180 /* Like realloc but get fatal error if memory is exhausted. */
186 extern void *realloc ();
187 void *result = realloc (obj, size);
189 fatal (_("virtual memory exhausted"), 0, 0);
193 /* Return a newly-allocated string
194 whose contents concatenate those of S1, S2, S3. */
199 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
200 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
203 strcpy (result + len1, s2);
204 strcpy (result + len1 + len2, s3);
205 *(result + len1 + len2 + len3) = 0;
210 /* Return a string containing SIZE characters
211 copied from starting at STRING. */
214 copy_string (string, size)
219 char *copy = (char *) xmalloc (size + 1);
220 for (i = 0; i < size; i++)
226 /* Print fatal error message based on errno, with file name NAME. */
229 pfatal_with_name (name)
232 char *s = concat ("", strerror (errno), _(" for %s"));
236 /* Given the full text of a menu entry, null terminated,
237 return just the menu item name (copied). */
240 extract_menu_item_name (item_text)
245 if (*item_text == '*')
247 while (*item_text == ' ')
251 while (*p && *p != ':') p++;
252 return copy_string (item_text, p - item_text);
255 /* Given the full text of a menu entry, terminated by null or newline,
256 return just the menu item file (copied). */
259 extract_menu_file_name (item_text)
264 /* If we have text that looks like * ITEM: (FILE)NODE...,
265 extract just FILE. Otherwise return "(none)". */
272 /* Skip to and past the colon. */
273 while (*p && *p != '\n' && *p != ':') p++;
276 /* Skip past the open-paren. */
281 else if (*p == ' ' || *p == '\t')
290 /* File name ends just before the close-paren. */
291 while (*p && *p != '\n' && *p != ')') p++;
295 return copy_string (item_text, p - item_text);
300 /* Return FNAME with any [.info][.gz] suffix removed. */
303 strip_info_suffix (fname)
306 char *ret = xstrdup (fname);
307 unsigned len = strlen (ret);
309 if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
315 if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
320 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
326 else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
327 || FILENAME_CMP (ret + len - 4, ".igz") == 0))
332 #endif /* __MSDOS__ */
338 /* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
339 can also be followed by `.gz', `.info.gz', or `.info' (and then
340 TERM_CHAR) and still match. */
343 menu_item_equal (item, term_char, name)
348 unsigned name_len = strlen (name);
349 /* First, ITEM must actually match NAME (usually it won't). */
350 int ret = strncasecmp (item, name, name_len) == 0;
353 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
354 ITEM. The various suffixes should never actually appear in the
355 dir file, but sometimes people put them in. */
356 static char *suffixes[]
357 = { "", ".info.gz", ".info", ".inf", ".gz",
364 for (i = 0; !ret && suffixes[i]; i++)
366 char *suffix = suffixes[i];
367 unsigned suffix_len = strlen (suffix);
368 ret = strncasecmp (item + name_len, suffix, suffix_len) == 0
369 && item[name_len + suffix_len] == term_char;
379 suggest_asking_for_help ()
381 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
389 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
391 Install or delete dir entries from INFO-FILE in the Info directory file\n\
395 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
396 don't insert any new entries.\n\
397 --dir-file=NAME specify file name of Info directory file.\n\
398 This is equivalent to using the DIR-FILE argument.\n\
399 --entry=TEXT insert TEXT as an Info directory entry.\n\
400 TEXT should have the form of an Info menu item line\n\
401 plus zero or more extra lines starting with whitespace.\n\
402 If you specify more than one entry, they are all added.\n\
403 If you don't specify any entries, they are determined\n\
404 from information in the Info file itself.\n\
405 --help display this help and exit.\n\
406 --info-file=FILE specify Info file to install in the directory.\n\
407 This is equivalent to using the INFO-FILE argument.\n\
408 --info-dir=DIR same as --dir-file=DIR/dir.\n\
409 --item=TEXT same as --entry TEXT.\n\
410 An Info directory entry is actually a menu item.\n\
411 --quiet suppress warnings.\n\
412 --remove same as --delete.\n\
413 --section=SEC put this file's entries in section SEC of the directory.\n\
414 If you specify more than one section, all the entries\n\
415 are added in each of the sections.\n\
416 If you don't specify any sections, they are determined\n\
417 from information in the Info file itself.\n\
418 --version display version information and exit.\n\
422 Email bug reports to bug-texinfo@gnu.org,\n\
423 general questions and discussion to help-texinfo@gnu.org.\n\
424 Texinfo home page: http://www.gnu.org/software/texinfo/"));
428 /* If DIRFILE does not exist, create a minimal one (or abort). If it
429 already exists, do nothing. */
432 ensure_dirfile_exists (dirfile)
435 int desc = open (dirfile, O_RDONLY);
436 if (desc < 0 && errno == ENOENT)
439 char *readerr = strerror (errno);
441 f = fopen (dirfile, "w");
444 fprintf (f, _("This is the file .../info/dir, which contains the\n\
445 topmost node of the Info hierarchy, called (dir)Top.\n\
446 The first time you invoke Info you start off looking at this node.\n\
448 %s\tThis is the top of the INFO tree\n\
450 This (the Directory node) gives a menu of major topics.\n\
451 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
452 \"h\" gives a primer for first-timers,\n\
453 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
455 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
459 "), "File: dir,\tNode: Top"); /* This part must not be translated. */
461 pfatal_with_name (dirfile);
465 /* Didn't exist, but couldn't open for writing. */
467 _("%s: could not read (%s) and could not create (%s)\n"),
468 dirfile, readerr, strerror (errno));
473 close (desc); /* It already existed, so fine. */
476 /* Open FILENAME and return the resulting stream pointer. If it doesn't
477 exist, try FILENAME.gz. If that doesn't exist either, call
478 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
479 non-NULL. If still no luck, fatal error.
481 If we do open it, return the actual name of the file opened in
482 OPENED_FILENAME and the compress program to use to (de)compress it in
483 COMPRESSION_PROGRAM. The compression program is determined by the
484 magic number, not the filename. */
487 open_possibly_compressed_file (filename, create_callback,
488 opened_filename, compression_program, is_pipe)
490 void (*create_callback) ();
491 char **opened_filename;
492 char **compression_program;
495 char *local_opened_filename, *local_compression_program;
500 /* We let them pass NULL if they don't want this info, but it's easier
501 to always determine it. */
502 if (!opened_filename)
503 opened_filename = &local_opened_filename;
505 *opened_filename = filename;
506 f = fopen (*opened_filename, FOPEN_RBIN);
509 *opened_filename = concat (filename, ".gz", "");
510 f = fopen (*opened_filename, FOPEN_RBIN);
514 free (*opened_filename);
515 *opened_filename = concat (filename, ".igz", "");
516 f = fopen (*opened_filename, FOPEN_RBIN);
520 free (*opened_filename);
521 *opened_filename = concat (filename, ".inz", "");
522 f = fopen (*opened_filename, FOPEN_RBIN);
528 { /* That didn't work either. Create the file if we can. */
529 (*create_callback) (filename);
531 /* And try opening it again. */
532 free (*opened_filename);
533 *opened_filename = filename;
534 f = fopen (*opened_filename, FOPEN_RBIN);
536 pfatal_with_name (filename);
539 pfatal_with_name (filename);
543 /* Read first few bytes of file rather than relying on the filename.
544 If the file is shorter than this it can't be usable anyway. */
545 nread = fread (data, sizeof (data), 1, f);
548 /* Empty files don't set errno, so we get something like
549 "install-info: No error for foo", which is confusing. */
551 fatal (_("%s: empty file"), *opened_filename, 0);
552 pfatal_with_name (*opened_filename);
555 if (!compression_program)
556 compression_program = &local_compression_program;
558 if (data[0] == '\x1f' && data[1] == '\x8b')
560 /* An explicit .exe yields a better diagnostics from popen below
561 if they don't have gzip installed. */
562 *compression_program = "gzip.exe";
564 *compression_program = "gzip";
567 *compression_program = NULL;
569 if (*compression_program)
570 { /* It's compressed, so fclose the file and then open a pipe. */
571 char *command = concat (*compression_program," -cd <", *opened_filename);
573 pfatal_with_name (*opened_filename);
574 f = popen (command, "r");
578 pfatal_with_name (command);
581 { /* It's a plain file, seek back over the magic bytes. */
582 if (fseek (f, 0, 0) < 0)
583 pfatal_with_name (*opened_filename);
585 /* Since this is a text file, and we opened it in binary mode,
586 switch back to text mode. */
587 f = freopen (*opened_filename, "r", f);
595 /* Read all of file FILENAME into memory and return the address of the
596 data. Store the size of the data into SIZEP. If need be, uncompress
597 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
598 the actual file name that was opened into OPENED_FILENAME (if it is
599 non-NULL), and the companion compression program (if any, else NULL)
600 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
604 readfile (filename, sizep, create_callback,
605 opened_filename, compression_program)
608 void (*create_callback) ();
609 char **opened_filename;
610 char **compression_program;
616 int data_size = 8192;
617 char *data = xmalloc (data_size);
619 /* If they passed the space for the file name to return, use it. */
620 f = open_possibly_compressed_file (filename, create_callback,
621 opened_filename ? opened_filename
623 compression_program, &pipe_p);
627 int nread = fread (data + filled, 1, data_size - filled, f);
629 pfatal_with_name (real_name);
634 if (filled == data_size)
637 data = xrealloc (data, data_size);
641 /* We'll end up wasting space if we're not passing the filename back
642 and it is not just FILENAME, but so what. */
643 /* We need to close the stream, since on some systems the pipe created
644 by popen is simulated by a temporary file which only gets removed
655 /* Output the old dir file, interpolating the new sections
656 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
657 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
658 we'll write dir.gz on output. */
661 output_dirfile (dirfile, dir_nlines, dir_lines,
662 n_entries_to_add, entries_to_add, input_sections,
666 struct line_data *dir_lines;
667 int n_entries_to_add;
668 struct spec_entry *entries_to_add;
669 struct spec_section *input_sections;
670 char *compression_program;
675 if (compression_program)
677 char *command = concat (compression_program, ">", dirfile);
678 output = popen (command, "w");
681 output = fopen (dirfile, "w");
689 for (i = 0; i <= dir_nlines; i++)
693 /* If we decided to output some new entries before this line,
695 if (dir_lines[i].add_entries_before)
696 for (j = 0; j < n_entries_to_add; j++)
698 struct spec_entry *this = dir_lines[i].add_entries_before[j];
701 fputs (this->text, output);
703 /* If we decided to add some sections here
704 because there are no such sections in the file,
706 if (dir_lines[i].add_sections_before)
708 struct spec_section *spec;
709 struct spec_section **sections;
711 struct spec_entry *entry;
712 struct spec_entry **entries;
715 /* Count the sections and allocate a vector for all of them. */
716 for (spec = input_sections; spec; spec = spec->next)
718 sections = ((struct spec_section **)
719 xmalloc (n_sections * sizeof (struct spec_section *)));
721 /* Fill the vector SECTIONS with pointers to all the sections,
724 for (spec = input_sections; spec; spec = spec->next)
725 sections[j++] = spec;
726 qsort (sections, n_sections, sizeof (struct spec_section *),
727 compare_section_names);
729 /* Count the entries and allocate a vector for all of them. */
730 for (entry = entries_to_add; entry; entry = entry->next)
732 entries = ((struct spec_entry **)
733 xmalloc (n_entries * sizeof (struct spec_entry *)));
735 /* Fill the vector ENTRIES with pointers to all the sections,
738 for (entry = entries_to_add; entry; entry = entry->next)
739 entries[j++] = entry;
740 qsort (entries, n_entries, sizeof (struct spec_entry *),
741 compare_entries_text);
743 /* Generate the new sections in alphabetical order. In each
744 new section, output all of the entries that belong to that
745 section, in alphabetical order. */
746 for (j = 0; j < n_sections; j++)
754 fputs (spec->name, output);
756 for (k = 0; k < n_entries; k++)
758 struct spec_section *spec1;
759 /* Did they at all want this entry to be put into
762 for (spec1 = entry->entry_sections;
763 spec1 && spec1 != entry->entry_sections_tail;
766 if (!strcmp (spec1->name, spec->name))
769 if (spec1 && spec1 != entry->entry_sections_tail)
770 fputs (entry->text, output);
779 /* Output the original dir lines unless marked for deletion. */
780 if (i < dir_nlines && !dir_lines[i].delete)
782 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
787 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
788 On those systems, the compressor actually gets run inside pclose,
789 so we must call pclose. */
790 if (compression_program)
796 /* Parse the input to find the section names and the entry names it
797 specifies. Return the number of entries to add from this file. */
799 parse_input (lines, nlines, sections, entries)
800 const struct line_data *lines;
802 struct spec_section **sections;
803 struct spec_entry **entries;
806 int prefix_length = strlen ("INFO-DIR-SECTION ");
807 struct spec_section *head = *sections, *tail = NULL;
809 char *start_of_this_entry = 0;
810 int ignore_sections = *sections != 0;
811 int ignore_entries = *entries != 0;
815 if (ignore_sections && ignore_entries)
818 /* Loop here processing lines from the input file. Each
819 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
820 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
821 list, and all its entries inherit the chain of SECTION entries
822 defined by the last group of INFO-DIR-SECTION entries we have
823 seen until that point. */
824 for (i = 0; i < nlines; i++)
827 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
829 struct spec_section *next
830 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
831 next->name = copy_string (lines[i].start + prefix_length,
832 lines[i].size - prefix_length);
833 next->next = *sections;
843 /* If entries were specified explicitly with command options,
844 ignore the entries in the input file. */
845 else if (!ignore_entries)
847 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
848 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
852 /* We found an entry, but didn't yet see any sections
853 specified. Default to section "Miscellaneous". */
854 *sections = (struct spec_section *)
855 xmalloc (sizeof (struct spec_section));
856 (*sections)->name = "Miscellaneous";
857 (*sections)->next = 0;
858 (*sections)->missing = 1;
861 /* Next time we see INFO-DIR-SECTION, we will reset the
865 if (start_of_this_entry != 0)
866 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"), 0, 0);
867 start_of_this_entry = lines[i + 1].start;
869 else if (start_of_this_entry)
871 if ((!strncmp ("* ", lines[i].start, 2)
872 && lines[i].start > start_of_this_entry)
873 || (!strncmp ("END-INFO-DIR-ENTRY",
874 lines[i].start, lines[i].size)
875 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
877 /* We found an end of this entry. Allocate another
878 entry, fill its data, and add it to the linked
880 struct spec_entry *next
881 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
883 = copy_string (start_of_this_entry,
884 lines[i].start - start_of_this_entry);
885 next->text_len = lines[i].start - start_of_this_entry;
886 next->entry_sections = head;
887 next->entry_sections_tail = tail;
888 next->next = *entries;
891 if (!strncmp ("END-INFO-DIR-ENTRY",
892 lines[i].start, lines[i].size)
893 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
894 start_of_this_entry = 0;
896 start_of_this_entry = lines[i].start;
898 else if (!strncmp ("END-INFO-DIR-ENTRY",
899 lines[i].start, lines[i].size)
900 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
901 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"), 0, 0);
905 if (start_of_this_entry != 0)
906 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"),
909 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
910 and plug the names of all the sections we found into every
911 element of the ENTRIES list. */
912 if (ignore_entries && *entries)
914 struct spec_entry *entry;
916 for (entry = *entries; entry; entry = entry->next)
918 entry->entry_sections = head;
919 entry->entry_sections_tail = tail;
926 /* Parse the dir file whose basename is BASE_NAME. Find all the
927 nodes, and their menus, and the sections of their menus. */
929 parse_dir_file (lines, nlines, nodes, base_name)
930 struct line_data *lines;
933 const char *base_name;
935 int node_header_flag = 0;
936 int something_deleted = 0;
940 for (i = 0; i < nlines; i++)
942 /* Parse node header lines. */
943 if (node_header_flag)
946 for (j = 0; j < lines[i].size; j++)
947 /* Find the node name and store it in the `struct node'. */
948 if (!strncmp ("Node:", lines[i].start + j, 5))
950 char *line = lines[i].start;
951 /* Find the start of the node name. */
953 while (line[j] == ' ' || line[j] == '\t')
955 /* Find the end of the node name. */
957 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
958 && line[end] != '\t')
960 (*nodes)->name = copy_string (line + j, end - j);
962 node_header_flag = 0;
965 /* Notice the start of a node. */
966 if (*lines[i].start == 037)
968 struct node *next = (struct node *) xmalloc (sizeof (struct node));
972 next->start_line = i;
974 next->menu_start = NULL;
975 next->sections = NULL;
976 next->last_section = NULL;
979 (*nodes)->end_line = i;
980 /* Fill in the end of the last menu section
981 of the previous node. */
982 if (*nodes != 0 && (*nodes)->last_section != 0)
983 (*nodes)->last_section->end_line = i;
987 /* The following line is the header of this node;
989 node_header_flag = 1;
992 /* Notice the lines that start menus. */
993 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
994 (*nodes)->menu_start = lines[i + 1].start;
996 /* Notice sections in menus. */
998 && (*nodes)->menu_start != 0
999 && *lines[i].start != '\n'
1000 && *lines[i].start != '*'
1001 && *lines[i].start != ' '
1002 && *lines[i].start != '\t')
1004 /* Add this menu section to the node's list.
1005 This list grows in forward order. */
1006 struct menu_section *next
1007 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1009 next->start_line = i + 1;
1012 next->name = copy_string (lines[i].start, lines[i].size);
1013 if ((*nodes)->sections)
1015 (*nodes)->last_section->next = next;
1016 (*nodes)->last_section->end_line = i;
1019 (*nodes)->sections = next;
1020 (*nodes)->last_section = next;
1023 /* Check for an existing entry that should be deleted.
1024 Delete all entries which specify this file name. */
1025 if (*lines[i].start == '*')
1028 char *p = lines[i].start;
1031 while (*p == ' ') p++; /* ignore following spaces */
1032 q = p; /* remember this, it's the beginning of the menu item. */
1034 /* Read menu item. */
1035 while (*p != 0 && *p != ':')
1040 { /* XEmacs-style entry, as in * Mew::Messaging. */
1041 if (menu_item_equal (q, ':', base_name))
1043 lines[i].delete = 1;
1044 something_deleted = 1;
1048 { /* Emacs-style entry, as in * Emacs: (emacs). */
1049 while (*p == ' ') p++; /* skip spaces after : */
1050 if (*p == '(') /* if at parenthesized (FILENAME) */
1053 if (menu_item_equal (p, ')', base_name))
1055 lines[i].delete = 1;
1056 something_deleted = 1;
1062 /* Treat lines that start with whitespace
1063 as continuations; if we are deleting an entry,
1064 delete all its continuations as well. */
1065 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1067 lines[i].delete = lines[i - 1].delete;
1071 /* Finish the info about the end of the last node. */
1074 (*nodes)->end_line = nlines;
1075 if ((*nodes)->last_section != 0)
1076 (*nodes)->last_section->end_line = nlines;
1079 return something_deleted;
1087 char *opened_dirfilename;
1088 char *compression_program;
1089 char *infile_sans_info;
1090 char *infile = 0, *dirfile = 0;
1091 unsigned infilelen_sans_info;
1093 /* Record the text of the Info file, as a sequence of characters
1094 and as a sequence of lines. */
1095 char *input_data = NULL;
1097 struct line_data *input_lines = NULL;
1098 int input_nlines = 0;
1100 /* Record here the specified section names and directory entries. */
1101 struct spec_section *input_sections = NULL;
1102 struct spec_entry *entries_to_add = NULL;
1103 int n_entries_to_add = 0;
1105 /* Record the old text of the dir file, as plain characters,
1106 as lines, and as nodes. */
1110 struct line_data *dir_lines;
1111 struct node *dir_nodes;
1113 /* Nonzero means --delete was specified (just delete existing entries). */
1114 int delete_flag = 0;
1115 int something_deleted = 0;
1116 /* Nonzero means -q was specified. */
1121 #ifdef HAVE_SETLOCALE
1122 /* Set locale via LC_ALL. */
1123 setlocale (LC_ALL, "");
1126 /* Set the text message domain. */
1127 bindtextdomain (PACKAGE, LOCALEDIR);
1128 textdomain (PACKAGE);
1132 int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
1140 /* If getopt returns 0, then it has already processed a
1141 long-named option. We should do nothing. */
1150 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
1152 suggest_asking_for_help ();
1160 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
1162 suggest_asking_for_help ();
1164 dirfile = concat (optarg, "", "/dir");
1169 struct spec_entry *next
1170 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1171 int olen = strlen (optarg);
1172 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
1174 optarg = concat (optarg, "\n", "");
1177 next->text = optarg;
1178 next->text_len = olen;
1179 next->entry_sections = NULL;
1180 next->entry_sections_tail = NULL;
1181 next->next = entries_to_add;
1182 entries_to_add = next;
1195 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
1197 suggest_asking_for_help ();
1212 struct spec_section *next
1213 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1214 next->name = optarg;
1215 next->next = input_sections;
1217 input_sections = next;
1222 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
1224 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
1225 There is NO warranty. You may redistribute this software\n\
1226 under the terms of the GNU General Public License.\n\
1227 For more information about these matters, see the files named COPYING.\n"),
1232 suggest_asking_for_help ();
1236 /* Interpret the non-option arguments as file names. */
1237 for (; optind < argc; ++optind)
1240 infile = argv[optind];
1241 else if (dirfile == 0)
1242 dirfile = argv[optind];
1244 error (_("excess command line argument `%s'"), argv[optind], 0);
1248 fatal (_("No input file specified; try --help for more information."),
1251 fatal (_("No dir file specified; try --help for more information."), 0, 0);
1253 /* Read the Info file and parse it into lines, unless we're deleting. */
1256 input_data = readfile (infile, &input_size, NULL, NULL, NULL);
1257 input_lines = findlines (input_data, input_size, &input_nlines);
1260 i = parse_input (input_lines, input_nlines,
1261 &input_sections, &entries_to_add);
1262 if (i > n_entries_to_add)
1263 n_entries_to_add = i;
1267 if (entries_to_add == 0)
1268 { /* No need to abort here, the original info file may not
1269 have the requisite Texinfo commands. This is not
1270 something an installer should have to correct (it's a
1271 problem for the maintainer), and there's no need to cause
1272 subsequent parts of `make install' to fail. */
1273 warning (_("no info dir entry in `%s'"), infile, 0);
1277 /* If the entries came from the command-line arguments, their
1278 entry_sections pointers are not yet set. Walk the chain of
1279 the entries and for each entry update entry_sections to point
1280 to the head of the list of sections where this entry should
1281 be put. Note that all the entries specified on the command
1282 line get put into ALL the sections we've got, either from the
1283 Info file, or (under --section) from the command line,
1284 because in the loop below every entry inherits the entire
1285 chain of sections. */
1286 if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
1288 struct spec_entry *ep;
1290 /* If we got no sections, default to "Miscellaneous". */
1291 if (input_sections == NULL)
1293 input_sections = (struct spec_section *)
1294 xmalloc (sizeof (struct spec_section));
1295 input_sections->name = "Miscellaneous";
1296 input_sections->next = NULL;
1297 input_sections->missing = 1;
1299 for (ep = entries_to_add; ep; ep = ep->next)
1300 ep->entry_sections = input_sections;
1304 /* Now read in the Info dir file. */
1305 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
1306 &opened_dirfilename, &compression_program);
1307 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
1309 /* We will be comparing the entries in the dir file against the
1310 current filename, so need to strip off any directory prefix and/or
1311 [.info][.gz] suffix. */
1313 char *infile_basename = infile + strlen (infile);
1315 if (HAVE_DRIVE (infile))
1316 infile += 2; /* get past the drive spec X: */
1318 while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
1321 infile_sans_info = strip_info_suffix (infile_basename);
1322 infilelen_sans_info = strlen (infile_sans_info);
1326 = parse_dir_file (dir_lines, dir_nlines, &dir_nodes, infile_sans_info);
1328 /* Decide where to add the new entries (unless --delete was used).
1329 Find the menu sections to add them in.
1330 In each section, find the proper alphabetical place to add
1331 each of the entries. */
1336 struct menu_section *section;
1337 struct spec_section *spec;
1339 for (node = dir_nodes; node; node = node->next)
1340 for (section = node->sections; section; section = section->next)
1342 for (i = section->end_line; i > section->start_line; i--)
1343 if (dir_lines[i - 1].size != 0)
1345 section->end_line = i;
1347 for (spec = input_sections; spec; spec = spec->next)
1348 if (!strcmp (spec->name, section->name))
1352 int add_at_line = section->end_line;
1353 struct spec_entry *entry;
1354 /* Say we have found at least one section with this name,
1355 so we need not add such a section. */
1357 /* For each entry, find the right place in this section
1359 for (entry = entries_to_add; entry; entry = entry->next)
1361 /* Did they at all want this entry to be put into
1363 for (spec = entry->entry_sections;
1364 spec && spec != entry->entry_sections_tail;
1367 if (!strcmp (spec->name, section->name))
1370 if (!spec || spec == entry->entry_sections_tail)
1373 /* Subtract one because dir_lines is zero-based,
1374 but the `end_line' and `start_line' members are
1376 for (i = section->end_line - 1;
1377 i >= section->start_line - 1; i--)
1379 /* If an entry exists with the same name,
1380 and was not marked for deletion
1381 (which means it is for some other file),
1382 we are in trouble. */
1383 if (dir_lines[i].start[0] == '*'
1384 && menu_line_equal (entry->text, entry->text_len,
1387 && !dir_lines[i].delete)
1388 fatal (_("menu item `%s' already exists, for file `%s'"),
1389 extract_menu_item_name (entry->text),
1390 extract_menu_file_name (dir_lines[i].start));
1391 if (dir_lines[i].start[0] == '*'
1392 && menu_line_lessp (entry->text, entry->text_len,
1397 insert_entry_here (entry, add_at_line,
1398 dir_lines, n_entries_to_add);
1403 /* Mark the end of the Top node as the place to add any
1404 new sections that are needed. */
1405 for (node = dir_nodes; node; node = node->next)
1406 if (node->name && strcmp (node->name, "Top") == 0)
1407 dir_lines[node->end_line].add_sections_before = 1;
1410 if (delete_flag && !something_deleted && !quiet_flag)
1411 warning (_("no entries found for `%s'; nothing deleted"), infile, 0);
1413 output_dirfile (opened_dirfilename, dir_nlines, dir_lines, n_entries_to_add,
1414 entries_to_add, input_sections, compression_program);
1419 /* Divide the text at DATA (of SIZE bytes) into lines.
1420 Return a vector of struct line_data describing the lines.
1421 Store the length of that vector into *NLINESP. */
1424 findlines (data, size, nlinesp)
1431 int lines_allocated = 511;
1433 struct line_data *lines
1434 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
1436 for (i = 0; i < size; i++)
1440 if (filled == lines_allocated)
1442 /* try to keep things somewhat page-aligned */
1443 lines_allocated = ((lines_allocated + 1) * 2) - 1;
1444 lines = xrealloc (lines, (lines_allocated + 1)
1445 * sizeof (struct line_data));
1447 lines[filled].start = &data[i];
1448 lines[filled].add_entries_before = 0;
1449 lines[filled].add_sections_before = 0;
1450 lines[filled].delete = 0;
1452 lines[filled - 1].size
1453 = lines[filled].start - lines[filled - 1].start - 1;
1456 lineflag = (data[i] == '\n');
1459 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
1461 /* Do not leave garbage in the last element. */
1462 lines[filled].start = NULL;
1463 lines[filled].add_entries_before = NULL;
1464 lines[filled].add_sections_before = 0;
1465 lines[filled].delete = 0;
1466 lines[filled].size = 0;
1472 /* Compare the menu item names in LINE1 (line length LEN1)
1473 and LINE2 (line length LEN2). Return 1 if the item name
1474 in LINE1 is less, 0 otherwise. */
1477 menu_line_lessp (line1, len1, line2, len2)
1483 int minlen = (len1 < len2 ? len1 : len2);
1486 for (i = 0; i < minlen; i++)
1488 /* If one item name is a prefix of the other,
1489 the former one is less. */
1490 if (line1[i] == ':' && line2[i] != ':')
1492 if (line2[i] == ':' && line1[i] != ':')
1494 /* If they both continue and differ, one is less. */
1495 if (line1[i] < line2[i])
1497 if (line1[i] > line2[i])
1500 /* With a properly formatted dir file,
1501 we can only get here if the item names are equal. */
1505 /* Compare the menu item names in LINE1 (line length LEN1)
1506 and LINE2 (line length LEN2). Return 1 if the item names are equal,
1510 menu_line_equal (line1, len1, line2, len2)
1516 int minlen = (len1 < len2 ? len1 : len2);
1519 for (i = 0; i < minlen; i++)
1521 /* If both item names end here, they are equal. */
1522 if (line1[i] == ':' && line2[i] == ':')
1524 /* If they both continue and differ, one is less. */
1525 if (line1[i] != line2[i])
1528 /* With a properly formatted dir file,
1529 we can only get here if the item names are equal. */
1533 /* This is the comparison function for qsort
1534 for a vector of pointers to struct spec_section.
1535 Compare the section names. */
1538 compare_section_names (sec1, sec2)
1539 struct spec_section **sec1, **sec2;
1541 char *name1 = (*sec1)->name;
1542 char *name2 = (*sec2)->name;
1543 return strcmp (name1, name2);
1546 /* This is the comparison function for qsort
1547 for a vector of pointers to struct spec_entry.
1548 Compare the entries' text. */
1551 compare_entries_text (entry1, entry2)
1552 struct spec_entry **entry1, **entry2;
1554 char *text1 = (*entry1)->text;
1555 char *text2 = (*entry2)->text;
1556 char *colon1 = strchr (text1, ':');
1557 char *colon2 = strchr (text2, ':');
1561 len1 = strlen (text1);
1563 len1 = colon1 - text1;
1565 len2 = strlen (text2);
1567 len2 = colon2 - text2;
1568 return strncmp (text1, text2, len1 <= len2 ? len1 : len2);
1571 /* Insert ENTRY into the add_entries_before vector
1572 for line number LINE_NUMBER of the dir file.
1573 DIR_LINES and N_ENTRIES carry information from like-named variables
1577 insert_entry_here (entry, line_number, dir_lines, n_entries)
1578 struct spec_entry *entry;
1580 struct line_data *dir_lines;
1585 if (dir_lines[line_number].add_entries_before == 0)
1587 dir_lines[line_number].add_entries_before
1588 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1589 for (i = 0; i < n_entries; i++)
1590 dir_lines[line_number].add_entries_before[i] = 0;
1593 /* Find the place where this entry belongs. If there are already
1594 several entries to add before LINE_NUMBER, make sure they are in
1595 alphabetical order. */
1596 for (i = 0; i < n_entries; i++)
1597 if (dir_lines[line_number].add_entries_before[i] == 0
1598 || menu_line_lessp (entry->text, strlen (entry->text),
1599 dir_lines[line_number].add_entries_before[i]->text,
1600 strlen (dir_lines[line_number].add_entries_before[i]->text)))
1606 /* If we need to plug ENTRY into the middle of the
1607 ADD_ENTRIES_BEFORE array, move the entries which should be output
1608 after this one down one notch, before adding a new one. */
1609 if (dir_lines[line_number].add_entries_before[i] != 0)
1610 for (j = n_entries - 1; j > i; j--)
1611 dir_lines[line_number].add_entries_before[j]
1612 = dir_lines[line_number].add_entries_before[j - 1];
1614 dir_lines[line_number].add_entries_before[i] = entry;