1 /* install-info -- create Info directory entry(ies) for an Info file.
2 $Id: install-info.c,v 1.13 2008/05/18 16:54:02 karl Exp $
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2007, 2008 Free Software Foundation, Inc.
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 3 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 static char *progname = "install-info";
32 struct line_data *findlines (char *data, int size, int *nlinesp);
33 void insert_entry_here (struct spec_entry *entry, int line_number,
34 struct line_data *dir_lines, int n_entries);
35 int compare_section_names (const void *s1, const void *s2);
36 int compare_entries_text (const void *e1, const void *e2);
38 /* Data structures. */
41 /* Record info about a single line from a file as read into core. */
44 /* The start of the line. */
46 /* The number of characters in the line,
47 excluding the terminating newline. */
49 /* Vector containing pointers to the entries to add before this line.
50 The vector is null-terminated. */
51 struct spec_entry **add_entries_before;
52 /* Vector containing pointers to the sections to add before this line.
53 The vector is not null-terminated. */
54 struct spec_section **add_sections_before;
55 /* The vector ADD_SECTIONS_BEFORE_HERE contains exactly this many
56 pointers to sections. */
57 int num_sections_to_add;
58 /* 1 means don't output this line. */
63 /* This is used for a list of the specified menu section names
64 in which entries should be added. */
67 struct spec_section *next;
69 /* 1 means we have not yet found an existing section with this name
70 in the dir file--so we will need to add a new section. */
75 /* This is used for a list of the entries specified to be added. */
78 struct spec_entry *next;
81 /* A pointer to the list of sections to which this entry should be
83 struct spec_section *entry_sections;
84 /* A pointer to a section that is beyond the end of the chain whose
85 head is pointed to by entry_sections. */
86 struct spec_section *entry_sections_tail;
87 /* Non-zero means that the entry doesn't have a name specified. This
88 can only happen if a --description preceeds a --name option. */
90 /* Non-zero means that the entry doesn't have a description. This
91 happens when a --name option is given prior to a --description
93 int missing_description;
94 /* Non-zero means that the entry doesn't have an Info file specified.
95 This means that the entry was taken from the command-line but it
96 only contains the name, and not the info file's basename, which
97 we get later on. This only happens on entries that originate
98 from --name options. */
103 /* This is used for a list of nodes found by parsing the dir file. */
109 /* The line number of the line where the node starts.
110 This is the line that contains control-underscore. */
112 /* The line number of the line where the node ends,
113 which is the end of the file or where the next line starts. */
115 /* Start of first line in this node's menu
116 (the line after the * Menu: line). */
118 /* The start of the chain of sections in this node's menu. */
119 struct menu_section *sections;
120 /* The last menu section in the chain. */
121 struct menu_section *last_section;
125 /* This is used for a list of sections found in a node's menu.
126 Each struct node has such a list in the sections field. */
129 struct menu_section *next;
131 /* Line number of start of section. */
133 /* Line number of end of section. */
137 /* This table defines all the long-named options, says whether they
138 use an argument, and maps them into equivalent single-letter options. */
140 struct option longopts[] =
142 { "add-once", no_argument, NULL, '1'},
143 { "align", required_argument, NULL, 'A'},
144 { "append-new-sections", no_argument, NULL, 'a'},
145 { "calign", required_argument, NULL, 'C'},
146 { "debug", no_argument, NULL, 'g' },
147 { "delete", no_argument, NULL, 'r' },
148 { "dir-file", required_argument, NULL, 'd' },
149 { "entry", required_argument, NULL, 'e' },
150 { "name", required_argument, NULL, 't' },
151 { "menuentry", required_argument, NULL, 't' },
152 { "description", required_argument, NULL, 'c' },
153 { "help", no_argument, NULL, 'h' },
154 { "no-indent", no_argument, NULL, 'I' },
155 { "infodir", required_argument, NULL, 'D' },
156 { "info-dir", required_argument, NULL, 'D' },
157 { "info-file", required_argument, NULL, 'i' },
158 { "item", required_argument, NULL, 'e' },
159 { "keep-old", no_argument, NULL, 'k' },
160 { "maxwidth", required_argument, NULL, 'W'},
161 { "max-width", required_argument, NULL, 'W'},
162 { "quiet", no_argument, NULL, 'q' },
163 { "remove", no_argument, NULL, 'r' },
164 { "remove-exactly", no_argument, NULL, 'x' },
165 { "section", required_argument, NULL, 's' },
166 { "regex", required_argument, NULL, 'R' },
167 { "silent", no_argument, NULL, 'q' },
168 { "test", no_argument, NULL, 'n' },
169 { "dry-run", no_argument, NULL, 'n' },
170 { "version", no_argument, NULL, 'V' },
174 regex_t *psecreg = NULL;
176 /* Nonzero means that the name specified for the Info file will be used
177 (without removing .gz, .info extension or leading path) to match the
178 entries that must be removed. */
179 int remove_exactly = 0;
181 /* Nonzero means that sections that don't have entries in them will be
183 int remove_empty_sections = 1;
185 /* Nonzero means that new Info entries into the DIR file will go into all
186 sections that match with --section-regex or --section. Zero means
187 that new entries wil go into the first section that matches.*/
188 int add_entries_into_all_matching_sections = 1;
190 /* Nonzero means we do not replace same-named info entries. */
191 int keep_old_flag = 0;
193 /* Nonzero means --test was specified, to inhibit updating the dir file. */
194 int chicken_flag = 0;
196 /* Zero means that entries will not be formatted when they are either
197 added or replaced. */
200 /* Zero means that new sections will be added at the end of the DIR file. */
201 int order_new_sections_alphabetically_flag = 1;
204 /* Error message functions. */
206 /* Print error message. S1 is printf control string, S2 and S3 args for it. */
210 error (const char *s1, const char *s2, const char *s3)
212 fprintf (stderr, "%s: ", progname);
213 fprintf (stderr, s1, s2, s3);
219 warning (const char *s1, const char *s2, const char *s3)
221 fprintf (stderr, _("%s: warning: "), progname);
222 fprintf (stderr, s1, s2, s3);
226 /* Print error message and exit. */
229 fatal (const char *s1, const char *s2, const char *s3)
235 /* Return a newly-allocated string
236 whose contents concatenate those of S1, S2, S3. */
238 concat (const char *s1, const char *s2, const char *s3)
240 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
241 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
244 strcpy (result + len1, s2);
245 strcpy (result + len1 + len2, s3);
246 *(result + len1 + len2 + len3) = 0;
251 /* Return a string containing SIZE characters
252 copied from starting at STRING. */
255 copy_string (const char *string, int size)
258 char *copy = (char *) xmalloc (size + 1);
259 for (i = 0; i < size; i++)
265 /* Print fatal error message based on errno, with file name NAME. */
268 pfatal_with_name (const char *name)
270 char *s = concat ("", strerror (errno), _(" for %s"));
274 /* Compare the menu item names in LINE1 (line length LEN1)
275 and LINE2 (line length LEN2). Return 1 if the item name
276 in LINE1 is less, 0 otherwise. */
279 menu_line_lessp (char *line1, int len1, char *line2, int len2)
281 int minlen = (len1 < len2 ? len1 : len2);
284 for (i = 0; i < minlen; i++)
286 /* If one item name is a prefix of the other,
287 the former one is less. */
288 if (line1[i] == ':' && line2[i] != ':')
290 if (line2[i] == ':' && line1[i] != ':')
292 /* If they both continue and differ, one is less. */
293 if (line1[i] < line2[i])
295 if (line1[i] > line2[i])
298 /* With a properly formatted dir file,
299 we can only get here if the item names are equal. */
303 /* Compare the menu item names in LINE1 (line length LEN1)
304 and LINE2 (line length LEN2). Return 1 if the item names are equal,
308 menu_line_equal (char *line1, int len1, char *line2, int len2)
310 int minlen = (len1 < len2 ? len1 : len2);
313 for (i = 0; i < minlen; i++)
315 /* If both item names end here, they are equal. */
316 if (line1[i] == ':' && line2[i] == ':')
318 /* If they both continue and differ, one is less. */
319 if (line1[i] != line2[i])
322 /* With a properly formatted dir file,
323 we can only get here if the item names are equal. */
328 /* Given the full text of a menu entry, null terminated,
329 return just the menu item name (copied). */
332 extract_menu_item_name (char *item_text)
336 if (*item_text == '*')
338 while (*item_text == ' ')
342 while (*p && *p != ':') p++;
343 return copy_string (item_text, p - item_text);
346 /* Given the full text of a menu entry, terminated by null or newline,
347 return just the menu item file (copied). */
350 extract_menu_file_name (char *item_text)
354 /* If we have text that looks like * ITEM: (FILE)NODE...,
355 extract just FILE. Otherwise return "(none)". */
362 /* Skip to and past the colon. */
363 while (*p && *p != '\n' && *p != ':') p++;
366 /* Skip past the open-paren. */
371 else if (*p == ' ' || *p == '\t')
380 /* File name ends just before the close-paren. */
381 while (*p && *p != '\n' && *p != ')') p++;
385 return copy_string (item_text, p - item_text);
390 /* Return FNAME with any [.info][.gz] suffix removed. */
393 strip_info_suffix (char *fname)
395 char *ret = xstrdup (fname);
396 unsigned len = strlen (ret);
398 if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
403 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".bz2") == 0)
408 else if (len > 5 && FILENAME_CMP (ret + len - 5, ".lzma") == 0)
414 if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
419 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
425 else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
426 || FILENAME_CMP (ret + len - 4, ".igz") == 0))
431 #endif /* __MSDOS__ */
437 /* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
438 can also be followed by `.gz', `.info.gz', or `.info' (and then
439 TERM_CHAR) and still match. */
442 menu_item_equal (const char *item, char term_char, const char *name)
445 const char *item_basename = item;
446 unsigned name_len = strlen (name);
448 /* We must compare the basename in ITEM, since we are passed the
449 basename of the original info file. Otherwise, a new entry like
450 "lilypond/lilypond" won't match "lilypond".
452 Actually, it seems to me that we should really compare the whole
453 name, and not just the basename. Couldn't there be dir1/foo.info
454 and dir2/foo.info? Also, it seems like we should be using the
455 filename from the new dir entries, not the filename on the command
456 line. Not worrying about those things right now, though. --karl,
458 if (!remove_exactly) {
459 while (*item_basename && !IS_SLASH (*item_basename)
460 && *item_basename != term_char)
462 if (! *item_basename || *item_basename == term_char)
463 item_basename = item; /* no /, use original */
465 item_basename++; /* have /, move past it */
468 /* First, ITEM must actually match NAME (usually it won't). */
469 ret = mbsncasecmp (item_basename, name, name_len) == 0;
472 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
473 ITEM. The various suffixes should never actually appear in the
474 dir file, but sometimes people put them in. */
475 static char *suffixes[]
476 = { "", ".info.gz", ".info", ".inf", ".gz",
483 for (i = 0; !ret && suffixes[i]; i++)
485 char *suffix = suffixes[i];
486 unsigned suffix_len = strlen (suffix);
487 ret = mbsncasecmp (item_basename + name_len, suffix, suffix_len) == 0
488 && item_basename[name_len + suffix_len] == term_char;
498 suggest_asking_for_help (void)
500 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
508 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n"), progname);
510 puts (_("Add or remove entries in INFO-FILE from the Info directory DIR-FILE."));
515 --debug report what is being done.\n\
516 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
517 don't insert any new entries.\n\
518 --description=TEXT the description of the entry is TEXT; used with\n\
519 the --name option to become synonymous with the\n\
521 --dir-file=NAME specify file name of Info directory file;\n\
522 equivalent to using the DIR-FILE argument.\n\
523 --dry-run same as --test."));
526 --entry=TEXT insert TEXT as an Info directory entry.\n\
527 TEXT is written as an Info menu item line followed\n\
528 by zero or more extra lines starting with whitespace.\n\
529 If you specify more than one entry, all are added.\n\
530 If you don't specify any entries, they are determined\n\
531 from information in the Info file itself.\n\
532 When removing, TEXT specifies the entry to remove.\n\
533 TEXT is only removed as a last resort, if the\n\
534 entry as determined from the Info file is not present,\n\
535 and the basename of the Info file isn't found either."));
538 --help display this help and exit.\n\
539 --info-dir=DIR same as --dir-file=DIR/dir.\n\
540 --info-file=FILE specify Info file to install in the directory;\n\
541 equivalent to using the INFO-FILE argument.\n\
542 --item=TEXT same as --entry=TEXT.\n\
543 --keep-old do not replace entries, or remove empty sections.\n\
544 --menuentry=TEXT same as --name=TEXT.\n\
545 --name=TEXT the name of the entry is TEXT; used with --description\n\
546 to become synonymous with the --entry option.\n\
547 --no-indent do not format new entries in the DIR file.\n\
548 --quiet suppress warnings."));
551 --regex=R put this file's entries in all sections that match the\n\
552 regular expression R (ignoring case).\n\
553 --remove same as --delete.\n\
554 --remove-exactly only remove if the info file name matches exactly;\n\
555 suffixes such as .info and .gz are not ignored.\n\
556 --section=SEC put entries in section SEC of the directory.\n\
557 If you specify more than one section, all the entries\n\
558 are added in each of the sections.\n\
559 If you don't specify any sections, they are determined\n\
560 from information in the Info file itself.\n\
561 --section R SEC equivalent to --regex=R --section=SEC --add-once."));
564 --silent suppress warnings.\n\
565 --test suppress updating of DIR-FILE.\n\
566 --version display version information and exit."));
571 Email bug reports to bug-texinfo@gnu.org,\n\
572 general questions and discussion to help-texinfo@gnu.org.\n\
573 Texinfo home page: http://www.gnu.org/software/texinfo/"));
577 /* If DIRFILE does not exist, and we are not in test mode, create a
578 minimal one (or abort). If it already exists, do nothing. */
581 ensure_dirfile_exists (char *dirfile)
588 desc = open (dirfile, O_RDONLY);
589 if (desc < 0 && errno == ENOENT)
592 char *readerr = strerror (errno);
594 f = fopen (dirfile, "w");
597 fprintf (f, _("This is the file .../info/dir, which contains the\n\
598 topmost node of the Info hierarchy, called (dir)Top.\n\
599 The first time you invoke Info you start off looking at this node.\n\
601 %s\tThis is the top of the INFO tree\n\
603 This (the Directory node) gives a menu of major topics.\n\
604 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
605 \"h\" gives a primer for first-timers,\n\
606 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
608 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
612 "), "File: dir,\tNode: Top", /* These keywords must not be translated. */
616 pfatal_with_name (dirfile);
620 /* Didn't exist, but couldn't open for writing. */
622 _("%s: could not read (%s) and could not create (%s)\n"),
623 dirfile, readerr, strerror (errno));
628 close (desc); /* It already existed, so fine. */
631 /* Open FILENAME and return the resulting stream pointer. If it doesn't
632 exist, try FILENAME.gz. If that doesn't exist either, call
633 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
634 non-NULL. If still no luck, fatal error.
636 If we do open it, return the actual name of the file opened in
637 OPENED_FILENAME and the compress program to use to (de)compress it in
638 COMPRESSION_PROGRAM. The compression program is determined by the
639 magic number, not the filename. */
642 open_possibly_compressed_file (char *filename,
643 void (*create_callback) (char *),
644 char **opened_filename, char **compression_program, int *is_pipe)
646 char *local_opened_filename, *local_compression_program;
651 /* We let them pass NULL if they don't want this info, but it's easier
652 to always determine it. */
653 if (!opened_filename)
654 opened_filename = &local_opened_filename;
656 *opened_filename = filename;
657 f = fopen (*opened_filename, FOPEN_RBIN);
660 *opened_filename = concat (filename, ".gz", "");
661 f = fopen (*opened_filename, FOPEN_RBIN);
664 free (*opened_filename);
665 *opened_filename = concat (filename, ".bz2", "");
666 f = fopen (*opened_filename, FOPEN_RBIN);
670 free (*opened_filename);
671 *opened_filename = concat (filename, ".lzma", "");
672 f = fopen (*opened_filename, FOPEN_RBIN);
678 free (*opened_filename);
679 *opened_filename = concat (filename, ".igz", "");
680 f = fopen (*opened_filename, FOPEN_RBIN);
684 free (*opened_filename);
685 *opened_filename = concat (filename, ".inz", "");
686 f = fopen (*opened_filename, FOPEN_RBIN);
692 { /* That didn't work either. Create the file if we can. */
693 (*create_callback) (filename);
695 /* And try opening it again. */
696 free (*opened_filename);
697 *opened_filename = filename;
698 f = fopen (*opened_filename, FOPEN_RBIN);
700 pfatal_with_name (filename);
703 pfatal_with_name (filename);
707 /* Read first few bytes of file rather than relying on the filename.
708 If the file is shorter than this it can't be usable anyway. */
709 nread = fread (data, sizeof (data), 1, f);
712 /* Empty files don't set errno, so we get something like
713 "install-info: No error for foo", which is confusing. */
715 fatal (_("%s: empty file"), *opened_filename, 0);
716 pfatal_with_name (*opened_filename);
719 if (!compression_program)
720 compression_program = &local_compression_program;
722 if (data[0] == '\x1f' && data[1] == '\x8b')
724 /* An explicit .exe yields a better diagnostics from popen below
725 if they don't have gzip installed. */
726 *compression_program = "gzip.exe";
728 *compression_program = "gzip";
730 else if (data[0] == 'B' && data[1] == 'Z' && data[2] == 'h')
731 #ifndef STRIP_DOT_EXE
732 *compression_program = "bzip2.exe";
734 *compression_program = "bzip2";
736 else if (data[0] == 'B' && data[1] == 'Z' && data[2] == '0')
737 #ifndef STRIP_DOT_EXE
738 *compression_program = "bzip.exe";
740 *compression_program = "bzip";
742 /* We (try to) match against old lzma format (which lacks proper
743 header, two first matches), as well as the new format (last match). */
744 else if ((data[9] == 0x00 && data[10] == 0x00 && data[11] == 0x00
746 || (data[5] == '\xFF' && data[6] == '\xFF' && data[7] == '\xFF'
747 && data[8] == '\xFF' && data[9] == '\xFF' && data[10] == '\xFF'
748 && data[11] == '\xFF' && data[12] == '\xFF')
749 || (data[0] == '\xFF' && data[1] == 'L' && data[2] == 'Z'
750 && data[3] == 'M' && data[4] == 'A' && data[5] == 0x00))
751 #ifndef STRIP_DOT_EXE
752 *compression_program = "lzma.exe";
754 *compression_program = "lzma";
757 *compression_program = NULL;
759 if (*compression_program)
760 { /* It's compressed, so fclose the file and then open a pipe. */
761 char *command = concat (*compression_program," -cd <", *opened_filename);
763 pfatal_with_name (*opened_filename);
764 f = popen (command, "r");
768 pfatal_with_name (command);
771 { /* It's a plain file, seek back over the magic bytes. */
772 if (fseek (f, 0, 0) < 0)
773 pfatal_with_name (*opened_filename);
775 /* Since this is a text file, and we opened it in binary mode,
776 switch back to text mode. */
777 f = freopen (*opened_filename, "r", f);
785 /* Read all of file FILENAME into memory and return the address of the
786 data. Store the size of the data into SIZEP. If need be, uncompress
787 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
788 the actual file name that was opened into OPENED_FILENAME (if it is
789 non-NULL), and the companion compression program (if any, else NULL)
790 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
794 readfile (char *filename, int *sizep,
795 void (*create_callback) (char *), char **opened_filename,
796 char **compression_program)
802 int data_size = 8192;
803 char *data = xmalloc (data_size);
805 /* If they passed the space for the file name to return, use it. */
806 f = open_possibly_compressed_file (filename, create_callback,
807 opened_filename ? opened_filename
809 compression_program, &pipe_p);
813 int nread = fread (data + filled, 1, data_size - filled, f);
815 pfatal_with_name (real_name);
820 if (filled == data_size)
823 data = xrealloc (data, data_size);
827 /* We'll end up wasting space if we're not passing the filename back
828 and it is not just FILENAME, but so what. */
829 /* We need to close the stream, since on some systems the pipe created
830 by popen is simulated by a temporary file which only gets removed
841 /* Output the old dir file, interpolating the new sections
842 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
843 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
844 we'll write dir.gz on output. */
847 output_dirfile (char *dirfile, int dir_nlines, struct line_data *dir_lines,
848 int n_entries_to_add, struct spec_entry *entries_to_add,
849 struct spec_section *input_sections, char *compression_program)
851 int n_entries_added = 0;
855 if (compression_program)
857 char *command = concat (compression_program, ">", dirfile);
858 output = popen (command, "w");
861 output = fopen (dirfile, "w");
869 for (i = 0; i <= dir_nlines; i++)
873 /* If we decided to output some new entries before this line,
875 if (dir_lines[i].add_entries_before)
876 for (j = 0; j < n_entries_to_add; j++)
878 struct spec_entry *this = dir_lines[i].add_entries_before[j];
881 if (n_entries_added >= 1 &&
882 !add_entries_into_all_matching_sections)
884 fputs (this->text, output);
887 /* If we decided to add some sections here
888 because there are no such sections in the file,
890 FIXME: we add all sections here, but they should
891 be interspersed throughout the DIR file in
893 if (dir_lines[i].add_sections_before)
895 struct spec_section *spec;
896 struct spec_entry *entry;
897 struct spec_entry **entries;
900 /* If we specified --add-once, and we've added an entry, then
901 it's time to bail. */
902 if (n_entries_added >= 1 &&
903 !add_entries_into_all_matching_sections)
906 qsort (dir_lines[i].add_sections_before,
907 dir_lines[i].num_sections_to_add,
908 sizeof (struct spec_section *), compare_section_names);
910 /* Count the entries and allocate a vector for all of them. */
911 for (entry = entries_to_add; entry; entry = entry->next)
913 entries = ((struct spec_entry **)
914 xmalloc (n_entries * sizeof (struct spec_entry *)));
916 /* Fill the vector ENTRIES with pointers to all the sections,
919 for (entry = entries_to_add; entry; entry = entry->next)
920 entries[j++] = entry;
921 qsort (entries, n_entries, sizeof (struct spec_entry *),
922 compare_entries_text);
924 /* Generate the new sections in alphabetical order. In each
925 new section, output all of the entries that belong to that
926 section, in alphabetical order. */
927 for (j = 0; j < dir_lines[i].num_sections_to_add; j++)
929 spec = dir_lines[i].add_sections_before[j];
935 fputs (spec->name, output);
938 for (k = 0; k < n_entries; k++)
940 struct spec_section *spec1;
941 /* Did they at all want this entry to be put into
944 for (spec1 = entry->entry_sections;
945 spec1 && spec1 != entry->entry_sections_tail;
948 if (!strcmp (spec1->name, spec->name))
951 if (spec1 && spec1 != entry->entry_sections_tail)
952 fputs (entry->text, output);
961 /* Output the original dir lines unless marked for deletion. */
962 if (i < dir_nlines && !dir_lines[i].delete)
964 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
969 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
970 On those systems, the compressor actually gets run inside pclose,
971 so we must call pclose. */
972 if (compression_program)
978 /* Parse the input to find the section names and the entry names it
979 specifies. Return the number of entries to add from this file. */
981 parse_input (const struct line_data *lines, int nlines,
982 struct spec_section **sections, struct spec_entry **entries,
986 int prefix_length = strlen ("INFO-DIR-SECTION ");
987 struct spec_section *head = *sections, *tail = NULL;
989 char *start_of_this_entry = 0;
990 int ignore_sections = *sections != 0;
991 int ignore_entries = delete_flag ? 0: *entries != 0;
995 if (ignore_sections && ignore_entries)
998 /* Loop here processing lines from the input file. Each
999 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
1000 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
1001 list, and all its entries inherit the chain of SECTION entries
1002 defined by the last group of INFO-DIR-SECTION entries we have
1003 seen until that point. */
1004 for (i = 0; i < nlines; i++)
1006 if (!ignore_sections
1007 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
1009 struct spec_section *next
1010 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1011 next->name = copy_string (lines[i].start + prefix_length,
1012 lines[i].size - prefix_length);
1013 next->next = *sections;
1023 /* If entries were specified explicitly with command options,
1024 ignore the entries in the input file. */
1025 else if (!ignore_entries)
1027 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
1028 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
1032 /* We found an entry, but didn't yet see any sections
1033 specified. Default to section "Miscellaneous". */
1034 *sections = (struct spec_section *)
1035 xmalloc (sizeof (struct spec_section));
1036 (*sections)->name = "Miscellaneous";
1037 (*sections)->next = 0;
1038 (*sections)->missing = 1;
1041 /* Next time we see INFO-DIR-SECTION, we will reset the
1045 if (start_of_this_entry != 0)
1046 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"), 0, 0);
1047 start_of_this_entry = lines[i + 1].start;
1049 else if (start_of_this_entry)
1051 if ((!strncmp ("* ", lines[i].start, 2)
1052 && lines[i].start > start_of_this_entry)
1053 || (!strncmp ("END-INFO-DIR-ENTRY",
1054 lines[i].start, lines[i].size)
1055 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
1057 /* We found an end of this entry. Allocate another
1058 entry, fill its data, and add it to the linked
1060 struct spec_entry *next
1061 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1063 = copy_string (start_of_this_entry,
1064 lines[i].start - start_of_this_entry);
1065 next->text_len = lines[i].start - start_of_this_entry;
1066 next->entry_sections = head;
1067 next->entry_sections_tail = tail;
1068 next->next = *entries;
1071 if (!strncmp ("END-INFO-DIR-ENTRY",
1072 lines[i].start, lines[i].size)
1073 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
1074 start_of_this_entry = 0;
1076 start_of_this_entry = lines[i].start;
1078 else if (!strncmp ("END-INFO-DIR-ENTRY",
1079 lines[i].start, lines[i].size)
1080 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
1081 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"), 0, 0);
1085 if (start_of_this_entry != 0)
1086 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"),
1089 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
1090 and plug the names of all the sections we found into every
1091 element of the ENTRIES list. */
1092 if (ignore_entries && *entries)
1094 struct spec_entry *entry;
1096 for (entry = *entries; entry; entry = entry->next)
1098 entry->entry_sections = head;
1099 entry->entry_sections_tail = tail;
1107 /* Parse the dir file whose basename is BASE_NAME. Find all the
1108 nodes, and their menus, and the sections of their menus. */
1110 parse_dir_file (struct line_data *lines, int nlines, struct node **nodes)
1112 int node_header_flag = 0;
1116 for (i = 0; i < nlines; i++)
1118 /* Parse node header lines. */
1119 if (node_header_flag)
1122 for (j = 0; j < lines[i].size; j++)
1123 /* Find the node name and store it in the `struct node'. */
1124 if (!strncmp ("Node:", lines[i].start + j, 5))
1126 char *line = lines[i].start;
1127 /* Find the start of the node name. */
1129 while (line[j] == ' ' || line[j] == '\t')
1131 /* Find the end of the node name. */
1133 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
1134 && line[end] != '\t')
1136 (*nodes)->name = copy_string (line + j, end - j);
1138 node_header_flag = 0;
1141 /* Notice the start of a node. */
1142 if (*lines[i].start == 037)
1144 struct node *next = (struct node *) xmalloc (sizeof (struct node));
1146 next->next = *nodes;
1148 next->start_line = i;
1150 next->menu_start = NULL;
1151 next->sections = NULL;
1152 next->last_section = NULL;
1155 (*nodes)->end_line = i;
1156 /* Fill in the end of the last menu section
1157 of the previous node. */
1158 if (*nodes != 0 && (*nodes)->last_section != 0)
1159 (*nodes)->last_section->end_line = i;
1163 /* The following line is the header of this node;
1165 node_header_flag = 1;
1168 /* Notice the lines that start menus. */
1169 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
1170 (*nodes)->menu_start = lines[i + 1].start;
1172 /* Notice sections in menus. */
1174 && (*nodes)->menu_start != 0
1175 && *lines[i].start != '\n'
1176 && *lines[i].start != '*'
1177 && *lines[i].start != ' '
1178 && *lines[i].start != '\t')
1180 /* Add this menu section to the node's list.
1181 This list grows in forward order. */
1182 struct menu_section *next
1183 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1185 next->start_line = i + 1;
1188 next->name = copy_string (lines[i].start, lines[i].size);
1189 if ((*nodes)->sections)
1191 (*nodes)->last_section->next = next;
1192 (*nodes)->last_section->end_line = i;
1195 (*nodes)->sections = next;
1196 (*nodes)->last_section = next;
1201 /* Finish the info about the end of the last node. */
1204 (*nodes)->end_line = nlines;
1205 if ((*nodes)->last_section != 0)
1206 (*nodes)->last_section->end_line = nlines;
1211 /* Iterate through NLINES LINES looking for an entry that has a name
1212 that matches NAME. If such an entry is found, flag the entry for
1213 deletion later on. */
1216 mark_entry_for_deletion (struct line_data *lines, int nlines, char *name)
1218 int something_deleted = 0;
1220 for (i = 0; i < nlines; i++)
1222 /* Check for an existing entry that should be deleted.
1223 Delete all entries which specify this file name. */
1224 if (*lines[i].start == '*')
1227 char *p = lines[i].start;
1230 while (*p == ' ') p++; /* ignore following spaces */
1231 q = p; /* remember this, it's the beginning of the menu item. */
1233 /* Read menu item. */
1234 while (*p != 0 && *p != ':')
1239 { /* XEmacs-style entry, as in * Mew::Messaging. */
1240 if (menu_item_equal (q, ':', name))
1242 lines[i].delete = 1;
1243 something_deleted = 1;
1247 { /* Emacs-style entry, as in * Emacs: (emacs). */
1248 while (*p == ' ') p++; /* skip spaces after : */
1249 if (*p == '(') /* if at parenthesized (FILENAME) */
1252 if (menu_item_equal (p, ')', name))
1254 lines[i].delete = 1;
1255 something_deleted = 1;
1261 /* Treat lines that start with whitespace
1262 as continuations; if we are deleting an entry,
1263 delete all its continuations as well. */
1264 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1266 lines[i].delete = lines[i - 1].delete;
1269 return something_deleted;
1273 /* Assuming the current column is COLUMN, return the column that
1274 printing C will move the cursor to.
1275 The first column is 0.
1276 This function is used to assist in indenting of entries. */
1279 adjust_column (size_t column, char c)
1289 column += TAB_WIDTH - column % TAB_WIDTH;
1290 else /* if (isprint (c)) */
1295 /* Indent the Info entry's NAME and DESCRIPTION. Lines are wrapped at the
1296 WIDTH column. The description on first line is indented at the CALIGN-th
1297 column, and all subsequent lines are indented at the ALIGN-th column.
1298 The resulting Info entry is put into OUTSTR.
1299 NAME is of the form "* TEXT (TEXT)[:TEXT].".
1302 format_entry (char *name, size_t name_len, char *desc, size_t desc_len,
1303 int calign, int align, size_t width,
1304 char **outstr, size_t *outstr_len)
1308 size_t column = 0; /* Screen column where next char will go */
1309 size_t offset_out = 0; /* Index in `line_out' for next char. */
1310 static char *line_out = NULL;
1311 static size_t allocated_out = 0;
1316 *outstr = malloc (width +
1317 (((desc_len + width) / (width - align)) * width) * 2
1321 strncat (*outstr, name, name_len);
1325 if (name_len > calign - 2)
1327 /* Name is too long to have description on the same line. */
1330 strncat (*outstr, "\n", 1);
1332 for (j = 0; j < calign - 1; j++)
1334 column = adjust_column (column, ' ');
1335 strncat (*outstr, " ", 1);
1340 for (j = 0; j < calign - name_len - 1; j++)
1344 column = adjust_column (column, ' ');
1345 strncat (*outstr, " ", 1);
1348 for (i = 0; i < desc_len; i++)
1353 if (offset_out + 1 >= allocated_out)
1355 allocated_out = offset_out + 1;
1356 line_out = (char *) realloc ((void *)line_out, allocated_out);
1361 line_out[offset_out++] = c;
1362 strncat (*outstr, line_out, offset_out);
1363 column = offset_out = 0;
1368 column = adjust_column (column, c);
1372 /* This character would make the line too long.
1373 Print the line plus a newline, and make this character
1374 start the next line. */
1376 int found_blank = 0;
1377 size_t logical_end = offset_out;
1379 /* Look for the last blank. */
1383 if (line_out[logical_end] == ' '
1384 || line_out[logical_end] == '\t')
1395 /* Found a blank. Don't output the part after it. */
1397 strncat (*outstr, line_out, logical_end);
1398 strncat (*outstr, "\n", 1);
1399 for (j = 0; j < align - 1; j++)
1401 column = adjust_column (column, ' ');
1402 strncat (*outstr, " ", 1);
1405 /* Move the remainder to the beginning of the next
1407 The areas being copied here might overlap. */
1408 memmove (line_out, line_out + logical_end,
1409 offset_out - logical_end);
1410 offset_out -= logical_end;
1411 for (column = i = 0; i < offset_out; i++)
1412 column = adjust_column (column, line_out[i]);
1416 if (offset_out == 0)
1418 line_out[offset_out++] = c;
1422 line_out[offset_out++] = '\n';
1423 strncat (*outstr, line_out, offset_out);
1424 column = offset_out = 0;
1428 line_out[offset_out++] = c;
1431 saved_errno = errno;
1434 strncat (*outstr, "\n", 1);
1437 strncat (*outstr, line_out, offset_out);
1439 *outstr_len = strlen (*outstr);
1444 /* Extract the NAME and DESCRIPTION from ENTRY. NAME and DESCRIPTION must be
1448 split_entry (const char *entry, char **name, size_t *name_len,
1449 char **description, size_t *description_len)
1453 /* on the first line, the description starts after the first ". ";
1454 that's a period and space -- our heuristic to handle item names like
1455 "config.status", and node names like "config.status Invocation".
1456 Also accept period-tab and period-newline. */
1457 char *ptr = strchr (entry, '.');
1458 while (ptr && ptr[1] != ' ' && ptr[1] != '\t' && ptr[1] != '\n') {
1459 ptr = strchr (ptr + 1, '.');
1462 /* Maybe there's no period, and no description */
1465 size_t length = strlen (entry);
1468 *name = strdup (entry);
1469 *name_len = length + 1;
1473 /* The name is everything up to and including the period. */
1474 *name_len = (size_t) (ptr - entry + 1);
1475 *name = xmalloc (*name_len + 1);
1477 strncat (*name, entry, *name_len);
1480 *description = xmalloc (strlen (entry));
1481 (*description)[0] = '\0';
1483 while (ptr[0] != '\0')
1485 /* Eat up the whitespace after the name, and at the start of a line. */
1486 while (isspace(ptr[0]))
1489 /* Okay, we're at the start of the description. */
1493 /* See how far the description goes... */
1494 endptr = strchr (ptr, '\n');
1495 /* Either the description continues up to the next newline. */
1498 size_t length = (size_t) (endptr - ptr) / sizeof (char);
1499 strncat (*description, ptr, length);
1501 /* First of all, we eat the newline here. But then what?
1502 Sometimes the newline separates 2 sentences, so we
1503 end up with the next word starting directly after the period,
1504 instead of after the customary 2 spaces in english.
1505 If the previous character was a `.', then we should add 2
1506 spaces if there is anything on the next line.
1507 if it's a comma, then we should put one space.
1508 If it's neither, we just put a space.
1509 If it's some other whitespace, we shouldn't do anything. */
1511 if (length > 1 && strlen (ptr) > 0)
1514 /* *ENDPTR is the 2nd last character */
1516 strncat (*description, " ", 2);
1517 else if (!isspace (*endptr))
1518 strncat (*description, " ", 1);
1521 /* Or the description continues to the end of the string. */
1524 /* Just show the rest when there's no newline. */
1525 size_t length = strlen (ptr);
1526 strncat (*description, ptr, length);
1530 /* Descriptions end in a new line. */
1531 strncat (*description, "\n", 1);
1532 *description_len = strlen (*description);
1536 /* Indent all ENTRIES according to some formatting options.
1537 CALIGN_CLI is the starting column for the first line of the description.
1538 ALIGN_CLI is the starting column for all subsequent lines of the
1539 description. MAXWIDTH_CLI is the number of columns in the line.
1540 When CALIGN_CLI, ALIGN_CLI, or MAXWIDTH_CLI is -1, choose a sane default. */
1543 reformat_new_entries (struct spec_entry *entries, int calign_cli, int align_cli,
1546 struct spec_entry *entry;
1547 for (entry = entries; entry; entry = entry->next)
1549 int calign = -1, align = -1, maxwidth = -1;
1550 char *name = NULL, *desc = NULL;
1551 size_t name_len = 0, desc_len = 0;
1552 split_entry (entry->text, &name, &name_len, &desc, &desc_len);
1555 /* Specify sane defaults if we need to */
1556 if (calign_cli == -1 || align_cli == -1)
1558 struct spec_section *section;
1559 calign = calign_cli;
1561 for (section = entry->entry_sections;
1562 section && section != entry->entry_sections_tail;
1563 section = section->next)
1565 if (!strcmp (section->name, "Individual utilities"))
1581 calign = calign_cli;
1585 if (maxwidth_cli == -1)
1588 format_entry (name, name_len, desc, desc_len, calign, align,
1589 maxwidth, &entry->text, &entry->text_len);
1593 /* Insert NAME into every entry in ENTRIES that requires it.
1594 NAME is the basename of the Info file being installed.
1595 The idea here is that there was a --name on the command-line
1596 and we need to put the basename in the empty parentheses. */
1598 add_missing_basenames (struct spec_entry *entries, char *name)
1600 struct spec_entry *entry;
1601 for (entry = entries; entry; entry = entry->next)
1603 if (entry->missing_basename)
1605 /* Insert NAME into the right place in ENTRY->TEXT. */
1606 char *info, *rest, *text;
1607 size_t name_len = strlen (name);
1608 char *ptr = strstr (entry->text, ": (). ");
1612 rest = ptr += strlen (": (). ");
1614 info = xmalloc (name_len + 7);
1615 snprintf (info, name_len + 7, ": (%s). ", name);
1616 text = concat (entry->text, info, rest);
1621 entry->text_len = strlen (entry->text);
1622 entry->missing_name = 0;
1623 entry->missing_basename = 0;
1629 /* Add NAME to the start of any entry in ENTRIES that is missing a name
1630 component. If NAME doesn't start with `*', it is formatted to look
1631 like an Info entry. */
1633 add_missing_names (struct spec_entry *entries, char *name)
1635 struct spec_entry *entry;
1636 for (entry = entries; entry; entry = entry->next)
1638 if (entry->missing_name)
1641 /* Prepend NAME onto ENTRY->TEXT. */
1644 if (entry->text[entry->text_len - 1] == '\n')
1648 text = concat (name, entry->text == NULL ? "" : entry->text,
1649 add_nl ? "\n" : "");
1652 size_t full_name_len = strlen (name) * 2 + 9;
1653 char *full_name = xmalloc (full_name_len);
1654 snprintf (full_name, full_name_len, "* %s: (%s).", name, name);
1655 text = concat (full_name,
1656 entry->text == NULL ? "" : entry->text,
1657 add_nl ? "\n" : "");
1663 entry->text_len = strlen (entry->text);
1664 entry->missing_name = 0;
1665 entry->missing_basename = 0;
1670 /* Append DESC to every entry in ENTRIES that needs it. */
1673 add_missing_descriptions (struct spec_entry *entries, char *desc)
1675 struct spec_entry *entry;
1676 for (entry = entries; entry; entry = entry->next)
1678 if (entry->missing_description)
1682 if (strlen (desc) > 1)
1683 if (desc[strlen (desc) - 1] == '\n')
1685 /* Append DESC onto ENTRY->TEXT. */
1686 text = concat (entry->text == NULL ? "" : entry->text, desc,
1687 add_nl ? "\n" : "");
1691 entry->text_len = strlen (entry->text);
1697 /* Detect old-style Debian `--section REGEX TITLE' semantics in ARGV.
1698 When detected the options are munged to look like:
1699 `--regex REGEX --section TITLE --add-once'
1700 Return 1 if munging took place, return 0 if not.
1701 Otherwise return a negative number if something went wrong.
1702 NEW_ARGC, and NEW_ARGV are filled with the newly munged options
1703 when munging took place.
1706 munge_old_style_debian_options (int argc, char **argv,
1707 int *new_argc, char ***new_argv)
1712 size_t argz_len = 0;
1713 const char *regex, *title;
1716 /* Flip through the options to detect the old `--section REGEX TITLE'
1718 for (i = 0; i < argc; i++)
1720 if (strcmp (argv[i], "--section") == 0)
1723 /* Go forward one arg and obtain the REGEX. */
1729 /* Go forward another arg and obtain the TITLE. */
1735 /* When the title starts with a `-' it's probably an option,
1737 if (title[0] == '-')
1739 /* When the title is a filename it's probably an Info file, or
1740 a dir file, and not a title. */
1741 fileptr = fopen (title, "r");
1747 /* Okay, it looks like we're using the old debian syntax
1751 /* Okay, we munge the options to look like this:
1752 --regex=REGEX --section=TITLE --add-once */
1753 opt = xmalloc (strlen (regex) + sizeof ("--regex="));
1754 if (sprintf (opt, "--regex=%s", regex) == -1)
1757 err = argz_add (&argz, &argz_len, opt);
1758 free (opt); opt = NULL;
1760 opt = xmalloc (strlen (regex) + sizeof ("--section="));
1761 if (sprintf (opt, "--section=%s", title) == -1)
1764 err = argz_add (&argz, &argz_len, opt);
1765 free (opt); opt = NULL;
1768 err = argz_add (&argz, &argz_len, "--add-once");
1771 err = argz_add (&argz, &argz_len, argv[i]);
1778 *new_argc = argz_count (argz, argz_len);
1779 *new_argv = xmalloc ((*new_argc + 1) * sizeof (char *));
1782 while ((opt = argz_next (argz, argz_len, opt)))
1784 (*new_argv)[i] = xstrdup (opt);
1787 (*new_argv)[*new_argc] = NULL;
1795 main (int argc, char *argv[])
1797 char *opened_dirfilename;
1798 char *compression_program;
1799 char *infile_sans_info;
1800 char *infile = 0, *dirfile = 0;
1805 /* Record the text of the Info file, as a sequence of characters
1806 and as a sequence of lines. */
1807 char *input_data = NULL;
1809 struct line_data *input_lines = NULL;
1810 int input_nlines = 0;
1812 /* Record here the specified section names and directory entries. */
1813 struct spec_section *input_sections = NULL;
1814 struct spec_entry *entries_to_add = NULL;
1815 struct spec_entry *entries_to_add_from_file = NULL;
1816 int n_entries_to_add = 0;
1818 /* Record the old text of the dir file, as plain characters,
1819 as lines, and as nodes. */
1823 struct line_data *dir_lines;
1824 struct node *dir_nodes;
1826 /* Nonzero means --delete was specified (just delete existing entries). */
1827 int delete_flag = 0;
1828 int something_deleted = 0;
1830 /* Nonzero means -quiet/--silent was specified. */
1833 /* Nonzero means --debug was specified. */
1838 #ifdef HAVE_SETLOCALE
1839 /* Set locale via LC_ALL. */
1840 setlocale (LC_ALL, "");
1843 /* Set the text message domain. */
1844 bindtextdomain (PACKAGE, LOCALEDIR);
1845 textdomain (PACKAGE);
1847 munge_old_style_debian_options (argc, argv, &argc, &argv);
1851 int opt = getopt_long (argc, argv,
1852 "i:d:e:s:t:E:c:C:W:A:hHrk1Ia", longopts, 0);
1860 /* If getopt returns 0, then it has already processed a
1861 long-named option. We should do nothing. */
1868 add_entries_into_all_matching_sections = 0;
1872 order_new_sections_alphabetically_flag = 0;
1878 unsigned long int val;
1879 val = strtoul (optarg, &end, 0);
1880 if (end == NULL || end == optarg || *end != '\0')
1881 suggest_asking_for_help ();
1884 suggest_asking_for_help ();
1891 struct spec_entry *next;
1892 size_t length = strlen (optarg);
1894 if (!entries_to_add)
1897 (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1901 next->entry_sections = NULL;
1902 next->entry_sections_tail = NULL;
1903 next->missing_name = 1;
1904 next->missing_basename = 1;
1905 next->next = entries_to_add;
1906 entries_to_add = next;
1910 next = entries_to_add;
1912 next->missing_description = 0;
1915 char *nl = strrchr (next->text, '\n');
1919 /* Concat the description onto the current entry, adding a
1920 newline if we need one. Prepend a space if we have no
1921 previous text, since eventually we will be adding the
1922 "* foo ()." and we want to end up with a ". " for parsing. */
1923 next->text = concat (next->text ? next->text : " ",
1925 optarg[length - 1] == '\n' ? "" : "\n");
1926 next->text_len = strlen (next->text);
1933 unsigned long int val;
1934 val = strtoul (optarg, &end, 0);
1935 if (end == NULL || end == optarg || *end != '\0')
1936 suggest_asking_for_help ();
1939 suggest_asking_for_help ();
1946 fprintf (stderr, _("%s: already have dir file: %s\n"),
1948 suggest_asking_for_help ();
1956 fprintf (stderr, _("%s: already have dir file: %s\n"),
1958 suggest_asking_for_help ();
1960 dirfile = concat (optarg, "", "/dir");
1965 struct spec_entry *next
1966 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1969 if (optarg[0] != '*')
1971 /* Make enough space for "* foo: (). ". */
1972 length = strlen (optarg) + 9;
1973 next->text = xmalloc (length);
1974 snprintf (next->text, length, "* %s: (). ", optarg);
1975 next->missing_basename = 1;
1976 /* The basename will be inserted in between the parentheses
1977 at a later time. See add_missing_basenames. */
1981 /* Make enough space for "foo ". */
1982 length = strlen (optarg) + 2;
1983 next->text = xmalloc (length);
1984 snprintf (next->text, length, "%s ", optarg);
1985 next->missing_basename = 0;
1986 /* FIXME: check for info entry correctness in TEXT.
1987 e.g. `* Aaa: (bbb).' */
1990 next->text_len = length - 1;
1991 next->entry_sections = NULL;
1992 next->entry_sections_tail = NULL;
1993 next->next = entries_to_add;
1994 next->missing_name = 0;
1995 next->missing_description = 1;
1996 entries_to_add = next;
2003 struct spec_entry *next
2004 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
2005 int olen = strlen (optarg);
2006 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
2008 optarg = concat (optarg, "\n", "");
2011 next->text = optarg;
2012 next->text_len = olen;
2013 next->entry_sections = NULL;
2014 next->entry_sections_tail = NULL;
2015 next->next = entries_to_add;
2016 next->missing_name = 0;
2017 next->missing_basename = 0;
2018 next->missing_description = 0;
2019 entries_to_add = next;
2036 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
2038 suggest_asking_for_help ();
2069 (_("Extra regular expression specified, ignoring `%s'"),
2073 psecreg = (regex_t *) xmalloc (sizeof (regex_t));
2075 error = regcomp (psecreg, optarg, REG_ICASE|REG_NOSUB);
2078 int errbuf_size = regerror (error, psecreg, NULL, 0);
2079 char *errbuf = (char *) xmalloc (errbuf_size);
2080 regerror (error, psecreg, errbuf, errbuf_size);
2081 fatal (_("Error in regular expression `%s': %s"),
2089 struct spec_section *next
2090 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
2091 next->name = optarg;
2092 next->next = input_sections;
2094 input_sections = next;
2099 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
2101 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
2102 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
2103 This is free software: you are free to change and redistribute it.\n\
2104 There is NO WARRANTY, to the extent permitted by law.\n"),
2111 unsigned long int val;
2112 val = strtoul (optarg, &end, 0);
2113 if (end == NULL || end == optarg || *end != '\0')
2114 suggest_asking_for_help ();
2117 suggest_asking_for_help ();
2127 suggest_asking_for_help ();
2131 /* Interpret the non-option arguments as file names. */
2132 for (; optind < argc; ++optind)
2135 infile = argv[optind];
2136 else if (dirfile == 0)
2137 dirfile = argv[optind];
2139 error (_("excess command line argument `%s'"), argv[optind], 0);
2143 fatal (_("No input file specified; try --help for more information."),
2146 fatal (_("No dir file specified; try --help for more information."), 0, 0);
2148 /* Now read in the Info dir file. */
2150 printf ("debug: reading dir file %s\n", dirfile);
2151 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
2152 &opened_dirfilename, &compression_program);
2153 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
2155 parse_dir_file (dir_lines, dir_nlines, &dir_nodes);
2159 /* Find which sections match our regular expression. */
2163 struct menu_section *section;
2164 for (node = dir_nodes; node ; node = node->next)
2165 for (section = node->sections; section ; section = section->next)
2166 if (regexec (psecreg, section->name, 0, NULL, 0) == 0)
2168 /* we have a match! */
2169 struct spec_section *next =
2170 (struct spec_section *) xmalloc
2171 (sizeof (struct spec_section));
2172 next->name = section->name;
2173 next->next = input_sections;
2175 input_sections = next;
2181 /* We will be comparing the entries in the dir file against the
2182 current filename, so need to strip off any directory prefix and/or
2183 [.info][.gz] suffix. */
2184 if (!remove_exactly) {
2185 char *infile_basename = infile + strlen (infile);
2187 if (HAVE_DRIVE (infile))
2188 infile += 2; /* get past the drive spec X: */
2190 while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
2193 infile_sans_info = strip_info_suffix (infile_basename);
2195 infile_sans_info = xstrdup(infile);
2197 /* Now Read the Info file and parse it into lines, unless we're
2198 removing exactly. */
2199 if (!remove_exactly)
2202 printf ("debug: reading input file %s\n", infile);
2203 input_data = readfile (infile, &input_size, NULL, NULL, NULL);
2204 input_lines = findlines (input_data, input_size, &input_nlines);
2207 i = parse_input (input_lines, input_nlines,
2208 &input_sections, &entries_to_add_from_file, delete_flag);
2211 /* If there are no entries on the command-line at all, so we use the
2212 entries found in the Info file itself (if any). */
2213 if (entries_to_add == NULL)
2215 entries_to_add = entries_to_add_from_file;
2216 n_entries_to_add = i;
2218 /* There are entries on the command-line, and they override the entries
2219 found in the Info file. */
2220 else if (entries_to_add)
2222 if (entries_to_add_from_file == NULL)
2224 /* No entries found in the file anyway. Fill in any
2225 missing names with the info file's basename. We're out
2226 of luck for any missing descriptions. */
2227 add_missing_names (entries_to_add, infile_sans_info);
2228 /* add_missing_descriptions (entries_to_add, "\n"); */
2232 /* Fill in any missing names or descriptions with what was
2233 found in the Info file. */
2235 size_t desc_len = 0;
2237 size_t name_len = 0;
2238 split_entry (entries_to_add_from_file->text, &name, &name_len,
2242 /* If the name doesn't look right, bail and use the
2243 name based on the Info file. */
2245 add_missing_names (entries_to_add, infile_sans_info);
2247 add_missing_names (entries_to_add, name);
2253 add_missing_descriptions (entries_to_add, desc);
2259 /* Lastly, fill in any missing basenames that might still be hanging
2260 around from --name options on the command-line. */
2261 add_missing_basenames (entries_to_add, infile_sans_info);
2263 /* Reformat the new entries if we're doing that. */
2266 char *no_indent = getenv ("INSTALL_INFO_NO_INDENT");
2268 reformat_new_entries (entries_to_add, calign, align, maxwidth);
2271 /* If we got no sections, default to "Miscellaneous". */
2272 if (input_sections == NULL)
2274 input_sections = (struct spec_section *)
2275 xmalloc (sizeof (struct spec_section));
2276 input_sections->name = "Miscellaneous";
2277 input_sections->next = NULL;
2278 input_sections->missing = 1;
2281 if (entries_to_add == 0)
2282 { /* No need to abort here, the original info file may not
2283 have the requisite Texinfo commands. This is not
2284 something an installer should have to correct (it's a
2285 problem for the maintainer), and there's no need to cause
2286 subsequent parts of `make install' to fail. */
2288 warning (_("no info dir entry in `%s'"), infile, 0);
2292 /* If the entries came from the command-line arguments, their
2293 entry_sections pointers are not yet set. Walk the chain of
2294 the entries and for each entry update entry_sections to point
2295 to the head of the list of sections where this entry should
2296 be put. Note that all the entries specified on the command
2297 line get put into ALL the sections we've got, either from the
2298 Info file, or (under --section) from the command line,
2299 because in the loop below every entry inherits the entire
2300 chain of sections. */
2301 if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
2303 struct spec_entry *ep;
2305 for (ep = entries_to_add; ep; ep = ep->next)
2306 ep->entry_sections = input_sections;
2312 something_deleted = mark_entry_for_deletion (dir_lines, dir_nlines,
2314 if (!something_deleted && !remove_exactly)
2316 struct spec_entry *entry;
2317 for (entry = entries_to_add; entry; entry = entry->next)
2319 /* If the entry came from the info file... */
2320 if (entry->entry_sections != NULL)
2322 char *name = extract_menu_item_name (entry->text);
2324 mark_entry_for_deletion (dir_lines, dir_nlines, name);
2329 if (!something_deleted)
2331 struct spec_entry *entry;
2332 for (entry = entries_to_add; entry; entry = entry->next)
2334 /* If the entry came from the command-line... */
2335 if (entry->entry_sections == NULL)
2337 mark_entry_for_deletion (dir_lines, dir_nlines,
2344 /* Check for sections with zero entries and mark them for deletion. */
2345 if (delete_flag && something_deleted && !keep_old_flag)
2348 struct menu_section *section;
2351 for (node = dir_nodes; node ; node = node->next)
2352 for (section = node->sections; section ; section = section->next)
2355 for (i = section->end_line; i > section->start_line; i--)
2357 if (dir_lines[i - 1].delete == 0 &&
2358 dir_lines[i - 1].size != 0)
2367 /* This gets rid of any trailing empty lines at the end
2368 of the section, and the title too. */
2369 for (i = section->end_line; i >= section->start_line; i--)
2370 dir_lines[i - 1].delete = 1;
2375 /* Decide where to add the new entries (unless --delete was used).
2376 Find the menu sections to add them in.
2377 In each section, find the proper alphabetical place to add
2378 each of the entries. */
2382 struct menu_section *section;
2383 struct spec_section *spec;
2385 for (node = dir_nodes; node; node = node->next)
2386 for (section = node->sections; section; section = section->next)
2388 for (i = section->end_line; i > section->start_line; i--)
2389 if (dir_lines[i - 1].size != 0)
2391 section->end_line = i;
2393 for (spec = input_sections; spec; spec = spec->next)
2394 if (!strcmp (spec->name, section->name))
2398 int add_at_line = section->end_line;
2399 struct spec_entry *entry;
2400 /* Say we have found at least one section with this name,
2401 so we need not add such a section. */
2403 /* For each entry, find the right place in this section
2405 for (entry = entries_to_add; entry; entry = entry->next)
2407 /* Did they at all want this entry to be put into
2409 for (spec = entry->entry_sections;
2410 spec && spec != entry->entry_sections_tail;
2413 if (!strcmp (spec->name, section->name))
2416 if (!spec || spec == entry->entry_sections_tail)
2419 /* Subtract one because dir_lines is zero-based,
2420 but the `end_line' and `start_line' members are
2422 for (i = section->end_line - 1;
2423 i >= section->start_line - 1; i--)
2425 /* If an entry exists with the same name,
2426 and was not marked for deletion
2427 (which means it is for some other file),
2428 we are in trouble. */
2429 if (dir_lines[i].start[0] == '*'
2430 && menu_line_equal (entry->text, entry->text_len,
2433 && !dir_lines[i].delete)
2443 dir_lines[i].delete = 1;
2444 for (j = i + 1; j < section->end_line; j++)
2446 if (dir_lines[j].start[0] == '*')
2448 dir_lines[j].delete = 1;
2452 if (dir_lines[i].start[0] == '*'
2453 && menu_line_lessp (entry->text, entry->text_len,
2458 if (add_at_line < 0)
2460 insert_entry_here (entry, add_at_line,
2461 dir_lines, n_entries_to_add);
2467 /* Decide where to add the new sections (unless --delete was used).
2468 Alphabetically find the menu sections to add them before. */
2472 struct node *top = NULL;
2474 /* Find the `Top' node. */
2475 for (node = dir_nodes; node; node = node->next)
2476 if (node->name && strcmp (node->name, "Top") == 0)
2481 struct spec_section *spec;
2483 struct line_data *target_line = NULL;
2484 for (spec = input_sections; spec; spec = spec->next)
2490 if (order_new_sections_alphabetically_flag)
2492 struct menu_section *section;
2493 struct menu_section *prev_section = NULL;
2495 /* Look for the first section name that
2496 exceeds SPEC->NAME. */
2497 for (section = top->sections; section ;
2498 section = section->next)
2500 found = (mbscasecmp (spec->name, section->name) < 0);
2503 /* Mark the section for addition at this point. */
2505 target_line = &dir_lines[prev_section->end_line];
2508 &dir_lines[top->sections->start_line - 2];
2512 prev_section = section;
2516 /* When we can't put a section anywhere, we put it at the
2517 bottom of the file. */
2519 target_line = &dir_lines[top->end_line];
2521 /* Add the section to our list of sections being added
2522 at this point of the DIR file. */
2523 target_line->num_sections_to_add++;
2524 target_line->add_sections_before =
2525 (struct spec_section **) xrealloc
2526 (target_line->add_sections_before,
2527 (target_line->num_sections_to_add *
2528 sizeof (struct spec_section *)));
2529 i = target_line->num_sections_to_add - 1;
2530 target_line->add_sections_before[i] = spec;
2535 if (delete_flag && !something_deleted && !quiet_flag)
2536 warning (_("no entries found for `%s'; nothing deleted"), infile, 0);
2539 printf ("debug: writing dir file %s\n", opened_dirfilename);
2541 printf ("test mode, not updating dir file %s\n", opened_dirfilename);
2543 output_dirfile (opened_dirfilename, dir_nlines, dir_lines,
2544 n_entries_to_add, entries_to_add,
2545 input_sections, compression_program);
2548 return 0; /* Avoid bogus warnings. */
2551 /* Divide the text at DATA (of SIZE bytes) into lines.
2552 Return a vector of struct line_data describing the lines.
2553 Store the length of that vector into *NLINESP. */
2556 findlines (char *data, int size, int *nlinesp)
2560 int lines_allocated = 511;
2562 struct line_data *lines
2563 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
2565 for (i = 0; i < size; i++)
2569 if (filled == lines_allocated)
2571 /* try to keep things somewhat page-aligned */
2572 lines_allocated = ((lines_allocated + 1) * 2) - 1;
2573 lines = xrealloc (lines, (lines_allocated + 1)
2574 * sizeof (struct line_data));
2576 lines[filled].start = &data[i];
2577 lines[filled].add_entries_before = 0;
2578 lines[filled].add_sections_before = NULL;
2579 lines[filled].num_sections_to_add = 0;
2580 lines[filled].delete = 0;
2582 lines[filled - 1].size
2583 = lines[filled].start - lines[filled - 1].start - 1;
2586 lineflag = (data[i] == '\n');
2589 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
2591 /* Do not leave garbage in the last element. */
2592 lines[filled].start = NULL;
2593 lines[filled].add_entries_before = NULL;
2594 lines[filled].add_sections_before = NULL;
2595 lines[filled].num_sections_to_add = 0;
2596 lines[filled].delete = 0;
2597 lines[filled].size = 0;
2603 /* This is the comparison function for qsort for a vector of pointers to
2604 struct spec_section. (Have to use const void * as the parameter type
2605 to avoid incompatible-with-qsort warnings.)
2606 Compare the section names. */
2609 compare_section_names (const void *p1, const void *p2)
2611 struct spec_section **sec1 = (struct spec_section **) p1;
2612 struct spec_section **sec2 = (struct spec_section **) p2;
2613 char *name1 = (*sec1)->name;
2614 char *name2 = (*sec2)->name;
2615 return strcmp (name1, name2);
2618 /* This is the comparison function for qsort
2619 for a vector of pointers to struct spec_entry.
2620 Compare the entries' text. */
2623 compare_entries_text (const void *p1, const void *p2)
2625 struct spec_entry **entry1 = (struct spec_entry **) p1;
2626 struct spec_entry **entry2 = (struct spec_entry **) p2;
2627 char *text1 = (*entry1)->text;
2628 char *text2 = (*entry2)->text;
2629 char *colon1 = strchr (text1, ':');
2630 char *colon2 = strchr (text2, ':');
2634 len1 = strlen (text1);
2636 len1 = colon1 - text1;
2638 len2 = strlen (text2);
2640 len2 = colon2 - text2;
2641 return mbsncasecmp (text1, text2, len1 <= len2 ? len1 : len2);
2644 /* Insert ENTRY into the add_entries_before vector
2645 for line number LINE_NUMBER of the dir file.
2646 DIR_LINES and N_ENTRIES carry information from like-named variables
2650 insert_entry_here (struct spec_entry *entry, int line_number,
2651 struct line_data *dir_lines, int n_entries)
2655 if (dir_lines[line_number].add_entries_before == 0)
2657 dir_lines[line_number].add_entries_before
2658 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
2659 for (i = 0; i < n_entries; i++)
2660 dir_lines[line_number].add_entries_before[i] = 0;
2663 /* Find the place where this entry belongs. If there are already
2664 several entries to add before LINE_NUMBER, make sure they are in
2665 alphabetical order. */
2666 for (i = 0; i < n_entries; i++)
2667 if (dir_lines[line_number].add_entries_before[i] == 0
2668 || menu_line_lessp (entry->text, strlen (entry->text),
2669 dir_lines[line_number].add_entries_before[i]->text,
2670 strlen (dir_lines[line_number].add_entries_before[i]->text)))
2676 /* If we need to plug ENTRY into the middle of the
2677 ADD_ENTRIES_BEFORE array, move the entries which should be output
2678 after this one down one notch, before adding a new one. */
2679 if (dir_lines[line_number].add_entries_before[i] != 0)
2680 for (j = n_entries - 1; j > i; j--)
2681 dir_lines[line_number].add_entries_before[j]
2682 = dir_lines[line_number].add_entries_before[j - 1];
2684 dir_lines[line_number].add_entries_before[i] = entry;