* expr.c (emit_move_insn_1): Only emit clobbers if one of
[official-gcc.git] / texinfo / util / install-info.c
blob91b599d57f0fdaac9c8e012b8ae68e4e16af663f
1 /* install-info -- create Info directory entry(ies) for an Info file.
2 $Id: install-info.c,v 1.1.1.3 1998/03/24 18:20:30 law Exp $
4 Copyright (C) 1996, 97, 98 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
20 #include "system.h"
21 #include <getopt.h>
23 #ifdef HAVE_LIBZ
24 #include <zlib.h>
25 #endif
27 /* Name this program was invoked with. */
28 char *progname;
30 char *readfile ();
31 struct line_data *findlines ();
32 void fatal ();
33 void insert_entry_here ();
34 int compare_section_names ();
36 struct spec_entry;
38 /* Data structures. */
41 /* Record info about a single line from a file as read into core. */
42 struct line_data
44 /* The start of the line. */
45 char *start;
46 /* The number of characters in the line,
47 excluding the terminating newline. */
48 int size;
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 /* 1 means output any needed new sections before this line. */
53 int add_sections_before;
54 /* 1 means don't output this line. */
55 int delete;
59 /* This is used for a list of the specified menu section names
60 in which entries should be added. */
61 struct spec_section
63 struct spec_section *next;
64 char *name;
65 /* 1 means we have not yet found an existing section with this name
66 in the dir file--so we will need to add a new section. */
67 int missing;
71 /* This is used for a list of the entries specified to be added. */
72 struct spec_entry
74 struct spec_entry *next;
75 char *text;
79 /* This is used for a list of nodes found by parsing the dir file. */
80 struct node
82 struct node *next;
83 /* The node name. */
84 char *name;
85 /* The line number of the line where the node starts.
86 This is the line that contains control-underscore. */
87 int start_line;
88 /* The line number of the line where the node ends,
89 which is the end of the file or where the next line starts. */
90 int end_line;
91 /* Start of first line in this node's menu
92 (the line after the * Menu: line). */
93 char *menu_start;
94 /* The start of the chain of sections in this node's menu. */
95 struct menu_section *sections;
96 /* The last menu section in the chain. */
97 struct menu_section *last_section;
101 /* This is used for a list of sections found in a node's menu.
102 Each struct node has such a list in the sections field. */
103 struct menu_section
105 struct menu_section *next;
106 char *name;
107 /* Line number of start of section. */
108 int start_line;
109 /* Line number of end of section. */
110 int end_line;
113 /* Memory allocation and string operations. */
115 /* Like malloc but get fatal error if memory is exhausted. */
116 void *
117 xmalloc (size)
118 unsigned int size;
120 extern void *malloc ();
121 void *result = malloc (size);
122 if (result == NULL)
123 fatal (_("virtual memory exhausted"), 0);
124 return result;
127 /* Like realloc but get fatal error if memory is exhausted. */
128 void *
129 xrealloc (obj, size)
130 void *obj;
131 unsigned int size;
133 extern void *realloc ();
134 void *result = realloc (obj, size);
135 if (result == NULL)
136 fatal (_("virtual memory exhausted"), 0);
137 return result;
140 /* Return a newly-allocated string
141 whose contents concatenate those of S1, S2, S3. */
142 char *
143 concat (s1, s2, s3)
144 char *s1, *s2, *s3;
146 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
147 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
149 strcpy (result, s1);
150 strcpy (result + len1, s2);
151 strcpy (result + len1 + len2, s3);
152 *(result + len1 + len2 + len3) = 0;
154 return result;
157 /* Return a string containing SIZE characters
158 copied from starting at STRING. */
160 char *
161 copy_string (string, size)
162 char *string;
163 int size;
165 int i;
166 char *copy = (char *) xmalloc (size + 1);
167 for (i = 0; i < size; i++)
168 copy[i] = string[i];
169 copy[size] = 0;
170 return copy;
173 /* Error message functions. */
175 /* Print error message. S1 is printf control string, S2 and S3 args for it. */
177 /* VARARGS1 */
178 void
179 error (s1, s2, s3)
180 char *s1, *s2, *s3;
182 fprintf (stderr, "%s: ", progname);
183 fprintf (stderr, s1, s2, s3);
184 putc ('\n', stderr);
187 /* VARARGS1 */
188 void
189 warning (s1, s2, s3)
190 char *s1, *s2, *s3;
192 fprintf (stderr, _("%s: warning: "), progname);
193 fprintf (stderr, s1, s2, s3);
194 putc ('\n', stderr);
197 /* Print error message and exit. */
199 void
200 fatal (s1, s2, s3)
201 char *s1, *s2, *s3;
203 error (s1, s2, s3);
204 exit (1);
207 /* Print fatal error message based on errno, with file name NAME. */
209 void
210 pfatal_with_name (name)
211 char *name;
213 char *s = concat ("", strerror (errno), _(" for %s"));
214 fatal (s, name);
217 /* Given the full text of a menu entry, null terminated,
218 return just the menu item name (copied). */
220 char *
221 extract_menu_item_name (item_text)
222 char *item_text;
224 char *p;
226 if (*item_text == '*')
227 item_text++;
228 while (*item_text == ' ')
229 item_text++;
231 p = item_text;
232 while (*p && *p != ':') p++;
233 return copy_string (item_text, p - item_text);
236 /* Given the full text of a menu entry, terminated by null or newline,
237 return just the menu item file (copied). */
239 char *
240 extract_menu_file_name (item_text)
241 char *item_text;
243 char *p = item_text;
245 /* If we have text that looks like * ITEM: (FILE)NODE...,
246 extract just FILE. Otherwise return "(none)". */
248 if (*p == '*')
249 p++;
250 while (*p == ' ')
251 p++;
253 /* Skip to and past the colon. */
254 while (*p && *p != '\n' && *p != ':') p++;
255 if (*p == ':') p++;
257 /* Skip past the open-paren. */
258 while (1)
260 if (*p == '(')
261 break;
262 else if (*p == ' ' || *p == '\t')
263 p++;
264 else
265 return "(none)";
267 p++;
269 item_text = p;
271 /* File name ends just before the close-paren. */
272 while (*p && *p != '\n' && *p != ')') p++;
273 if (*p != ')')
274 return "(none)";
276 return copy_string (item_text, p - item_text);
279 void
280 suggest_asking_for_help ()
282 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
283 progname);
284 exit (1);
287 void
288 print_help ()
290 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
292 Install INFO-FILE in the Info directory file DIR-FILE.\n\
294 Options:\n\
295 --delete Delete existing entries in INFO-FILE;\n\
296 don't insert any new entries.\n\
297 --dir-file=NAME Specify file name of Info directory file.\n\
298 This is equivalent to using the DIR-FILE argument.\n\
299 --entry=TEXT Insert TEXT as an Info directory entry.\n\
300 TEXT should have the form of an Info menu item line\n\
301 plus zero or more extra lines starting with whitespace.\n\
302 If you specify more than one entry, they are all added.\n\
303 If you don't specify any entries, they are determined\n\
304 from information in the Info file itself.\n\
305 --help Display this help and exit.\n\
306 --info-file=FILE Specify Info file to install in the directory.\n\
307 This is equivalent to using the INFO-FILE argument.\n\
308 --info-dir=DIR Same as --dir-file=DIR/dir.\n\
309 --item=TEXT Same as --entry TEXT.\n\
310 An Info directory entry is actually a menu item.\n\
311 --quiet Suppress warnings.\n\
312 --remove Same as --delete.\n\
313 --section=SEC Put this file's entries in section SEC of the directory.\n\
314 If you specify more than one section, all the entries\n\
315 are added in each of the sections.\n\
316 If you don't specify any sections, they are determined\n\
317 from information in the Info file itself.\n\
318 --version Display version information and exit.\n\
320 Email bug reports to bug-texinfo@gnu.org.\n\
321 "), progname);
325 /* If DIRFILE does not exist, create a minimal one (or abort). If it
326 already exists, do nothing. */
328 void
329 ensure_dirfile_exists (dirfile)
330 char *dirfile;
332 int desc = open (dirfile, O_RDONLY);
333 if (desc < 0 && errno == ENOENT)
335 FILE *f;
336 char *readerr = strerror (errno);
337 close (desc);
338 f = fopen (dirfile, "w");
339 if (f)
341 fputs (_("This is the file .../info/dir, which contains the\n\
342 topmost node of the Info hierarchy, called (dir)Top.\n\
343 The first time you invoke Info you start off looking at this node.\n\
344 \x1f\n\
345 File: dir,\tNode: Top,\tThis is the top of the INFO tree\n\
347 This (the Directory node) gives a menu of major topics.\n\
348 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
349 \"h\" gives a primer for first-timers,\n\
350 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
352 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
353 to select it.\n\
355 * Menu:\n\
356 "), f);
357 if (fclose (f) < 0)
358 pfatal_with_name (dirfile);
360 else
362 /* Didn't exist, but couldn't open for writing. */
363 fprintf (stderr,
364 _("%s: could not read (%s) and could not create (%s)\n"),
365 dirfile, readerr, strerror (errno));
366 exit (1);
369 else
370 close (desc); /* It already existed, so fine. */
373 /* This table defines all the long-named options, says whether they
374 use an argument, and maps them into equivalent single-letter options. */
376 struct option longopts[] =
378 { "delete", no_argument, NULL, 'r' },
379 { "dir-file", required_argument, NULL, 'd' },
380 { "entry", required_argument, NULL, 'e' },
381 { "help", no_argument, NULL, 'h' },
382 { "info-dir", required_argument, NULL, 'D' },
383 { "info-file", required_argument, NULL, 'i' },
384 { "item", required_argument, NULL, 'e' },
385 { "quiet", no_argument, NULL, 'q' },
386 { "remove", no_argument, NULL, 'r' },
387 { "section", required_argument, NULL, 's' },
388 { "version", no_argument, NULL, 'V' },
389 { 0 }
394 main (argc, argv)
395 int argc;
396 char **argv;
398 char *infile = 0, *dirfile = 0;
399 char *infile_sans_info;
400 unsigned infilelen_sans_info;
401 FILE *output;
403 /* Record the text of the Info file, as a sequence of characters
404 and as a sequence of lines. */
405 char *input_data;
406 int input_size;
407 struct line_data *input_lines;
408 int input_nlines;
410 /* Record here the specified section names and directory entries. */
411 struct spec_section *input_sections = NULL;
412 struct spec_entry *entries_to_add = NULL;
413 int n_entries_to_add = 0;
415 /* Record the old text of the dir file, as plain characters,
416 as lines, and as nodes. */
417 char *dir_data;
418 int dir_size;
419 int dir_nlines;
420 struct line_data *dir_lines;
421 struct node *dir_nodes;
423 /* Nonzero means --delete was specified (just delete existing entries). */
424 int delete_flag = 0;
425 int something_deleted = 0;
426 /* Nonzero means -q was specified. */
427 int quiet_flag = 0;
429 int node_header_flag;
430 int prefix_length;
431 int i;
433 progname = argv[0];
435 #ifdef HAVE_SETLOCALE
436 /* Set locale via LC_ALL. */
437 setlocale (LC_ALL, "");
438 #endif
440 /* Set the text message domain. */
441 bindtextdomain (PACKAGE, LOCALEDIR);
442 textdomain (PACKAGE);
444 while (1)
446 int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
448 if (opt == EOF)
449 break;
451 switch (opt)
453 case 0:
454 /* If getopt returns 0, then it has already processed a
455 long-named option. We should do nothing. */
456 break;
458 case 1:
459 abort ();
461 case 'd':
462 if (dirfile)
464 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
465 progname);
466 suggest_asking_for_help ();
468 dirfile = optarg;
469 break;
471 case 'D':
472 if (dirfile)
474 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
475 progname);
476 suggest_asking_for_help ();
478 dirfile = concat (optarg, "", "/dir");
479 break;
481 case 'e':
483 struct spec_entry *next
484 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
485 if (! (*optarg != 0 && optarg[strlen (optarg) - 1] == '\n'))
486 optarg = concat (optarg, "\n", "");
487 next->text = optarg;
488 next->next = entries_to_add;
489 entries_to_add = next;
490 n_entries_to_add++;
492 break;
494 case 'h':
495 case 'H':
496 print_help ();
497 exit (0);
499 case 'i':
500 if (infile)
502 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
503 progname);
504 suggest_asking_for_help ();
506 infile = optarg;
507 break;
509 case 'q':
510 quiet_flag = 1;
511 break;
513 case 'r':
514 delete_flag = 1;
515 break;
517 case 's':
519 struct spec_section *next
520 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
521 next->name = optarg;
522 next->next = input_sections;
523 next->missing = 1;
524 input_sections = next;
526 break;
528 case 'V':
529 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
530 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
531 There is NO warranty. You may redistribute this software\n\
532 under the terms of the GNU General Public License.\n\
533 For more information about these matters, see the files named COPYING.\n"),
534 "1998");
535 exit (0);
537 default:
538 suggest_asking_for_help ();
542 /* Interpret the non-option arguments as file names. */
543 for (; optind < argc; ++optind)
545 if (infile == 0)
546 infile = argv[optind];
547 else if (dirfile == 0)
548 dirfile = argv[optind];
549 else
550 error (_("excess command line argument `%s'"), argv[optind]);
553 if (!infile)
554 fatal (_("No input file specified; try --help for more information."));
555 if (!dirfile)
556 fatal (_("No dir file specified; try --help for more information."));
558 /* Read the Info file and parse it into lines. */
560 input_data = readfile (infile, &input_size);
561 input_lines = findlines (input_data, input_size, &input_nlines);
563 /* Parse the input file to find the section names it specifies. */
565 if (input_sections == 0)
567 prefix_length = strlen ("INFO-DIR-SECTION ");
568 for (i = 0; i < input_nlines; i++)
570 if (!strncmp ("INFO-DIR-SECTION ", input_lines[i].start,
571 prefix_length))
573 struct spec_section *next
574 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
575 next->name = copy_string (input_lines[i].start + prefix_length,
576 input_lines[i].size - prefix_length);
577 next->next = input_sections;
578 next->missing = 1;
579 input_sections = next;
584 /* Default to section "Miscellaneous" if no sections specified. */
585 if (input_sections == 0)
587 input_sections
588 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
589 input_sections->name = "Miscellaneous";
590 input_sections->next = 0;
591 input_sections->missing = 1;
594 /* Now find the directory entries specified in the file
595 and put them on entries_to_add. But not if entries
596 were specified explicitly with command options. */
598 if (entries_to_add == 0)
600 char *start_of_this_entry = 0;
601 for (i = 0; i < input_nlines; i++)
603 if (!strncmp ("START-INFO-DIR-ENTRY", input_lines[i].start,
604 input_lines[i].size)
605 && sizeof ("START-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
607 if (start_of_this_entry != 0)
608 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
609 start_of_this_entry = input_lines[i + 1].start;
611 if (!strncmp ("END-INFO-DIR-ENTRY", input_lines[i].start,
612 input_lines[i].size)
613 && sizeof ("END-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
615 if (start_of_this_entry != 0)
617 struct spec_entry *next
618 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
619 next->text = copy_string (start_of_this_entry,
620 input_lines[i].start - start_of_this_entry);
621 next->next = entries_to_add;
622 entries_to_add = next;
623 n_entries_to_add++;
624 start_of_this_entry = 0;
626 else
627 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"));
630 if (start_of_this_entry != 0)
631 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
634 if (!delete_flag)
635 if (entries_to_add == 0)
636 { /* No need to abort here, the original info file may not have
637 the requisite Texinfo commands. This is not something an
638 installer should have to correct (it's a problem for the
639 maintainer), and there's no need to cause subsequent parts of
640 `make install' to fail. */
641 warning (_("no info dir entry in `%s'"), infile);
642 exit (0);
645 /* Now read in the Info dir file. */
646 ensure_dirfile_exists (dirfile);
647 dir_data = readfile (dirfile, &dir_size);
648 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
650 /* We will be comparing the entries in the dir file against the
651 current filename, so need to strip off any directory prefix and any
652 .info suffix. */
654 unsigned basename_len;
655 char *infile_basename = strrchr (infile, '/');
656 if (infile_basename)
657 infile_basename++;
658 else
659 infile_basename = infile;
661 basename_len = strlen (infile_basename);
662 infile_sans_info
663 = (strlen (infile_basename) > 5
664 && strcmp (infile_basename + basename_len - 5, ".info") == 0)
665 ? copy_string (infile_basename, basename_len - 5)
666 : infile_basename;
668 infilelen_sans_info = strlen (infile_sans_info);
671 /* Parse the dir file. Find all the nodes, and their menus,
672 and the sections of their menus. */
674 dir_nodes = 0;
675 node_header_flag = 0;
676 for (i = 0; i < dir_nlines; i++)
678 /* Parse node header lines. */
679 if (node_header_flag)
681 int j, end;
682 for (j = 0; j < dir_lines[i].size; j++)
683 /* Find the node name and store it in the `struct node'. */
684 if (!strncmp ("Node:", dir_lines[i].start + j, 5))
686 char *line = dir_lines[i].start;
687 /* Find the start of the node name. */
688 j += 5;
689 while (line[j] == ' ' || line[j] == '\t')
690 j++;
691 /* Find the end of the node name. */
692 end = j;
693 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
694 && line[end] != '\t')
695 end++;
696 dir_nodes->name = copy_string (line + j, end - j);
698 node_header_flag = 0;
701 /* Notice the start of a node. */
702 if (*dir_lines[i].start == 037)
704 struct node *next
705 = (struct node *) xmalloc (sizeof (struct node));
706 next->next = dir_nodes;
707 next->name = NULL;
708 next->start_line = i;
709 next->end_line = 0;
710 next->menu_start = NULL;
711 next->sections = NULL;
712 next->last_section = NULL;
714 if (dir_nodes != 0)
715 dir_nodes->end_line = i;
716 /* Fill in the end of the last menu section
717 of the previous node. */
718 if (dir_nodes != 0 && dir_nodes->last_section != 0)
719 dir_nodes->last_section->end_line = i;
721 dir_nodes = next;
723 /* The following line is the header of this node;
724 parse it. */
725 node_header_flag = 1;
728 /* Notice the lines that start menus. */
729 if (dir_nodes != 0
730 && !strncmp ("* Menu:", dir_lines[i].start, 7))
731 dir_nodes->menu_start = dir_lines[i + 1].start;
733 /* Notice sections in menus. */
734 if (dir_nodes != 0
735 && dir_nodes->menu_start != 0
736 && *dir_lines[i].start != '\n'
737 && *dir_lines[i].start != '*'
738 && *dir_lines[i].start != ' '
739 && *dir_lines[i].start != '\t')
741 /* Add this menu section to the node's list.
742 This list grows in forward order. */
743 struct menu_section *next
744 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
745 next->start_line = i + 1;
746 next->next = 0;
747 next->end_line = 0;
748 next->name = copy_string (dir_lines[i].start, dir_lines[i].size);
749 if (dir_nodes->sections)
751 dir_nodes->last_section->next = next;
752 dir_nodes->last_section->end_line = i;
754 else
755 dir_nodes->sections = next;
756 dir_nodes->last_section = next;
759 /* Check for an existing entry that should be deleted.
760 Delete all entries which specify this file name. */
761 if (*dir_lines[i].start == '*')
763 char *p = dir_lines[i].start;
765 while (*p != 0 && *p != ':')
766 p++;
767 p++;
768 while (*p == ' ') p++;
769 if (*p == '(')
771 p++;
772 if ((dir_lines[i].size
773 > (p - dir_lines[i].start + infilelen_sans_info))
774 && !strncmp (p, infile_sans_info, infilelen_sans_info)
775 && (p[infilelen_sans_info] == ')'
776 || !strncmp (p + infilelen_sans_info, ".info)", 6)))
778 dir_lines[i].delete = 1;
779 something_deleted = 1;
783 /* Treat lines that start with whitespace
784 as continuations; if we are deleting an entry,
785 delete all its continuations as well. */
786 else if (i > 0
787 && (*dir_lines[i].start == ' '
788 || *dir_lines[i].start == '\t'))
790 dir_lines[i].delete = dir_lines[i - 1].delete;
791 something_deleted = 1;
795 /* Finish the info about the end of the last node. */
796 if (dir_nodes != 0)
798 dir_nodes->end_line = dir_nlines;
799 if (dir_nodes->last_section != 0)
800 dir_nodes->last_section->end_line = dir_nlines;
803 /* Decide where to add the new entries (unless --delete was used).
804 Find the menu sections to add them in.
805 In each section, find the proper alphabetical place to add
806 each of the entries. */
808 if (!delete_flag)
810 struct node *node;
811 struct menu_section *section;
812 struct spec_section *spec;
814 for (node = dir_nodes; node; node = node->next)
815 for (section = node->sections; section; section = section->next)
817 for (i = section->end_line; i > section->start_line; i--)
818 if (dir_lines[i - 1].size != 0)
819 break;
820 section->end_line = i;
822 for (spec = input_sections; spec; spec = spec->next)
823 if (!strcmp (spec->name, section->name))
824 break;
825 if (spec)
827 int add_at_line = section->end_line;
828 struct spec_entry *entry;
829 /* Say we have found at least one section with this name,
830 so we need not add such a section. */
831 spec->missing = 0;
832 /* For each entry, find the right place in this section
833 to add it. */
834 for (entry = entries_to_add; entry; entry = entry->next)
836 int textlen = strlen (entry->text);
837 /* Subtract one because dir_lines is zero-based,
838 but the `end_line' and `start_line' members are
839 one-based. */
840 for (i = section->end_line - 1;
841 i >= section->start_line - 1; i--)
843 /* If an entry exists with the same name,
844 and was not marked for deletion
845 (which means it is for some other file),
846 we are in trouble. */
847 if (dir_lines[i].start[0] == '*'
848 && menu_line_equal (entry->text, textlen,
849 dir_lines[i].start,
850 dir_lines[i].size)
851 && !dir_lines[i].delete)
852 fatal (_("menu item `%s' already exists, for file `%s'"),
853 extract_menu_item_name (entry->text),
854 extract_menu_file_name (dir_lines[i].start));
855 if (dir_lines[i].start[0] == '*'
856 && menu_line_lessp (entry->text, textlen,
857 dir_lines[i].start,
858 dir_lines[i].size))
859 add_at_line = i;
861 insert_entry_here (entry, add_at_line,
862 dir_lines, n_entries_to_add);
867 /* Mark the end of the Top node as the place to add any
868 new sections that are needed. */
869 for (node = dir_nodes; node; node = node->next)
870 if (node->name && strcmp (node->name, "Top") == 0)
871 dir_lines[node->end_line].add_sections_before = 1;
874 if (delete_flag && !something_deleted && !quiet_flag)
875 warning (_("no entries found for `%s'; nothing deleted"), infile);
877 /* Output the old dir file, interpolating the new sections
878 and/or new entries where appropriate. */
880 output = fopen (dirfile, "w");
881 if (!output)
883 perror (dirfile);
884 exit (1);
887 for (i = 0; i <= dir_nlines; i++)
889 int j;
891 /* If we decided to output some new entries before this line,
892 output them now. */
893 if (dir_lines[i].add_entries_before)
894 for (j = 0; j < n_entries_to_add; j++)
896 struct spec_entry *this = dir_lines[i].add_entries_before[j];
897 if (this == 0)
898 break;
899 fputs (this->text, output);
901 /* If we decided to add some sections here
902 because there are no such sections in the file,
903 output them now. */
904 if (dir_lines[i].add_sections_before)
906 struct spec_section *spec;
907 struct spec_section **sections;
908 int n_sections = 0;
910 /* Count the sections and allocate a vector for all of them. */
911 for (spec = input_sections; spec; spec = spec->next)
912 n_sections++;
913 sections = ((struct spec_section **)
914 xmalloc (n_sections * sizeof (struct spec_section *)));
916 /* Fill the vector SECTIONS with pointers to all the sections,
917 and sort them. */
918 j = 0;
919 for (spec = input_sections; spec; spec = spec->next)
920 sections[j++] = spec;
921 qsort (sections, n_sections, sizeof (struct spec_section *),
922 compare_section_names);
924 /* Generate the new sections in alphabetical order.
925 In each new section, output all of our entries. */
926 for (j = 0; j < n_sections; j++)
928 spec = sections[j];
929 if (spec->missing)
931 struct spec_entry *entry;
933 putc ('\n', output);
934 fputs (spec->name, output);
935 putc ('\n', output);
936 for (entry = entries_to_add; entry; entry = entry->next)
937 fputs (entry->text, output);
941 free (sections);
944 /* Output the original dir lines unless marked for deletion. */
945 if (i < dir_nlines && !dir_lines[i].delete)
947 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
948 putc ('\n', output);
952 fclose (output);
954 exit (0);
957 /* Read all of file FILNAME into memory
958 and return the address of the data.
959 Store the size into SIZEP.
960 If there is trouble, do a fatal error. */
962 char *
963 readfile (filename, sizep)
964 char *filename;
965 int *sizep;
967 int desc;
968 int data_size = 1024;
969 char *data = (char *) xmalloc (data_size);
970 int filled = 0;
971 int nread = 0;
972 #ifdef HAVE_LIBZ
973 int isGZ = 0;
974 gzFile zdesc;
975 #endif
977 desc = open (filename, O_RDONLY);
978 if (desc < 0)
979 pfatal_with_name (filename);
981 #ifdef HAVE_LIBZ
982 /* The file should always be two bytes long. */
983 if (read (desc, data, 2) != 2)
984 pfatal_with_name (filename);
986 /* Undo that read. */
987 lseek (desc, 0, SEEK_SET);
989 /* If we see gzip magic, use gzdopen. */
990 if (data[0] == '\x1f' && data[1] == '\x8b')
992 isGZ = 1;
993 zdesc = gzdopen (desc, "r");
994 if (zdesc == NULL) {
995 close (desc);
996 pfatal_with_name (filename);
999 #endif /* HAVE_LIBZ */
1001 while (1)
1003 #ifdef HAVE_LIBZ
1004 if (isGZ)
1005 nread = gzread (zdesc, data + filled, data_size - filled);
1006 else
1007 #endif
1008 nread = read (desc, data + filled, data_size - filled);
1010 if (nread < 0)
1011 pfatal_with_name (filename);
1012 if (nread == 0)
1013 break;
1015 filled += nread;
1016 if (filled == data_size)
1018 data_size *= 2;
1019 data = (char *) xrealloc (data, data_size);
1023 *sizep = filled;
1025 #ifdef HAVE_LIBZ
1026 if (isGZ)
1027 gzclose (zdesc);
1028 else
1029 #endif
1030 close(desc);
1032 return data;
1035 /* Divide the text at DATA (of SIZE bytes) into lines.
1036 Return a vector of struct line_data describing the lines.
1037 Store the length of that vector into *NLINESP. */
1039 struct line_data *
1040 findlines (data, size, nlinesp)
1041 char *data;
1042 int size;
1043 int *nlinesp;
1045 struct line_data *lines;
1046 int lines_allocated = 512;
1047 int filled = 0;
1048 int i = 0;
1049 int lineflag;
1051 lines = (struct line_data *) xmalloc (lines_allocated * sizeof (struct line_data));
1053 lineflag = 1;
1054 for (i = 0; i < size; i++)
1056 if (lineflag)
1058 if (filled == lines_allocated)
1060 lines_allocated *= 2;
1061 lines = (struct line_data *) xrealloc (lines, lines_allocated * sizeof (struct line_data));
1063 lines[filled].start = &data[i];
1064 lines[filled].add_entries_before = 0;
1065 lines[filled].add_sections_before = 0;
1066 lines[filled].delete = 0;
1067 if (filled > 0)
1068 lines[filled - 1].size
1069 = lines[filled].start - lines[filled - 1].start - 1;
1070 filled++;
1072 lineflag = (data[i] == '\n');
1074 if (filled > 0)
1075 lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
1077 /* Do not leave garbage in the last element. */
1078 lines[filled].start = NULL;
1079 lines[filled].add_entries_before = NULL;
1080 lines[filled].add_sections_before = 0;
1081 lines[filled].delete = 0;
1082 lines[filled].size = 0;
1084 *nlinesp = filled;
1085 return lines;
1088 /* Compare the menu item names in LINE1 (line length LEN1)
1089 and LINE2 (line length LEN2). Return 1 if the item name
1090 in LINE1 is less, 0 otherwise. */
1093 menu_line_lessp (line1, len1, line2, len2)
1094 char *line1;
1095 int len1;
1096 char *line2;
1097 int len2;
1099 int minlen = (len1 < len2 ? len1 : len2);
1100 int i;
1102 for (i = 0; i < minlen; i++)
1104 /* If one item name is a prefix of the other,
1105 the former one is less. */
1106 if (line1[i] == ':' && line2[i] != ':')
1107 return 1;
1108 if (line2[i] == ':' && line1[i] != ':')
1109 return 0;
1110 /* If they both continue and differ, one is less. */
1111 if (line1[i] < line2[i])
1112 return 1;
1113 if (line1[i] > line2[i])
1114 return 0;
1116 /* With a properly formatted dir file,
1117 we can only get here if the item names are equal. */
1118 return 0;
1121 /* Compare the menu item names in LINE1 (line length LEN1)
1122 and LINE2 (line length LEN2). Return 1 if the item names are equal,
1123 0 otherwise. */
1126 menu_line_equal (line1, len1, line2, len2)
1127 char *line1;
1128 int len1;
1129 char *line2;
1130 int len2;
1132 int minlen = (len1 < len2 ? len1 : len2);
1133 int i;
1135 for (i = 0; i < minlen; i++)
1137 /* If both item names end here, they are equal. */
1138 if (line1[i] == ':' && line2[i] == ':')
1139 return 1;
1140 /* If they both continue and differ, one is less. */
1141 if (line1[i] != line2[i])
1142 return 0;
1144 /* With a properly formatted dir file,
1145 we can only get here if the item names are equal. */
1146 return 1;
1149 /* This is the comparison function for qsort
1150 for a vector of pointers to struct spec_section.
1151 Compare the section names. */
1154 compare_section_names (sec1, sec2)
1155 struct spec_section **sec1, **sec2;
1157 char *name1 = (*sec1)->name;
1158 char *name2 = (*sec2)->name;
1159 return strcmp (name1, name2);
1162 /* Insert ENTRY into the add_entries_before vector
1163 for line number LINE_NUMBER of the dir file.
1164 DIR_LINES and N_ENTRIES carry information from like-named variables
1165 in main. */
1167 void
1168 insert_entry_here (entry, line_number, dir_lines, n_entries)
1169 struct spec_entry *entry;
1170 int line_number;
1171 struct line_data *dir_lines;
1172 int n_entries;
1174 int i;
1176 if (dir_lines[line_number].add_entries_before == 0)
1178 dir_lines[line_number].add_entries_before
1179 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1180 for (i = 0; i < n_entries; i++)
1181 dir_lines[line_number].add_entries_before[i] = 0;
1184 for (i = 0; i < n_entries; i++)
1185 if (dir_lines[line_number].add_entries_before[i] == 0)
1186 break;
1188 if (i == n_entries)
1189 abort ();
1191 dir_lines[line_number].add_entries_before[i] = entry;