DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
target = ntarget;
}
+ #endif /* 0 */
+
+ /* 2004-09-20 SMS.
+ A relative directory is relative to the initial directory.
+ Thus, what _is_ useful on VMS (and probably elsewhere) is
+ to CWD to the initial directory (ideally, whatever the
+ server reports, _exactly_, NOT badly UNIX-ixed), and then
+ CWD to the (new) relative directory. This should probably
+ be restructured as a function, called once or twice, but
+ I'm lazy enough to take the badly indented loop short-cut
+ for now.
+ */
+
+ /* Decide on one pass (absolute) or two (relative).
+ The VMS restriction may be relaxed when the squirrely code
+ above is reformed.
+ */
+ if ((con->rs == ST_VMS) && (target[0] != '/'))
+ {
+ cwd_start = 0;
+ DEBUGP (("Using two-step CWD for relative path.\n"));
+ }
+ else
+ {
+ /* Go straight to the target. */
+ cwd_start = 1;
+ }
+
+ /* At least one VMS FTP server (TCPware V5.6-2) can switch to
+ a UNIX emulation mode when given a UNIX-like directory
+ specification (like "a/b/c"). If allowed to continue this
+ way, LIST interpretation will be confused, because the
+ system type (SYST response) will not be re-checked, and
+ future UNIX-format directory listings (for multiple URLs or
+ "-r") will be horribly misinterpreted.
+
+ The cheap and nasty work-around is to do a "CWD []" after a
+ UNIX-like directory specification is used. (A single-level
+ directory is harmless.) This puts the TCPware server back
+ into VMS mode, and does no harm on other servers.
+
+ Unlike the rest of this block, this particular behavior
+ _is_ VMS-specific, so it gets its own VMS test.
+ */
+ if ((con->rs == ST_VMS) && (strchr( target, '/') != NULL))
+ {
+ cwd_end = 3;
+ DEBUGP (("Using extra \"CWD []\" step for VMS server.\n"));
+ }
+ else
+ {
+ cwd_end = 2;
+ }
+
+ /* 2004-09-20 SMS. */
+ /* Sorry about the deviant indenting. Laziness. */
+
+ for (cwd_count = cwd_start; cwd_count < cwd_end; cwd_count++)
+ {
+ switch (cwd_count)
+ {
+ case 0:
+ /* Step one (optional): Go to the initial directory,
+ exactly as reported by the server.
+ */
+ targ = con->id;
+ break;
+
+ case 1:
+ /* Step two: Go to the target directory. (Absolute or
+ relative will work now.)
+ */
+ targ = target;
+ break;
+
+ case 2:
+ /* Step three (optional): "CWD []" to restore server
+ VMS-ness.
+ */
+ targ = "[]";
+ break;
+
+ default:
+ /* Can't happen. */
+ assert (1);
+ }
if (!opt.server_response)
- logprintf (LOG_VERBOSE, "==> CWD %s ... ",
- logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ",
- cwd_count, escnonprint (target));
- err = ftp_cwd (csock, targ);
++ logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ", cwd_count,
+ quotearg_style (escape_quoting_style, target));
+ err = ftp_cwd (csock, target);
/* FTPRERR, WRITEFAILED, FTPNSFOD */
switch (err)
{
uerr_t err;
struct_stat st;
- if (!con->target)
- con->target = url_file_name (u);
+ /* Get the target, and set the name for the message accordingly. */
+ if ((f == NULL) && (con->target))
+ {
+ /* Explicit file (like ".listing"). */
+ locf = con->target;
+ }
+ else
+ {
+ /* URL-derived file. Consider "-O file" name. */
+ con->target = url_file_name (u);
+ if (!opt.output_document)
+ locf = con->target;
+ else
+ locf = opt.output_document;
+ }
- if (opt.noclobber && file_exists_p (con->target))
+ /* If the output_document was given, then this check was already done and
+ the file didn't exist. Hence the !opt.output_document */
+ if (opt.noclobber && !opt.output_document && file_exists_p (con->target))
{
logprintf (LOG_VERBOSE,
- _("File `%s' already there; not retrieving.\n"), con->target);
+ _("File %s already there; not retrieving.\n"), quote (con->target));
/* If the file is there, we suppose it's retrieved OK. */
return RETROK;
}
break;
} /* switch */
- /* Set the time-stamp information to the local file. Symlinks
- are not to be stamped because it sets the stamp on the
- original. :( */
- if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
- && f->tstamp != -1
- && dlthis
- && file_exists_p (con->target))
+
+ /* 2004-12-15 SMS.
+ * Set permissions _before_ setting the times, as setting the
+ * permissions changes the modified-time, at least on VMS.
+ * Also, use the opt.output_document name here, too, as
+ * appropriate. (Do the test once, and save the result.)
+ */
+
- /* #### This code repeats in http.c and ftp.c. Move it to a
- function! */
- actual_target = NULL;
- if (opt.output_document)
- {
- if (output_stream_regular)
- actual_target = opt.output_document;
- }
- else
- actual_target = con->target;
++ set_local_file (&actual_target, con->target);
+
+ /* If downloading a plain file, set valid (non-zero) permissions. */
+ if (dlthis && (actual_target != NULL) && (f->type == FT_PLAINFILE))
{
- const char *fl = NULL;
- set_local_file (&fl, con->target);
- if (fl)
- touch (fl, f->tstamp);
+ if (f->perms)
+ chmod (actual_target, f->perms);
+ else
+ DEBUGP (("Unrecognized permissions for %s.\n", actual_target));
}
- else if (f->tstamp == -1)
- logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
- if (f->perms && f->type == FT_PLAINFILE && dlthis)
+ /* Set the time-stamp information to the local file. Symlinks
+ are not to be stamped because it sets the stamp on the
+ original. :( */
-
+ if (actual_target != NULL)
{
- if (opt.preserve_perm)
- chmod (con->target, f->perms);
+ if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
+ && f->tstamp != -1
+ && dlthis
+ && file_exists_p (con->target))
+ {
+ touch (actual_target, f->tstamp);
+ }
+ else if (f->tstamp == -1)
+ logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"),
- actual_target);
++ actual_target);
}
- else
- DEBUGP (("Unrecognized permissions for %s.\n", con->target));
xfree (con->target);
con->target = old_target;
/* No luck. */
/* #### This message SUCKS. We should see what was the
reason that nothing was retrieved. */
- logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"),
- escnonprint (u->file));
+ logprintf (LOG_VERBOSE, _("No matches on pattern %s.\n"),
+ quote (u->file));
}
- else /* GLOB_GETONE or GLOB_GETALL */
+ else if (action == GLOB_GETONE) /* GLOB_GETONE or GLOB_GETALL */
{
/* Let's try retrieving it anyway. */
con->st |= ON_YOUR_OWN;
#include "test.h"
#endif
- extern char *version_string;
+ #include "version.h"
+
+ #ifdef __VMS
+ # include "vms.h"
+ #endif /* def __VMS */
/* Forward decls. */
+struct http_stat;
static char *create_authorization_line (const char *, const char *,
const char *, const char *,
const char *, bool *);
}
return xstrdup (env);
}
+ return NULL;
+}
+/* Check for the existance of '$HOME/.wgetrc' and return it's path
+ if it exists and is set. */
+char *
+wgetrc_user_file_name (void)
+{
+ char *home = home_dir ();
+ char *file = NULL;
+ /* If that failed, try $HOME/.wgetrc (or equivalent). */
+
+ #ifdef __VMS
+ file = "SYS$LOGIN:.wgetrc";
+ #else /* def __VMS */
+ home = home_dir ();
if (home)
file = aprintf ("%s/.wgetrc", home);
xfree_null (home);
- char *home = NULL;
+ #endif /* def __VMS [else] */
+
+ if (!file)
+ return NULL;
+ if (!file_exists_p (file))
+ {
+ xfree (file);
+ return NULL;
+ }
+ return file;
+}
+
+/* Return the path to the user's .wgetrc. This is either the value of
+ `WGETRC' environment variable, or `$HOME/.wgetrc'.
+
+ Additionally, for windows, look in the directory where wget.exe
+ resides. */
+char *
+wgetrc_file_name (void)
+{
+ char *file = wgetrc_env_file_name ();
+ if (file && *file)
+ return file;
+
+ file = wgetrc_user_file_name ();
+
#ifdef WINDOWS
/* Under Windows, if we still haven't found .wgetrc, look for the file
`wget.ini' in the directory where `wget.exe' resides; we do this for
backward compatibility with previous versions of Wget.
SYSTEM_WGETRC should not be defined under WINDOWS. */
- home = home_dir ();
-- if (!file || !file_exists_p (file))
++ if (!file)
{
++ char *home = home_dir ();
xfree_null (file);
file = NULL;
home = ws_mypath ();
if (home)
-- file = aprintf ("%s/wget.ini", home);
++ {
++ file = aprintf ("%s/wget.ini", home);
++ if (!file_exists_p (file))
++ {
++ xfree (file);
++ file = NULL;
++ }
++ xfree (home);
++ }
}
- xfree_null (home);
#endif /* WINDOWS */
-- if (!file)
-- return NULL;
-- if (!file_exists_p (file))
-- {
-- xfree (file);
-- return NULL;
-- }
return file;
}
#include "utils.h"
#include "log.h"
- /* This file implement support for "logging". Logging means printing
+ /* 2005-10-25 SMS.
+ VMS log files are often VFC record format, not stream, so fputs() can
+ produce multiple records, even when there's no newline terminator in
+ the buffer. The result is unsightly output with spurious newlines.
+ Using fprintf() instead of fputs(), along with inhibiting some
+ fflush() activity below, seems to solve the problem.
+ */
+ #ifdef __VMS
+ # define FPUTS( s, f) fprintf( (f), "%s", (s))
+ #else /* def __VMS */
+ # define FPUTS( s, f) fputs( (s), (f))
+ #endif /* def __VMS [else] */
+
-/* This file impplement support for "logging". Logging means printing
++/* This file implements support for "logging". Logging means printing
output, plus several additional features:
- Cataloguing output by importance. You can specify that a log
#include "http.h" /* for save_cookies */
#include <getopt.h>
+#include <getpass.h>
+#include <quote.h>
+ #ifdef __VMS
+ #include "vms.h"
+ #endif /* __VMS */
+
+ #include "version.h"
+
#ifndef PATH_SEPARATOR
# define PATH_SEPARATOR '/'
#endif
N_("\
--delete-after delete files locally after downloading them.\n"),
N_("\
- -k, --convert-links make links in downloaded HTML point to local files.\n"),
+ -k, --convert-links make links in downloaded HTML or CSS point to\n\
+ local files.\n"),
+ #ifdef __VMS
+ N_("\
+ -K, --backup-converted before converting file X, back up as X_orig.\n"),
+ #else /* def __VMS */
N_("\
-K, --backup-converted before converting file X, back up as X.orig.\n"),
+ #endif /* def __VMS [else] */
N_("\
-m, --mirror shortcut for -N -r -l inf --no-remove-listing.\n"),
N_("\
N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
};
- int i;
+ size_t i;
printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
- version_string);
+ VERSION_STRING);
print_usage ();
for (i = 0; i < countof (help); i++)
static void
print_version (void)
{
- printf ("GNU Wget %s built on %s.\n\n", VERSION_STRING, OS_TYPE);
+ const char *wgetrc_title = _("Wgetrc: ");
+ const char *locale_title = _("Locale: ");
+ const char *compile_title = _("Compile: ");
+ const char *link_title = _("Link: ");
+ char *line;
+ char *env_wgetrc, *user_wgetrc;
+ int i;
+
+ printf (_("GNU Wget %s\n\n"), version_string);
+ #ifdef __VMS
+ printf ("GNU Wget %s built on VMS %s %s.\n\n",
+ VERSION_STRING, vms_arch(), vms_vers());
+ #else /* def __VMS */
++ printf ("GNU Wget %s built on %s.\n\n", version_string, OS_TYPE);
+ #endif /* def __VMS */
+ /* compiled_features is a char*[]. We limit the characters per
+ line to MAX_CHARS_PER_LINE and prefix each line with a constant
+ number of spaces for proper alignment. */
+ for (i = 0; compiled_features[i] != NULL; )
+ {
+ int line_length = MAX_CHARS_PER_LINE;
+ while ((line_length > 0) && (compiled_features[i] != NULL))
+ {
+ printf ("%s ", compiled_features[i]);
+ line_length -= strlen (compiled_features[i]) + 2;
+ i++;
+ }
+ printf ("\n");
+ }
+ printf ("\n");
+ /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is
+ absent. */
+ printf ("%s\n", wgetrc_title);
+ env_wgetrc = wgetrc_env_file_name ();
+ if (env_wgetrc && *env_wgetrc)
+ {
+ printf (" %s (env)\n", env_wgetrc);
+ xfree (env_wgetrc);
+ }
+ user_wgetrc = wgetrc_user_file_name ();
+ if (user_wgetrc)
+ {
+ printf (" %s (user)\n", user_wgetrc);
+ xfree (user_wgetrc);
+ }
+#ifdef SYSTEM_WGETRC
+ printf (" %s (system)\n", SYSTEM_WGETRC);
+#endif
+
+ format_and_print_line (locale_title,
+ LOCALEDIR,
+ MAX_CHARS_PER_LINE);
+
+ format_and_print_line (compile_title,
+ compilation_string,
+ MAX_CHARS_PER_LINE);
+
+ format_and_print_line (link_title,
+ link_string,
+ MAX_CHARS_PER_LINE);
+
+ printf ("\n");
/* TRANSLATORS: When available, an actual copyright character
(cirle-c) should be used in preference to "(C)". */
fputs (_("\
bool content_disposition; /* Honor HTTP Content-Disposition header. */
bool auth_without_challenge; /* Issue Basic authentication creds without
- waiting for a challenge. */
+ waiting for a challenge. */
+
+ bool enable_iri;
+ char *encoding_remote;
+ char *locale;
+
+ #ifdef __VMS
+ int ftp_stmlf; /* Force Stream_LF format for binary FTP. */
+ #endif /* def __VMS */
+
};
extern struct options opt;
#include "test.h"
#endif
+static void
+memfatal (const char *context, long attempted_size)
+{
+ /* Make sure we don't try to store part of the log line, and thus
+ call malloc. */
+ log_set_save_context (false);
+
+ /* We have different log outputs in different situations:
+ 1) output without bytes information
+ 2) output with bytes information */
+ if (attempted_size == UNKNOWN_ATTEMPTED_SIZE)
+ {
+ logprintf (LOG_ALWAYS,
+ _("%s: %s: Failed to allocate enough memory; memory exhausted.\n"),
+ exec_name, context);
+ }
+ else
+ {
+ logprintf (LOG_ALWAYS,
+ _("%s: %s: Failed to allocate %ld bytes; memory exhausted.\n"),
+ exec_name, context, attempted_size);
+ }
+
+ exit (1);
+}
+
+ /* Character property table for (re-)escaping VMS ODS5 extended file
+ names. Note that this table ignores Unicode.
+
+ ODS2 valid characters: 0-9 A-Z a-z $ - _ ~
+
+ ODS5 Invalid characters:
+ C0 control codes (0x00 to 0x1F inclusive)
+ Asterisk (*)
+ Question mark (?)
+
+ ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
+ Double quotation marks (")
+ Backslash (\)
+ Colon (:)
+ Left angle bracket (<)
+ Right angle bracket (>)
+ Slash (/)
+ Vertical bar (|)
+
+ Characters escaped by "^":
+ SP ! # % & ' ( ) + , . ; = @ [ ] ^ ` { } ~
+
+ Either "^_" or "^ " is accepted as a space. Period (.) is a special
+ case. Note that un-escaped < and > can also confuse a directory
+ spec.
+
+ Characters put out as ^xx:
+ 7F (DEL)
+ 80-9F (C1 control characters)
+ A0 (nonbreaking space)
+ FF (Latin small letter y diaeresis)
+
+ Other cases:
+ Unicode: "^Uxxxx", where "xxxx" is four hex digits.
+
+ Property table values:
+ Normal escape: 1
+ Space: 2
+ Dot: 4
+ Hex-hex escape: 8
+ ODS2 normal: 16
+ ODS2 lower case: 32
+ Hex digit: 64
+ */
+
+ unsigned char char_prop[ 256] = {
+
+ /* NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* SP ! " # $ % & ' ( ) * + , - . / */
+ 2, 1, 0, 1, 16, 1, 1, 1, 1, 1, 0, 1, 1, 16, 4, 0,
+
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 1, 1, 1, 1, 1,
+
+ /* @ A B C D E F G H I J K L M N O */
+ 1, 80, 80, 80, 80, 80, 80, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 0, 1, 1, 16,
+
+ /* ` a b c d e f g h i j k l m n o */
+ 1, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+
+ /* p q r s t u v w x y z { | } ~ DEL */
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1, 0, 1, 17, 8,
+
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8
+ };
+
/* Utility function: like xstrdup(), but also lowercases S. */
char *