Deleted Added
full compact
install-info.c (43579) install-info.c (56165)
1/* install-info -- create Info directory entry(ies) for an Info file.
1/* install-info -- create Info directory entry(ies) for an Info file.
2 $Id: install-info.c,v 1.21 1998/03/01 15:38:45 karl Exp $
2 $Id: install-info.c,v 1.48 1999/08/06 18:13:32 karl Exp $
3 $FreeBSD: head/contrib/texinfo/util/install-info.c 56165 2000-01-17 10:50:35Z ru $
3
4
4 Copyright (C) 1996, 97, 98 Free Software Foundation, Inc.
5 Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
5
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.
10
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.
15
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.*/
19
20#include "system.h"
21#include <getopt.h>
22
6
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 2 of the License, or
10 (at your option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
20
21#include "system.h"
22#include <getopt.h>
23
23#ifdef HAVE_LIBZ
24#include <zlib.h>
25#endif
24static char *progname = "install-info";
25static char *default_section = NULL;
26
26
27/* Name this program was invoked with. */
28char *progname;
29
30char *readfile ();
31struct line_data *findlines ();
27struct line_data *findlines ();
32void fatal ();
33void insert_entry_here ();
28void insert_entry_here ();
34int compare_section_names ();
29int compare_section_names (), compare_entries_text ();
35
36struct spec_entry;
37
38/* Data structures. */
39
40
41/* Record info about a single line from a file as read into core. */
42struct line_data

--- 25 unchanged lines hidden (view full) ---

68};
69
70
71/* This is used for a list of the entries specified to be added. */
72struct spec_entry
73{
74 struct spec_entry *next;
75 char *text;
30
31struct spec_entry;
32
33/* Data structures. */
34
35
36/* Record info about a single line from a file as read into core. */
37struct line_data

--- 25 unchanged lines hidden (view full) ---

63};
64
65
66/* This is used for a list of the entries specified to be added. */
67struct spec_entry
68{
69 struct spec_entry *next;
70 char *text;
71 int text_len;
72 /* A pointer to the list of sections to which this entry should be
73 added. */
74 struct spec_section *entry_sections;
75 /* A pointer to a section that is beyond the end of the chain whose
76 head is pointed to by entry_sections. */
77 struct spec_section *entry_sections_tail;
76};
77
78
79/* This is used for a list of nodes found by parsing the dir file. */
80struct node
81{
82 struct node *next;
83 /* The node name. */

--- 21 unchanged lines hidden (view full) ---

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;
111};
112
78};
79
80
81/* This is used for a list of nodes found by parsing the dir file. */
82struct node
83{
84 struct node *next;
85 /* The node name. */

--- 21 unchanged lines hidden (view full) ---

107 struct menu_section *next;
108 char *name;
109 /* Line number of start of section. */
110 int start_line;
111 /* Line number of end of section. */
112 int end_line;
113};
114
115/* This table defines all the long-named options, says whether they
116 use an argument, and maps them into equivalent single-letter options. */
117
118struct option longopts[] =
119{
120 { "delete", no_argument, NULL, 'r' },
121 { "defentry", required_argument, NULL, 'E' },
122 { "defsection", required_argument, NULL, 'S' },
123 { "dir-file", required_argument, NULL, 'd' },
124 { "entry", required_argument, NULL, 'e' },
125 { "help", no_argument, NULL, 'h' },
126 { "info-dir", required_argument, NULL, 'D' },
127 { "info-file", required_argument, NULL, 'i' },
128 { "item", required_argument, NULL, 'e' },
129 { "quiet", no_argument, NULL, 'q' },
130 { "remove", no_argument, NULL, 'r' },
131 { "section", required_argument, NULL, 's' },
132 { "version", no_argument, NULL, 'V' },
133 { 0 }
134};
135
136/* Error message functions. */
137
138/* Print error message. S1 is printf control string, S2 and S3 args for it. */
139
140/* VARARGS1 */
141void
142error (s1, s2, s3)
143 char *s1, *s2, *s3;
144{
145 fprintf (stderr, "%s: ", progname);
146 fprintf (stderr, s1, s2, s3);
147 putc ('\n', stderr);
148}
149
150/* VARARGS1 */
151void
152warning (s1, s2, s3)
153 char *s1, *s2, *s3;
154{
155 fprintf (stderr, _("%s: warning: "), progname);
156 fprintf (stderr, s1, s2, s3);
157 putc ('\n', stderr);
158}
159
160/* Print error message and exit. */
161
162void
163fatal (s1, s2, s3)
164 char *s1, *s2, *s3;
165{
166 error (s1, s2, s3);
167 xexit (1);
168}
169
113/* Memory allocation and string operations. */
114
115/* Like malloc but get fatal error if memory is exhausted. */
116void *
117xmalloc (size)
118 unsigned int size;
119{
120 extern void *malloc ();

--- 43 unchanged lines hidden (view full) ---

164{
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;
171}
170/* Memory allocation and string operations. */
171
172/* Like malloc but get fatal error if memory is exhausted. */
173void *
174xmalloc (size)
175 unsigned int size;
176{
177 extern void *malloc ();

--- 43 unchanged lines hidden (view full) ---

221{
222 int i;
223 char *copy = (char *) xmalloc (size + 1);
224 for (i = 0; i < size; i++)
225 copy[i] = string[i];
226 copy[size] = 0;
227 return copy;
228}
172
173/* Error message functions. */
174
229
175/* Print error message. S1 is printf control string, S2 and S3 args for it. */
176
177/* VARARGS1 */
178void
179error (s1, s2, s3)
180 char *s1, *s2, *s3;
181{
182 fprintf (stderr, "%s: ", progname);
183 fprintf (stderr, s1, s2, s3);
184 putc ('\n', stderr);
185}
186
187/* VARARGS1 */
188void
189warning (s1, s2, s3)
190 char *s1, *s2, *s3;
191{
192 fprintf (stderr, _("%s: warning: "), progname);
193 fprintf (stderr, s1, s2, s3);
194 putc ('\n', stderr);
195}
196
197/* Print error message and exit. */
198
199void
200fatal (s1, s2, s3)
201 char *s1, *s2, *s3;
202{
203 error (s1, s2, s3);
204 exit (1);
205}
206
207/* Print fatal error message based on errno, with file name NAME. */
208
209void
210pfatal_with_name (name)
211 char *name;
212{
213 char *s = concat ("", strerror (errno), _(" for %s"));
214 fatal (s, name);

--- 55 unchanged lines hidden (view full) ---

270
271 /* File name ends just before the close-paren. */
272 while (*p && *p != '\n' && *p != ')') p++;
273 if (*p != ')')
274 return "(none)";
275
276 return copy_string (item_text, p - item_text);
277}
230/* Print fatal error message based on errno, with file name NAME. */
231
232void
233pfatal_with_name (name)
234 char *name;
235{
236 char *s = concat ("", strerror (errno), _(" for %s"));
237 fatal (s, name);

--- 55 unchanged lines hidden (view full) ---

293
294 /* File name ends just before the close-paren. */
295 while (*p && *p != '\n' && *p != ')') p++;
296 if (*p != ')')
297 return "(none)";
298
299 return copy_string (item_text, p - item_text);
300}
301
302
278
303
304/* Return FNAME with any [.info][.gz] suffix removed. */
305
306static char *
307strip_info_suffix (fname)
308 char *fname;
309{
310 char *ret = xstrdup (fname);
311 unsigned len = strlen (ret);
312
313 if (len > 3 && FILENAME_CMP (ret + len - 3, ".gz") == 0)
314 {
315 len -= 3;
316 ret[len] = 0;
317 }
318
319 if (len > 5 && FILENAME_CMP (ret + len - 5, ".info") == 0)
320 {
321 len -= 5;
322 ret[len] = 0;
323 }
324 else if (len > 4 && FILENAME_CMP (ret + len - 4, ".inf") == 0)
325 {
326 len -= 4;
327 ret[len] = 0;
328 }
329#ifdef __MSDOS__
330 else if (len > 4 && (FILENAME_CMP (ret + len - 4, ".inz") == 0
331 || FILENAME_CMP (ret + len - 4, ".igz") == 0))
332 {
333 len -= 4;
334 ret[len] = 0;
335 }
336#endif /* __MSDOS__ */
337
338 return ret;
339}
340
341
342/* Return true if ITEM matches NAME and is followed by TERM_CHAR. ITEM
343 can also be followed by `.gz', `.info.gz', or `.info' (and then
344 TERM_CHAR) and still match. */
345
346static int
347menu_item_equal (item, term_char, name)
348 char *item;
349 char term_char;
350 char *name;
351{
352 unsigned name_len = strlen (name);
353 /* First, ITEM must actually match NAME (usually it won't). */
354 int ret = strncasecmp (item, name, name_len) == 0;
355 if (ret)
356 {
357 /* Then, `foobar' doesn't match `foo', so be sure we've got all of
358 ITEM. The various suffixes should never actually appear in the
359 dir file, but sometimes people put them in. */
360 static char *suffixes[]
361 = { "", ".info.gz", ".info", ".inf", ".gz",
362#ifdef __MSDOS__
363 ".inz", ".igz",
364#endif
365 NULL };
366 unsigned i;
367 ret = 0;
368 for (i = 0; !ret && suffixes[i]; i++)
369 {
370 char *suffix = suffixes[i];
371 unsigned suffix_len = strlen (suffix);
372 ret = strncasecmp (item + name_len, suffix, suffix_len) == 0
373 && item[name_len + suffix_len] == term_char;
374 }
375 }
376
377 return ret;
378}
379
380
381
279void
280suggest_asking_for_help ()
281{
282 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
283 progname);
382void
383suggest_asking_for_help ()
384{
385 fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
386 progname);
284 exit (1);
387 xexit (1);
285}
286
287void
288print_help ()
289{
290 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
291\n\
388}
389
390void
391print_help ()
392{
393 printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
394\n\
292Install INFO-FILE in the Info directory file DIR-FILE.\n\
395Install or delete dir entries from INFO-FILE in the Info directory file\n\
396DIR-FILE.\n\
293\n\
294Options:\n\
397\n\
398Options:\n\
295--delete Delete existing entries in INFO-FILE;\n\
296 don't insert any new entries.\n\
297--defentry=TEXT Like --entry, but only use TEXT if an entry\n\
298 is not present in INFO-FILE.\n\
299--defsection=TEXT Like --section, but only use TEXT if a section\n\
300 is not present in INFO-FILE.\n\
301--dir-file=NAME Specify file name of Info directory file.\n\
302 This is equivalent to using the DIR-FILE argument.\n\
303--entry=TEXT Insert TEXT as an Info directory entry.\n\
304 TEXT should have the form of an Info menu item line\n\
305 plus zero or more extra lines starting with whitespace.\n\
306 If you specify more than one entry, they are all added.\n\
307 If you don't specify any entries, they are determined\n\
308 from information in the Info file itself.\n\
309--forceentry=TEXT Like --entry, but ignore any entry in INFO-FILE.\n\
310--help Display this help and exit.\n\
311--info-file=FILE Specify Info file to install in the directory.\n\
312 This is equivalent to using the INFO-FILE argument.\n\
313--info-dir=DIR Same as --dir-file=DIR/dir.\n\
314--item=TEXT Same as --entry TEXT.\n\
315 An Info directory entry is actually a menu item.\n\
316--quiet Suppress warnings.\n\
317--remove Same as --delete.\n\
318--section=SEC Put this file's entries in section SEC of the directory.\n\
319 If you specify more than one section, all the entries\n\
320 are added in each of the sections.\n\
321 If you don't specify any sections, they are determined\n\
322 from information in the Info file itself.\n\
323--version Display version information and exit.\n\
399 --delete delete existing entries for INFO-FILE from DIR-FILE;\n\
400 don't insert any new entries.\n\
401 --defentry=TEXT like --entry, but only use TEXT if an entry\n\
402 is not present in INFO-FILE.\n\
403 --defsection=TEXT like --section, but only use TEXT if a section\n\
404 is not present in INFO-FILE.\n\
405 --dir-file=NAME specify file name of Info directory file.\n\
406 This is equivalent to using the DIR-FILE argument.\n\
407 --entry=TEXT insert TEXT as an Info directory entry.\n\
408 TEXT should have the form of an Info menu item line\n\
409 plus zero or more extra lines starting with whitespace.\n\
410 If you specify more than one entry, they are all added.\n\
411 If you don't specify any entries, they are determined\n\
412 from information in the Info file itself.\n\
413 --help display this help and exit.\n\
414 --info-file=FILE specify Info file to install in the directory.\n\
415 This is equivalent to using the INFO-FILE argument.\n\
416 --info-dir=DIR same as --dir-file=DIR/dir.\n\
417 --item=TEXT same as --entry TEXT.\n\
418 An Info directory entry is actually a menu item.\n\
419 --quiet suppress warnings.\n\
420 --remove same as --delete.\n\
421 --section=SEC put this file's entries in section SEC of the directory.\n\
422 If you specify more than one section, all the entries\n\
423 are added in each of the sections.\n\
424 If you don't specify any sections, they are determined\n\
425 from information in the Info file itself.\n\
426 --version display version information and exit.\n\
324\n\
427\n\
325Email bug reports to bug-texinfo@gnu.org.\n\
428Email bug reports to bug-texinfo@gnu.org,\n\
429general questions and discussion to help-texinfo@gnu.org.\n\
326"), progname);
327}
328
329
330/* If DIRFILE does not exist, create a minimal one (or abort). If it
331 already exists, do nothing. */
332
333void

--- 4 unchanged lines hidden (view full) ---

338 if (desc < 0 && errno == ENOENT)
339 {
340 FILE *f;
341 char *readerr = strerror (errno);
342 close (desc);
343 f = fopen (dirfile, "w");
344 if (f)
345 {
430"), progname);
431}
432
433
434/* If DIRFILE does not exist, create a minimal one (or abort). If it
435 already exists, do nothing. */
436
437void

--- 4 unchanged lines hidden (view full) ---

442 if (desc < 0 && errno == ENOENT)
443 {
444 FILE *f;
445 char *readerr = strerror (errno);
446 close (desc);
447 f = fopen (dirfile, "w");
448 if (f)
449 {
346 fputs (_("This is the file .../info/dir, which contains the\n\
450 fprintf (f, _("This is the file .../info/dir, which contains the\n\
347topmost node of the Info hierarchy, called (dir)Top.\n\
348The first time you invoke Info you start off looking at this node.\n\
349\n\
451topmost node of the Info hierarchy, called (dir)Top.\n\
452The first time you invoke Info you start off looking at this node.\n\
453\n\
350File: dir,\tNode: Top,\tThis is the top of the INFO tree\n\
454%s\tThis is the top of the INFO tree\n\
351\n\
352 This (the Directory node) gives a menu of major topics.\n\
353 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
354 \"h\" gives a primer for first-timers,\n\
355 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
356\n\
357 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
358 to select it.\n\
359\n\
360* Menu:\n\
455\n\
456 This (the Directory node) gives a menu of major topics.\n\
457 Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
458 \"h\" gives a primer for first-timers,\n\
459 \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
460\n\
461 In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
462 to select it.\n\
463\n\
464* Menu:\n\
361"), f);
465"), "File: dir,\tNode: Top"); /* This part must not be translated. */
362 if (fclose (f) < 0)
363 pfatal_with_name (dirfile);
364 }
365 else
366 {
367 /* Didn't exist, but couldn't open for writing. */
368 fprintf (stderr,
369 _("%s: could not read (%s) and could not create (%s)\n"),
370 dirfile, readerr, strerror (errno));
466 if (fclose (f) < 0)
467 pfatal_with_name (dirfile);
468 }
469 else
470 {
471 /* Didn't exist, but couldn't open for writing. */
472 fprintf (stderr,
473 _("%s: could not read (%s) and could not create (%s)\n"),
474 dirfile, readerr, strerror (errno));
371 exit (1);
475 xexit (1);
372 }
373 }
374 else
375 close (desc); /* It already existed, so fine. */
376}
377
476 }
477 }
478 else
479 close (desc); /* It already existed, so fine. */
480}
481
378/* This table defines all the long-named options, says whether they
379 use an argument, and maps them into equivalent single-letter options. */
482/* Open FILENAME and return the resulting stream pointer. If it doesn't
483 exist, try FILENAME.gz. If that doesn't exist either, call
484 CREATE_CALLBACK (with FILENAME as arg) to create it, if that is
485 non-NULL. If still no luck, fatal error.
380
486
381struct option longopts[] =
487 If we do open it, return the actual name of the file opened in
488 OPENED_FILENAME and the compress program to use to (de)compress it in
489 COMPRESSION_PROGRAM. The compression program is determined by the
490 magic number, not the filename. */
491
492FILE *
493open_possibly_compressed_file (filename, create_callback,
494 opened_filename, compression_program, is_pipe)
495 char *filename;
496 void (*create_callback) ();
497 char **opened_filename;
498 char **compression_program;
499 int *is_pipe;
382{
500{
383 { "delete", no_argument, NULL, 'r' },
384 { "defentry", required_argument, NULL, 'E' },
385 { "defsection", required_argument, NULL, 'S' },
386 { "dir-file", required_argument, NULL, 'd' },
387 { "entry", required_argument, NULL, 'e' },
388 { "forceentry", required_argument, NULL, 'f' },
389 { "help", no_argument, NULL, 'h' },
390 { "info-dir", required_argument, NULL, 'D' },
391 { "info-file", required_argument, NULL, 'i' },
392 { "item", required_argument, NULL, 'e' },
393 { "quiet", no_argument, NULL, 'q' },
394 { "remove", no_argument, NULL, 'r' },
395 { "section", required_argument, NULL, 's' },
396 { "version", no_argument, NULL, 'V' },
397 { 0 }
398};
501 char *local_opened_filename, *local_compression_program;
502 int nread;
503 char data[4];
504 FILE *f;
399
505
506 /* We let them pass NULL if they don't want this info, but it's easier
507 to always determine it. */
508 if (!opened_filename)
509 opened_filename = &local_opened_filename;
510
511 *opened_filename = filename;
512 f = fopen (*opened_filename, FOPEN_RBIN);
513 if (!f)
514 {
515 *opened_filename = concat (filename, ".gz", "");
516 f = fopen (*opened_filename, FOPEN_RBIN);
517#ifdef __MSDOS__
518 if (!f)
519 {
520 free (*opened_filename);
521 *opened_filename = concat (filename, ".igz", "");
522 f = fopen (*opened_filename, FOPEN_RBIN);
523 }
524 if (!f)
525 {
526 free (*opened_filename);
527 *opened_filename = concat (filename, ".inz", "");
528 f = fopen (*opened_filename, FOPEN_RBIN);
529 }
530#endif
531 if (!f)
532 {
533 if (create_callback)
534 { /* That didn't work either. Create the file if we can. */
535 (*create_callback) (filename);
536
537 /* And try opening it again. */
538 free (*opened_filename);
539 *opened_filename = filename;
540 f = fopen (*opened_filename, FOPEN_RBIN);
541 if (!f)
542 pfatal_with_name (filename);
543 }
544 else
545 pfatal_with_name (filename);
546 }
547 }
548
549 /* Read first few bytes of file rather than relying on the filename.
550 If the file is shorter than this it can't be usable anyway. */
551 nread = fread (data, sizeof (data), 1, f);
552 if (nread != 1)
553 {
554 /* Empty files don't set errno, so we get something like
555 "install-info: No error for foo", which is confusing. */
556 if (nread == 0)
557 fatal (_("%s: empty file"), *opened_filename);
558 pfatal_with_name (*opened_filename);
559 }
560
561 if (!compression_program)
562 compression_program = &local_compression_program;
563
564 if (data[0] == '\x1f' && data[1] == '\x8b')
565#if STRIP_DOT_EXE
566 /* An explicit .exe yields a better diagnostics from popen below
567 if they don't have gzip installed. */
568 *compression_program = "gzip.exe";
569#else
570 *compression_program = "gzip";
571#endif
572 else
573 *compression_program = NULL;
574
575 if (*compression_program)
576 { /* It's compressed, so fclose the file and then open a pipe. */
577 char *command = concat (*compression_program," -cd <", *opened_filename);
578 if (fclose (f) < 0)
579 pfatal_with_name (*opened_filename);
580 f = popen (command, "r");
581 if (f)
582 *is_pipe = 1;
583 else
584 pfatal_with_name (command);
585 }
586 else
587 { /* It's a plain file, seek back over the magic bytes. */
588 if (fseek (f, 0, 0) < 0)
589 pfatal_with_name (*opened_filename);
590#if O_BINARY
591 /* Since this is a text file, and we opened it in binary mode,
592 switch back to text mode. */
593 f = freopen (*opened_filename, "r", f);
594#endif
595 *is_pipe = 0;
596 }
597
598 return f;
599}
400
600
601/* Read all of file FILENAME into memory and return the address of the
602 data. Store the size of the data into SIZEP. If need be, uncompress
603 (i.e., try FILENAME.gz et al. if FILENAME does not exist) and store
604 the actual file name that was opened into OPENED_FILENAME (if it is
605 non-NULL), and the companion compression program (if any, else NULL)
606 into COMPRESSION_PROGRAM (if that is non-NULL). If trouble, do
607 a fatal error. */
608
609char *
610readfile (filename, sizep, create_callback,
611 opened_filename, compression_program)
612 char *filename;
613 int *sizep;
614 void (*create_callback) ();
615 char **opened_filename;
616 char **compression_program;
617{
618 char *real_name;
619 FILE *f;
620 int pipe_p;
621 int filled = 0;
622 int data_size = 8192;
623 char *data = xmalloc (data_size);
624
625 /* If they passed the space for the file name to return, use it. */
626 f = open_possibly_compressed_file (filename, create_callback,
627 opened_filename ? opened_filename
628 : &real_name,
629 compression_program, &pipe_p);
630
631 for (;;)
632 {
633 int nread = fread (data + filled, 1, data_size - filled, f);
634 if (nread < 0)
635 pfatal_with_name (real_name);
636 if (nread == 0)
637 break;
638
639 filled += nread;
640 if (filled == data_size)
641 {
642 data_size += 65536;
643 data = xrealloc (data, data_size);
644 }
645 }
646
647 /* We'll end up wasting space if we're not passing the filename back
648 and it is not just FILENAME, but so what. */
649 /* We need to close the stream, since on some systems the pipe created
650 by popen is simulated by a temporary file which only gets removed
651 inside pclose. */
652 if (pipe_p)
653 pclose (f);
654 else
655 fclose (f);
656
657 *sizep = filled;
658 return data;
659}
660
661/* Output the old dir file, interpolating the new sections
662 and/or new entries where appropriate. If COMPRESSION_PROGRAM is not
663 null, pipe to it to create DIRFILE. Thus if we read dir.gz on input,
664 we'll write dir.gz on output. */
665
666static void
667output_dirfile (dirfile, dir_nlines, dir_lines,
668 n_entries_to_add, entries_to_add, input_sections,
669 compression_program)
670 char *dirfile;
671 int dir_nlines;
672 struct line_data *dir_lines;
673 int n_entries_to_add;
674 struct spec_entry *entries_to_add;
675 struct spec_section *input_sections;
676 char *compression_program;
677{
678 int i;
679 FILE *output;
680
681 if (compression_program)
682 {
683 char *command = concat (compression_program, ">", dirfile);
684 output = popen (command, "w");
685 }
686 else
687 output = fopen (dirfile, "w");
688
689 if (!output)
690 {
691 perror (dirfile);
692 xexit (1);
693 }
694
695 for (i = 0; i <= dir_nlines; i++)
696 {
697 int j;
698
699 /* If we decided to output some new entries before this line,
700 output them now. */
701 if (dir_lines[i].add_entries_before)
702 for (j = 0; j < n_entries_to_add; j++)
703 {
704 struct spec_entry *this = dir_lines[i].add_entries_before[j];
705 if (this == 0)
706 break;
707 fputs (this->text, output);
708 }
709 /* If we decided to add some sections here
710 because there are no such sections in the file,
711 output them now. */
712 if (dir_lines[i].add_sections_before)
713 {
714 struct spec_section *spec;
715 struct spec_section **sections;
716 int n_sections = 0;
717 struct spec_entry *entry;
718 struct spec_entry **entries;
719 int n_entries = 0;
720
721 /* Count the sections and allocate a vector for all of them. */
722 for (spec = input_sections; spec; spec = spec->next)
723 n_sections++;
724 sections = ((struct spec_section **)
725 xmalloc (n_sections * sizeof (struct spec_section *)));
726
727 /* Fill the vector SECTIONS with pointers to all the sections,
728 and sort them. */
729 j = 0;
730 for (spec = input_sections; spec; spec = spec->next)
731 sections[j++] = spec;
732 qsort (sections, n_sections, sizeof (struct spec_section *),
733 compare_section_names);
734
735 /* Count the entries and allocate a vector for all of them. */
736 for (entry = entries_to_add; entry; entry = entry->next)
737 n_entries++;
738 entries = ((struct spec_entry **)
739 xmalloc (n_entries * sizeof (struct spec_entry *)));
740
741 /* Fill the vector ENTRIES with pointers to all the sections,
742 and sort them. */
743 j = 0;
744 for (entry = entries_to_add; entry; entry = entry->next)
745 entries[j++] = entry;
746 qsort (entries, n_entries, sizeof (struct spec_entry *),
747 compare_entries_text);
748
749 /* Generate the new sections in alphabetical order. In each
750 new section, output all of the entries that belong to that
751 section, in alphabetical order. */
752 for (j = 0; j < n_sections; j++)
753 {
754 spec = sections[j];
755 if (spec->missing)
756 {
757 int k;
758
759 putc ('\n', output);
760 fputs (spec->name, output);
761 putc ('\n', output);
762 for (k = 0; k < n_entries; k++)
763 {
764 struct spec_section *spec1;
765 /* Did they at all want this entry to be put into
766 this section? */
767 entry = entries[k];
768 for (spec1 = entry->entry_sections;
769 spec1 && spec1 != entry->entry_sections_tail;
770 spec1 = spec1->next)
771 {
772 if (!strcmp (spec1->name, spec->name))
773 break;
774 }
775 if (spec1 && spec1 != entry->entry_sections_tail)
776 fputs (entry->text, output);
777 }
778 }
779 }
780
781 free (entries);
782 free (sections);
783 }
784
785 /* Output the original dir lines unless marked for deletion. */
786 if (i < dir_nlines && !dir_lines[i].delete)
787 {
788 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
789 putc ('\n', output);
790 }
791 }
792
793 /* Some systems, such as MS-DOS, simulate pipes with temporary files.
794 On those systems, the compressor actually gets run inside pclose,
795 so we must call pclose. */
796 if (compression_program)
797 pclose (output);
798 else
799 fclose (output);
800}
801
802/* Parse the input to find the section names and the entry names it
803 specifies. Return the number of entries to add from this file. */
401int
804int
805parse_input (lines, nlines, sections, entries)
806 const struct line_data *lines;
807 int nlines;
808 struct spec_section **sections;
809 struct spec_entry **entries;
810{
811 int n_entries = 0;
812 int prefix_length = strlen ("INFO-DIR-SECTION ");
813 struct spec_section *head = *sections, *tail = NULL;
814 int reset_tail = 0;
815 char *start_of_this_entry = 0;
816 int ignore_sections = *sections != 0;
817 int ignore_entries = *entries != 0;
818
819 int i;
820
821 if (ignore_sections && ignore_entries)
822 return 0;
823
824 /* Loop here processing lines from the input file. Each
825 INFO-DIR-SECTION entry is added to the SECTIONS linked list.
826 Each START-INFO-DIR-ENTRY block is added to the ENTRIES linked
827 list, and all its entries inherit the chain of SECTION entries
828 defined by the last group of INFO-DIR-SECTION entries we have
829 seen until that point. */
830 for (i = 0; i < nlines; i++)
831 {
832 if (!ignore_sections
833 && !strncmp ("INFO-DIR-SECTION ", lines[i].start, prefix_length))
834 {
835 struct spec_section *next
836 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
837 next->name = copy_string (lines[i].start + prefix_length,
838 lines[i].size - prefix_length);
839 next->next = *sections;
840 next->missing = 1;
841 if (reset_tail)
842 {
843 tail = *sections;
844 reset_tail = 0;
845 }
846 *sections = next;
847 head = *sections;
848 }
849 /* If entries were specified explicitly with command options,
850 ignore the entries in the input file. */
851 else if (!ignore_entries)
852 {
853 if (!strncmp ("START-INFO-DIR-ENTRY", lines[i].start, lines[i].size)
854 && sizeof ("START-INFO-DIR-ENTRY") - 1 == lines[i].size)
855 {
856 if (!*sections)
857 {
858 /* We found an entry, but didn't yet see any sections
859 specified. Default to section "Miscellaneous". */
860 *sections = (struct spec_section *)
861 xmalloc (sizeof (struct spec_section));
862 (*sections)->name =
863 default_section ? default_section : "Miscellaneous";
864 (*sections)->next = 0;
865 (*sections)->missing = 1;
866 head = *sections;
867 }
868 /* Next time we see INFO-DIR-SECTION, we will reset the
869 tail pointer. */
870 reset_tail = 1;
871
872 if (start_of_this_entry != 0)
873 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
874 start_of_this_entry = lines[i + 1].start;
875 }
876 else if (start_of_this_entry)
877 {
878 if ((!strncmp ("* ", lines[i].start, 2)
879 && lines[i].start > start_of_this_entry)
880 || (!strncmp ("END-INFO-DIR-ENTRY",
881 lines[i].start, lines[i].size)
882 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size))
883 {
884 /* We found an end of this entry. Allocate another
885 entry, fill its data, and add it to the linked
886 list. */
887 struct spec_entry *next
888 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
889 next->text
890 = copy_string (start_of_this_entry,
891 lines[i].start - start_of_this_entry);
892 next->text_len = lines[i].start - start_of_this_entry;
893 next->entry_sections = head;
894 next->entry_sections_tail = tail;
895 next->next = *entries;
896 *entries = next;
897 n_entries++;
898 if (!strncmp ("END-INFO-DIR-ENTRY",
899 lines[i].start, lines[i].size)
900 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
901 start_of_this_entry = 0;
902 else
903 start_of_this_entry = lines[i].start;
904 }
905 else if (!strncmp ("END-INFO-DIR-ENTRY",
906 lines[i].start, lines[i].size)
907 && sizeof ("END-INFO-DIR-ENTRY") - 1 == lines[i].size)
908 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"));
909 }
910 }
911 }
912 if (start_of_this_entry != 0)
913 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
914
915 /* If we ignored the INFO-DIR-ENTRY directives, we need now go back
916 and plug the names of all the sections we found into every
917 element of the ENTRIES list. */
918 if (ignore_entries && *entries)
919 {
920 struct spec_entry *entry;
921
922 for (entry = *entries; entry; entry = entry->next)
923 {
924 entry->entry_sections = head;
925 entry->entry_sections_tail = tail;
926 }
927 }
928
929 return n_entries;
930}
931
932/* Parse the dir file whose basename is BASE_NAME. Find all the
933 nodes, and their menus, and the sections of their menus. */
934int
935parse_dir_file (lines, nlines, nodes, base_name)
936 struct line_data *lines;
937 int nlines;
938 struct node **nodes;
939 const char *base_name;
940{
941 int node_header_flag = 0;
942 int something_deleted = 0;
943 int i;
944
945 *nodes = 0;
946 for (i = 0; i < nlines; i++)
947 {
948 /* Parse node header lines. */
949 if (node_header_flag)
950 {
951 int j, end;
952 for (j = 0; j < lines[i].size; j++)
953 /* Find the node name and store it in the `struct node'. */
954 if (!strncmp ("Node:", lines[i].start + j, 5))
955 {
956 char *line = lines[i].start;
957 /* Find the start of the node name. */
958 j += 5;
959 while (line[j] == ' ' || line[j] == '\t')
960 j++;
961 /* Find the end of the node name. */
962 end = j;
963 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
964 && line[end] != '\t')
965 end++;
966 (*nodes)->name = copy_string (line + j, end - j);
967 }
968 node_header_flag = 0;
969 }
970
971 /* Notice the start of a node. */
972 if (*lines[i].start == 037)
973 {
974 struct node *next = (struct node *) xmalloc (sizeof (struct node));
975
976 next->next = *nodes;
977 next->name = NULL;
978 next->start_line = i;
979 next->end_line = 0;
980 next->menu_start = NULL;
981 next->sections = NULL;
982 next->last_section = NULL;
983
984 if (*nodes != 0)
985 (*nodes)->end_line = i;
986 /* Fill in the end of the last menu section
987 of the previous node. */
988 if (*nodes != 0 && (*nodes)->last_section != 0)
989 (*nodes)->last_section->end_line = i;
990
991 *nodes = next;
992
993 /* The following line is the header of this node;
994 parse it. */
995 node_header_flag = 1;
996 }
997
998 /* Notice the lines that start menus. */
999 if (*nodes != 0 && !strncmp ("* Menu:", lines[i].start, 7))
1000 (*nodes)->menu_start = lines[i + 1].start;
1001
1002 /* Notice sections in menus. */
1003 if (*nodes != 0
1004 && (*nodes)->menu_start != 0
1005 && *lines[i].start != '\n'
1006 && *lines[i].start != '*'
1007 && *lines[i].start != ' '
1008 && *lines[i].start != '\t')
1009 {
1010 /* Add this menu section to the node's list.
1011 This list grows in forward order. */
1012 struct menu_section *next
1013 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
1014
1015 next->start_line = i + 1;
1016 next->next = 0;
1017 next->end_line = 0;
1018 next->name = copy_string (lines[i].start, lines[i].size);
1019 if ((*nodes)->sections)
1020 {
1021 (*nodes)->last_section->next = next;
1022 (*nodes)->last_section->end_line = i;
1023 }
1024 else
1025 (*nodes)->sections = next;
1026 (*nodes)->last_section = next;
1027 }
1028
1029 /* Check for an existing entry that should be deleted.
1030 Delete all entries which specify this file name. */
1031 if (*lines[i].start == '*')
1032 {
1033 char *q;
1034 char *p = lines[i].start;
1035
1036 p++; /* skip * */
1037 while (*p == ' ') p++; /* ignore following spaces */
1038 q = p; /* remember this, it's the beginning of the menu item. */
1039
1040 /* Read menu item. */
1041 while (*p != 0 && *p != ':')
1042 p++;
1043 p++; /* skip : */
1044
1045 if (*p == ':')
1046 { /* XEmacs-style entry, as in * Mew::Messaging. */
1047 if (menu_item_equal (q, ':', base_name))
1048 {
1049 lines[i].delete = 1;
1050 something_deleted = 1;
1051 }
1052 }
1053 else
1054 { /* Emacs-style entry, as in * Emacs: (emacs). */
1055 while (*p == ' ') p++; /* skip spaces after : */
1056 if (*p == '(') /* if at parenthesized (FILENAME) */
1057 {
1058 p++;
1059 if (menu_item_equal (p, ')', base_name))
1060 {
1061 lines[i].delete = 1;
1062 something_deleted = 1;
1063 }
1064 }
1065 }
1066 }
1067
1068 /* Treat lines that start with whitespace
1069 as continuations; if we are deleting an entry,
1070 delete all its continuations as well. */
1071 else if (i > 0 && (*lines[i].start == ' ' || *lines[i].start == '\t'))
1072 {
1073 lines[i].delete = lines[i - 1].delete;
1074 }
1075 }
1076
1077 /* Finish the info about the end of the last node. */
1078 if (*nodes != 0)
1079 {
1080 (*nodes)->end_line = nlines;
1081 if ((*nodes)->last_section != 0)
1082 (*nodes)->last_section->end_line = nlines;
1083 }
1084
1085 return something_deleted;
1086}
1087
1088int
402main (argc, argv)
403 int argc;
404 char **argv;
405{
1089main (argc, argv)
1090 int argc;
1091 char **argv;
1092{
406 char *infile = 0, *dirfile = 0;
1093 char *opened_dirfilename;
1094 char *compression_program;
407 char *infile_sans_info;
1095 char *infile_sans_info;
1096 char *infile = 0, *dirfile = 0;
408 unsigned infilelen_sans_info;
1097 unsigned infilelen_sans_info;
409 FILE *output;
410
411 /* Record the text of the Info file, as a sequence of characters
412 and as a sequence of lines. */
1098
1099 /* Record the text of the Info file, as a sequence of characters
1100 and as a sequence of lines. */
413 char *input_data;
414 int input_size;
415 struct line_data *input_lines;
416 int input_nlines;
1101 char *input_data = NULL;
1102 int input_size = 0;
1103 struct line_data *input_lines = NULL;
1104 int input_nlines = 0;
417
418 /* Record here the specified section names and directory entries. */
419 struct spec_section *input_sections = NULL;
420 struct spec_entry *entries_to_add = NULL;
421 int n_entries_to_add = 0;
1105
1106 /* Record here the specified section names and directory entries. */
1107 struct spec_section *input_sections = NULL;
1108 struct spec_entry *entries_to_add = NULL;
1109 int n_entries_to_add = 0;
1110 struct spec_entry *default_entries_to_add = NULL;
1111 int n_default_entries_to_add = 0;
422
423 /* Record the old text of the dir file, as plain characters,
424 as lines, and as nodes. */
425 char *dir_data;
426 int dir_size;
427 int dir_nlines;
428 struct line_data *dir_lines;
429 struct node *dir_nodes;
430
431 /* Nonzero means --delete was specified (just delete existing entries). */
432 int delete_flag = 0;
433 int something_deleted = 0;
434 /* Nonzero means -q was specified. */
435 int quiet_flag = 0;
436
1112
1113 /* Record the old text of the dir file, as plain characters,
1114 as lines, and as nodes. */
1115 char *dir_data;
1116 int dir_size;
1117 int dir_nlines;
1118 struct line_data *dir_lines;
1119 struct node *dir_nodes;
1120
1121 /* Nonzero means --delete was specified (just delete existing entries). */
1122 int delete_flag = 0;
1123 int something_deleted = 0;
1124 /* Nonzero means -q was specified. */
1125 int quiet_flag = 0;
1126
437 int node_header_flag;
438 int prefix_length;
439 int i;
440
1127 int i;
1128
441 /* Nonzero means only use if not present in info file. */
442 int entry_default = 0;
443 int entry_force = 0;
444 int section_default = 0;
445
446 progname = argv[0];
447
448#ifdef HAVE_SETLOCALE
449 /* Set locale via LC_ALL. */
450 setlocale (LC_ALL, "");
451#endif
452
453 /* Set the text message domain. */
454 bindtextdomain (PACKAGE, LOCALEDIR);
455 textdomain (PACKAGE);

--- 30 unchanged lines hidden (view full) ---

486 {
487 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
488 progname);
489 suggest_asking_for_help ();
490 }
491 dirfile = concat (optarg, "", "/dir");
492 break;
493
1129#ifdef HAVE_SETLOCALE
1130 /* Set locale via LC_ALL. */
1131 setlocale (LC_ALL, "");
1132#endif
1133
1134 /* Set the text message domain. */
1135 bindtextdomain (PACKAGE, LOCALEDIR);
1136 textdomain (PACKAGE);

--- 30 unchanged lines hidden (view full) ---

1167 {
1168 fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
1169 progname);
1170 suggest_asking_for_help ();
1171 }
1172 dirfile = concat (optarg, "", "/dir");
1173 break;
1174
494 case 'f':
495 entry_force = 1;
496 if (!optarg[0])
497 {
498 fprintf (stderr, "%s: Must provide entry name.\n", progname);
499 suggest_asking_for_help ();
500 }
501 case 'E':
1175 case 'E':
502 entry_default = 1;
503 if (!optarg[0])
504 break;
505 case 'e':
506 {
507 struct spec_entry *next
508 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
1176 case 'e':
1177 {
1178 struct spec_entry *next
1179 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
509 if (! (*optarg != 0 && optarg[strlen (optarg) - 1] == '\n'))
510 optarg = concat (optarg, "\n", "");
1180 int olen = strlen (optarg);
1181 if (! (*optarg != 0 && optarg[olen - 1] == '\n'))
1182 {
1183 optarg = concat (optarg, "\n", "");
1184 olen++;
1185 }
511 next->text = optarg;
1186 next->text = optarg;
512 next->next = entries_to_add;
513 entries_to_add = next;
514 n_entries_to_add++;
1187 next->text_len = olen;
1188 next->entry_sections = NULL;
1189 next->entry_sections_tail = NULL;
1190 if (opt == 'e')
1191 {
1192 next->next = entries_to_add;
1193 entries_to_add = next;
1194 n_entries_to_add++;
1195 }
1196 else
1197 {
1198 next->next = default_entries_to_add;
1199 default_entries_to_add = next;
1200 n_default_entries_to_add++;
1201 }
515 }
516 break;
517
518 case 'h':
519 case 'H':
520 print_help ();
1202 }
1203 break;
1204
1205 case 'h':
1206 case 'H':
1207 print_help ();
521 exit (0);
1208 xexit (0);
522
523 case 'i':
524 if (infile)
525 {
526 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
527 progname);
528 suggest_asking_for_help ();
529 }
530 infile = optarg;
531 break;
532
533 case 'q':
534 quiet_flag = 1;
535 break;
536
537 case 'r':
538 delete_flag = 1;
539 break;
540
1209
1210 case 'i':
1211 if (infile)
1212 {
1213 fprintf (stderr, _("%s: Specify the Info file only once.\n"),
1214 progname);
1215 suggest_asking_for_help ();
1216 }
1217 infile = optarg;
1218 break;
1219
1220 case 'q':
1221 quiet_flag = 1;
1222 break;
1223
1224 case 'r':
1225 delete_flag = 1;
1226 break;
1227
541 case 'S':
542 section_default = 1;
543 if (!optarg[0])
544 break;
545 case 's':
546 {
547 struct spec_section *next
548 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
549 next->name = optarg;
550 next->next = input_sections;
551 next->missing = 1;
552 input_sections = next;
553 }
554 break;
555
1228 case 's':
1229 {
1230 struct spec_section *next
1231 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
1232 next->name = optarg;
1233 next->next = input_sections;
1234 next->missing = 1;
1235 input_sections = next;
1236 }
1237 break;
1238
1239 case 'S':
1240 default_section = optarg;
1241 break;
1242
556 case 'V':
557 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
1243 case 'V':
1244 printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
1245 puts ("");
558 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
559There is NO warranty. You may redistribute this software\n\
560under the terms of the GNU General Public License.\n\
561For more information about these matters, see the files named COPYING.\n"),
1246 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
1247There is NO warranty. You may redistribute this software\n\
1248under the terms of the GNU General Public License.\n\
1249For more information about these matters, see the files named COPYING.\n"),
562 "1998");
563 exit (0);
1250 "1999");
1251 xexit (0);
564
565 default:
566 suggest_asking_for_help ();
567 }
568 }
569
1252
1253 default:
1254 suggest_asking_for_help ();
1255 }
1256 }
1257
570 if (entry_force)
571 entry_default = 0;
572
573 /* Interpret the non-option arguments as file names. */
574 for (; optind < argc; ++optind)
575 {
576 if (infile == 0)
577 infile = argv[optind];
578 else if (dirfile == 0)
579 dirfile = argv[optind];
580 else
581 error (_("excess command line argument `%s'"), argv[optind]);
582 }
583
584 if (!infile)
585 fatal (_("No input file specified; try --help for more information."));
586 if (!dirfile)
587 fatal (_("No dir file specified; try --help for more information."));
588
1258 /* Interpret the non-option arguments as file names. */
1259 for (; optind < argc; ++optind)
1260 {
1261 if (infile == 0)
1262 infile = argv[optind];
1263 else if (dirfile == 0)
1264 dirfile = argv[optind];
1265 else
1266 error (_("excess command line argument `%s'"), argv[optind]);
1267 }
1268
1269 if (!infile)
1270 fatal (_("No input file specified; try --help for more information."));
1271 if (!dirfile)
1272 fatal (_("No dir file specified; try --help for more information."));
1273
589 /* Read the Info file and parse it into lines. */
590
591 input_data = readfile (infile, &input_size);
592 input_lines = findlines (input_data, input_size, &input_nlines);
593
594 /* Parse the input file to find the section names it specifies. */
595
596 if (input_sections == 0 || section_default)
1274 /* Read the Info file and parse it into lines, unless we're deleting. */
1275 if (!delete_flag)
597 {
1276 {
598 prefix_length = strlen ("INFO-DIR-SECTION ");
599 for (i = 0; i < input_nlines; i++)
600 {
601 if (!strncmp ("INFO-DIR-SECTION ", input_lines[i].start,
602 prefix_length))
603 {
604 struct spec_section *next
605 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
606
607 if (section_default)
608 {
609 input_sections = NULL; /* This leaks. */
610 section_default = 0;
611 }
612
613 next->name = copy_string (input_lines[i].start + prefix_length,
614 input_lines[i].size - prefix_length);
615 next->next = input_sections;
616 next->missing = 1;
617 input_sections = next;
618 }
619 }
1277 input_data = readfile (infile, &input_size, NULL, NULL, NULL);
1278 input_lines = findlines (input_data, input_size, &input_nlines);
620 }
621
1279 }
1280
622 /* Default to section "Miscellaneous" if no sections specified. */
623 if (input_sections == 0)
1281 i = parse_input (input_lines, input_nlines,
1282 &input_sections, &entries_to_add);
1283 if (i > n_entries_to_add)
1284 n_entries_to_add = i;
1285 else if (n_entries_to_add == 0)
624 {
1286 {
625 input_sections
626 = (struct spec_section *) xmalloc (sizeof (struct spec_section));
627 input_sections->name = "Miscellaneous";
628 input_sections->next = 0;
629 input_sections->missing = 1;
1287 entries_to_add = default_entries_to_add;
1288 n_entries_to_add = n_default_entries_to_add;
630 }
631
1289 }
1290
632 /* Now find the directory entries specified in the file
633 and put them on entries_to_add. But not if entries
634 were specified explicitly with command options. */
635
636 if ( !entry_force && (entries_to_add == 0 || entry_default) )
1291 if (!delete_flag)
637 {
1292 {
638 char *start_of_this_entry = 0;
639 for (i = 0; i < input_nlines; i++)
1293 if (entries_to_add == 0)
1294 { /* No need to abort here, the original info file may not
1295 have the requisite Texinfo commands. This is not
1296 something an installer should have to correct (it's a
1297 problem for the maintainer), and there's no need to cause
1298 subsequent parts of `make install' to fail. */
1299 warning (_("no info dir entry in `%s'"), infile);
1300 xexit (0);
1301 }
1302
1303 /* If the entries came from the command-line arguments, their
1304 entry_sections pointers are not yet set. Walk the chain of
1305 the entries and for each entry update entry_sections to point
1306 to the head of the list of sections where this entry should
1307 be put. Note that all the entries specified on the command
1308 line get put into ALL the sections we've got, either from the
1309 Info file, or (under --section) from the command line,
1310 because in the loop below every entry inherits the entire
1311 chain of sections. */
1312 if (n_entries_to_add > 0 && entries_to_add->entry_sections == NULL)
640 {
1313 {
641 if (!strncmp ("START-INFO-DIR-ENTRY", input_lines[i].start,
642 input_lines[i].size)
643 && sizeof ("START-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
1314 struct spec_entry *ep;
1315
1316 /* If we got no sections, default to "Miscellaneous". */
1317 if (input_sections == NULL)
644 {
1318 {
645 if (start_of_this_entry != 0)
646 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
647 start_of_this_entry = input_lines[i + 1].start;
1319 input_sections = (struct spec_section *)
1320 xmalloc (sizeof (struct spec_section));
1321 input_sections->name =
1322 default_section ? default_section : "Miscellaneous";
1323 input_sections->next = NULL;
1324 input_sections->missing = 1;
648 }
1325 }
649 if (!strncmp ("END-INFO-DIR-ENTRY", input_lines[i].start,
650 input_lines[i].size)
651 && sizeof ("END-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
652 {
653 if (start_of_this_entry != 0)
654 {
655 struct spec_entry *next
656 = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
657
658 if (entry_default)
659 {
660 entries_to_add = NULL;
661 entry_default = 0;
662 }
663
664 next->text = copy_string (start_of_this_entry,
665 input_lines[i].start - start_of_this_entry);
666 next->next = entries_to_add;
667 entries_to_add = next;
668 n_entries_to_add++;
669 start_of_this_entry = 0;
670 }
671 else
672 fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"));
673 }
1326 for (ep = entries_to_add; ep; ep = ep->next)
1327 ep->entry_sections = input_sections;
674 }
1328 }
675 if (start_of_this_entry != 0)
676 fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
677 }
678
1329 }
1330
679 if (!delete_flag)
680 if (entries_to_add == 0)
681 { /* No need to abort here, the original info file may not have
682 the requisite Texinfo commands. This is not something an
683 installer should have to correct (it's a problem for the
684 maintainer), and there's no need to cause subsequent parts of
685 `make install' to fail. */
686 warning (_("no info dir entry in `%s'"), infile);
687 exit (0);
688 }
689
690 /* Now read in the Info dir file. */
1331 /* Now read in the Info dir file. */
691 ensure_dirfile_exists (dirfile);
692 dir_data = readfile (dirfile, &dir_size);
1332 dir_data = readfile (dirfile, &dir_size, ensure_dirfile_exists,
1333 &opened_dirfilename, &compression_program);
693 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
694
695 /* We will be comparing the entries in the dir file against the
1334 dir_lines = findlines (dir_data, dir_size, &dir_nlines);
1335
1336 /* We will be comparing the entries in the dir file against the
696 current filename, so need to strip off any directory prefix and any
697 .info suffix. */
1337 current filename, so need to strip off any directory prefix and/or
1338 [.info][.gz] suffix. */
698 {
1339 {
699 unsigned basename_len;
700 char *infile_basename = strrchr (infile, '/');
701 if (infile_basename)
702 infile_basename++;
703 else
704 infile_basename = infile;
705
706 basename_len = strlen (infile_basename);
707 infile_sans_info
708 = (strlen (infile_basename) > 5
709 && strcmp (infile_basename + basename_len - 5, ".info") == 0)
710 ? copy_string (infile_basename, basename_len - 5)
711 : infile_basename;
1340 char *infile_basename = infile + strlen (infile);
712
1341
1342 if (HAVE_DRIVE (infile))
1343 infile += 2; /* get past the drive spec X: */
1344
1345 while (infile_basename > infile && !IS_SLASH (infile_basename[-1]))
1346 infile_basename--;
1347
1348 infile_sans_info = strip_info_suffix (infile_basename);
713 infilelen_sans_info = strlen (infile_sans_info);
714 }
1349 infilelen_sans_info = strlen (infile_sans_info);
1350 }
715
716 /* Parse the dir file. Find all the nodes, and their menus,
717 and the sections of their menus. */
718
1351
719 dir_nodes = 0;
720 node_header_flag = 0;
721 for (i = 0; i < dir_nlines; i++)
722 {
723 /* Parse node header lines. */
724 if (node_header_flag)
725 {
726 int j, end;
727 for (j = 0; j < dir_lines[i].size; j++)
728 /* Find the node name and store it in the `struct node'. */
729 if (!strncmp ("Node:", dir_lines[i].start + j, 5))
730 {
731 char *line = dir_lines[i].start;
732 /* Find the start of the node name. */
733 j += 5;
734 while (line[j] == ' ' || line[j] == '\t')
735 j++;
736 /* Find the end of the node name. */
737 end = j;
738 while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
739 && line[end] != '\t')
740 end++;
741 dir_nodes->name = copy_string (line + j, end - j);
742 }
743 node_header_flag = 0;
744 }
1352 something_deleted
1353 = parse_dir_file (dir_lines, dir_nlines, &dir_nodes, infile_sans_info);
745
1354
746 /* Notice the start of a node. */
747 if (*dir_lines[i].start == 037)
748 {
749 struct node *next
750 = (struct node *) xmalloc (sizeof (struct node));
751 next->next = dir_nodes;
752 next->name = NULL;
753 next->start_line = i;
754 next->end_line = 0;
755 next->menu_start = NULL;
756 next->sections = NULL;
757 next->last_section = NULL;
758
759 if (dir_nodes != 0)
760 dir_nodes->end_line = i;
761 /* Fill in the end of the last menu section
762 of the previous node. */
763 if (dir_nodes != 0 && dir_nodes->last_section != 0)
764 dir_nodes->last_section->end_line = i;
765
766 dir_nodes = next;
767
768 /* The following line is the header of this node;
769 parse it. */
770 node_header_flag = 1;
771 }
772
773 /* Notice the lines that start menus. */
774 if (dir_nodes != 0
775 && !strncmp ("* Menu:", dir_lines[i].start, 7))
776 dir_nodes->menu_start = dir_lines[i + 1].start;
777
778 /* Notice sections in menus. */
779 if (dir_nodes != 0
780 && dir_nodes->menu_start != 0
781 && *dir_lines[i].start != '\n'
782 && *dir_lines[i].start != '*'
783 && *dir_lines[i].start != ' '
784 && *dir_lines[i].start != '\t')
785 {
786 /* Add this menu section to the node's list.
787 This list grows in forward order. */
788 struct menu_section *next
789 = (struct menu_section *) xmalloc (sizeof (struct menu_section));
790 next->start_line = i + 1;
791 next->next = 0;
792 next->end_line = 0;
793 next->name = copy_string (dir_lines[i].start, dir_lines[i].size);
794 if (dir_nodes->sections)
795 {
796 dir_nodes->last_section->next = next;
797 dir_nodes->last_section->end_line = i;
798 }
799 else
800 dir_nodes->sections = next;
801 dir_nodes->last_section = next;
802 }
803
804 /* Check for an existing entry that should be deleted.
805 Delete all entries which specify this file name. */
806 if (*dir_lines[i].start == '*')
807 {
808 char *p = dir_lines[i].start;
809
810 while (*p != 0 && *p != ':')
811 p++;
812 p++;
813 while (*p == ' ') p++;
814 if (*p == '(')
815 {
816 p++;
817 if ((dir_lines[i].size
818 > (p - dir_lines[i].start + infilelen_sans_info))
819 && !strncmp (p, infile_sans_info, infilelen_sans_info)
820 && (p[infilelen_sans_info] == ')'
821 || !strncmp (p + infilelen_sans_info, ".info)", 6)))
822 {
823 dir_lines[i].delete = 1;
824 something_deleted = 1;
825 }
826 }
827 }
828 /* Treat lines that start with whitespace
829 as continuations; if we are deleting an entry,
830 delete all its continuations as well. */
831 else if (i > 0
832 && (*dir_lines[i].start == ' '
833 || *dir_lines[i].start == '\t'))
834 {
835 dir_lines[i].delete = dir_lines[i - 1].delete;
836 something_deleted = 1;
837 }
838 }
839
840 /* Finish the info about the end of the last node. */
841 if (dir_nodes != 0)
842 {
843 dir_nodes->end_line = dir_nlines;
844 if (dir_nodes->last_section != 0)
845 dir_nodes->last_section->end_line = dir_nlines;
846 }
847
848 /* Decide where to add the new entries (unless --delete was used).
849 Find the menu sections to add them in.
850 In each section, find the proper alphabetical place to add
851 each of the entries. */
852
853 if (!delete_flag)
854 {
855 struct node *node;

--- 17 unchanged lines hidden (view full) ---

873 struct spec_entry *entry;
874 /* Say we have found at least one section with this name,
875 so we need not add such a section. */
876 spec->missing = 0;
877 /* For each entry, find the right place in this section
878 to add it. */
879 for (entry = entries_to_add; entry; entry = entry->next)
880 {
1355 /* Decide where to add the new entries (unless --delete was used).
1356 Find the menu sections to add them in.
1357 In each section, find the proper alphabetical place to add
1358 each of the entries. */
1359
1360 if (!delete_flag)
1361 {
1362 struct node *node;

--- 17 unchanged lines hidden (view full) ---

1380 struct spec_entry *entry;
1381 /* Say we have found at least one section with this name,
1382 so we need not add such a section. */
1383 spec->missing = 0;
1384 /* For each entry, find the right place in this section
1385 to add it. */
1386 for (entry = entries_to_add; entry; entry = entry->next)
1387 {
881 int textlen = strlen (entry->text);
1388 /* Did they at all want this entry to be put into
1389 this section? */
1390 for (spec = entry->entry_sections;
1391 spec && spec != entry->entry_sections_tail;
1392 spec = spec->next)
1393 {
1394 if (!strcmp (spec->name, section->name))
1395 break;
1396 }
1397 if (!spec || spec == entry->entry_sections_tail)
1398 continue;
1399
882 /* Subtract one because dir_lines is zero-based,
883 but the `end_line' and `start_line' members are
884 one-based. */
885 for (i = section->end_line - 1;
886 i >= section->start_line - 1; i--)
887 {
888 /* If an entry exists with the same name,
889 and was not marked for deletion
890 (which means it is for some other file),
891 we are in trouble. */
892 if (dir_lines[i].start[0] == '*'
1400 /* Subtract one because dir_lines is zero-based,
1401 but the `end_line' and `start_line' members are
1402 one-based. */
1403 for (i = section->end_line - 1;
1404 i >= section->start_line - 1; i--)
1405 {
1406 /* If an entry exists with the same name,
1407 and was not marked for deletion
1408 (which means it is for some other file),
1409 we are in trouble. */
1410 if (dir_lines[i].start[0] == '*'
893 && menu_line_equal (entry->text, textlen,
1411 && menu_line_equal (entry->text, entry->text_len,
894 dir_lines[i].start,
895 dir_lines[i].size)
896 && !dir_lines[i].delete)
897 fatal (_("menu item `%s' already exists, for file `%s'"),
898 extract_menu_item_name (entry->text),
899 extract_menu_file_name (dir_lines[i].start));
900 if (dir_lines[i].start[0] == '*'
1412 dir_lines[i].start,
1413 dir_lines[i].size)
1414 && !dir_lines[i].delete)
1415 fatal (_("menu item `%s' already exists, for file `%s'"),
1416 extract_menu_item_name (entry->text),
1417 extract_menu_file_name (dir_lines[i].start));
1418 if (dir_lines[i].start[0] == '*'
901 && menu_line_lessp (entry->text, textlen,
1419 && menu_line_lessp (entry->text, entry->text_len,
902 dir_lines[i].start,
903 dir_lines[i].size))
904 add_at_line = i;
905 }
906 insert_entry_here (entry, add_at_line,
907 dir_lines, n_entries_to_add);
908 }
909 }

--- 4 unchanged lines hidden (view full) ---

914 for (node = dir_nodes; node; node = node->next)
915 if (node->name && strcmp (node->name, "Top") == 0)
916 dir_lines[node->end_line].add_sections_before = 1;
917 }
918
919 if (delete_flag && !something_deleted && !quiet_flag)
920 warning (_("no entries found for `%s'; nothing deleted"), infile);
921
1420 dir_lines[i].start,
1421 dir_lines[i].size))
1422 add_at_line = i;
1423 }
1424 insert_entry_here (entry, add_at_line,
1425 dir_lines, n_entries_to_add);
1426 }
1427 }

--- 4 unchanged lines hidden (view full) ---

1432 for (node = dir_nodes; node; node = node->next)
1433 if (node->name && strcmp (node->name, "Top") == 0)
1434 dir_lines[node->end_line].add_sections_before = 1;
1435 }
1436
1437 if (delete_flag && !something_deleted && !quiet_flag)
1438 warning (_("no entries found for `%s'; nothing deleted"), infile);
1439
922 /* Output the old dir file, interpolating the new sections
923 and/or new entries where appropriate. */
1440 output_dirfile (opened_dirfilename, dir_nlines, dir_lines, n_entries_to_add,
1441 entries_to_add, input_sections, compression_program);
924
1442
925 output = fopen (dirfile, "w");
926 if (!output)
927 {
928 perror (dirfile);
929 exit (1);
930 }
931
932 for (i = 0; i <= dir_nlines; i++)
933 {
934 int j;
935
936 /* If we decided to output some new entries before this line,
937 output them now. */
938 if (dir_lines[i].add_entries_before)
939 for (j = 0; j < n_entries_to_add; j++)
940 {
941 struct spec_entry *this = dir_lines[i].add_entries_before[j];
942 if (this == 0)
943 break;
944 fputs (this->text, output);
945 }
946 /* If we decided to add some sections here
947 because there are no such sections in the file,
948 output them now. */
949 if (dir_lines[i].add_sections_before)
950 {
951 struct spec_section *spec;
952 struct spec_section **sections;
953 int n_sections = 0;
954
955 /* Count the sections and allocate a vector for all of them. */
956 for (spec = input_sections; spec; spec = spec->next)
957 n_sections++;
958 sections = ((struct spec_section **)
959 xmalloc (n_sections * sizeof (struct spec_section *)));
960
961 /* Fill the vector SECTIONS with pointers to all the sections,
962 and sort them. */
963 j = 0;
964 for (spec = input_sections; spec; spec = spec->next)
965 sections[j++] = spec;
966 qsort (sections, n_sections, sizeof (struct spec_section *),
967 compare_section_names);
968
969 /* Generate the new sections in alphabetical order.
970 In each new section, output all of our entries. */
971 for (j = 0; j < n_sections; j++)
972 {
973 spec = sections[j];
974 if (spec->missing)
975 {
976 struct spec_entry *entry;
977
978 putc ('\n', output);
979 fputs (spec->name, output);
980 putc ('\n', output);
981 for (entry = entries_to_add; entry; entry = entry->next)
982 fputs (entry->text, output);
983 }
984 }
985
986 free (sections);
987 }
988
989 /* Output the original dir lines unless marked for deletion. */
990 if (i < dir_nlines && !dir_lines[i].delete)
991 {
992 fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
993 putc ('\n', output);
994 }
995 }
996
997 fclose (output);
998
999 exit (0);
1443 xexit (0);
1000}
1001
1444}
1445
1002/* Read all of file FILNAME into memory
1003 and return the address of the data.
1004 Store the size into SIZEP.
1005 If there is trouble, do a fatal error. */
1006
1007char *
1008readfile (filename, sizep)
1009 char *filename;
1010 int *sizep;
1011{
1012 int desc;
1013 int data_size = 1024;
1014 char *data = (char *) xmalloc (data_size);
1015 int filled = 0;
1016 int nread = 0;
1017#ifdef HAVE_LIBZ
1018 int isGZ = 0;
1019 gzFile zdesc;
1020#endif
1021
1022 desc = open (filename, O_RDONLY);
1023 if (desc < 0)
1024 pfatal_with_name (filename);
1025
1026#ifdef HAVE_LIBZ
1027 /* The file should always be two bytes long. */
1028 if (read (desc, data, 2) != 2)
1029 pfatal_with_name (filename);
1030
1031 /* Undo that read. */
1032 lseek (desc, 0, SEEK_SET);
1033
1034 /* If we see gzip magic, use gzdopen. */
1035 if (data[0] == '\x1f' && data[1] == '\x8b')
1036 {
1037 isGZ = 1;
1038 zdesc = gzdopen (desc, "r");
1039 if (zdesc == NULL) {
1040 close (desc);
1041 pfatal_with_name (filename);
1042 }
1043 }
1044#endif /* HAVE_LIBZ */
1045
1046 while (1)
1047 {
1048#ifdef HAVE_LIBZ
1049 if (isGZ)
1050 nread = gzread (zdesc, data + filled, data_size - filled);
1051 else
1052#endif
1053 nread = read (desc, data + filled, data_size - filled);
1054
1055 if (nread < 0)
1056 pfatal_with_name (filename);
1057 if (nread == 0)
1058 break;
1059
1060 filled += nread;
1061 if (filled == data_size)
1062 {
1063 data_size *= 2;
1064 data = (char *) xrealloc (data, data_size);
1065 }
1066 }
1067
1068 *sizep = filled;
1069
1070#ifdef HAVE_LIBZ
1071 if (isGZ)
1072 gzclose (zdesc);
1073 else
1074#endif
1075 close(desc);
1076
1077 return data;
1078}
1079
1080/* Divide the text at DATA (of SIZE bytes) into lines.
1081 Return a vector of struct line_data describing the lines.
1082 Store the length of that vector into *NLINESP. */
1083
1084struct line_data *
1085findlines (data, size, nlinesp)
1086 char *data;
1087 int size;
1088 int *nlinesp;
1089{
1446/* Divide the text at DATA (of SIZE bytes) into lines.
1447 Return a vector of struct line_data describing the lines.
1448 Store the length of that vector into *NLINESP. */
1449
1450struct line_data *
1451findlines (data, size, nlinesp)
1452 char *data;
1453 int size;
1454 int *nlinesp;
1455{
1090 struct line_data *lines;
1091 int lines_allocated = 512;
1456 int i;
1457 int lineflag = 1;
1458 int lines_allocated = 511;
1092 int filled = 0;
1459 int filled = 0;
1093 int i = 0;
1094 int lineflag;
1460 struct line_data *lines
1461 = xmalloc ((lines_allocated + 1) * sizeof (struct line_data));
1095
1462
1096 lines = (struct line_data *) xmalloc (lines_allocated * sizeof (struct line_data));
1097
1098 lineflag = 1;
1099 for (i = 0; i < size; i++)
1100 {
1101 if (lineflag)
1102 {
1103 if (filled == lines_allocated)
1104 {
1463 for (i = 0; i < size; i++)
1464 {
1465 if (lineflag)
1466 {
1467 if (filled == lines_allocated)
1468 {
1105 lines_allocated *= 2;
1106 lines = (struct line_data *) xrealloc (lines, lines_allocated * sizeof (struct line_data));
1469 /* try to keep things somewhat page-aligned */
1470 lines_allocated = ((lines_allocated + 1) * 2) - 1;
1471 lines = xrealloc (lines, (lines_allocated + 1)
1472 * sizeof (struct line_data));
1107 }
1108 lines[filled].start = &data[i];
1109 lines[filled].add_entries_before = 0;
1110 lines[filled].add_sections_before = 0;
1111 lines[filled].delete = 0;
1112 if (filled > 0)
1113 lines[filled - 1].size
1114 = lines[filled].start - lines[filled - 1].start - 1;

--- 23 unchanged lines hidden (view full) ---

1138menu_line_lessp (line1, len1, line2, len2)
1139 char *line1;
1140 int len1;
1141 char *line2;
1142 int len2;
1143{
1144 int minlen = (len1 < len2 ? len1 : len2);
1145 int i;
1473 }
1474 lines[filled].start = &data[i];
1475 lines[filled].add_entries_before = 0;
1476 lines[filled].add_sections_before = 0;
1477 lines[filled].delete = 0;
1478 if (filled > 0)
1479 lines[filled - 1].size
1480 = lines[filled].start - lines[filled - 1].start - 1;

--- 23 unchanged lines hidden (view full) ---

1504menu_line_lessp (line1, len1, line2, len2)
1505 char *line1;
1506 int len1;
1507 char *line2;
1508 int len2;
1509{
1510 int minlen = (len1 < len2 ? len1 : len2);
1511 int i;
1146
1512
1147 for (i = 0; i < minlen; i++)
1148 {
1149 /* If one item name is a prefix of the other,
1150 the former one is less. */
1151 if (line1[i] == ':' && line2[i] != ':')
1152 return 1;
1153 if (line2[i] == ':' && line1[i] != ':')
1154 return 0;

--- 16 unchanged lines hidden (view full) ---

1171menu_line_equal (line1, len1, line2, len2)
1172 char *line1;
1173 int len1;
1174 char *line2;
1175 int len2;
1176{
1177 int minlen = (len1 < len2 ? len1 : len2);
1178 int i;
1513 for (i = 0; i < minlen; i++)
1514 {
1515 /* If one item name is a prefix of the other,
1516 the former one is less. */
1517 if (line1[i] == ':' && line2[i] != ':')
1518 return 1;
1519 if (line2[i] == ':' && line1[i] != ':')
1520 return 0;

--- 16 unchanged lines hidden (view full) ---

1537menu_line_equal (line1, len1, line2, len2)
1538 char *line1;
1539 int len1;
1540 char *line2;
1541 int len2;
1542{
1543 int minlen = (len1 < len2 ? len1 : len2);
1544 int i;
1179
1545
1180 for (i = 0; i < minlen; i++)
1181 {
1182 /* If both item names end here, they are equal. */
1183 if (line1[i] == ':' && line2[i] == ':')
1184 return 1;
1185 /* If they both continue and differ, one is less. */
1186 if (line1[i] != line2[i])
1187 return 0;

--- 11 unchanged lines hidden (view full) ---

1199compare_section_names (sec1, sec2)
1200 struct spec_section **sec1, **sec2;
1201{
1202 char *name1 = (*sec1)->name;
1203 char *name2 = (*sec2)->name;
1204 return strcmp (name1, name2);
1205}
1206
1546 for (i = 0; i < minlen; i++)
1547 {
1548 /* If both item names end here, they are equal. */
1549 if (line1[i] == ':' && line2[i] == ':')
1550 return 1;
1551 /* If they both continue and differ, one is less. */
1552 if (line1[i] != line2[i])
1553 return 0;

--- 11 unchanged lines hidden (view full) ---

1565compare_section_names (sec1, sec2)
1566 struct spec_section **sec1, **sec2;
1567{
1568 char *name1 = (*sec1)->name;
1569 char *name2 = (*sec2)->name;
1570 return strcmp (name1, name2);
1571}
1572
1573/* This is the comparison function for qsort
1574 for a vector of pointers to struct spec_entry.
1575 Compare the entries' text. */
1576
1577int
1578compare_entries_text (entry1, entry2)
1579 struct spec_entry **entry1, **entry2;
1580{
1581 char *text1 = (*entry1)->text;
1582 char *text2 = (*entry2)->text;
1583 char *colon1 = strchr (text1, ':');
1584 char *colon2 = strchr (text2, ':');
1585 int len1, len2;
1586
1587 if (!colon1)
1588 len1 = strlen (text1);
1589 else
1590 len1 = colon1 - text1;
1591 if (!colon2)
1592 len2 = strlen (text2);
1593 else
1594 len2 = colon2 - text2;
1595 return strncmp (text1, text2, len1 <= len2 ? len1 : len2);
1596}
1597
1207/* Insert ENTRY into the add_entries_before vector
1208 for line number LINE_NUMBER of the dir file.
1209 DIR_LINES and N_ENTRIES carry information from like-named variables
1210 in main. */
1211
1212void
1213insert_entry_here (entry, line_number, dir_lines, n_entries)
1214 struct spec_entry *entry;
1215 int line_number;
1216 struct line_data *dir_lines;
1217 int n_entries;
1218{
1598/* Insert ENTRY into the add_entries_before vector
1599 for line number LINE_NUMBER of the dir file.
1600 DIR_LINES and N_ENTRIES carry information from like-named variables
1601 in main. */
1602
1603void
1604insert_entry_here (entry, line_number, dir_lines, n_entries)
1605 struct spec_entry *entry;
1606 int line_number;
1607 struct line_data *dir_lines;
1608 int n_entries;
1609{
1219 int i;
1610 int i, j;
1220
1221 if (dir_lines[line_number].add_entries_before == 0)
1222 {
1223 dir_lines[line_number].add_entries_before
1224 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1225 for (i = 0; i < n_entries; i++)
1226 dir_lines[line_number].add_entries_before[i] = 0;
1227 }
1228
1611
1612 if (dir_lines[line_number].add_entries_before == 0)
1613 {
1614 dir_lines[line_number].add_entries_before
1615 = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
1616 for (i = 0; i < n_entries; i++)
1617 dir_lines[line_number].add_entries_before[i] = 0;
1618 }
1619
1620 /* Find the place where this entry belongs. If there are already
1621 several entries to add before LINE_NUMBER, make sure they are in
1622 alphabetical order. */
1229 for (i = 0; i < n_entries; i++)
1623 for (i = 0; i < n_entries; i++)
1230 if (dir_lines[line_number].add_entries_before[i] == 0)
1624 if (dir_lines[line_number].add_entries_before[i] == 0
1625 || menu_line_lessp (entry->text, strlen (entry->text),
1626 dir_lines[line_number].add_entries_before[i]->text,
1627 strlen (dir_lines[line_number].add_entries_before[i]->text)))
1231 break;
1232
1233 if (i == n_entries)
1234 abort ();
1235
1628 break;
1629
1630 if (i == n_entries)
1631 abort ();
1632
1633 /* If we need to plug ENTRY into the middle of the
1634 ADD_ENTRIES_BEFORE array, move the entries which should be output
1635 after this one down one notch, before adding a new one. */
1636 if (dir_lines[line_number].add_entries_before[i] != 0)
1637 for (j = n_entries - 1; j > i; j--)
1638 dir_lines[line_number].add_entries_before[j]
1639 = dir_lines[line_number].add_entries_before[j - 1];
1640
1236 dir_lines[line_number].add_entries_before[i] = entry;
1237}
1641 dir_lines[line_number].add_entries_before[i] = entry;
1642}