1 /* Get the contents of an URL.
2 Copyright (C) 2001-2003, 2005-2010, 2012, 2015 Free Software
4 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
35 #include "error-progname.h"
37 #include "relocatable.h"
39 #include "full-write.h"
42 #include "binary-io.h"
43 #include "propername.h"
46 #define _(str) gettext (str)
49 # define STDOUT_FILENO 1
53 /* Only high-level toolkits, written in languages with exception handling,
54 have an URL datatype and operations to fetch an URL's contents. Such
55 toolkits are Java (class java.net.URL), Qt (classes QUrl and QUrlOperator).
56 We use the Java toolkit.
57 Note that this program doesn't handle redirection pages; programs which
58 wish to process HTML redirection tags need to include a HTML parser,
59 and only full-fledged browsers like w3m, lynx, links have have both
60 an URL fetcher (which covers at least the protocols "http", "ftp", "file")
61 and a HTML parser. [Well, this is not true: libxml2 and Java (see
62 <http://java.sun.com/products/jfc/tsc/articles/bookmarks/>) also contain
66 /* Whether to output something on standard error.
67 This is true by default, because the user should know why we are trying to
68 establish an internet connection. Also, users get confused if a program
69 produces no output for more than 10 seconds for no apparent reason. */
70 static bool verbose = true;
73 static const struct option long_options[] =
75 { "help", no_argument, NULL, 'h' },
76 { "quiet", no_argument, NULL, 'q' },
77 { "silent", no_argument, NULL, 'q' },
78 { "version", no_argument, NULL, 'V' },
83 /* Forward declaration of local functions. */
84 static void usage (int status)
85 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
86 __attribute__ ((noreturn))
89 static void fetch (const char *url, const char *file);
93 main (int argc, char *argv[])
99 /* Set program name for messages. */
100 set_program_name (argv[0]);
101 error_print_progname = maybe_print_progname;
103 #ifdef HAVE_SETLOCALE
104 /* Set locale via LC_ALL. */
105 setlocale (LC_ALL, "");
108 /* Set the text message domain. */
109 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
110 textdomain (PACKAGE);
112 /* Ensure that write errors on stdout are detected. */
113 atexit (close_stdout);
115 /* Set default values for variables. */
119 /* Parse command line options. */
120 while ((optchar = getopt_long (argc, argv, "hqV", long_options, NULL)) != EOF)
123 case '\0': /* Long option. */
125 case 'h': /* --help */
128 case 'q': /* --quiet / --silent */
131 case 'V': /* --version */
135 usage (EXIT_FAILURE);
139 /* Version information requested. */
142 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
143 /* xgettext: no-wrap */
144 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
145 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
146 This is free software: you are free to change and redistribute it.\n\
147 There is NO WARRANTY, to the extent permitted by law.\n\
149 "2001-2003, 2005-2009");
150 printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
154 /* Help is requested. */
156 usage (EXIT_SUCCESS);
158 /* Test argument count. */
159 if (optind + 2 != argc)
160 error (EXIT_FAILURE, 0, _("expected two arguments"));
162 /* Fetch the contents. */
163 fetch (argv[optind], argv[optind + 1]);
168 /* Display usage information and exit. */
172 if (status != EXIT_SUCCESS)
173 fprintf (stderr, _("Try '%s --help' for more information.\n"),
178 Usage: %s [OPTION] URL FILE\n\
181 /* xgettext: no-wrap */
183 Fetches and outputs the contents of an URL. If the URL cannot be accessed,\n\
184 the locally accessible FILE is used instead.\n\
188 Informative output:\n"));
190 -h, --help display this help and exit\n"));
192 -V, --version output version information and exit\n"));
194 -q, --quiet, --silent suppress progress indicators\n"));
196 /* TRANSLATORS: The placeholder indicates the bug-reporting address
197 for this package. Please add _another line_ saying
198 "Report translation bugs to <...>\n" with the address for translation
199 bugs (typically your translation team's web or email address). */
200 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
207 /* Copy a file's contents to stdout. */
209 cat_file (const char *src_filename)
213 const int buf_size = sizeof (buf);
215 src_fd = open (src_filename, O_RDONLY | O_BINARY);
217 error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"),
222 ssize_t n_read = read (src_fd, buf, buf_size);
229 error (EXIT_FAILURE, errno, _("error reading \"%s\""), src_filename);
234 if (full_write (STDOUT_FILENO, buf, n_read) < n_read)
235 error (EXIT_FAILURE, errno, _("error writing stdout"));
238 if (close (src_fd) < 0)
239 error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
242 /* Exit code of the Java program. */
243 static int java_exitcode;
246 execute_it (const char *progname,
247 const char *prog_path, char **prog_argv,
253 execute (progname, prog_path, prog_argv, true, true, false, false, true,
255 /* Exit code 0 means success, 2 means timed out. */
256 return !(java_exitcode == 0 || java_exitcode == 2);
259 /* Fetch the URL. Upon error, use the FILE as fallback. */
261 fetch (const char *url, const char *file)
265 fprintf (stderr, _("Retrieving %s..."), url);
270 /* First try: using Java. */
272 const char *class_name = "gnu.gettext.GetURL";
273 const char *gettextjexedir;
274 const char *gettextjar;
278 /* Make it possible to override the executable's location. This is
279 necessary for running the testsuite before "make install". */
280 gettextjexedir = getenv ("GETTEXTJEXEDIR");
281 if (gettextjexedir == NULL || gettextjexedir[0] == '\0')
282 gettextjexedir = relocate (GETTEXTJEXEDIR);
284 gettextjexedir = NULL;
287 /* Make it possible to override the gettext.jar location. This is
288 necessary for running the testsuite before "make install". */
289 gettextjar = getenv ("GETTEXTJAR");
290 if (gettextjar == NULL || gettextjar[0] == '\0')
291 gettextjar = relocate (GETTEXTJAR);
293 /* Prepare arguments. */
297 /* Fetch the URL's contents. */
299 if (!execute_java_class (class_name, &gettextjar, 1, true, gettextjexedir,
306 if (java_exitcode == 0)
307 fprintf (stderr, _(" done.\n"));
308 else if (java_exitcode == 2)
309 fprintf (stderr, _(" timed out.\n"));
316 /* Second try: using "wget -q -O - -T 30 url". */
318 static bool wget_tested;
319 static bool wget_present;
323 /* Test for presence of wget: "wget --version > /dev/null" */
328 argv[1] = "--version";
330 exitstatus = execute ("wget", "wget", argv, false, false, true, true,
332 wget_present = (exitstatus == 0);
343 argv[2] = "-O"; argv[3] = "-";
344 argv[4] = "-T"; argv[5] = "30";
345 argv[6] = (char *) url;
347 exitstatus = execute ("wget", "wget", argv, true, false, false, false,
349 if (exitstatus != 127)
354 fprintf (stderr, _(" done.\n"));
360 /* Third try: using "lynx -source url". */
362 static bool lynx_tested;
363 static bool lynx_present;
367 /* Test for presence of lynx: "lynx --version > /dev/null" */
372 argv[1] = "--version";
374 exitstatus = execute ("lynx", "lynx", argv, false, false, true, true,
376 lynx_present = (exitstatus == 0);
387 argv[2] = (char *) url;
389 exitstatus = execute ("lynx", "lynx", argv, true, false, false, false,
391 if (exitstatus != 127)
396 fprintf (stderr, _(" done.\n"));
402 /* Fourth try: using "curl --silent url". */
404 static bool curl_tested;
405 static bool curl_present;
409 /* Test for presence of curl: "curl --version > /dev/null" */
414 argv[1] = "--version";
416 exitstatus = execute ("curl", "curl", argv, false, false, true, true,
418 curl_present = (exitstatus == 0 || exitstatus == 2);
428 argv[1] = "--silent";
429 argv[2] = (char *) url;
431 exitstatus = execute ("curl", "curl", argv, true, false, false, false,
433 if (exitstatus != 127)
438 fprintf (stderr, _(" done.\n"));
446 fprintf (stderr, _(" failed.\n"));
447 /* Use the file as fallback. */