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