1/* infokey.c -- compile ~/.infokey to ~/.info.
| 1/* infokey.c -- compile ~/.infokey to ~/.info.
|
2 $Id: infokey.c,v 1.5 2002/02/26 16:17:57 karl Exp $
| 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 28static char *program_name = "infokey"; 29 30/* Non-zero means print version info only. */ 31static int print_version_p = 0; 32 33/* Non-zero means print a short description of the options. */ 34static 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. */ 38static 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. */ 42static 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. */ 47static 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. */ 56static char *short_options = "o:"; 57 58/* Structure for holding the compiled sections. */ 59enum sect_e 60 { 61 info = 0, 62 ea = 1,
| 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 28static char *program_name = "infokey"; 29 30/* Non-zero means print version info only. */ 31static int print_version_p = 0; 32 33/* Non-zero means print a short description of the options. */ 34static 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. */ 38static 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. */ 42static 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. */ 47static 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. */ 56static char *short_options = "o:"; 57 58/* Structure for holding the compiled sections. */ 59enum sect_e 60 { 61 info = 0, 62 ea = 1,
|
63 var = 2,
| 63 var = 2
|
64 }; 65struct sect 66 { 67 unsigned int cur; 68 unsigned char data[INFOKEY_MAX_SECTIONLEN]; 69 }; 70 71/* Some "forward" declarations. */ 72static char *mkpath (); 73static int compile (), write_infokey_file (); 74static void syntax_error (), error_message (), suggest_help (), short_help (); 75 76 77/* **************************************************************** */ 78/* */ 79/* Main Entry Point to the Infokey Program */ 80/* */ 81/* **************************************************************** */ 82 83int 84main (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\ 140There is NO warranty. You may redistribute this software\n\ 141under the terms of the GNU General Public License.\n\ 142For 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 239static char * 240mkpath (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 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 369static 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 */ 374static int 375compile (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,
| 64 }; 65struct sect 66 { 67 unsigned int cur; 68 unsigned char data[INFOKEY_MAX_SECTIONLEN]; 69 }; 70 71/* Some "forward" declarations. */ 72static char *mkpath (); 73static int compile (), write_infokey_file (); 74static void syntax_error (), error_message (), suggest_help (), short_help (); 75 76 77/* **************************************************************** */ 78/* */ 79/* Main Entry Point to the Infokey Program */ 80/* */ 81/* **************************************************************** */ 82 83int 84main (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\ 140There is NO warranty. You may redistribute this software\n\ 141under the terms of the GNU General Public License.\n\ 142For 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 239static char * 240mkpath (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 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 369static 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 */ 374static int 375compile (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,
| 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,
| 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,
| 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 (§ions[section], seq, slen) 664 && add_to_section (§ions[section], "", 1) 665 && add_to_section (§ions[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 (§ions[section], varn, varlen) 729 && add_to_section (§ions[section], "", 1) 730 && add_to_section (§ions[section], val, vallen) 731 && add_to_section (§ions[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 */ 756static int 757add_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 */ 772static int 773lookup_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 */ 790static int 791putint (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 */ 802static int 803putsect (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 */ 817static int 818write_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 (§ions[info], INFOKEY_SECTION_INFO, fp) 837 && putsect (§ions[ea], INFOKEY_SECTION_EA, fp) 838 && putsect (§ions[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 845 846/* Error handling. */ 847 848/* Give the user a "syntax error" message in the form 849 progname: "filename", line N: message 850 */ 851static void 852error_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 */ 867static void 868syntax_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. */ 881static void 882suggest_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. */ 888static void 889short_help () 890{
| 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 (§ions[section], seq, slen) 664 && add_to_section (§ions[section], "", 1) 665 && add_to_section (§ions[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 (§ions[section], varn, varlen) 729 && add_to_section (§ions[section], "", 1) 730 && add_to_section (§ions[section], val, vallen) 731 && add_to_section (§ions[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 */ 756static int 757add_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 */ 772static int 773lookup_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 */ 790static int 791putint (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 */ 802static int 803putsect (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 */ 817static int 818write_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 (§ions[info], INFOKEY_SECTION_INFO, fp) 837 && putsect (§ions[ea], INFOKEY_SECTION_EA, fp) 838 && putsect (§ions[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 845 846/* Error handling. */ 847 848/* Give the user a "syntax error" message in the form 849 progname: "filename", line N: message 850 */ 851static void 852error_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 */ 867static void 868syntax_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. */ 881static void 882suggest_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. */ 888static void 889short_help () 890{
|
891 printf (_ ("\
| 891 printf (_("\
|
892Usage: %s [OPTION]... [INPUT-FILE]\n\ 893\n\ 894Compile 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\ 897Options:\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\
| 892Usage: %s [OPTION]... [INPUT-FILE]\n\ 893\n\ 894Compile 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\ 897Options:\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\n\
| 901"), program_name); 902 903 puts (_("\n\
|
902Email bug reports to bug-texinfo@gnu.org,\n\ 903general questions and discussion to help-texinfo@gnu.org.\n\
| 904Email bug reports to bug-texinfo@gnu.org,\n\ 905general questions and discussion to help-texinfo@gnu.org.\n\
|
904"), 905 program_name 906 );
| 906Texinfo home page: http://www.gnu.org/software/texinfo/")); 907
|
907 xexit (0); 908}
| 908 xexit (0); 909}
|