summaryrefslogtreecommitdiff
path: root/gettext-tools/src/urlget.c
diff options
context:
space:
mode:
Diffstat (limited to 'gettext-tools/src/urlget.c')
-rw-r--r--gettext-tools/src/urlget.c448
1 files changed, 448 insertions, 0 deletions
diff --git a/gettext-tools/src/urlget.c b/gettext-tools/src/urlget.c
new file mode 100644
index 0000000..f3243e1
--- /dev/null
+++ b/gettext-tools/src/urlget.c
@@ -0,0 +1,448 @@
+/* Get the contents of an URL.
+ Copyright (C) 2001-2003, 2005-2010, 2012 Free Software Foundation, Inc.
+ Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+
+#include "closeout.h"
+#include "error.h"
+#include "error-progname.h"
+#include "progname.h"
+#include "relocatable.h"
+#include "basename.h"
+#include "full-write.h"
+#include "execute.h"
+#include "javaexec.h"
+#include "binary-io.h"
+#include "propername.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+
+/* Only high-level toolkits, written in languages with exception handling,
+ have an URL datatype and operations to fetch an URL's contents. Such
+ toolkits are Java (class java.net.URL), Qt (classes QUrl and QUrlOperator).
+ We use the Java toolkit.
+ Note that this program doesn't handle redirection pages; programs which
+ wish to process HTML redirection tags need to include a HTML parser,
+ and only full-fledged browsers like w3m, lynx, links have have both
+ an URL fetcher (which covers at least the protocols "http", "ftp", "file")
+ and a HTML parser. [Well, this is not true: libxml2 and Java (see
+ <http://java.sun.com/products/jfc/tsc/articles/bookmarks/>) also contain
+ HTML parsers.] */
+
+
+/* Whether to output something on standard error.
+ This is true by default, because the user should know why we are trying to
+ establish an internet connection. Also, users get confused if a program
+ produces no output for more than 10 seconds for no apparent reason. */
+static bool verbose = true;
+
+/* Long options. */
+static const struct option long_options[] =
+{
+ { "help", no_argument, NULL, 'h' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "silent", no_argument, NULL, 'q' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+};
+
+
+/* Forward declaration of local functions. */
+static void usage (int status)
+#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
+ __attribute__ ((noreturn))
+#endif
+;
+static void fetch (const char *url, const char *file);
+
+
+int
+main (int argc, char *argv[])
+{
+ int optchar;
+ bool do_help;
+ bool do_version;
+
+ /* Set program name for messages. */
+ set_program_name (argv[0]);
+ error_print_progname = maybe_print_progname;
+
+#ifdef HAVE_SETLOCALE
+ /* Set locale via LC_ALL. */
+ setlocale (LC_ALL, "");
+#endif
+
+ /* Set the text message domain. */
+ bindtextdomain (PACKAGE, relocate (LOCALEDIR));
+ textdomain (PACKAGE);
+
+ /* Ensure that write errors on stdout are detected. */
+ atexit (close_stdout);
+
+ /* Set default values for variables. */
+ do_help = false;
+ do_version = false;
+
+ /* Parse command line options. */
+ while ((optchar = getopt_long (argc, argv, "hqV", long_options, NULL)) != EOF)
+ switch (optchar)
+ {
+ case '\0': /* Long option. */
+ break;
+ case 'h': /* --help */
+ do_help = true;
+ break;
+ case 'q': /* --quiet / --silent */
+ verbose = false;
+ break;
+ case 'V': /* --version */
+ do_version = true;
+ break;
+ default:
+ usage (EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+
+ /* Version information requested. */
+ if (do_version)
+ {
+ printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
+ /* xgettext: no-wrap */
+ printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
+This is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n\
+"),
+ "2001-2003, 2005-2009");
+ printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
+ exit (EXIT_SUCCESS);
+ }
+
+ /* Help is requested. */
+ if (do_help)
+ usage (EXIT_SUCCESS);
+
+ /* Test argument count. */
+ if (optind + 2 != argc)
+ error (EXIT_FAILURE, 0, _("expected two arguments"));
+
+ /* Fetch the contents. */
+ fetch (argv[optind], argv[optind + 1]);
+
+ exit (EXIT_SUCCESS);
+}
+
+/* Display usage information and exit. */
+static void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try '%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ printf (_("\
+Usage: %s [OPTION] URL FILE\n\
+"), program_name);
+ printf ("\n");
+ /* xgettext: no-wrap */
+ printf (_("\
+Fetches and outputs the contents of an URL. If the URL cannot be accessed,\n\
+the locally accessible FILE is used instead.\n\
+"));
+ printf ("\n");
+ printf (_("\
+Informative output:\n"));
+ printf (_("\
+ -h, --help display this help and exit\n"));
+ printf (_("\
+ -V, --version output version information and exit\n"));
+ printf (_("\
+ -q, --quiet, --silent suppress progress indicators\n"));
+ printf ("\n");
+ /* TRANSLATORS: The placeholder indicates the bug-reporting address
+ for this package. Please add _another line_ saying
+ "Report translation bugs to <...>\n" with the address for translation
+ bugs (typically your translation team's web or email address). */
+ fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
+ stdout);
+ }
+
+ exit (status);
+}
+
+/* Copy a file's contents to stdout. */
+static void
+cat_file (const char *src_filename)
+{
+ int src_fd;
+ char buf[4096];
+ const int buf_size = sizeof (buf);
+
+ src_fd = open (src_filename, O_RDONLY | O_BINARY);
+ if (src_fd < 0)
+ error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"),
+ src_filename);
+
+ for (;;)
+ {
+ ssize_t n_read = read (src_fd, buf, buf_size);
+ if (n_read < 0)
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ error (EXIT_FAILURE, errno, _("error reading \"%s\""), src_filename);
+ }
+ if (n_read == 0)
+ break;
+
+ if (full_write (STDOUT_FILENO, buf, n_read) < n_read)
+ error (EXIT_FAILURE, errno, _("error writing stdout"));
+ }
+
+ if (close (src_fd) < 0)
+ error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
+}
+
+/* Exit code of the Java program. */
+static int java_exitcode;
+
+static bool
+execute_it (const char *progname,
+ const char *prog_path, char **prog_argv,
+ void *private_data)
+{
+ (void) private_data;
+
+ java_exitcode =
+ execute (progname, prog_path, prog_argv, true, true, false, false, true,
+ false, NULL);
+ /* Exit code 0 means success, 2 means timed out. */
+ return !(java_exitcode == 0 || java_exitcode == 2);
+}
+
+/* Fetch the URL. Upon error, use the FILE as fallback. */
+static void
+fetch (const char *url, const char *file)
+{
+ if (verbose)
+ {
+ fprintf (stderr, _("Retrieving %s..."), url);
+ fflush (stderr);
+ }
+
+#if USEJAVA
+ /* First try: using Java. */
+ {
+ const char *class_name = "gnu.gettext.GetURL";
+ const char *gettextjexedir;
+ const char *gettextjar;
+ const char *args[2];
+
+# if USEJEXE
+ /* Make it possible to override the executable's location. This is
+ necessary for running the testsuite before "make install". */
+ gettextjexedir = getenv ("GETTEXTJEXEDIR");
+ if (gettextjexedir == NULL || gettextjexedir[0] == '\0')
+ gettextjexedir = relocate (GETTEXTJEXEDIR);
+# else
+ gettextjexedir = NULL;
+# endif
+
+ /* Make it possible to override the gettext.jar location. This is
+ necessary for running the testsuite before "make install". */
+ gettextjar = getenv ("GETTEXTJAR");
+ if (gettextjar == NULL || gettextjar[0] == '\0')
+ gettextjar = relocate (GETTEXTJAR);
+
+ /* Prepare arguments. */
+ args[0] = url;
+ args[1] = NULL;
+
+ /* Fetch the URL's contents. */
+ java_exitcode = 127;
+ if (!execute_java_class (class_name, &gettextjar, 1, true, gettextjexedir,
+ args,
+ false, true,
+ execute_it, NULL))
+ {
+ if (verbose)
+ {
+ if (java_exitcode == 0)
+ fprintf (stderr, _(" done.\n"));
+ else if (java_exitcode == 2)
+ fprintf (stderr, _(" timed out.\n"));
+ }
+ return;
+ }
+ }
+#endif
+
+ /* Second try: using "wget -q -O - -T 30 url". */
+ {
+ static bool wget_tested;
+ static bool wget_present;
+
+ if (!wget_tested)
+ {
+ /* Test for presence of wget: "wget --version > /dev/null" */
+ char *argv[3];
+ int exitstatus;
+
+ argv[0] = "wget";
+ argv[1] = "--version";
+ argv[2] = NULL;
+ exitstatus = execute ("wget", "wget", argv, false, false, true, true,
+ true, false, NULL);
+ wget_present = (exitstatus == 0);
+ wget_tested = true;
+ }
+
+ if (wget_present)
+ {
+ char *argv[8];
+ int exitstatus;
+
+ argv[0] = "wget";
+ argv[1] = "-q";
+ argv[2] = "-O"; argv[3] = "-";
+ argv[4] = "-T"; argv[5] = "30";
+ argv[6] = (char *) url;
+ argv[7] = NULL;
+ exitstatus = execute ("wget", "wget", argv, true, false, false, false,
+ true, false, NULL);
+ if (exitstatus != 127)
+ {
+ if (exitstatus != 0)
+ goto failed;
+ if (verbose)
+ fprintf (stderr, _(" done.\n"));
+ return;
+ }
+ }
+ }
+
+ /* Third try: using "lynx -source url". */
+ {
+ static bool lynx_tested;
+ static bool lynx_present;
+
+ if (!lynx_tested)
+ {
+ /* Test for presence of lynx: "lynx --version > /dev/null" */
+ char *argv[3];
+ int exitstatus;
+
+ argv[0] = "lynx";
+ argv[1] = "--version";
+ argv[2] = NULL;
+ exitstatus = execute ("lynx", "lynx", argv, false, false, true, true,
+ true, false, NULL);
+ lynx_present = (exitstatus == 0);
+ lynx_tested = true;
+ }
+
+ if (lynx_present)
+ {
+ char *argv[4];
+ int exitstatus;
+
+ argv[0] = "lynx";
+ argv[1] = "-source";
+ argv[2] = (char *) url;
+ argv[3] = NULL;
+ exitstatus = execute ("lynx", "lynx", argv, true, false, false, false,
+ true, false, NULL);
+ if (exitstatus != 127)
+ {
+ if (exitstatus != 0)
+ goto failed;
+ if (verbose)
+ fprintf (stderr, _(" done.\n"));
+ return;
+ }
+ }
+ }
+
+ /* Fourth try: using "curl --silent url". */
+ {
+ static bool curl_tested;
+ static bool curl_present;
+
+ if (!curl_tested)
+ {
+ /* Test for presence of curl: "curl --version > /dev/null" */
+ char *argv[3];
+ int exitstatus;
+
+ argv[0] = "curl";
+ argv[1] = "--version";
+ argv[2] = NULL;
+ exitstatus = execute ("curl", "curl", argv, false, false, true, true,
+ true, false, NULL);
+ curl_present = (exitstatus == 0 || exitstatus == 2);
+ curl_tested = true;
+ }
+
+ if (curl_present)
+ {
+ char *argv[4];
+ int exitstatus;
+
+ argv[0] = "curl";
+ argv[1] = "--silent";
+ argv[2] = (char *) url;
+ argv[3] = NULL;
+ exitstatus = execute ("curl", "curl", argv, true, false, false, false,
+ true, false, NULL);
+ if (exitstatus != 127)
+ {
+ if (exitstatus != 0)
+ goto failed;
+ if (verbose)
+ fprintf (stderr, _(" done.\n"));
+ return;
+ }
+ }
+ }
+
+ failed:
+ if (verbose)
+ fprintf (stderr, _(" failed.\n"));
+ /* Use the file as fallback. */
+ cat_file (file);
+}