1 /* infokey.c -- compile ~/.infokey to ~/.info. 2 $Id: infokey.c,v 1.2 2015/11/14 23:06:06 deraadt Exp $ 3 4 Copyright (C) 1999, 2001, 2002, 2003, 2004 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, or (at your option) 9 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 Written by Andrew Bettison <andrewb@zip.com.au>. */ 21 22 #include "info.h" 23 #include "infomap.h" 24 #include "infokey.h" 25 #include "key.h" 26 #include "getopt.h" 27 28 static char *program_name = "infokey"; 29 30 /* Non-zero means print version info only. */ 31 static int print_version_p = 0; 32 33 /* Non-zero means print a short description of the options. */ 34 static int print_help_p = 0; 35 36 /* String specifying the source file. This is set by the user on the 37 command line, or a default is used. */ 38 static char *input_filename = (char *) NULL; 39 40 /* String specifying the name of the file to output to. This is 41 set by the user on the command line, or a default is used. */ 42 static char *output_filename = (char *) NULL; 43 44 /* Structure describing the options that Infokey accepts. We pass this 45 structure to getopt_long (). If you add or otherwise change this 46 structure, you must also change the string which follows it. */ 47 static struct option long_options[] = 48 { 49 {"output", 1, 0, 'o'}, 50 {"help", 0, &print_help_p, 1}, 51 {"version", 0, &print_version_p, 1}, 52 {NULL, 0, NULL, 0} 53 }; 54 55 /* String describing the shorthand versions of the long options found above. */ 56 static char *short_options = "o:"; 57 58 /* Structure for holding the compiled sections. */ 59 enum sect_e 60 { 61 info = 0, 62 ea = 1, 63 var = 2 64 }; 65 struct sect 66 { 67 unsigned int cur; 68 unsigned char data[INFOKEY_MAX_SECTIONLEN]; 69 }; 70 71 /* Some "forward" declarations. */ 72 static char *mkpath (const char *dir, const char *file); 73 static int compile (FILE *fp, const char *filename, struct sect *sections); 74 static int write_infokey_file (FILE *fp, struct sect *sections); 75 static void syntax_error (const char *filename, 76 unsigned int linenum, const char *fmt, 77 const void *a1, const void *a2, const void *a3, const void *a4); 78 static void error_message (int error_code, const char *fmt, 79 const void *a1, const void *a2, const void *a3, const void *a4); 80 static void suggest_help (void); 81 static void short_help (void); 82 83 84 /* **************************************************************** */ 85 /* */ 86 /* Main Entry Point to the Infokey Program */ 87 /* */ 88 /* **************************************************************** */ 89 90 int 91 main (int argc, char **argv) 92 { 93 int getopt_long_index; /* Index returned by getopt_long (). */ 94 95 #ifdef HAVE_SETLOCALE 96 /* Set locale via LC_ALL. */ 97 setlocale (LC_ALL, ""); 98 #endif 99 100 if (pledge ("stdio rpath wpath cpath tty", NULL) == -1) { 101 perror("pledge"); 102 exit(1); 103 } 104 105 #ifdef ENABLE_NLS 106 /* Set the text message domain. */ 107 bindtextdomain (PACKAGE, LOCALEDIR); 108 textdomain (PACKAGE); 109 #endif 110 111 while (1) 112 { 113 int option_character; 114 115 option_character = getopt_long 116 (argc, argv, short_options, long_options, &getopt_long_index); 117 118 /* getopt_long () returns EOF when there are no more long options. */ 119 if (option_character == EOF) 120 break; 121 122 /* If this is a long option, then get the short version of it. */ 123 if (option_character == 0 && long_options[getopt_long_index].flag == 0) 124 option_character = long_options[getopt_long_index].val; 125 126 /* Case on the option that we have received. */ 127 switch (option_character) 128 { 129 case 0: 130 break; 131 132 /* User is specifying the name of a file to output to. */ 133 case 'o': 134 if (output_filename) 135 free (output_filename); 136 output_filename = xstrdup (optarg); 137 break; 138 139 default: 140 suggest_help (); 141 xexit (1); 142 } 143 } 144 145 /* If the user specified --version, then show the version and exit. */ 146 if (print_version_p) 147 { 148 printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION); 149 puts (""); 150 printf (_ ("Copyright (C) %s Free Software Foundation, Inc.\n\ 151 There is NO warranty. You may redistribute this software\n\ 152 under the terms of the GNU General Public License.\n\ 153 For more information about these matters, see the files named COPYING.\n"), 154 "2003"); 155 xexit (0); 156 } 157 158 /* If the `--help' option was present, show the help and exit. */ 159 if (print_help_p) 160 { 161 short_help (); 162 xexit (0); 163 } 164 165 /* If there is one argument remaining, it is the name of the input 166 file. */ 167 if (optind == argc - 1) 168 { 169 if (input_filename) 170 free (input_filename); 171 input_filename = xstrdup (argv[optind]); 172 } 173 else if (optind != argc) 174 { 175 error_message (0, _("incorrect number of arguments"), 176 NULL, NULL, NULL, NULL); 177 suggest_help (); 178 xexit (1); 179 } 180 181 /* Use default filenames where none given. */ 182 { 183 char *homedir; 184 185 homedir = getenv ("HOME"); 186 #ifdef __MSDOS__ 187 if (!homedir) 188 homedir = "."; 189 #endif 190 if (!input_filename) 191 input_filename = mkpath (homedir, INFOKEY_SRCFILE); 192 if (!output_filename) 193 output_filename = mkpath (homedir, INFOKEY_FILE); 194 } 195 196 { 197 FILE *inf; 198 FILE *outf; 199 int write_error; 200 static struct sect sections[3]; 201 202 /* Open the input file. */ 203 inf = fopen (input_filename, "r"); 204 if (!inf) 205 { 206 error_message (errno, _("cannot open input file `%s'"), 207 input_filename, NULL, NULL, NULL); 208 xexit (1); 209 } 210 211 /* Compile the input file to its verious sections, then write the 212 section data to the output file. */ 213 214 if (compile (inf, input_filename, sections)) 215 { 216 /* Open the output file. */ 217 outf = fopen (output_filename, FOPEN_WBIN); 218 if (!outf) 219 { 220 error_message (errno, _("cannot create output file `%s'"), 221 output_filename, NULL, NULL, NULL); 222 xexit (1); 223 } 224 225 /* Write the contents of the output file and close it. If there is 226 an error writing to the file, delete it and exit with a failure 227 status. */ 228 write_error = 0; 229 if (!write_infokey_file (outf, sections)) 230 { 231 error_message (errno, _("error writing to `%s'"), 232 output_filename, NULL, NULL, NULL); 233 write_error = 1; 234 } 235 if (fclose (outf) == EOF) 236 { 237 error_message (errno, _("error closing output file `%s'"), 238 output_filename, NULL, NULL, NULL); 239 write_error = 1; 240 } 241 if (write_error) 242 { 243 unlink (output_filename); 244 xexit (1); 245 } 246 } 247 248 /* Close the input file. */ 249 fclose (inf); 250 } 251 252 return 0; 253 } 254 255 static char * 256 mkpath (const char *dir, const char *file) 257 { 258 char *p; 259 260 p = xmalloc (strlen (dir) + 1 + strlen (file) + 2); 261 strcpy (p, dir); 262 strcat (p, "/"); 263 strcat (p, file); 264 return p; 265 } 266 267 268 /* Compilation - the real work. 269 270 Source file syntax 271 ------------------ 272 The source file is a line-based text file with the following 273 structure: 274 275 # comments 276 # more comments 277 278 #info 279 u prev-line 280 d next-line 281 ^a invalid # just beep 282 \ku prev-line 283 #stop 284 \kd next-line 285 q quit # of course! 286 287 #echo-area 288 ^a echo-area-beg-of-line 289 ^e echo-area-end-of-line 290 \kr echo-area-forward 291 \kl echo-area-backward 292 \kh echo-area-beg-of-line 293 \ke echo-area-end-of-line 294 295 #var 296 scroll-step=1 297 ISO-Latin=Off 298 299 Lines starting with '#' are comments, and are ignored. Blank 300 lines are ignored. Each section is introduced by one of the 301 following lines: 302 303 #info 304 #echo-area 305 #var 306 307 The sections may occur in any order. Each section may be 308 omitted completely. If the 'info' section is the first in the 309 file, its '#info' line may be omitted. 310 311 The 'info' and 'echo-area' sections 312 ----------------------------------- 313 Each line in the 'info' or 'echo-area' sections has the 314 following syntax: 315 316 key-sequence SPACE action-name [ SPACE [ # comment ] ] \n 317 318 Where SPACE is one or more white space characters excluding 319 newline, "action-name" is the name of a GNU Info command, 320 "comment" is any sequence of characters excluding newline, and 321 "key-sequence" is a concatenation of one or more key definitions 322 using the following syntax: 323 324 1. A carat ^ followed by one character indicates a single 325 control character; 326 327 2. A backslash \ followed by one, two, or three octal 328 digits indicates a single character having that ASCII 329 code; 330 331 3. \n indicates a single NEWLINE; 332 \e indicates a single ESC; 333 \r indicates a single CR; 334 \t indicates a single TAB; 335 \b indicates a single BACKSPACE; 336 337 4. \ku indicates the Up Arrow key; 338 \kd indicates the Down Arrow key; 339 \kl indicates the Left Arrow key; 340 \kr indicates the Right Arrow key; 341 \kP indicates the Page Up (PRIOR) key; 342 \kN indicates the Page Down (NEXT) key; 343 \kh indicates the Home key; 344 \ke indicates the End key; 345 \kx indicates the DEL key; 346 \k followed by any other character indicates a single 347 control-K, and the following character is interpreted 348 as in rules 1, 2, 3, 5 and 6. 349 350 5. \m followed by any sequence defined in rules 1, 2, 3, 4 351 or 6 indicates the "Meta" modification of that key. 352 353 6. A backslash \ followed by any character not described 354 above indicates that character itself. In particular: 355 \\ indicates a single backslash \, 356 \ (backslash-space) indicates a single space, 357 \^ indicates a single caret ^, 358 359 If the following line: 360 361 #stop 362 363 occurs anywhere in an 'info' or 'echo-area' section, that 364 indicates to GNU Info to suppress all of its default key 365 bindings in that context. 366 367 The 'var' section 368 ----------------- 369 Each line in the 'var' section has the following syntax: 370 371 variable-name = value \n 372 373 Where "variable-name" is the name of a GNU Info variable and 374 "value" is the value that GNU Info will assign to that variable 375 when commencing execution. There must be no white space in the 376 variable name, nor between the variable name and the '='. All 377 characters immediately following the '=', up to but not 378 including the terminating newline, are considered to be the 379 value that will be assigned. In other words, white space 380 following the '=' is not ignored. 381 */ 382 383 static int add_to_section (struct sect *s, const char *str, unsigned int len); 384 static int lookup_action (const char *actname); 385 386 /* Compile the input file into its various sections. Return true if no 387 error was encountered. 388 */ 389 static int 390 compile (FILE *fp, const char *filename, struct sect *sections) 391 { 392 int error = 0; 393 char rescan = 0; 394 unsigned int lnum = 0; 395 int c = 0; 396 397 /* This parser is a true state machine, with no sneaky fetching 398 of input characters inside the main loop. In other words, all 399 state is fully represented by the following variables: 400 */ 401 enum 402 { 403 start_of_line, 404 start_of_comment, 405 in_line_comment, 406 in_trailing_comment, 407 get_keyseq, 408 got_keyseq, 409 get_action, 410 got_action, 411 get_varname, 412 got_varname, 413 get_equals, 414 got_equals, 415 get_value 416 } 417 state = start_of_line; 418 enum sect_e section = info; 419 enum 420 { 421 normal, 422 slosh, 423 control, 424 octal, 425 special_key 426 } 427 seqstate; /* used if state == get_keyseq */ 428 char meta = 0; 429 char ocnt = 0; /* used if state == get_keyseq && seqstate == octal */ 430 431 /* Data is accumulated in the following variables. The code 432 avoids overflowing these strings, and throws an error 433 where appropriate if a string limit is exceeded. These string 434 lengths are arbitrary (and should be large enough) and their 435 lengths are not hard-coded anywhere else, so increasing them 436 here will not break anything. */ 437 char oval = 0; 438 char comment[10]; 439 unsigned int clen = 0; 440 char seq[20]; 441 unsigned int slen = 0; 442 char act[80]; 443 unsigned int alen = 0; 444 char varn[80]; 445 unsigned int varlen = 0; 446 char val[80]; 447 unsigned int vallen = 0; 448 449 #define To_seq(c) \ 450 do { \ 451 if (slen < sizeof seq) \ 452 seq[slen++] = meta ? Meta(c) : (c); \ 453 else \ 454 { \ 455 syntax_error(filename, lnum, _("key sequence too long"), \ 456 NULL, NULL, NULL, NULL); \ 457 error = 1; \ 458 } \ 459 meta = 0; \ 460 } while (0) 461 462 sections[info].cur = 1; 463 sections[info].data[0] = 0; 464 sections[ea].cur = 1; 465 sections[ea].data[0] = 0; 466 sections[var].cur = 0; 467 468 while (!error && (rescan || (c = fgetc (fp)) != EOF)) 469 { 470 rescan = 0; 471 switch (state) 472 { 473 case start_of_line: 474 lnum++; 475 if (c == '#') 476 state = start_of_comment; 477 else if (c != '\n') 478 { 479 switch (section) 480 { 481 case info: 482 case ea: 483 state = get_keyseq; 484 seqstate = normal; 485 slen = 0; 486 break; 487 case var: 488 state = get_varname; 489 varlen = 0; 490 break; 491 } 492 rescan = 1; 493 } 494 break; 495 496 case start_of_comment: 497 clen = 0; 498 state = in_line_comment; 499 /* fall through */ 500 case in_line_comment: 501 if (c == '\n') 502 { 503 state = start_of_line; 504 comment[clen] = '\0'; 505 if (strcmp (comment, "info") == 0) 506 section = info; 507 else if (strcmp (comment, "echo-area") == 0) 508 section = ea; 509 else if (strcmp (comment, "var") == 0) 510 section = var; 511 else if (strcmp (comment, "stop") == 0 512 && (section == info || section == ea)) 513 sections[section].data[0] = 1; 514 } 515 else if (clen < sizeof comment - 1) 516 comment[clen++] = c; 517 break; 518 519 case in_trailing_comment: 520 if (c == '\n') 521 state = start_of_line; 522 break; 523 524 case get_keyseq: 525 switch (seqstate) 526 { 527 case normal: 528 if (c == '\n' || isspace (c)) 529 { 530 state = got_keyseq; 531 rescan = 1; 532 if (slen == 0) 533 { 534 syntax_error (filename, lnum, _("missing key sequence"), 535 NULL, NULL, NULL, NULL); 536 error = 1; 537 } 538 } 539 else if (c == '\\') 540 seqstate = slosh; 541 else if (c == '^') 542 seqstate = control; 543 else 544 To_seq (c); 545 break; 546 547 case slosh: 548 switch (c) 549 { 550 case '0': case '1': case '2': case '3': 551 case '4': case '5': case '6': case '7': 552 seqstate = octal; 553 oval = c - '0'; 554 ocnt = 1; 555 break; 556 case 'b': 557 To_seq ('\b'); 558 seqstate = normal; 559 break; 560 case 'e': 561 To_seq ('\033'); 562 seqstate = normal; 563 break; 564 case 'n': 565 To_seq ('\n'); 566 seqstate = normal; 567 break; 568 case 'r': 569 To_seq ('\r'); 570 seqstate = normal; 571 break; 572 case 't': 573 To_seq ('\t'); 574 seqstate = normal; 575 break; 576 case 'm': 577 meta = 1; 578 seqstate = normal; 579 break; 580 case 'k': 581 seqstate = special_key; 582 break; 583 default: 584 /* Backslash followed by any other char 585 just means that char. */ 586 To_seq (c); 587 seqstate = normal; 588 break; 589 } 590 break; 591 592 case octal: 593 switch (c) 594 { 595 case '0': case '1': case '2': case '3': 596 case '4': case '5': case '6': case '7': 597 if (++ocnt <= 3) 598 oval = oval * 8 + c - '0'; 599 if (ocnt == 3) 600 seqstate = normal; 601 break; 602 default: 603 ocnt = 4; 604 seqstate = normal; 605 rescan = 1; 606 break; 607 } 608 if (seqstate != octal) 609 { 610 if (oval) 611 To_seq (oval); 612 else 613 { 614 syntax_error (filename, lnum, 615 _("NUL character (\\000) not permitted"), 616 NULL, NULL, NULL, NULL); 617 error = 1; 618 } 619 } 620 break; 621 622 case special_key: 623 To_seq (SK_ESCAPE); 624 switch (c) 625 { 626 case 'u': To_seq (SK_UP_ARROW); break; 627 case 'd': To_seq (SK_DOWN_ARROW); break; 628 case 'r': To_seq (SK_RIGHT_ARROW); break; 629 case 'l': To_seq (SK_LEFT_ARROW); break; 630 case 'U': To_seq (SK_PAGE_UP); break; 631 case 'D': To_seq (SK_PAGE_DOWN); break; 632 case 'h': To_seq (SK_HOME); break; 633 case 'e': To_seq (SK_END); break; 634 case 'x': To_seq (SK_DELETE); break; 635 default: To_seq (SK_LITERAL); rescan = 1; break; 636 } 637 seqstate = normal; 638 break; 639 640 case control: 641 if (CONTROL (c)) 642 To_seq (CONTROL (c)); 643 else 644 { 645 syntax_error (filename, lnum, 646 (char *) _("NUL character (^%c) not permitted"), 647 (void *) (long) c, NULL, NULL, NULL); 648 error = 1; 649 } 650 seqstate = normal; 651 break; 652 } 653 break; 654 655 case got_keyseq: 656 if (isspace (c) && c != '\n') 657 break; 658 state = get_action; 659 alen = 0; 660 /* fall through */ 661 case get_action: 662 if (c == '\n' || isspace (c)) 663 { 664 int a; 665 666 state = got_action; 667 rescan = 1; 668 if (alen == 0) 669 { 670 syntax_error (filename, lnum, (char *) _("missing action name"), 671 (void *) (long) c, NULL, NULL, NULL); 672 error = 1; 673 } 674 else 675 { 676 act[alen] = '\0'; 677 a = lookup_action (act); 678 if (a != -1) 679 { 680 char av = a; 681 682 if (!(add_to_section (§ions[section], seq, slen) 683 && add_to_section (§ions[section], "", 1) 684 && add_to_section (§ions[section], &av, 1))) 685 { 686 syntax_error (filename, lnum, _("section too long"), 687 NULL, NULL, NULL, NULL); 688 error = 1; 689 } 690 } 691 else 692 { 693 syntax_error (filename, lnum, _("unknown action `%s'"), 694 act, NULL, NULL, NULL); 695 error = 1; 696 } 697 } 698 } 699 else if (alen < sizeof act - 1) 700 act[alen++] = c; 701 else 702 { 703 syntax_error (filename, lnum, _("action name too long"), 704 NULL, NULL, NULL, NULL); 705 error = 1; 706 } 707 break; 708 709 case got_action: 710 if (c == '#') 711 state = in_trailing_comment; 712 else if (c == '\n') 713 state = start_of_line; 714 else if (!isspace (c)) 715 { 716 syntax_error (filename, lnum, 717 _("extra characters following action `%s'"), 718 act, NULL, NULL, NULL); 719 error = 1; 720 } 721 break; 722 723 case get_varname: 724 if (c == '=') 725 { 726 if (varlen == 0) 727 { 728 syntax_error (filename, lnum, _("missing variable name"), 729 NULL, NULL, NULL, NULL); 730 error = 1; 731 } 732 state = get_value; 733 vallen = 0; 734 } 735 else if (c == '\n' || isspace (c)) 736 { 737 syntax_error (filename, lnum, 738 _("missing `=' immediately after variable name"), 739 NULL, NULL, NULL, NULL); 740 error = 1; 741 } 742 else if (varlen < sizeof varn) 743 varn[varlen++] = c; 744 else 745 { 746 syntax_error (filename, lnum, _("variable name too long"), 747 NULL, NULL, NULL, NULL); 748 error = 1; 749 } 750 break; 751 752 case get_value: 753 if (c == '\n') 754 { 755 state = start_of_line; 756 if (!(add_to_section (§ions[section], varn, varlen) 757 && add_to_section (§ions[section], "", 1) 758 && add_to_section (§ions[section], val, vallen) 759 && add_to_section (§ions[section], "", 1))) 760 { 761 syntax_error (filename, lnum, _("section too long"), 762 NULL, NULL, NULL, NULL); 763 error = 1; 764 } 765 } 766 else if (vallen < sizeof val) 767 val[vallen++] = c; 768 else 769 { 770 syntax_error (filename, lnum, _("value too long"), 771 NULL, NULL, NULL, NULL); 772 error = 1; 773 } 774 break; 775 776 case get_equals: 777 case got_equals: 778 case got_varname: 779 break; 780 } 781 } 782 783 #undef To_seq 784 785 return !error; 786 } 787 788 /* Add some characters to a section's data. Return true if all the 789 characters fit, or false if the section's size limit was exceeded. 790 */ 791 static int 792 add_to_section (struct sect *s, const char *str, unsigned int len) 793 { 794 if (s->cur + len > sizeof s->data) 795 return 0; 796 strncpy ((char *) s->data + s->cur, str, len); 797 s->cur += len; 798 return 1; 799 } 800 801 /* Translate from an action name to its numeric code. This uses the 802 auto-generated array in key.c. 803 */ 804 static int 805 lookup_action (const char *actname) 806 { 807 int i; 808 809 if (strcmp ("invalid", actname) == 0) 810 return A_INVALID; 811 for (i = 0; function_key_array[i].name != NULL; i++) 812 if (strcmp (function_key_array[i].name, actname) == 0) 813 return function_key_array[i].code; 814 return -1; 815 } 816 817 /* Put an integer to an infokey file. 818 Integers are stored as two bytes, low order first, 819 in radix INFOKEY_RADIX. 820 */ 821 static int 822 putint (int i, FILE *fp) 823 { 824 return fputc (i % INFOKEY_RADIX, fp) != EOF 825 && fputc ((i / INFOKEY_RADIX) % INFOKEY_RADIX, fp) != EOF; 826 } 827 828 /* Write an entire section to an infokey file. If the section is 829 empty, simply omit it. 830 */ 831 static int 832 putsect (struct sect *s, int code, FILE *fp) 833 { 834 if (s->cur == 0) 835 return 1; 836 return fputc (code, fp) != EOF 837 && putint (s->cur, fp) 838 && fwrite (s->data, s->cur, 1, fp) == 1; 839 } 840 841 /* Write an entire infokey file, given an array containing its sections. 842 */ 843 static int 844 write_infokey_file (FILE *fp, struct sect *sections) 845 { 846 /* Get rid of sections with no effect. */ 847 if (sections[info].cur == 1 && sections[info].data[0] == 0) 848 sections[info].cur = 0; 849 if (sections[ea].cur == 1 && sections[ea].data[0] == 0) 850 sections[ea].cur = 0; 851 852 /* Write all parts of the file out in order (no lseeks), 853 checking for errors all the way. */ 854 return fputc (INFOKEY_MAGIC_S0, fp) != EOF 855 && fputc (INFOKEY_MAGIC_S1, fp) != EOF 856 && fputc (INFOKEY_MAGIC_S2, fp) != EOF 857 && fputc (INFOKEY_MAGIC_S3, fp) != EOF 858 && fputs (VERSION, fp) != EOF 859 && fputc ('\0', fp) != EOF 860 && putsect (§ions[info], INFOKEY_SECTION_INFO, fp) 861 && putsect (§ions[ea], INFOKEY_SECTION_EA, fp) 862 && putsect (§ions[var], INFOKEY_SECTION_VAR, fp) 863 && fputc (INFOKEY_MAGIC_E0, fp) != EOF 864 && fputc (INFOKEY_MAGIC_E1, fp) != EOF 865 && fputc (INFOKEY_MAGIC_E2, fp) != EOF 866 && fputc (INFOKEY_MAGIC_E3, fp) != EOF; 867 } 868 869 870 /* Error handling. */ 871 872 /* Give the user a "syntax error" message in the form 873 progname: "filename", line N: message 874 */ 875 static void 876 error_message (int error_code, const char *fmt, 877 const void *a1, const void *a2, const void *a3, const void *a4) 878 { 879 fprintf (stderr, "%s: ", program_name); 880 fprintf (stderr, fmt, a1, a2, a3, a4); 881 if (error_code) 882 fprintf (stderr, " - %s", strerror (error_code)); 883 fprintf (stderr, "\n"); 884 } 885 886 /* Give the user a generic error message in the form 887 progname: message 888 */ 889 static void 890 syntax_error (const char *filename, 891 unsigned int linenum, const char *fmt, 892 const void *a1, const void *a2, const void *a3, const void *a4) 893 { 894 fprintf (stderr, "%s: ", program_name); 895 fprintf (stderr, _("\"%s\", line %u: "), filename, linenum); 896 fprintf (stderr, fmt, a1, a2, a3, a4); 897 fprintf (stderr, "\n"); 898 } 899 900 /* Produce a gentle rtfm. */ 901 static void 902 suggest_help (void) 903 { 904 fprintf (stderr, _("Try --help for more information.\n")); 905 } 906 907 /* Produce a scaled down description of the available options to Info. */ 908 static void 909 short_help (void) 910 { 911 printf (_("\ 912 Usage: %s [OPTION]... [INPUT-FILE]\n\ 913 \n\ 914 Compile infokey source file to infokey file. Reads INPUT-FILE (default\n\ 915 $HOME/.infokey) and writes compiled key file to (by default) $HOME/.info.\n\ 916 \n\ 917 Options:\n\ 918 --output FILE output to FILE instead of $HOME/.info\n\ 919 --help display this help and exit.\n\ 920 --version display version information and exit.\n\ 921 "), program_name); 922 923 puts (_("\n\ 924 Email bug reports to bug-texinfo@gnu.org,\n\ 925 general questions and discussion to help-texinfo@gnu.org.\n\ 926 Texinfo home page: http://www.gnu.org/software/texinfo/")); 927 928 xexit (0); 929 } 930