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} |