1 /* Get the contents of an URL.
2 Copyright (C) 2001-2003, 2005-2010, 2012 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
34 #include "error-progname.h"
36 #include "relocatable.h"
38 #include "full-write.h"
41 #include "binary-io.h"
42 #include "propername.h"
45 #define _(str) gettext (str)
48 # define STDOUT_FILENO 1
52 /* Only high-level toolkits, written in languages with exception handling,
53 have an URL datatype and operations to fetch an URL's contents. Such
54 toolkits are Java (class java.net.URL), Qt (classes QUrl and QUrlOperator).
55 We use the Java toolkit.
56 Note that this program doesn't handle redirection pages; programs which
57 wish to process HTML redirection tags need to include a HTML parser,
58 and only full-fledged browsers like w3m, lynx, links have have both
59 an URL fetcher (which covers at least the protocols "http", "ftp", "file")
60 and a HTML parser. [Well, this is not true: libxml2 and Java (see
61 <http://java.sun.com/products/jfc/tsc/articles/bookmarks/>) also contain
65 /* Whether to output something on standard error.
66 This is true by default, because the user should know why we are trying to
67 establish an internet connection. Also, users get confused if a program
68 produces no output for more than 10 seconds for no apparent reason. */
69 static bool verbose = true;
72 static const struct option long_options[] =
74 { "help", no_argument, NULL, 'h' },
75 { "quiet", no_argument, NULL, 'q' },
76 { "silent", no_argument, NULL, 'q' },
77 { "version", no_argument, NULL, 'V' },
82 /* Forward declaration of local functions. */
83 static void usage (int status)
84 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
85 __attribute__ ((noreturn))
88 static void fetch (const char *url, const char *file);
92 main (int argc, char *argv[])
98 /* Set program name for messages. */
99 set_program_name (argv[0]);
100 error_print_progname = maybe_print_progname;
102 #ifdef HAVE_SETLOCALE
103 /* Set locale via LC_ALL. */
104 setlocale (LC_ALL, "");
107 /* Set the text message domain. */
108 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
109 textdomain (PACKAGE);
111 /* Ensure that write errors on stdout are detected. */
112 atexit (close_stdout);
114 /* Set default values for variables. */
118 /* Parse command line options. */
119 while ((optchar = getopt_long (argc, argv, "hqV", long_options, NULL)) != EOF)
122 case '\0': /* Long option. */
124 case 'h': /* --help */
127 case 'q': /* --quiet / --silent */
130 case 'V': /* --version */
134 usage (EXIT_FAILURE);
138 /* Version information requested. */
141 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
142 /* xgettext: no-wrap */
143 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
144 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
145 This is free software: you are free to change and redistribute it.\n\
146 There is NO WARRANTY, to the extent permitted by law.\n\
148 "2001-2003, 2005-2009");
149 printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
153 /* Help is requested. */
155 usage (EXIT_SUCCESS);
157 /* Test argument count. */
158 if (optind + 2 != argc)
159 error (EXIT_FAILURE, 0, _("expected two arguments"));
161 /* Fetch the contents. */
162 fetch (argv[optind], argv[optind + 1]);
167 /* Display usage information and exit. */
171 if (status != EXIT_SUCCESS)
172 fprintf (stderr, _("Try '%s --help' for more information.\n"),
177 Usage: %s [OPTION] URL FILE\n\
180 /* xgettext: no-wrap */
182 Fetches and outputs the contents of an URL. If the URL cannot be accessed,\n\
183 the locally accessible FILE is used instead.\n\
187 Informative output:\n"));
189 -h, --help display this help and exit\n"));
191 -V, --version output version information and exit\n"));
193 -q, --quiet, --silent suppress progress indicators\n"));
195 /* TRANSLATORS: The placeholder indicates the bug-reporting address
196 for this package. Please add _another line_ saying
197 "Report translation bugs to <...>\n" with the address for translation
198 bugs (typically your translation team's web or email address). */
199 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
206 /* Copy a file's contents to stdout. */
208 cat_file (const char *src_filename)
212 const int buf_size = sizeof (buf);
214 src_fd = open (src_filename, O_RDONLY | O_BINARY);
216 error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"),
221 ssize_t n_read = read (src_fd, buf, buf_size);
228 error (EXIT_FAILURE, errno, _("error reading \"%s\""), src_filename);
233 if (full_write (STDOUT_FILENO, buf, n_read) < n_read)
234 error (EXIT_FAILURE, errno, _("error writing stdout"));
237 if (close (src_fd) < 0)
238 error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
241 /* Exit code of the Java program. */
242 static int java_exitcode;
245 execute_it (const char *progname,
246 const char *prog_path, char **prog_argv,
252 execute (progname, prog_path, prog_argv, true, true, false, false, true,
254 /* Exit code 0 means success, 2 means timed out. */
255 return !(java_exitcode == 0 || java_exitcode == 2);
258 /* Fetch the URL. Upon error, use the FILE as fallback. */
260 fetch (const char *url, const char *file)
264 fprintf (stderr, _("Retrieving %s..."), url);
269 /* First try: using Java. */
271 const char *class_name = "gnu.gettext.GetURL";
272 const char *gettextjexedir;
273 const char *gettextjar;
277 /* Make it possible to override the executable's location. This is
278 necessary for running the testsuite before "make install". */
279 gettextjexedir = getenv ("GETTEXTJEXEDIR");
280 if (gettextjexedir == NULL || gettextjexedir[0] == '\0')
281 gettextjexedir = relocate (GETTEXTJEXEDIR);
283 gettextjexedir = NULL;
286 /* Make it possible to override the gettext.jar location. This is
287 necessary for running the testsuite before "make install". */
288 gettextjar = getenv ("GETTEXTJAR");
289 if (gettextjar == NULL || gettextjar[0] == '\0')
290 gettextjar = relocate (GETTEXTJAR);
292 /* Prepare arguments. */
296 /* Fetch the URL's contents. */
298 if (!execute_java_class (class_name, &gettextjar, 1, true, gettextjexedir,
305 if (java_exitcode == 0)
306 fprintf (stderr, _(" done.\n"));
307 else if (java_exitcode == 2)
308 fprintf (stderr, _(" timed out.\n"));
315 /* Second try: using "wget -q -O - -T 30 url". */
317 static bool wget_tested;
318 static bool wget_present;
322 /* Test for presence of wget: "wget --version > /dev/null" */
327 argv[1] = "--version";
329 exitstatus = execute ("wget", "wget", argv, false, false, true, true,
331 wget_present = (exitstatus == 0);
342 argv[2] = "-O"; argv[3] = "-";
343 argv[4] = "-T"; argv[5] = "30";
344 argv[6] = (char *) url;
346 exitstatus = execute ("wget", "wget", argv, true, false, false, false,
348 if (exitstatus != 127)
353 fprintf (stderr, _(" done.\n"));
359 /* Third try: using "lynx -source url". */
361 static bool lynx_tested;
362 static bool lynx_present;
366 /* Test for presence of lynx: "lynx --version > /dev/null" */
371 argv[1] = "--version";
373 exitstatus = execute ("lynx", "lynx", argv, false, false, true, true,
375 lynx_present = (exitstatus == 0);
386 argv[2] = (char *) url;
388 exitstatus = execute ("lynx", "lynx", argv, true, false, false, false,
390 if (exitstatus != 127)
395 fprintf (stderr, _(" done.\n"));
401 /* Fourth try: using "curl --silent url". */
403 static bool curl_tested;
404 static bool curl_present;
408 /* Test for presence of curl: "curl --version > /dev/null" */
413 argv[1] = "--version";
415 exitstatus = execute ("curl", "curl", argv, false, false, true, true,
417 curl_present = (exitstatus == 0 || exitstatus == 2);
427 argv[1] = "--silent";
428 argv[2] = (char *) url;
430 exitstatus = execute ("curl", "curl", argv, true, false, false, false,
432 if (exitstatus != 127)
437 fprintf (stderr, _(" done.\n"));
445 fprintf (stderr, _(" failed.\n"));
446 /* Use the file as fallback. */