1 /* Command line processing */
10 #ifdef HAVE_SYS_SOCKET_H
11 #include <sys/socket.h> /* OS/2 needs this after sys/types.h */
13 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
18 /* We need to have it here. Stupid BSD. */
19 #ifdef HAVE_NETINET_IN_H
20 #include <netinet/in.h>
22 #ifdef HAVE_ARPA_INET_H
23 #include <arpa/inet.h>
28 #include "config/cmdline.h"
29 #include "config/conf.h"
30 #include "config/options.h"
31 #include "config/opttypes.h"
32 #include "intl/gettext/libintl.h"
33 #include "network/dns.h"
34 #include "protocol/uri.h"
35 #include "session/session.h"
36 #include "util/error.h"
37 #include "util/file.h"
38 #include "util/lists.h"
39 #include "util/memory.h"
40 #include "util/string.h"
43 /* Hack to handle URL extraction for -remote commands */
44 static unsigned char *remote_url
;
47 parse_options_(int argc
, unsigned char *argv
[], struct option
*opt
,
48 struct list_head
*url_list
)
53 if (argv
[-1][0] == '-' && argv
[-1][1]) {
54 struct option
*option
;
55 unsigned char *argname
= &argv
[-1][1];
56 unsigned char *oname
= stracpy(argname
);
61 /* Treat --foo same as -foo. */
62 if (argname
[0] == '-') argname
++;
64 option
= get_opt_rec(opt
, argname
);
65 if (!option
) option
= get_opt_rec(opt
, oname
);
69 oname
++; /* the '-' */
70 /* Substitute '-' by '_'. This helps
71 * compatibility with that very wicked browser
73 for (pos
= strchr(oname
, '_'); pos
;
74 pos
= strchr(pos
, '_'))
76 option
= get_opt_rec(opt
, oname
);
82 if (!option
) goto unknown_option
;
84 if (!option_types
[option
->type
].cmdline
)
87 err
= option_types
[option
->type
].cmdline(option
, &argv
, &argc
);
91 usrerror(gettext("Cannot parse option %s: %s"), argv
[-1], err
);
96 /* XXX: Empty strings means all is well and have
97 * a cup of shut the fsck up. */
100 } else if (remote_url
) {
101 if (url_list
) add_to_string_list(url_list
, remote_url
, -1);
102 mem_free(remote_url
);
106 } else if (url_list
) {
107 add_to_string_list(url_list
, argv
[-1], -1);
114 usrerror(gettext("Unknown option %s"), argv
[-1]);
119 parse_options(int argc
, unsigned char *argv
[], struct list_head
*url_list
)
121 return parse_options_(argc
, argv
, cmdline_options
, url_list
);
125 /**********************************************************************
127 **********************************************************************/
129 static unsigned char *
130 eval_cmd(struct option
*o
, unsigned char ***argv
, int *argc
)
132 if (*argc
< 1) return gettext("Parameter expected");
134 (*argv
)++; (*argc
)--; /* Consume next argument */
136 parse_config_file(config_options
, "-eval", *(*argv
- 1), NULL
, 0);
143 static unsigned char *
144 forcehtml_cmd(struct option
*o
, unsigned char ***argv
, int *argc
)
146 safe_strncpy(get_opt_str("mime.default_type"), "text/html", MAX_STR_LEN
);
150 static unsigned char *
151 lookup_cmd(struct option
*o
, unsigned char ***argv
, int *argc
)
153 struct sockaddr_storage
*addrs
= NULL
;
156 if (!*argc
) return gettext("Parameter expected");
157 if (*argc
> 1) return gettext("Too many parameters");
159 (*argv
)++; (*argc
)--;
160 if (do_real_lookup(*(*argv
- 1), &addrs
, &addrno
, 0) == DNS_ERROR
) {
162 herror(gettext("error"));
164 usrerror(gettext("Host not found"));
169 for (i
= 0; i
< addrno
; i
++) {
171 struct sockaddr_in6 addr
= *((struct sockaddr_in6
*) &(addrs
)[i
]);
172 unsigned char p
[INET6_ADDRSTRLEN
];
174 if (! inet_ntop(addr
.sin6_family
,
175 (addr
.sin6_family
== AF_INET6
? (void *) &addr
.sin6_addr
176 : (void *) &((struct sockaddr_in
*) &addr
)->sin_addr
),
177 p
, INET6_ADDRSTRLEN
))
178 ERROR(gettext("Resolver error"));
182 struct sockaddr_in addr
= *((struct sockaddr_in
*) &(addrs
)[i
]);
183 unsigned char *p
= (unsigned char *) &addr
.sin_addr
.s_addr
;
185 printf("%d.%d.%d.%d\n", (int) p
[0], (int) p
[1],
186 (int) p
[2], (int) p
[3]);
197 #define skipback_whitespace(start, S) \
198 while ((start) < (S) && isspace((S)[-1])) (S)--;
200 static unsigned char *
201 remote_cmd(struct option
*o
, unsigned char ***argv
, int *argc
)
206 REMOTE_METHOD_OPENURL
,
208 REMOTE_METHOD_XFEDOCOMMAND
,
209 REMOTE_METHOD_ADDBOOKMARK
,
210 REMOTE_METHOD_INFOBOX
,
211 REMOTE_METHOD_NOT_SUPPORTED
,
213 } remote_methods
[] = {
214 { "openURL", REMOTE_METHOD_OPENURL
},
215 { "ping", REMOTE_METHOD_PING
},
216 { "addBookmark", REMOTE_METHOD_ADDBOOKMARK
},
217 { "infoBox", REMOTE_METHOD_INFOBOX
},
218 { "xfeDoCommand", REMOTE_METHOD_XFEDOCOMMAND
},
219 { NULL
, REMOTE_METHOD_NOT_SUPPORTED
},
221 unsigned char *command
, *arg
, *argend
= NULL
;
224 if (*argc
< 1) return gettext("Parameter expected");
228 while (isalpha(command
[len
]))
231 arg
= strchr(&command
[len
], '(');
236 argend
= strchr(arg
, ')');
240 /* Just open any passed URLs in new tabs */
241 remote_session_flags
|= SES_REMOTE_NEW_TAB
;
245 skipback_whitespace(arg
, argend
);
247 for (method
= 0; remote_methods
[method
].name
; method
++) {
248 unsigned char *name
= remote_methods
[method
].name
;
250 if (!strlcasecmp(command
, len
, name
, -1))
254 switch (remote_methods
[method
].type
) {
255 case REMOTE_METHOD_OPENURL
:
257 /* Prompt for a URL with a dialog box */
258 remote_session_flags
|= SES_REMOTE_PROMPT_URL
;
262 len
= strcspn(arg
, ",)");
263 if (arg
[len
] == ',') {
264 unsigned char *where
= arg
+ len
+ 1;
266 if (strstr(where
, "new-window")) {
267 remote_session_flags
|= SES_REMOTE_NEW_WINDOW
;
269 } else if (strstr(where
, "new-tab")) {
270 remote_session_flags
|= SES_REMOTE_NEW_TAB
;
273 /* Bail out when getting unknown parameter */
274 /* TODO: new-screen */
279 remote_session_flags
|= SES_REMOTE_CURRENT_TAB
;
282 while (len
> 0 && isspace(arg
[len
- 1])) len
--;
285 /* Skip possible string delimiters. Atleast urlview
286 * seems to add them. */
287 if ((arg
[0] == '\'' && arg
[len
- 1] == '\'')
288 || (arg
[0] == '"' && arg
[len
- 1] == '"'))
292 if (len
) remote_url
= memacpy(arg
, len
);
296 case REMOTE_METHOD_XFEDOCOMMAND
:
299 if (!strlcasecmp(arg
, len
, "openBrowser", 11)) {
300 remote_session_flags
= SES_REMOTE_NEW_WINDOW
;
304 case REMOTE_METHOD_PING
:
305 remote_session_flags
= SES_REMOTE_PING
;
308 case REMOTE_METHOD_ADDBOOKMARK
:
309 if (arg
== argend
) break;
310 remote_url
= memacpy(arg
, argend
- arg
);
311 remote_session_flags
= SES_REMOTE_ADD_BOOKMARK
;
314 case REMOTE_METHOD_INFOBOX
:
315 if (arg
== argend
) break;
316 remote_url
= memacpy(arg
, argend
- arg
);
318 insert_in_string(&remote_url
, 0, "about:", 6);
319 remote_session_flags
= SES_REMOTE_INFO_BOX
;
322 case REMOTE_METHOD_NOT_SUPPORTED
:
326 /* If no flags was applied it can only mean we are dealing with
328 if (!remote_session_flags
)
329 return gettext("Remote method not supported");
331 (*argv
)++; (*argc
)--; /* Consume next argument */
336 static unsigned char *
337 version_cmd(struct option
*o
, unsigned char ***argv
, int *argc
)
339 printf("%s\n", full_static_version
);
345 /* Below we handle help usage printing.
347 * We're trying to achieve several goals here:
349 * - Genericly define a function to print option trees iteratively.
350 * - Make output parsable for various doc tools (to make manpages).
351 * - Do some non generic fancy stuff like printing semi-aliased
352 * options (like: -?, -h and -help) on one line when printing
355 #define gettext_nonempty(x) (*(x) ? gettext(x) : (x))
358 print_full_help(struct option
*tree
, unsigned char *path
)
360 struct option
*option
;
361 unsigned char saved
[MAX_STR_LEN
];
362 unsigned char *savedpos
= saved
;
366 foreach (option
, *tree
->value
.tree
) {
367 enum option_type type
= option
->type
;
369 unsigned char *capt
= option
->capt
;
370 unsigned char *desc
= (option
->desc
&& *option
->desc
)
371 ? (unsigned char *) gettext(option
->desc
)
372 : (unsigned char *) "N/A";
374 /* Don't print deprecated aliases (if we don't walk command
375 * line options which use aliases for legitimate options). */
376 if ((type
== OPT_ALIAS
&& tree
!= cmdline_options
)
377 || (option
->flags
& OPT_HIDDEN
))
380 if (!capt
&& !strncasecmp(option
->name
, "_template_", 10))
381 capt
= (unsigned char *) N_("Template option folder");
384 int len
= strlen(option
->name
);
385 int max
= MAX_STR_LEN
- (savedpos
- saved
);
387 safe_strncpy(savedpos
, option
->name
, max
);
388 safe_strncpy(savedpos
+ len
, ", -", max
- len
);
393 help
= gettext_nonempty(option_types
[option
->type
].help_str
);
395 if (type
!= OPT_TREE
)
396 printf(" %s%s%s %s ",
397 path
, saved
, option
->name
, help
);
399 /* Print the 'title' of each option type. */
404 printf(gettext("(default: %ld)"),
406 ? option
->value
.big_number
407 : (long) option
->value
.number
);
411 printf(gettext("(default: \"%s\")"),
412 option
->value
.string
);
416 printf(gettext("(alias for %s)"),
417 option
->value
.string
);
421 printf(gettext("(default: %s)"),
422 get_cp_name(option
->value
.number
));
427 color_T color
= option
->value
.color
;
428 unsigned char hexcolor
[8];
430 printf(gettext("(default: %s)"),
431 get_color_string(color
, hexcolor
));
440 printf(gettext("(default: \"%s\")"),
441 language_to_name(option
->value
.number
));
447 int pathlen
= strlen(path
);
448 int namelen
= strlen(option
->name
);
450 if (pathlen
+ namelen
+ 2 > MAX_STR_LEN
)
453 /* Append option name to path */
455 memcpy(saved
, path
, pathlen
);
456 savedpos
= saved
+ pathlen
;
460 memcpy(savedpos
, option
->name
, namelen
+ 1);
463 capt
= gettext_nonempty(capt
);
464 printf(" %s: (%s)", capt
, saved
);
469 printf("\n %8s", "");
471 int l
= strlen(desc
);
474 for (i
= 0; i
< l
; i
++) {
483 if (option
->type
== OPT_TREE
) {
484 memcpy(savedpos
, ".", 2);
485 print_full_help(option
, saved
);
494 print_short_help(void)
496 #define ALIGN_WIDTH 20
497 struct option
*option
;
498 struct string string
= NULL_STRING
;
499 struct string
*saved
= NULL
;
500 unsigned char align
[ALIGN_WIDTH
];
502 /* Initialize @space used to align captions. */
503 memset(align
, ' ', sizeof(align
) - 1);
504 align
[sizeof(align
) - 1] = 0;
506 foreach (option
, *cmdline_options
->value
.tree
) {
509 unsigned char *info
= saved
? saved
->source
510 : (unsigned char *) "";
511 int len
= strlen(option
->name
);
513 /* Avoid printing compatibility options */
514 if (option
->flags
& OPT_HIDDEN
)
517 /* When no caption is available the option name is 'stacked'
518 * and the caption is shared with next options that has one. */
521 if (!init_string(&string
))
527 add_to_string(saved
, option
->name
);
528 add_to_string(saved
, ", -");
532 capt
= gettext_nonempty(option
->capt
);
533 help
= gettext_nonempty(option_types
[option
->type
].help_str
);
535 /* When @help string is non empty align at least one space. */
536 len
= ALIGN_WIDTH
- len
- strlen(help
);
537 len
-= (saved
? saved
->length
: 0);
538 len
= (len
< 0) ? !!(*help
) : len
;
541 printf(" -%s%s %s%s%s\n",
542 info
, option
->name
, help
, align
, capt
);
552 #undef gettext_nonempty
554 static unsigned char *
555 printhelp_cmd(struct option
*option
, unsigned char ***argv
, int *argc
)
557 unsigned char *lineend
= strchr(full_static_version
, '\n');
559 if (lineend
) *lineend
= '\0';
561 printf("%s\n\n", full_static_version
);
563 if (!strcmp(option
->name
, "config-help")) {
564 printf("%s:\n", gettext("Configuration options"));
565 print_full_help(config_options
, "");
567 printf("%s\n\n%s:\n",
568 gettext("Usage: elinks [OPTION]... [URL]..."),
570 if (!strcmp(option
->name
, "long-help")) {
571 print_full_help(cmdline_options
, "-");
581 static unsigned char *
582 redir_cmd(struct option
*option
, unsigned char ***argv
, int *argc
)
584 unsigned char *target
;
586 /* I can't get any dirtier. --pasky */
588 if (!strcmp(option
->name
, "confdir")) {
589 target
= "config-dir";
590 } else if (!strcmp(option
->name
, "conffile")) {
591 target
= "config-file";
592 } else if (!strcmp(option
->name
, "stdin")) {
593 static int complained
;
599 /* Emulate bool option, possibly eating following 0/1. */
601 && ((*argv
)[0][0] == '0' || (*argv
)[0][0] == '1')
603 (*argv
)++, (*argc
)--;
604 fprintf(stderr
, "Warning: Deprecated option -stdin used!\n");
605 fprintf(stderr
, "ELinks now determines the -stdin option value automatically.\n");
606 fprintf(stderr
, "In the future versions ELinks will report error when you will\n");
607 fprintf(stderr
, "continue to use this option.\a\n");
611 return gettext("Internal consistency error");
614 option
= get_opt_rec(cmdline_options
, target
);
616 option_types
[option
->type
].cmdline(option
, argv
, argc
);
620 static unsigned char *
621 printconfigdump_cmd(struct option
*option
, unsigned char ***argv
, int *argc
)
623 unsigned char *config_string
;
626 get_opt_int("config.saving_style") = 2;
628 config_string
= create_config_string("", "", config_options
);
630 printf("%s", config_string
);
631 mem_free(config_string
);
639 /**********************************************************************
641 **********************************************************************/
643 /* Keep options in alphabetical order. */
645 struct option_info cmdline_options_info
[] = {
646 /* [gettext_accelerator_context(IGNORE)] */
647 INIT_OPT_BOOL("", N_("Restrict to anonymous mode"),
649 N_("Restricts ELinks so it can run on an anonymous account.\n"
650 "Local file browsing, downloads, and modification of options\n"
651 "will be disabled. Execution of viewers is allowed, but entries\n"
652 "in the association table can't be added or modified.")),
654 INIT_OPT_BOOL("", N_("Autosubmit first form"),
656 N_("Automatically submit the first form in the given URLs.")),
658 INIT_OPT_INT("", N_("Clone internal session with given ID"),
659 "base-session", 0, 0, INT_MAX
, 0,
660 N_("Used internally when opening ELinks instances in new windows.\n"
661 "The ID maps to information that will be used when creating the\n"
662 "new instance. You don't want to use it.")),
664 INIT_OPT_COMMAND("", NULL
, "confdir", OPT_HIDDEN
, redir_cmd
, NULL
),
666 INIT_OPT_STRING("", N_("Name of directory with configuration file"),
668 N_("Path of the directory ELinks will read and write its\n"
669 "config and runtime state files to instead of ~/.elinks.\n"
670 "If the path does not begin with a '/' it is assumed to be\n"
671 "relative to your HOME directory.")),
673 INIT_OPT_COMMAND("", N_("Print default configuration file to stdout"),
674 "config-dump", 0, printconfigdump_cmd
,
675 N_("Print a configuration file with options set to the built-in\n"
676 "defaults to stdout.")),
678 INIT_OPT_COMMAND("", NULL
, "conffile", OPT_HIDDEN
, redir_cmd
, NULL
),
680 INIT_OPT_STRING("", N_("Name of configuration file"),
681 "config-file", 0, "elinks.conf",
682 N_("Name of the configuration file that all configuration\n"
683 "options will be read from and written to. It should be\n"
684 "relative to config-dir.")),
686 INIT_OPT_COMMAND("", N_("Print help for configuration options"),
687 "config-help", 0, printhelp_cmd
,
688 N_("Print help for configuration options and exit.")),
690 INIT_OPT_CMDALIAS("", N_("MIME type assumed for unknown document types"),
691 "default-mime-type", 0, "mime.default_type",
692 N_("The default MIME type used for documents of unknown type.")),
694 INIT_OPT_BOOL("", N_("Ignore user-defined keybindings"),
695 "default-keys", 0, 0,
696 N_("When set, all keybindings from configuration files will be\n"
697 "ignored. It forces use of default keybindings and will reset\n"
698 "user-defined ones on save.")),
700 INIT_OPT_BOOL("", N_("Print formatted versions of given URLs to stdout"),
702 N_("Print formatted plain-text versions of given URLs to stdout.")),
704 INIT_OPT_CMDALIAS("", N_("Codepage to use with -dump"),
705 "dump-charset", 0, "document.dump.codepage",
706 N_("Codepage used when formatting dump output.")),
708 INIT_OPT_CMDALIAS("", N_("Color mode used with -dump"),
709 "dump-color-mode", 0, "document.dump.color_mode",
710 N_("Color mode used with -dump.")),
712 INIT_OPT_CMDALIAS("", N_("Width of document formatted with -dump"),
713 "dump-width", 0, "document.dump.width",
714 N_("Width of the dump output.")),
716 INIT_OPT_COMMAND("", N_("Evaluate configuration file directive"),
718 N_("Specify configuration file directives on the command-line\n"
719 "which will be evaluated after all configuration files has been\n"
720 "read. Example usage:\n"
721 "\t-eval 'set protocol.file.allow_special_files = 1'")),
723 /* lynx compatibility */
724 INIT_OPT_COMMAND("", N_("Interpret documents of unknown types as HTML"),
725 "force-html", 0, forcehtml_cmd
,
726 N_("Makes ELinks assume documents of unknown types are HTML.\n"
727 "Useful when using ELinks as an external viewer from MUAs.\n"
728 "This is equivalent to -default-mime-type text/html.")),
730 /* XXX: -?, -h and -help share the same caption and should be kept in
731 * the current order for usage help printing to be ok */
732 INIT_OPT_COMMAND("", NULL
, "?", 0, printhelp_cmd
, NULL
),
734 INIT_OPT_COMMAND("", NULL
, "h", 0, printhelp_cmd
, NULL
),
736 INIT_OPT_COMMAND("", N_("Print usage help and exit"),
737 "help", 0, printhelp_cmd
,
738 N_("Print usage help and exit.")),
740 INIT_OPT_BOOL("", N_("Only permit local connections"),
742 N_("Restricts ELinks to work offline and only connect to servers\n"
743 "with local addresses (ie. 127.0.0.1). No connections to remote\n"
744 "servers will be permitted.")),
746 INIT_OPT_COMMAND("", N_("Print detailed usage help and exit"),
747 "long-help", 0, printhelp_cmd
,
748 N_("Print detailed usage help and exit.")),
750 INIT_OPT_COMMAND("", N_("Look up specified host"),
751 "lookup", 0, lookup_cmd
,
752 N_("Look up specified host and print all DNS resolved IP addresses.")),
754 INIT_OPT_BOOL("", N_("Run as separate instance"),
756 N_("Run ELinks as a separate instance instead of connecting to an\n"
757 "existing instance. Note that normally no runtime state files\n"
758 "(bookmarks, history, etc.) are written to the disk when this\n"
759 "option is used. See also -touch-files.")),
761 INIT_OPT_BOOL("", N_("Disable use of files in ~/.elinks"),
763 N_("Disables creation and use of files in the user specific home\n"
764 "configuration directory (~/.elinks). It forces default configuration\n"
765 "values to be used and disables saving of runtime state files.")),
767 INIT_OPT_CMDALIAS("", N_("Disable link numbering in dump output"),
768 "no-numbering", OPT_ALIAS_NEGATE
, "document.dump.numbering",
769 N_("Prevents printing of link number in dump output.\n"
770 "Note that this really affects only -dump, nothing else.")),
772 INIT_OPT_CMDALIAS("", N_("Disable printing of link references in dump output"),
773 "no-references", OPT_ALIAS_NEGATE
, "document.dump.references",
774 N_("Prevents printing of references (URIs) of document links\n"
776 "Note that this really affects only -dump, nothing else.")),
778 INIT_OPT_COMMAND("", N_("Control an already running ELinks"),
779 "remote", 0, remote_cmd
,
780 N_("Control a remote ELinks instance by passing commands to it.\n"
781 "The option takes an additional argument containing the method\n"
782 "which should be invoked and any parameters that should be passed\n"
783 "to it. For ease of use, the additional method argument can be\n"
784 "omitted in which case any URL arguments will be opened in new\n"
785 "tabs in the remote instance.\n"
786 "Following is a list of the supported methods:\n"
787 "\tping() : look for a remote instance\n"
788 "\topenURL() : prompt URL in current tab\n"
789 "\topenURL(URL) : open URL in current tab\n"
790 "\topenURL(URL, new-tab) : open URL in new tab\n"
791 "\topenURL(URL, new-window) : open URL in new window\n"
792 "\taddBookmark(URL) : bookmark URL\n"
793 "\tinfoBox(text) : show text in a message box\n"
794 "\txfeDoCommand(openBrowser) : open new window")),
796 INIT_OPT_INT("", N_("Connect to session ring with given ID"),
797 "session-ring", 0, 0, INT_MAX
, 0,
798 N_("ID of session ring this ELinks session should connect to. ELinks\n"
799 "works in so-called session rings, whereby all instances of ELinks\n"
800 "are interconnected and share state (cache, bookmarks, cookies,\n"
801 "and so on). By default, all ELinks instances connect to session\n"
802 "ring 0. You can change that behaviour with this switch and form as\n"
803 "many session rings as you want. Obviously, if the session-ring with\n"
804 "this number doesn't exist yet, it's created and this ELinks instance\n"
805 "will become the master instance (that usually doesn't matter for you\n"
806 "as a user much). Note that you usually don't want to use this unless\n"
807 "you're a developer and you want to do some testing - if you want the\n"
808 "ELinks instances each running standalone, rather use the -no-connect\n"
809 "command-line option. Also note that normally no runtime state files\n"
810 "are written to the disk when this option is used. See also\n"
813 INIT_OPT_BOOL("", N_("Print the source of given URLs to stdout"),
815 N_("Print given URLs in source form to stdout.")),
817 INIT_OPT_COMMAND("", NULL
, "stdin", OPT_HIDDEN
, redir_cmd
, NULL
),
819 INIT_OPT_BOOL("", N_("Touch files in ~/.elinks when running with -no-connect/-session-ring"),
821 N_("When enabled, runtime state files (bookmarks, history, etc.) are\n"
822 "written to disk, even when -no-connect or -session-ring is used.\n"
823 "The option has no effect if not used in conjunction with any of\n"
826 INIT_OPT_INT("", N_("Verbose level"),
827 "verbose", 0, 0, VERBOSE_LEVELS
- 1, VERBOSE_WARNINGS
,
828 N_("The verbose level controls what messages are shown at\n"
829 "start up and while running:\n"
830 "\t0 means only show serious errors\n"
831 "\t1 means show serious errors and warnings\n"
832 "\t2 means show all messages")),
834 INIT_OPT_COMMAND("", N_("Print version information and exit"),
835 "version", 0, version_cmd
,
836 N_("Print ELinks version information and exit.")),