Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / texinfo / util / install-info.c
blob82c67ea84c3d59cc3a1e526ada35404b3645bc5f
1 /* $NetBSD: install-info.c,v 1.1.1.7 2008/09/02 07:50:56 christos Exp $ */
3 /* install-info -- create Info directory entry(ies) for an Info file.
4 Id: install-info.c,v 1.12 2004/04/11 17:56:47 karl Exp
6 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
7 Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
23 #include "system.h"
24 #include <getopt.h>
26 static char *progname = "install-info";
28 struct spec_entry;
29 struct spec_section;
31 struct line_data *findlines (char *data, int size, int *nlinesp);
32 void insert_entry_here (struct spec_entry *entry, int line_number,
33 struct line_data *dir_lines, int n_entries);
34 int compare_section_names (const void *s1, const void *s2);
35 int compare_entries_text (const void *e1, const void *e2);
37 /* Data structures. */
40 /* Record info about a single line from a file as read into core. */
41 struct line_data
43 /* The start of the line. */
44 char *start;
45 /* The number of characters in the line,
46 excluding the terminating newline. */
47 int size;
48 /* Vector containing pointers to the entries to add before this line.
49 The vector is null-terminated. */
50 struct spec_entry **add_entries_before;
51 /* 1 means output any needed new sections before this line. */
52 int add_sections_before;
53 /* 1 means don't output this line. */
54 int delete;
58 /* This is used for a list of the specified menu section names
59 in which entries should be added. */
60 struct spec_section
62 struct spec_section *next;
63 char *name;
64 /* 1 means we have not yet found an existing section with this name
65 in the dir file--so we will need to add a new section. */
66 int missing;
70 /* This is used for a list of the entries specified to be added. */
71 struct spec_entry
73 struct spec_entry *next;
74 char *text;
75 int text_len;
76 /* A pointer to the list of sections to which this entry should be
77 added. */
78 struct spec_section *entry_sections;
79 /* A pointer to a section that is beyond the end of the chain whose
80 head is pointed to by entry_sections. */
81 struct spec_section *entry_sections_tail;
85 /* This is used for a list of nodes found by parsing the dir file. */
86 struct node
88 struct node *next;
89 /* The node name. */
90 char *name;
91 /* The line number of the line where the node starts.
92 This is the line that contains control-underscore. */
93 int start_line;
94 /* The line number of the line where the node ends,
95 which is the end of the file or where the next line starts. */
96 int end_line;
97 /* Start of first line in this node's menu
98 (the line after the * Menu: line). */
99 char *menu_start;
100 /* The start of the chain of sections in this node's menu. */
101 struct menu_section *sections;
102 /* The last menu section in the chain. */
103 struct menu_section *last_section;
107 /* This is used for a list of sections found in a node's menu.
108 Each struct node has such a list in the sections field. */
109 struct menu_section
111 struct menu_section *next;
112 char *name;
113 /* Line number of start of section. */
114 int start_line;
115 /* Line number of end of section. */
116 int end_line;
119 /* This table defines all the long-named options, says whether they
120 use an argument, and maps them into equivalent single-letter options. */
122 struct option longopts[] =
124 { "delete", no_argument, NULL, 'r' },
125 { "dir-file", required_argument, NULL, 'd' },
126 { "entry", required_argument, NULL, 'e' },
127 { "help", no_argument, NULL, 'h' },
128 { "infodir", required_argument, NULL, 'D' },
129 { "info-dir", required_argument, NULL, 'D' },
130 { "info-file", required_argument, NULL, 'i' },
131 { "item", required_argument, NULL, 'e' },
132 { "quiet", no_argument, NULL, 'q' },
133 { "remove", no_argument, NULL, 'r' },
134 { "section", required_argument, NULL, 's' },
135 { "version", no_argument, NULL, 'V' },
136 { 0 }
139 /* Error message functions. */
141 /* Print error message. S1 is printf control string, S2 and S3 args for it. */
143 /* VARARGS1 */
144 void
145 error (const char *s1, const char *s2, const char *s3)
147 fprintf (stderr, "%s: ", progname);
148 fprintf (stderr, s1, s2, s3);
149 putc ('\n', stderr);
152 /* VARARGS1 */
153 void
154 warning (const char *s1, const char *s2, const char *s3)
156 fprintf (stderr, _("%s: warning: "), progname);
157 fprintf (stderr, s1, s2, s3);
158 putc ('\n', stderr);
161 /* Print error message and exit. */
163 void
164 fatal (const char *s1, const char *s2, const char *s3)
166 error (s1, s2, s3);
167 xexit (1);
170 /* Return a newly-allocated string
171 whose contents concatenate those of S1, S2, S3. */
172 char *
173 concat (const char *s1, const char *s2, const char *s3)
175 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
176 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
178 strcpy (result, s1);
179 strcpy (result + len1, s2);
180 strcpy (result + len1 + len2, s3);
181 *(result + len1 + len2 + len3) = 0;
183 return result;
186 /* Return a string containing SIZE characters
187 copied from starting at STRING. */
189 char *
190 copy_string (const char *string, int size)
192 int i;
193 char *copy = (char *) xmalloc (size + 1);
194 for (i = 0; i < size; i++)
195 copy[i] = string[i];
196 copy[size] = 0;
197 return copy;
200 /* Print fatal error message based on errno, with file name NAME. */
202 void
203 pfatal_with_name (const char *name)
205 char *s = concat ("", strerror (errno), _(" for %s"));
206 fatal (s, name, 0);
209 /* Compare the menu item names in LINE1 (line length LEN1)
210 and LINE2 (line length LEN2). Return 1 if the item name
211 in LINE1 is less, 0 otherwise. */
213 static int
214 menu_line_lessp (char *line1, int len1, char *line2, int len2)
216 int minlen = (len1 < len2 ? len1 : len2);
217 int i;
219 for (i = 0; i < minlen; i++)
221 /* If one item name is a prefix of the other,
222 the former one is less. */
223 if (line1[i] == ':' && line2[i] != ':')
224 return 1;
225 if (line2[i] == ':' && line1[i] != ':')
226 return 0;
227 /* If they both continue and differ, one is less. */
228 if (line1[i] < line2[i])
229 return 1;
230 if (line1[i] > line2[i])
231 return 0;
233 /* With a properly formatted dir file,
234 we can only get here if the item names are equal. */
235 return 0;
238 /* Compare the menu item names in LINE1 (line length LEN1)
239 and LINE2 (line length LEN2). Return 1 if the item names are equal,
240 0 otherwise. */
242 static int
243 menu_line_equal (char *line1, int len1, char *line2, int len2)
245 int minlen = (len1 < len2 ? len1 : len2);
246 int i;
248 for (i = 0; i < minlen; i++)
250 /* If both item names end here, they are equal. */
251 if (line1[i] == ':' && line2[i] == ':')
252 return 1;
253 /* If they both continue and differ, one is less. */
254 if (line1[i] != line2[i])
255 return 0;
257 /* With a properly formatted dir file,
258 we can only get here if the item names are equal. */
259 return 1;
263 /* Given the full text of a menu entry, null terminated,
264 return just the menu item name (copied). */
266 char *
267 extract_menu_item_name (char *item_text)
269 char *p;
271 if (*item_text == '*')
272 item_text++;
273 while (*item_text == ' ')
274 item_text++;
276 p = item_text;
277 while (*p && *p != ':') p++;
278 return copy_string (item_text, p - item_text);
281 /* Given the full text of a menu entry, terminated by null or newline,
282 return just the menu item file (copied). */
284 char *
285 extract_menu_file_name (char *item_text)
287 char *p = item_text;
289 /* If we have text that looks like * ITEM: (FILE)NODE...,
290 extract just FILE. Otherwise return "(none)". */
292 if (*p == '*')
293 p++;
294 while (*p == ' ')
295 p++;
297 /* Skip to and past the colon. */
298 while (*p && *p != '\n' && *p != ':') p++;
299 if (*p == ':') p++;
301 /* Skip past the open-paren. */
302 while (1)
304 if (*p == '(')
305 break;
306 else if (*p == ' ' || *p == '\t')
307 p++;
308 else
309 return "(none)";
311 p++;
313 item_text = p;
315 /* File name ends just before the close-paren. */
316 while (*p && *p != '\n' && *p != ')') p++;
317 if (*p != ')')
318 return "(none)";
320 return copy_string (item_text, p - item_text);
325 /* Return FNAME with any [.info][.gz] suffix removed. */
327 static char *
328 strip_info_suffix (char *fname)
330 char *ret = xstrdup (fname);
331 unsigned len = strlen (ret);
333 if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
335 len -= 3;
336 ret[len] = 0;
338 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".bz2") == 0)
340 len -= 4;
341 ret[len] = 0;
344 if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
346 len -= 5;
347 ret[len] = 0;
349 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
351 len -= 4;
352 ret[len] = 0;
354 #ifdef __MSDOS__
355 else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
356 || FILENAME_CMP (ret + len - 4, ".igz") == 0))
358 len -= 4;
359 ret[len] = 0;
361 #endif /* __MSDOS__ */
363 return ret;
367 /* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
368 can also be followed by `.gz', `.info.gz', or `.info' (and then
369 TERM_CHAR) and still match. */
371 static int
372 menu_item_equal (const char *item, char term_char, const char *name)
374 int ret;
375 const char *item_basename = item;
376 unsigned name_len = strlen (name);
378 /* We must compare the basename in ITEM, since we are passed the
379 basename of the original info file. Otherwise, a new entry like
380 "lilypond/lilypond" won't match "lilypond".
382 Actually, it seems to me that we should really compare the whole
383 name, and not just the basename. Couldn't there be dir1/foo.info
384 and dir2/foo.info? Also, it seems like we should be using the
385 filename from the new dir entries, not the filename on the command
386 line. Not worrying about those things right now, though. --karl,
387 26mar04. */
388 while (*item_basename && !IS_SLASH (*item_basename)
389 && *item_basename != term_char)
390 item_basename++;
391 if (! *item_basename || *item_basename == term_char)
392 item_basename = item; /* no /, use original */
393 else
394 item_basename++; /* have /, move past it */
396 /* First, ITEM must actually match NAME (usually it won't). */
397 ret = strncasecmp (item_basename, name, name_len) == 0;
398 if (ret)
400 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
401 ITEM. The various suffixes should never actually appear in the
402 dir file, but sometimes people put them in. */
403 static char *suffixes[]
404 = { "", ".info.gz", ".info", ".inf", ".gz",
405 #ifdef __MSDOS__
406 ".inz", ".igz",
407 #endif
408 NULL };
409 unsigned i;
410 ret = 0;
411 for (i = 0; !ret && suffixes[i]; i++)
413 char *suffix = suffixes[i];
414 unsigned suffix_len = strlen (suffix);
415 ret = strncasecmp (item_basename + name_len, suffix, suffix_len) == 0
416 && item_basename[name_len + suffix_len] == term_char;
420 return ret;
425 void
426 suggest_asking_for_help (void)
428 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
429 progname);
430 xexit (1);
433 void
434 print_help (void)
436 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
438 Install or delete dir entries from INFO-FILE in the Info directory file\n\
439 DIR-FILE.\n\
441 Options:\n\
442 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
443 don't insert any new entries.\n\
444 --dir-file=NAME specify file name of Info directory file.\n\
445 This is equivalent to using the DIR-FILE argument.\n\
446 --entry=TEXT insert TEXT as an Info directory entry.\n\
447 TEXT should have the form of an Info menu item line\n\
448 plus zero or more extra lines starting with whitespace.\n\
449 If you specify more than one entry, they are all added.\n\
450 If you don't specify any entries, they are determined\n\
451 from information in the Info file itself.\n\
452 --help display this help and exit.\n\
453 --info-file=FILE specify Info file to install in the directory.\n\
454 This is equivalent to using the INFO-FILE argument.\n\
455 --info-dir=DIR same as --dir-file=DIR/dir.\n\
456 --item=TEXT same as --entry TEXT.\n\
457 An Info directory entry is actually a menu item.\n\
458 --quiet suppress warnings.\n\
459 --remove same as --delete.\n\
460 --section=SEC put this file's entries in section SEC of the directory.\n\
461 If you specify more than one section, all the entries\n\
462 are added in each of the sections.\n\
463 If you don't specify any sections, they are determined\n\
464 from information in the Info file itself.\n\
465 --version display version information and exit.\n\
466 "), progname);
468 puts (_("\n\
469 Email bug reports to bug-texinfo@gnu.org,\n\
470 general questions and discussion to help-texinfo@gnu.org.\n\
471 Texinfo home page: http://www.gnu.org/software/texinfo/"));
475 /* If DIRFILE does not exist, create a minimal one (or abort). If it
476 already exists, do nothing. */
478 void
479 ensure_dirfile_exists (char *dirfile)
481 int desc = open (dirfile, O_RDONLY);
482 if (desc < 0 && errno == ENOENT)
484 FILE *f;
485 char *readerr = strerror (errno);
486 close (desc);
487 f = fopen (dirfile, "w");
488 if (f)
490 fprintf (f, _("This is the file .../info/dir, which contains the\n\
491 topmost node of the Info hierarchy, called (dir)Top.\n\
492 The first time you invoke Info you start off looking at this node.\n\
493 \x1f\n\
494 %s\tThis is the top of the INFO tree\n\
496 This (the Directory node) gives a menu of major topics.\n\
497 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
498 \"h\" gives a primer for first-timers,\n\
499 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
501 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
502 to select it.\n\
504 %s\n\
505 "), "File: dir,\tNode: Top", /* These keywords must not be translated. */
506 "* Menu:"
508 if (fclose (f) < 0)
509 pfatal_with_name (dirfile);
511 else
513 /* Didn't exist, but couldn't open for writing. */
514 fprintf (stderr,
515 _("%s: could not read (%s) and could not create (%s)\n"),
516 dirfile, readerr, strerror (errno));
517 xexit (1);
520 else
521 close (desc); /* It already existed, so fine. */
524 /* Open FILENAME and return the resulting stream pointer. If it doesn't
525 exist, try FILENAME.gz. If that doesn't exist either, call
526 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
527 non-NULL. If still no luck, fatal error.
529 If we do open it, return the actual name of the file opened in
530 OPENED_FILENAME and the compress program to use to (de)compress it in
531 COMPRESSION_PROGRAM. The compression program is determined by the
532 magic number, not the filename. */
534 FILE *
535 open_possibly_compressed_file (char *filename,
536 void (*create_callback) (char *),
537 char **opened_filename, char **compression_program, int *is_pipe)
539 char *local_opened_filename, *local_compression_program;
540 int nread;
541 char data[4];
542 FILE *f;
544 /* We let them pass NULL if they don't want this info, but it's easier
545 to always determine it. */
546 if (!opened_filename)
547 opened_filename = &local_opened_filename;
549 *opened_filename = filename;
550 f = fopen (*opened_filename, FOPEN_RBIN);
551 if (!f)
553 *opened_filename = concat (filename, ".gz", "");
554 f = fopen (*opened_filename, FOPEN_RBIN);
555 if (!f)
557 free (*opened_filename);
558 *opened_filename = concat (filename, ".bz2", "");
559 f = fopen (*opened_filename, FOPEN_RBIN);
562 #ifdef __MSDOS__
563 if (!f)
565 free (*opened_filename);
566 *opened_filename = concat (filename, ".igz", "");
567 f = fopen (*opened_filename, FOPEN_RBIN);
569 if (!f)
571 free (*opened_filename);
572 *opened_filename = concat (filename, ".inz", "");
573 f = fopen (*opened_filename, FOPEN_RBIN);
575 #endif
576 if (!f)
578 if (create_callback)
579 { /* That didn't work either. Create the file if we can. */
580 (*create_callback) (filename);
582 /* And try opening it again. */
583 free (*opened_filename);
584 *opened_filename = filename;
585 f = fopen (*opened_filename, FOPEN_RBIN);
586 if (!f)
587 pfatal_with_name (filename);
589 else
590 pfatal_with_name (filename);
594 /* Read first few bytes of file rather than relying on the filename.
595 If the file is shorter than this it can't be usable anyway. */
596 nread = fread (data, sizeof (data), 1, f);
597 if (nread != 1)
599 /* Empty files don't set errno, so we get something like
600 "install-info: No error for foo", which is confusing. */
601 if (nread == 0)
602 fatal (_("%s: empty file"), *opened_filename, 0);
603 pfatal_with_name (*opened_filename);
606 if (!compression_program)
607 compression_program = &local_compression_program;
609 if (data[0] == '\x1f' && data[1] == '\x8b')
610 #if STRIP_DOT_EXE
611 /* An explicit .exe yields a better diagnostics from popen below
612 if they don't have gzip installed. */
613 *compression_program = "gzip.exe";
614 #else
615 *compression_program = "gzip";
616 #endif
617 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == 'h')
618 #ifndef STRIP_DOT_EXE
619 *compression_program = "bzip2.exe";
620 #else
621 *compression_program = "bzip2";
622 #endif
623 else if(data[0] == 'B' && data[1] == 'Z' && data[2] == '0')
624 #ifndef STRIP_DOT_EXE
625 *compression_program = "bzip.exe";
626 #else
627 *compression_program = "bzip";
628 #endif
629 else
630 *compression_program = NULL;
632 if (*compression_program)
633 { /* It's compressed, so fclose the file and then open a pipe. */
634 char *command = concat (*compression_program," -cd <", *opened_filename);
635 if (fclose (f) < 0)
636 pfatal_with_name (*opened_filename);
637 f = popen (command, "r");
638 if (f)
639 *is_pipe = 1;
640 else
641 pfatal_with_name (command);
643 else
644 { /* It's a plain file, seek back over the magic bytes. */
645 if (fseek (f, 0, 0) < 0)
646 pfatal_with_name (*opened_filename);
647 #if O_BINARY
648 /* Since this is a text file, and we opened it in binary mode,
649 switch back to text mode. */
650 f = freopen (*opened_filename, "r", f);
651 #endif
652 *is_pipe = 0;
655 return f;
658 /* Read all of file FILENAME into memory and return the address of the
659 data. Store the size of the data into SIZEP. If need be, uncompress
660 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
661 the actual file name that was opened into OPENED_FILENAME (if it is
662 non-NULL), and the companion compression program (if any, else NULL)
663 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
664 a fatal error. */
666 char *
667 readfile (char *filename, int *sizep,
668 void (*create_callback) (char *), char **opened_filename,
669 char **compression_program)
671 char *real_name;
672 FILE *f;
673 int pipe_p;
674 int filled = 0;
675 int data_size = 8192;
676 char *data = xmalloc (data_size);
678 /* If they passed the space for the file name to return, use it. */
679 f = open_possibly_compressed_file (filename, create_callback,
680 opened_filename ? opened_filename
681 : &real_name,
682 compression_program, &pipe_p);
684 for (;;)
686 int nread = fread (data + filled, 1, data_size - filled, f);
687 if (nread < 0)
688 pfatal_with_name (real_name);
689 if (nread == 0)
690 break;
692 filled += nread;
693 if (filled == data_size)
695 data_size += 65536;
696 data = xrealloc (data, data_size);
700 /* We'll end up wasting space if we're not passing the filename back
701 and it is not just FILENAME, but so what. */
702 /* We need to close the stream, since on some systems the pipe created
703 by popen is simulated by a temporary file which only gets removed
704 inside pclose. */
705 if (pipe_p)
706 pclose (f);
707 else
708 fclose (f);
710 *sizep = filled;
711 return data;
714 /* Output the old dir file, interpolating the new sections
715 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
716 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
717 we'll write dir.gz on output. */
719 static void
720 output_dirfile (char *dirfile, int dir_nlines, struct line_data *dir_lines,
721 int n_entries_to_add, struct spec_entry *entries_to_add,
722 struct spec_section *input_sections, char *compression_program)
724 int i;
725 FILE *output;
727 if (compression_program)
729 char *command = concat (compression_program, ">", dirfile);
730 output = popen (command, "w");
732 else
733 output = fopen (dirfile, "w");
735 if (!output)
737 perror (dirfile);
738 xexit (1);
741 for (i = 0; i <= dir_nlines; i++)
743 int j;
745 /* If we decided to output some new entries before this line,
746 output them now. */
747 if (dir_lines[i].add_entries_before)
748 for (j = 0; j < n_entries_to_add; j++)
750 struct spec_entry *this = dir_lines[i].add_entries_before[j];
751 if (this == 0)
752 break;
753 fputs (this->text, output);
755 /* If we decided to add some sections here
756 because there are no such sections in the file,
757 output them now. */
758 if (dir_lines[i].add_sections_before)
760 struct spec_section *spec;
761 struct spec_section **sections;
762 int n_sections = 0;
763 struct spec_entry *entry;
764 struct spec_entry **entries;
765 int n_entries = 0;
767 /* Count the sections and allocate a vector for all of them. */
768 for (spec = input_sections; spec; spec = spec->next)
769 n_sections++;
770 sections = ((struct spec_section **)
771 xmalloc (n_sections * sizeof (struct spec_section *)));
773 /* Fill the vector SECTIONS with pointers to all the sections,
774 and sort them. */
775 j = 0;
776 for (spec = input_sections; spec; spec = spec->next)
777 sections[j++] = spec;
778 qsort (sections, n_sections, sizeof (struct spec_section *),
779 compare_section_names);
781 /* Count the entries and allocate a vector for all of them. */
782 for (entry = entries_to_add; entry; entry = entry->next)
783 n_entries++;
784 entries = ((struct spec_entry **)
785 xmalloc (n_entries * sizeof (struct spec_entry *)));
787 /* Fill the vector ENTRIES with pointers to all the sections,
788 and sort them. */
789 j = 0;
790 for (entry = entries_to_add; entry; entry = entry->next)
791 entries[j++] = entry;
792 qsort (entries, n_entries, sizeof (struct spec_entry *),
793 compare_entries_text);
795 /* Generate the new sections in alphabetical order. In each
796 new section, output all of the entries that belong to that
797 section, in alphabetical order. */
798 for (j = 0; j < n_sections; j++)
800 spec = sections[j];
801 if (spec->missing)
803 int k;
805 putc ('\n', output);
806 fputs (spec->name, output);
807 putc ('\n', output);
808 for (k = 0; k < n_entries; k++)
810 struct spec_section *spec1;
811 /* Did they at all want this entry to be put into
812 this section? */
813 entry = entries[k];
814 for (spec1 = entry->entry_sections;
815 spec1 && spec1 != entry->entry_sections_tail;
816 spec1 = spec1->next)
818 if (!strcmp (spec1->name, spec->name))
819 break;
821 if (spec1 && spec1 != entry->entry_sections_tail)
822 fputs (entry->text, output);
827 free (entries);
828 free (sections);
831 /* Output the original dir lines unless marked for deletion. */
832 if (i < dir_nlines && !dir_lines[i].delete)
834 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
835 putc ('\n', output);
839 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
840 On those systems, the compressor actually gets run inside pclose,
841 so we must call pclose. */
842 if (compression_program)
843 pclose (output);
844 else
845 fclose (output);
848 /* Parse the input to find the section names and the entry names it
849 specifies. Return the number of entries to add from this file. */
851 parse_input (const struct line_data *lines, int nlines,
852 struct spec_section **sections, struct spec_entry **entries)
854 int n_entries = 0;
855 int prefix_length = strlen ("INFO-DIR-SECTION ");
856 struct spec_section *head = *sections, *tail = NULL;
857 int reset_tail = 0;
858 char *start_of_this_entry = 0;
859 int ignore_sections = *sections != 0;
860 int ignore_entries = *entries != 0;
862 int i;
864 if (ignore_sections && ignore_entries)
865 return 0;
867 /* Loop here processing lines from the input file. Each
868 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
869 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
870 list, and all its entries inherit the chain of SECTION entries
871 defined by the last group of INFO-DIR-SECTION entries we have
872 seen until that point. */
873 for (i = 0; i < nlines; i++)
875 if (!ignore_sections
876 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
878 struct spec_section *next
879 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
880 next->name = copy_string (lines[i].start + prefix_length,
881 lines[i].size - prefix_length);
882 next->next = *sections;
883 next->missing = 1;
884 if (reset_tail)
886 tail = *sections;
887 reset_tail = 0;
889 *sections = next;
890 head = *sections;
892 /* If entries were specified explicitly with command options,
893 ignore the entries in the input file. */
894 else if (!ignore_entries)
896 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
897 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
899 if (!*sections)
901 /* We found an entry, but didn't yet see any sections
902 specified. Default to section "Miscellaneous". */
903 *sections = (struct spec_section *)
904 xmalloc (sizeof (struct spec_section));
905 (*sections)->name = "Miscellaneous";
906 (*sections)->next = 0;
907 (*sections)->missing = 1;
908 head = *sections;
910 /* Next time we see INFO-DIR-SECTION, we will reset the
911 tail pointer. */
912 reset_tail = 1;
914 if (start_of_this_entry != 0)
915 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"), 0, 0);
916 start_of_this_entry = lines[i + 1].start;
918 else if (start_of_this_entry)
920 if ((!strncmp ("* ", lines[i].start, 2)
921 && lines[i].start > start_of_this_entry)
922 || (!strncmp ("END-INFO-DIR-ENTRY",
923 lines[i].start, lines[i].size)
924 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
926 /* We found an end of this entry. Allocate another
927 entry, fill its data, and add it to the linked
928 list. */
929 struct spec_entry *next
930 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
931 next->text
932 = copy_string (start_of_this_entry,
933 lines[i].start - start_of_this_entry);
934 next->text_len = lines[i].start - start_of_this_entry;
935 next->entry_sections = head;
936 next->entry_sections_tail = tail;
937 next->next = *entries;
938 *entries = next;
939 n_entries++;
940 if (!strncmp ("END-INFO-DIR-ENTRY",
941 lines[i].start, lines[i].size)
942 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
943 start_of_this_entry = 0;
944 else
945 start_of_this_entry = lines[i].start;
947 else if (!strncmp ("END-INFO-DIR-ENTRY",
948 lines[i].start, lines[i].size)
949 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
950 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"), 0, 0);
954 if (start_of_this_entry != 0)
955 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"),
956 0, 0);
958 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
959 and plug the names of all the sections we found into every
960 element of the ENTRIES list. */
961 if (ignore_entries && *entries)
963 struct spec_entry *entry;
965 for (entry = *entries; entry; entry = entry->next)
967 entry->entry_sections = head;
968 entry->entry_sections_tail = tail;
972 return n_entries;
975 /* Parse the dir file whose basename is BASE_NAME. Find all the
976 nodes, and their menus, and the sections of their menus. */
978 parse_dir_file (struct line_data *lines, int nlines, struct node **nodes,
979 const char *base_name)
981 int node_header_flag = 0;
982 int something_deleted = 0;
983 int i;
985 *nodes = 0;
986 for (i = 0; i < nlines; i++)
988 /* Parse node header lines. */
989 if (node_header_flag)
991 int j, end;
992 for (j = 0; j < lines[i].size; j++)
993 /* Find the node name and store it in the `struct node'. */
994 if (!strncmp ("Node:", lines[i].start + j, 5))
996 char *line = lines[i].start;
997 /* Find the start of the node name. */
998 j += 5;
999 while (line[j] == ' ' || line[j] == '\t')
1000 j++;
1001 /* Find the end of the node name. */
1002 end = j;
1003 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
1004 && line[end] != '\t')
1005 end++;
1006 (*nodes)->name = copy_string (line + j, end - j);
1008 node_header_flag = 0;
1011 /* Notice the start of a node. */
1012 if (*lines[i].start == 037)
1014 struct node *next = (struct node *) xmalloc (sizeof (struct node));
1016 next->next = *nodes;
1017 next->name = NULL;
1018 next->start_line = i;
1019 next->end_line = 0;
1020 next->menu_start = NULL;
1021 next->sections = NULL;
1022 next->last_section = NULL;
1024 if (*nodes != 0)
1025 (*nodes)->end_line = i;
1026 /* Fill in the end of the last menu section
1027 of the previous node. */
1028 if (*nodes != 0 && (*nodes)->last_section != 0)
1029 (*nodes)->last_section->end_line = i;
1031 *nodes = next;
1033 /* The following line is the header of this node;
1034 parse it. */
1035 node_header_flag = 1;
1038 /* Notice the lines that start menus. */
1039 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
1040 (*nodes)->menu_start = lines[i + 1].start;
1042 /* Notice sections in menus. */
1043 if (*nodes != 0
1044 && (*nodes)->menu_start != 0
1045 && *lines[i].start != '\n'
1046 && *lines[i].start != '*'
1047 && *lines[i].start != ' '
1048 && *lines[i].start != '\t')
1050 /* Add this menu section to the node's list.
1051 This list grows in forward order. */
1052 struct menu_section *next
1053 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1055 next->start_line = i + 1;
1056 next->next = 0;
1057 next->end_line = 0;
1058 next->name = copy_string (lines[i].start, lines[i].size);
1059 if ((*nodes)->sections)
1061 (*nodes)->last_section->next = next;
1062 (*nodes)->last_section->end_line = i;
1064 else
1065 (*nodes)->sections = next;
1066 (*nodes)->last_section = next;
1069 /* Check for an existing entry that should be deleted.
1070 Delete all entries which specify this file name. */
1071 if (*lines[i].start == '*')
1073 char *q;
1074 char *p = lines[i].start;
1076 p++; /* skip * */
1077 while (*p == ' ') p++; /* ignore following spaces */
1078 q = p; /* remember this, it's the beginning of the menu item. */
1080 /* Read menu item. */
1081 while (*p != 0 && *p != ':')
1082 p++;
1083 p++; /* skip : */
1085 if (*p == ':')
1086 { /* XEmacs-style entry, as in * Mew::Messaging. */
1087 if (menu_item_equal (q, ':', base_name))
1089 lines[i].delete = 1;
1090 something_deleted = 1;
1093 else
1094 { /* Emacs-style entry, as in * Emacs: (emacs). */
1095 while (*p == ' ') p++; /* skip spaces after : */
1096 if (*p == '(') /* if at parenthesized (FILENAME) */
1098 p++;
1099 if (menu_item_equal (p, ')', base_name))
1101 lines[i].delete = 1;
1102 something_deleted = 1;
1108 /* Treat lines that start with whitespace
1109 as continuations; if we are deleting an entry,
1110 delete all its continuations as well. */
1111 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1113 lines[i].delete = lines[i - 1].delete;
1117 /* Finish the info about the end of the last node. */
1118 if (*nodes != 0)
1120 (*nodes)->end_line = nlines;
1121 if ((*nodes)->last_section != 0)
1122 (*nodes)->last_section->end_line = nlines;
1125 return something_deleted;
1129 main (int argc, char **argv)
1131 char *opened_dirfilename;
1132 char *compression_program;
1133 char *infile_sans_info;
1134 char *infile = 0, *dirfile = 0;
1136 /* Record the text of the Info file, as a sequence of characters
1137 and as a sequence of lines. */
1138 char *input_data = NULL;
1139 int input_size = 0;
1140 struct line_data *input_lines = NULL;
1141 int input_nlines = 0;
1143 /* Record here the specified section names and directory entries. */
1144 struct spec_section *input_sections = NULL;
1145 struct spec_entry *entries_to_add = NULL;
1146 int n_entries_to_add = 0;
1148 /* Record the old text of the dir file, as plain characters,
1149 as lines, and as nodes. */
1150 char *dir_data;
1151 int dir_size;
1152 int dir_nlines;
1153 struct line_data *dir_lines;
1154 struct node *dir_nodes;
1156 /* Nonzero means --delete was specified (just delete existing entries). */
1157 int delete_flag = 0;
1158 int something_deleted = 0;
1159 /* Nonzero means -q was specified. */
1160 int quiet_flag = 0;
1162 int i;
1164 #ifdef HAVE_SETLOCALE
1165 /* Set locale via LC_ALL. */
1166 setlocale (LC_ALL, "");
1167 #endif
1169 /* Set the text message domain. */
1170 bindtextdomain (PACKAGE, LOCALEDIR);
1171 textdomain (PACKAGE);
1173 while (1)
1175 int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
1177 if (opt == EOF)
1178 break;
1180 switch (opt)
1182 case 0:
1183 /* If getopt returns 0, then it has already processed a
1184 long-named option. We should do nothing. */
1185 break;
1187 case 1:
1188 abort ();
1190 case 'd':
1191 if (dirfile)
1193 fprintf (stderr, _("%s: already have dir file: %s\n"),
1194 progname, dirfile);
1195 suggest_asking_for_help ();
1197 dirfile = optarg;
1198 break;
1200 case 'D':
1201 if (dirfile)
1203 fprintf (stderr, _("%s: already have dir file: %s\n"),
1204 progname, dirfile);
1205 suggest_asking_for_help ();
1207 dirfile = concat (optarg, "", "/dir");
1208 break;
1210 case 'e':
1212 struct spec_entry *next
1213 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1214 int olen = strlen (optarg);
1215 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
1217 optarg = concat (optarg, "\n", "");
1218 olen++;
1220 next->text = optarg;
1221 next->text_len = olen;
1222 next->entry_sections = NULL;
1223 next->entry_sections_tail = NULL;
1224 next->next = entries_to_add;
1225 entries_to_add = next;
1226 n_entries_to_add++;
1228 break;
1230 case 'h':
1231 case 'H':
1232 print_help ();
1233 xexit (0);
1235 case 'i':
1236 if (infile)
1238 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
1239 progname);
1240 suggest_asking_for_help ();
1242 infile = optarg;
1243 break;
1245 case 'q':
1246 quiet_flag = 1;
1247 break;
1249 case 'r':
1250 delete_flag = 1;
1251 break;
1253 case 's':
1255 struct spec_section *next
1256 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1257 next->name = optarg;
1258 next->next = input_sections;
1259 next->missing = 1;
1260 input_sections = next;
1262 break;
1264 case 'V':
1265 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
1266 puts ("");
1267 puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
1268 printf (_("There is NO warranty. You may redistribute this software\n\
1269 under the terms of the GNU General Public License.\n\
1270 For more information about these matters, see the files named COPYING.\n"));
1271 xexit (0);
1273 default:
1274 suggest_asking_for_help ();
1278 /* Interpret the non-option arguments as file names. */
1279 for (; optind < argc; ++optind)
1281 if (infile == 0)
1282 infile = argv[optind];
1283 else if (dirfile == 0)
1284 dirfile = argv[optind];
1285 else
1286 error (_("excess command line argument `%s'"), argv[optind], 0);
1289 if (!infile)
1290 fatal (_("No input file specified; try --help for more information."),
1291 0, 0);
1292 if (!dirfile)
1293 fatal (_("No dir file specified; try --help for more information."), 0, 0);
1295 /* Read the Info file and parse it into lines, unless we're deleting. */
1296 if (!delete_flag)
1298 input_data = readfile (infile, &input_size, NULL, NULL, NULL);
1299 input_lines = findlines (input_data, input_size, &input_nlines);
1302 i = parse_input (input_lines, input_nlines,
1303 &input_sections, &entries_to_add);
1304 if (i > n_entries_to_add)
1305 n_entries_to_add = i;
1307 if (!delete_flag)
1309 if (entries_to_add == 0)
1310 { /* No need to abort here, the original info file may not
1311 have the requisite Texinfo commands. This is not
1312 something an installer should have to correct (it's a
1313 problem for the maintainer), and there's no need to cause
1314 subsequent parts of `make install' to fail. */
1315 warning (_("no info dir entry in `%s'"), infile, 0);
1316 xexit (0);
1319 /* If the entries came from the command-line arguments, their
1320 entry_sections pointers are not yet set. Walk the chain of
1321 the entries and for each entry update entry_sections to point
1322 to the head of the list of sections where this entry should
1323 be put. Note that all the entries specified on the command
1324 line get put into ALL the sections we've got, either from the
1325 Info file, or (under --section) from the command line,
1326 because in the loop below every entry inherits the entire
1327 chain of sections. */
1328 if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
1330 struct spec_entry *ep;
1332 /* If we got no sections, default to "Miscellaneous". */
1333 if (input_sections == NULL)
1335 input_sections = (struct spec_section *)
1336 xmalloc (sizeof (struct spec_section));
1337 input_sections->name = "Miscellaneous";
1338 input_sections->next = NULL;
1339 input_sections->missing = 1;
1341 for (ep = entries_to_add; ep; ep = ep->next)
1342 ep->entry_sections = input_sections;
1346 /* Now read in the Info dir file. */
1347 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
1348 &opened_dirfilename, &compression_program);
1349 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
1351 /* We will be comparing the entries in the dir file against the
1352 current filename, so need to strip off any directory prefix and/or
1353 [.info][.gz] suffix. */
1355 char *infile_basename = infile + strlen (infile);
1357 if (HAVE_DRIVE (infile))
1358 infile += 2; /* get past the drive spec X: */
1360 while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
1361 infile_basename--;
1363 infile_sans_info = strip_info_suffix (infile_basename);
1366 something_deleted
1367 = parse_dir_file (dir_lines, dir_nlines, &dir_nodes, infile_sans_info);
1369 /* Decide where to add the new entries (unless --delete was used).
1370 Find the menu sections to add them in.
1371 In each section, find the proper alphabetical place to add
1372 each of the entries. */
1373 if (!delete_flag)
1375 struct node *node;
1376 struct menu_section *section;
1377 struct spec_section *spec;
1379 for (node = dir_nodes; node; node = node->next)
1380 for (section = node->sections; section; section = section->next)
1382 for (i = section->end_line; i > section->start_line; i--)
1383 if (dir_lines[i - 1].size != 0)
1384 break;
1385 section->end_line = i;
1387 for (spec = input_sections; spec; spec = spec->next)
1388 if (!strcmp (spec->name, section->name))
1389 break;
1390 if (spec)
1392 int add_at_line = section->end_line;
1393 struct spec_entry *entry;
1394 /* Say we have found at least one section with this name,
1395 so we need not add such a section. */
1396 spec->missing = 0;
1397 /* For each entry, find the right place in this section
1398 to add it. */
1399 for (entry = entries_to_add; entry; entry = entry->next)
1401 /* Did they at all want this entry to be put into
1402 this section? */
1403 for (spec = entry->entry_sections;
1404 spec && spec != entry->entry_sections_tail;
1405 spec = spec->next)
1407 if (!strcmp (spec->name, section->name))
1408 break;
1410 if (!spec || spec == entry->entry_sections_tail)
1411 continue;
1413 /* Subtract one because dir_lines is zero-based,
1414 but the `end_line' and `start_line' members are
1415 one-based. */
1416 for (i = section->end_line - 1;
1417 i >= section->start_line - 1; i--)
1419 /* If an entry exists with the same name,
1420 and was not marked for deletion
1421 (which means it is for some other file),
1422 we are in trouble. */
1423 if (dir_lines[i].start[0] == '*'
1424 && menu_line_equal (entry->text, entry->text_len,
1425 dir_lines[i].start,
1426 dir_lines[i].size)
1427 && !dir_lines[i].delete)
1428 fatal (_("menu item `%s' already exists, for file `%s'"),
1429 extract_menu_item_name (entry->text),
1430 extract_menu_file_name (dir_lines[i].start));
1431 if (dir_lines[i].start[0] == '*'
1432 && menu_line_lessp (entry->text, entry->text_len,
1433 dir_lines[i].start,
1434 dir_lines[i].size))
1435 add_at_line = i;
1437 insert_entry_here (entry, add_at_line,
1438 dir_lines, n_entries_to_add);
1443 /* Mark the end of the Top node as the place to add any
1444 new sections that are needed. */
1445 for (node = dir_nodes; node; node = node->next)
1446 if (node->name && strcmp (node->name, "Top") == 0)
1447 dir_lines[node->end_line].add_sections_before = 1;
1450 if (delete_flag && !something_deleted && !quiet_flag)
1451 warning (_("no entries found for `%s'; nothing deleted"), infile, 0);
1453 output_dirfile (opened_dirfilename, dir_nlines, dir_lines, n_entries_to_add,
1454 entries_to_add, input_sections, compression_program);
1456 xexit (0);
1457 return 0; /* Avoid bogus warnings. */
1460 /* Divide the text at DATA (of SIZE bytes) into lines.
1461 Return a vector of struct line_data describing the lines.
1462 Store the length of that vector into *NLINESP. */
1464 struct line_data *
1465 findlines (char *data, int size, int *nlinesp)
1467 int i;
1468 int lineflag = 1;
1469 int lines_allocated = 511;
1470 int filled = 0;
1471 struct line_data *lines
1472 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
1474 for (i = 0; i < size; i++)
1476 if (lineflag)
1478 if (filled == lines_allocated)
1480 /* try to keep things somewhat page-aligned */
1481 lines_allocated = ((lines_allocated + 1) * 2) - 1;
1482 lines = xrealloc (lines, (lines_allocated + 1)
1483 * sizeof (struct line_data));
1485 lines[filled].start = &data[i];
1486 lines[filled].add_entries_before = 0;
1487 lines[filled].add_sections_before = 0;
1488 lines[filled].delete = 0;
1489 if (filled > 0)
1490 lines[filled - 1].size
1491 = lines[filled].start - lines[filled - 1].start - 1;
1492 filled++;
1494 lineflag = (data[i] == '\n');
1496 if (filled > 0)
1497 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
1499 /* Do not leave garbage in the last element. */
1500 lines[filled].start = NULL;
1501 lines[filled].add_entries_before = NULL;
1502 lines[filled].add_sections_before = 0;
1503 lines[filled].delete = 0;
1504 lines[filled].size = 0;
1506 *nlinesp = filled;
1507 return lines;
1510 /* This is the comparison function for qsort for a vector of pointers to
1511 struct spec_section. (Have to use const void * as the parameter type
1512 to avoid incompatible-with-qsort warnings.)
1513 Compare the section names. */
1516 compare_section_names (const void *p1, const void *p2)
1518 struct spec_section **sec1 = (struct spec_section **) p1;
1519 struct spec_section **sec2 = (struct spec_section **) p2;
1520 char *name1 = (*sec1)->name;
1521 char *name2 = (*sec2)->name;
1522 return strcmp (name1, name2);
1525 /* This is the comparison function for qsort
1526 for a vector of pointers to struct spec_entry.
1527 Compare the entries' text. */
1530 compare_entries_text (const void *p1, const void *p2)
1532 struct spec_entry **entry1 = (struct spec_entry **) p1;
1533 struct spec_entry **entry2 = (struct spec_entry **) p2;
1534 char *text1 = (*entry1)->text;
1535 char *text2 = (*entry2)->text;
1536 char *colon1 = strchr (text1, ':');
1537 char *colon2 = strchr (text2, ':');
1538 int len1, len2;
1540 if (!colon1)
1541 len1 = strlen (text1);
1542 else
1543 len1 = colon1 - text1;
1544 if (!colon2)
1545 len2 = strlen (text2);
1546 else
1547 len2 = colon2 - text2;
1548 return strncmp (text1, text2, len1 <= len2 ? len1 : len2);
1551 /* Insert ENTRY into the add_entries_before vector
1552 for line number LINE_NUMBER of the dir file.
1553 DIR_LINES and N_ENTRIES carry information from like-named variables
1554 in main. */
1556 void
1557 insert_entry_here (struct spec_entry *entry, int line_number,
1558 struct line_data *dir_lines, int n_entries)
1560 int i, j;
1562 if (dir_lines[line_number].add_entries_before == 0)
1564 dir_lines[line_number].add_entries_before
1565 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1566 for (i = 0; i < n_entries; i++)
1567 dir_lines[line_number].add_entries_before[i] = 0;
1570 /* Find the place where this entry belongs. If there are already
1571 several entries to add before LINE_NUMBER, make sure they are in
1572 alphabetical order. */
1573 for (i = 0; i < n_entries; i++)
1574 if (dir_lines[line_number].add_entries_before[i] == 0
1575 || menu_line_lessp (entry->text, strlen (entry->text),
1576 dir_lines[line_number].add_entries_before[i]->text,
1577 strlen (dir_lines[line_number].add_entries_before[i]->text)))
1578 break;
1580 if (i == n_entries)
1581 abort ();
1583 /* If we need to plug ENTRY into the middle of the
1584 ADD_ENTRIES_BEFORE array, move the entries which should be output
1585 after this one down one notch, before adding a new one. */
1586 if (dir_lines[line_number].add_entries_before[i] != 0)
1587 for (j = n_entries - 1; j > i; j--)
1588 dir_lines[line_number].add_entries_before[j]
1589 = dir_lines[line_number].add_entries_before[j - 1];
1591 dir_lines[line_number].add_entries_before[i] = entry;