X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Finit.c;h=6ad97f3645100b745090c6e21ac5789cd4b519e9;hb=4d7c5e087b2bc82c9f503dff003916d1047903ce;hp=bc57b60e06cb054460f9e4f68343580994b89d37;hpb=b633022e24381a4accc52d0a406d84c5b8f8f727;p=wget diff --git a/src/init.c b/src/init.c index bc57b60e..6ad97f36 100644 --- a/src/init.c +++ b/src/init.c @@ -1,11 +1,11 @@ /* Reading/parsing the initialization file. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 1996-2006 Free Software Foundation, Inc. This file is part of GNU Wget. GNU Wget 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 2 of the License, or +the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, @@ -14,8 +14,7 @@ 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 Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +along with Wget. If not, see . In addition, as a special exception, the Free Software Foundation gives permission to link the code of its release of Wget with the @@ -30,16 +29,11 @@ so, delete this exception statement from your version. */ #include #include -#include #include #ifdef HAVE_UNISTD_H # include #endif -#ifdef HAVE_STRING_H -# include -#else -# include -#endif +#include #include #ifdef HAVE_PWD_H @@ -56,29 +50,29 @@ so, delete this exception statement from your version. */ #include "recur.h" /* for INFINITE_RECURSION */ #include "convert.h" /* for convert_cleanup */ #include "res.h" /* for res_cleanup */ +#include "http.h" /* for http_cleanup */ +#include "retr.h" /* for output_stream */ -#ifndef errno -extern int errno; +#ifdef TESTING +#include "test.h" #endif /* We want tilde expansion enabled only when reading `.wgetrc' lines; otherwise, it will be performed by the shell. This variable will be set by the wgetrc-reading function. */ -static int enable_tilde_expansion; +static bool enable_tilde_expansion; -#define CMD_DECLARE(func) static int func \ - PARAMS ((const char *, const char *, void *)) +#define CMD_DECLARE(func) static bool func (const char *, const char *, void *) CMD_DECLARE (cmd_boolean); CMD_DECLARE (cmd_bytes); -CMD_DECLARE (cmd_bytes_large); +CMD_DECLARE (cmd_bytes_sum); #ifdef HAVE_SSL CMD_DECLARE (cmd_cert_type); #endif CMD_DECLARE (cmd_directory_vector); -CMD_DECLARE (cmd_lockable_boolean); CMD_DECLARE (cmd_number); CMD_DECLARE (cmd_number_inf); CMD_DECLARE (cmd_string); @@ -100,19 +94,21 @@ CMD_DECLARE (cmd_spec_secure_protocol); #endif CMD_DECLARE (cmd_spec_timeout); CMD_DECLARE (cmd_spec_useragent); +CMD_DECLARE (cmd_spec_verbose); /* List of recognized commands, each consisting of name, place and function. When adding a new command, simply add it to the list, but be sure to keep the list sorted alphabetically, as - command_by_name depends on it. Also, be sure to add any entries - that allocate memory (e.g. cmd_string and cmd_vector guys) to the - cleanup() function below. */ + command_by_name's binary search depends on it. Also, be sure to + add any entries that allocate memory (e.g. cmd_string and + cmd_vector) to the cleanup() function below. */ static struct { const char *name; void *place; - int (*action) PARAMS ((const char *, const char *, void *)); + bool (*action) (const char *, const char *, void *); } commands[] = { + /* KEEP THIS LIST ALPHABETICALLY SORTED */ { "accept", &opt.accepts, cmd_vector }, { "addhostdir", &opt.add_hostdir, cmd_boolean }, { "alwaysrest", &opt.always_rest, cmd_boolean }, /* deprecated */ @@ -132,6 +128,7 @@ static struct { { "checkcertificate", &opt.check_cert, cmd_boolean }, #endif { "connecttimeout", &opt.connect_timeout, cmd_time }, + { "contentdisposition", &opt.content_disposition, cmd_boolean }, { "continue", &opt.always_rest, cmd_boolean }, { "convertlinks", &opt.convert_links, cmd_boolean }, { "cookies", &opt.cookies, cmd_boolean }, @@ -159,10 +156,10 @@ static struct { { "forcehtml", &opt.force_html, cmd_boolean }, { "ftppasswd", &opt.ftp_passwd, cmd_string }, /* deprecated */ { "ftppassword", &opt.ftp_passwd, cmd_string }, - { "ftpuser", &opt.ftp_user, cmd_string }, { "ftpproxy", &opt.ftp_proxy, cmd_string }, + { "ftpuser", &opt.ftp_user, cmd_string }, { "glob", &opt.ftp_glob, cmd_boolean }, - { "header", &opt.user_headers, cmd_spec_header }, + { "header", NULL, cmd_spec_header }, { "htmlextension", &opt.html_extension, cmd_boolean }, { "htmlify", NULL, cmd_spec_htmlify }, { "httpkeepalive", &opt.http_keep_alive, cmd_boolean }, @@ -171,6 +168,7 @@ static struct { { "httpproxy", &opt.http_proxy, cmd_string }, { "httpsproxy", &opt.https_proxy, cmd_string }, { "httpuser", &opt.http_user, cmd_string }, + { "ignorecase", &opt.ignore_case, cmd_boolean }, { "ignorelength", &opt.ignore_length, cmd_boolean }, { "ignoretags", &opt.ignore_tags, cmd_vector }, { "includedirectories", &opt.includes, cmd_directory_vector }, @@ -180,7 +178,6 @@ static struct { #endif { "input", &opt.input_filename, cmd_file }, { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean }, - { "killlonger", &opt.kill_longer, cmd_boolean }, { "limitrate", &opt.limit_rate, cmd_bytes }, { "loadcookies", &opt.cookies_input, cmd_file }, { "logfile", &opt.lfilename, cmd_file }, @@ -193,7 +190,7 @@ static struct { { "numtries", &opt.ntry, cmd_number_inf },/* deprecated*/ { "outputdocument", &opt.output_document, cmd_file }, { "pagerequisites", &opt.page_requisites, cmd_boolean }, - { "passiveftp", &opt.ftp_pasv, cmd_lockable_boolean }, + { "passiveftp", &opt.ftp_pasv, cmd_boolean }, { "passwd", &opt.ftp_passwd, cmd_string },/* deprecated*/ { "password", &opt.passwd, cmd_string }, { "postdata", &opt.post_data, cmd_string }, @@ -210,7 +207,7 @@ static struct { { "proxypassword", &opt.proxy_passwd, cmd_string }, { "proxyuser", &opt.proxy_user, cmd_string }, { "quiet", &opt.quiet, cmd_boolean }, - { "quota", &opt.quota, cmd_bytes_large }, + { "quota", &opt.quota, cmd_bytes_sum }, #ifdef HAVE_SSL { "randomfile", &opt.random_file, cmd_file }, #endif @@ -241,7 +238,7 @@ static struct { { "useproxy", &opt.use_proxy, cmd_boolean }, { "user", &opt.user, cmd_string }, { "useragent", NULL, cmd_spec_useragent }, - { "verbose", &opt.verbose, cmd_boolean }, + { "verbose", NULL, cmd_spec_verbose }, { "wait", &opt.wait, cmd_time }, { "waitretry", &opt.waitretry, cmd_time } }; @@ -276,42 +273,42 @@ defaults (void) { char *tmp; - /* Most of the default values are 0. Just reset everything, and - fill in the non-zero values. Note that initializing pointers to - NULL this way is technically illegal, but porting Wget to a - machine where NULL is not all-zero bit pattern will be the least - of the implementors' worries. */ + /* Most of the default values are 0 (and 0.0, NULL, and false). + Just reset everything, and fill in the non-zero values. Note + that initializing pointers to NULL this way is technically + illegal, but porting Wget to a machine where NULL is not all-zero + bit pattern will be the least of the implementors' worries. */ xzero (opt); - opt.cookies = 1; + opt.cookies = true; opt.verbose = -1; opt.ntry = 20; opt.reclevel = 5; - opt.add_hostdir = 1; - opt.netrc = 1; - opt.ftp_glob = 1; - opt.htmlify = 1; - opt.http_keep_alive = 1; - opt.use_proxy = 1; + opt.add_hostdir = true; + opt.netrc = true; + opt.ftp_glob = true; + opt.htmlify = true; + opt.http_keep_alive = true; + opt.use_proxy = true; tmp = getenv ("no_proxy"); if (tmp) opt.no_proxy = sepstring (tmp); - opt.allow_cache = 1; + opt.allow_cache = true; opt.read_timeout = 900; - opt.use_robots = 1; + opt.use_robots = true; - opt.remove_listing = 1; + opt.remove_listing = true; opt.dot_bytes = 1024; opt.dot_spacing = 10; opt.dots_in_line = 50; - opt.dns_cache = 1; - opt.ftp_pasv = 1; + opt.dns_cache = true; + opt.ftp_pasv = true; #ifdef HAVE_SSL - opt.check_cert = 1; + opt.check_cert = true; #endif /* The default for file name restriction defaults to the OS type. */ @@ -320,7 +317,10 @@ defaults (void) #else opt.restrict_files_os = restrict_windows; #endif - opt.restrict_files_ctrl = 1; + opt.restrict_files_ctrl = true; + opt.restrict_files_case = restrict_no_case_restriction; + + opt.content_disposition = true; } /* Return the user's home directory (strdup-ed), or NULL if none is @@ -404,51 +404,78 @@ wgetrc_file_name (void) return file; } -static int parse_line PARAMS ((const char *, char **, char **, int *)); -static int setval_internal PARAMS ((int, const char *, const char *)); +/* Return values of parse_line. */ +enum parse_line { + line_ok, + line_empty, + line_syntax_error, + line_unknown_command +}; -/* Initialize variables from a wgetrc file. */ +static enum parse_line parse_line (const char *, char **, char **, int *); +static bool setval_internal (int, const char *, const char *); -static void +/* Initialize variables from a wgetrc file. Returns zero (failure) if + there were errors in the file. */ + +static bool run_wgetrc (const char *file) { FILE *fp; char *line; int ln; + int errcnt = 0; fp = fopen (file, "rb"); if (!fp) { fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name, file, strerror (errno)); - return; + return true; /* not a fatal error */ } - enable_tilde_expansion = 1; + enable_tilde_expansion = true; ln = 1; while ((line = read_whole_line (fp)) != NULL) { - char *com, *val; - int comind, status; + char *com = NULL, *val = NULL; + int comind; /* Parse the line. */ - status = parse_line (line, &com, &val, &comind); - xfree (line); - /* If everything is OK, set the value. */ - if (status == 1) + switch (parse_line (line, &com, &val, &comind)) { + case line_ok: + /* If everything is OK, set the value. */ if (!setval_internal (comind, com, val)) - fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name, - file, ln); - xfree (com); - xfree (val); + { + fprintf (stderr, _("%s: Error in %s at line %d.\n"), + exec_name, file, ln); + ++errcnt; + } + break; + case line_syntax_error: + fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"), + exec_name, file, ln); + ++errcnt; + break; + case line_unknown_command: + fprintf (stderr, _("%s: Unknown command `%s' in %s at line %d.\n"), + exec_name, com, file, ln); + ++errcnt; + break; + case line_empty: + break; + default: + abort (); } - else if (status == 0) - fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name, - file, ln); + xfree_null (com); + xfree_null (val); + xfree (line); ++ln; } - enable_tilde_expansion = 0; + enable_tilde_expansion = false; fclose (fp); + + return errcnt == 0; } /* Initialize the defaults and run the system wgetrc and user's own @@ -457,6 +484,7 @@ void initialize (void) { char *file; + int ok = true; /* Load the hard-coded defaults. */ defaults (); @@ -464,7 +492,7 @@ initialize (void) /* If SYSTEM_WGETRC is defined, use it. */ #ifdef SYSTEM_WGETRC if (file_exists_p (SYSTEM_WGETRC)) - run_wgetrc (SYSTEM_WGETRC); + ok &= run_wgetrc (SYSTEM_WGETRC); #endif /* Override it with your own, if one exists. */ file = wgetrc_file_name (); @@ -481,7 +509,12 @@ initialize (void) } else #endif - run_wgetrc (file); + ok &= run_wgetrc (file); + + /* If there were errors processing either `.wgetrc', abort. */ + if (!ok) + exit (2); + xfree (file); return; } @@ -505,18 +538,15 @@ dehyphen (char *s) /* Parse the line pointed by line, with the syntax: * command * = * value * Uses malloc to allocate space for command and value. - If the line is invalid, data is freed and 0 is returned. - Return values: - 1 - success - 0 - error - -1 - empty + Returns one of line_ok, line_empty, line_syntax_error, or + line_unknown_command. - In case of success, *COM and *VAL point to freshly allocated + In case of line_ok, *COM and *VAL point to freshly allocated strings, and *COMIND points to com's index. In case of error or - empty line, those values are unaffected. */ + empty line, their values are unmodified. */ -static int +static enum parse_line parse_line (const char *line, char **com, char **val, int *comind) { const char *p; @@ -535,12 +565,12 @@ parse_line (const char *line, char **com, char **val, int *comind) /* Skip empty lines and comments. */ if (!*line || *line == '#') - return -1; + return line_empty; p = line; cmdstart = p; - while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-')) + while (p < end && (ISALNUM (*p) || *p == '_' || *p == '-')) ++p; cmdend = p; @@ -548,7 +578,7 @@ parse_line (const char *line, char **com, char **val, int *comind) while (p < end && ISSPACE (*p)) ++p; if (p == end || *p != '=') - return 0; + return line_syntax_error; ++p; while (p < end && ISSPACE (*p)) ++p; @@ -556,30 +586,32 @@ parse_line (const char *line, char **com, char **val, int *comind) valstart = p; valend = end; + /* The syntax is valid (even though the command might not be). Fill + in the command name and value. */ + *com = strdupdelim (cmdstart, cmdend); + *val = strdupdelim (valstart, valend); + /* The line now known to be syntactically correct. Check whether the command is valid. */ BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy); dehyphen (cmdcopy); ind = command_by_name (cmdcopy); if (ind == -1) - return 0; + return line_unknown_command; - /* The command is valid. Now fill in the values and report success - to the caller. */ + /* Report success to the caller. */ *comind = ind; - *com = strdupdelim (cmdstart, cmdend); - *val = strdupdelim (valstart, valend); - return 1; + return line_ok; } /* Run commands[comind].action. */ -static int +static bool setval_internal (int comind, const char *com, const char *val) { assert (0 <= comind && comind < countof (commands)); - DEBUGP (("Setting %s (%d) to %s\n", com, comind, val)); - return ((*commands[comind].action) (com, val, commands[comind].place)); + DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val)); + return commands[comind].action (com, val, commands[comind].place); } /* Run command COM with value VAL. If running the command produces an @@ -593,10 +625,16 @@ setval_internal (int comind, const char *com, const char *val) to accept COMIND directly. */ void -setoptval (const char *com, const char *val) +setoptval (const char *com, const char *val, const char *optname) { + /* Prepend "--" to OPTNAME. */ + char *dd_optname = (char *) alloca (2 + strlen (optname) + 1); + dd_optname[0] = '-'; + dd_optname[1] = '-'; + strcpy (dd_optname + 2, optname); + assert (val != NULL); - if (!setval_internal (command_by_name (com), com, val)) + if (!setval_internal (command_by_name (com), dd_optname, val)) exit (2); } @@ -609,16 +647,15 @@ run_command (const char *opt) { char *com, *val; int comind; - int status = parse_line (opt, &com, &val, &comind); - if (status == 1) + switch (parse_line (opt, &com, &val, &comind)) { + case line_ok: if (!setval_internal (comind, com, val)) exit (2); xfree (com); xfree (val); - } - else if (status == 0) - { + break; + default: fprintf (stderr, _("%s: Invalid --execute command `%s'\n"), exec_name, opt); exit (2); @@ -632,10 +669,9 @@ struct decode_item { const char *name; int code; }; -static int decode_string PARAMS ((const char *, const struct decode_item *, - int, int *)); -static int simple_atoi PARAMS ((const char *, const char *, int *)); -static int simple_atof PARAMS ((const char *, const char *, double *)); +static bool decode_string (const char *, const struct decode_item *, int, int *); +static bool simple_atoi (const char *, const char *, int *); +static bool simple_atof (const char *, const char *, double *); #define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0') @@ -651,75 +687,32 @@ static int simple_atof PARAMS ((const char *, const char *, double *)); /* Store the boolean value from VAL to PLACE. COM is ignored, except for error messages. */ -static int +static bool cmd_boolean (const char *com, const char *val, void *place) { - int bool_value; + bool value; if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1')) /* "on", "yes" and "1" mean true. */ - bool_value = 1; + value = true; else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0')) /* "off", "no" and "0" mean false. */ - bool_value = 0; - else - { - fprintf (stderr, - _("%s: %s: Invalid boolean `%s', use `on' or `off'.\n"), - exec_name, com, val); - return 0; - } - - *(int *)place = bool_value; - return 1; -} - -/* Store the lockable_boolean {2, 1, 0, -1} value from VAL to PLACE. - COM is ignored, except for error messages. Values 2 and -1 - indicate that once defined, the value may not be changed by - successive wgetrc files or command-line arguments. - - Values: 2 - Enable a particular option for good ("always") - 1 - Enable an option ("on") - 0 - Disable an option ("off") - -1 - Disable an option for good ("never") */ -static int -cmd_lockable_boolean (const char *com, const char *val, void *place) -{ - int lockable_boolean_value; - - int oldval = *(int *)place; - - /* - * If a config file said "always" or "never", don't allow command line - * arguments to override the config file. - */ - if (oldval == -1 || oldval == 2) - return 1; - - if (0 == strcasecmp (val, "always") || CMP1 (val, '2')) - lockable_boolean_value = 2; - else if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1')) - lockable_boolean_value = 1; - else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0')) - lockable_boolean_value = 0; - else if (0 == strcasecmp (val, "never") || CMP2 (val, '-', '1')) - lockable_boolean_value = -1; + value = false; else { fprintf (stderr, - _("%s: %s: Invalid boolean `%s', use always, on, off, or never.\n"), + _("%s: %s: Invalid boolean `%s'; use `on' or `off'.\n"), exec_name, com, val); - return 0; + return false; } - *(int *)place = lockable_boolean_value; - return 1; + *(bool *) place = value; + return true; } /* Set the non-negative integer value from VAL to PLACE. With incorrect specification, the number remains unchanged. */ -static int +static bool cmd_number (const char *com, const char *val, void *place) { if (!simple_atoi (val, val + strlen (val), place) @@ -727,33 +720,33 @@ cmd_number (const char *com, const char *val, void *place) { fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"), exec_name, com, val); - return 0; + return false; } - return 1; + return true; } /* Similar to cmd_number(), only accepts `inf' as a synonym for 0. */ -static int +static bool cmd_number_inf (const char *com, const char *val, void *place) { if (!strcasecmp (val, "inf")) { - *(int *)place = 0; - return 1; + *(int *) place = 0; + return true; } return cmd_number (com, val, place); } /* Copy (strdup) the string at COM to a new location and place a pointer to *PLACE. */ -static int +static bool cmd_string (const char *com, const char *val, void *place) { char **pstring = (char **)place; xfree_null (*pstring); *pstring = xstrdup (val); - return 1; + return true; } #ifndef WINDOWS @@ -765,7 +758,7 @@ cmd_string (const char *com, const char *val, void *place) /* Like the above, but handles tilde-expansion when reading a user's `.wgetrc'. In that case, and if VAL begins with `~', the tilde gets expanded to the user's home directory. */ -static int +static bool cmd_file (const char *com, const char *val, void *place) { char **pstring = (char **)place; @@ -806,11 +799,11 @@ cmd_file (const char *com, const char *val, void *place) *s = '/'; } #endif - return 1; + return true; } /* Like cmd_file, but strips trailing '/' characters. */ -static int +static bool cmd_directory (const char *com, const char *val, void *place) { char *s, *t; @@ -819,21 +812,21 @@ cmd_directory (const char *com, const char *val, void *place) canonicalization (backslash -> slash under Windows). These things should perhaps be in a separate function. */ if (!cmd_file (com, val, place)) - return 0; + return false; s = *(char **)place; t = s + strlen (s); while (t > s && *--t == '/') *t = '\0'; - return 1; + return true; } /* Split VAL by space to a vector of values, and append those values to vector pointed to by the PLACE argument. If VAL is empty, the PLACE vector is cleared instead. */ -static int +static bool cmd_vector (const char *com, const char *val, void *place) { char ***pvec = (char ***)place; @@ -845,10 +838,10 @@ cmd_vector (const char *com, const char *val, void *place) free_vec (*pvec); *pvec = NULL; } - return 1; + return true; } -static int +static bool cmd_directory_vector (const char *com, const char *val, void *place) { char ***pvec = (char ***)place; @@ -876,13 +869,13 @@ cmd_directory_vector (const char *com, const char *val, void *place) free_vec (*pvec); *pvec = NULL; } - return 1; + return true; } -/* Engine for cmd_bytes and cmd_bytes_large: converts a string such as +/* Engine for cmd_bytes and cmd_bytes_sum: converts a string such as "100k" or "2.5G" to a floating point number. */ -static int +static bool parse_bytes_helper (const char *val, double *result) { double number, mult; @@ -892,14 +885,14 @@ parse_bytes_helper (const char *val, double *result) if (0 == strcmp (val, "inf")) { *result = 0; - return 1; + return true; } /* Strip trailing whitespace. */ while (val < end && ISSPACE (end[-1])) --end; if (val == end) - return 0; + return false; switch (TOLOWER (end[-1])) { @@ -927,13 +920,13 @@ parse_bytes_helper (const char *val, double *result) while (val < end && ISSPACE (end[-1])) --end; if (val == end) - return 0; + return false; if (!simple_atof (val, end, &number) || number < 0) - return 0; + return false; *result = number * mult; - return 1; + return true; } /* Parse VAL as a number and set its value to PLACE (which should @@ -947,10 +940,10 @@ parse_bytes_helper (const char *val, double *result) The string "inf" is returned as 0. - In case of error, 0 is returned and memory pointed to by PLACE + In case of error, false is returned and memory pointed to by PLACE remains unmodified. */ -static int +static bool cmd_bytes (const char *com, const char *val, void *place) { double byte_value; @@ -958,36 +951,36 @@ cmd_bytes (const char *com, const char *val, void *place) { fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"), exec_name, com, val); - return 0; + return false; } *(wgint *)place = (wgint)byte_value; - return 1; + return true; } /* Like cmd_bytes, but PLACE is interpreted as a pointer to - LARGE_INT. It works by converting the string to double, therefore + SIZE_SUM. It works by converting the string to double, therefore working with values up to 2^53-1 without loss of precision. This value (8192 TB) is large enough to serve for a while. */ -static int -cmd_bytes_large (const char *com, const char *val, void *place) +static bool +cmd_bytes_sum (const char *com, const char *val, void *place) { double byte_value; if (!parse_bytes_helper (val, &byte_value)) { fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"), exec_name, com, val); - return 0; + return false; } - *(LARGE_INT *)place = (LARGE_INT)byte_value; - return 1; + *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value; + return true; } /* Store the value of VAL to *OUT. The value is a time period, by default expressed in seconds, but also accepting suffixes "m", "h", "d", and "w" for minutes, hours, days, and weeks respectively. */ -static int +static bool cmd_time (const char *com, const char *val, void *place) { double number, mult; @@ -1002,7 +995,7 @@ cmd_time (const char *com, const char *val, void *place) err: fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"), exec_name, com, val); - return 0; + return false; } switch (TOLOWER (end[-1])) @@ -1040,11 +1033,11 @@ cmd_time (const char *com, const char *val, void *place) goto err; *(double *)place = number * mult; - return 1; + return true; } #ifdef HAVE_SSL -static int +static bool cmd_cert_type (const char *com, const char *val, void *place) { static const struct decode_item choices[] = { @@ -1062,69 +1055,78 @@ cmd_cert_type (const char *com, const char *val, void *place) /* Specialized helper functions, used by `commands' to handle some options specially. */ -static int check_user_specified_header PARAMS ((const char *)); +static bool check_user_specified_header (const char *); -static int +static bool cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored) { if (!cmd_boolean (com, val, &opt.dirstruct)) - return 0; + return false; /* Since dirstruct behaviour is explicitly changed, no_dirstruct must be affected inversely. */ if (opt.dirstruct) - opt.no_dirstruct = 0; + opt.no_dirstruct = false; else - opt.no_dirstruct = 1; - return 1; + opt.no_dirstruct = true; + return true; } -static int -cmd_spec_header (const char *com, const char *val, void *place) +static bool +cmd_spec_header (const char *com, const char *val, void *place_ignored) { + /* Empty value means reset the list of headers. */ + if (*val == '\0') + { + free_vec (opt.user_headers); + opt.user_headers = NULL; + return true; + } + if (!check_user_specified_header (val)) { fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"), exec_name, com, val); - return 0; + return false; } - return cmd_vector (com, val, place); + opt.user_headers = vec_append (opt.user_headers, val); + return true; } -static int +static bool cmd_spec_htmlify (const char *com, const char *val, void *place_ignored) { int flag = cmd_boolean (com, val, &opt.htmlify); if (flag && !opt.htmlify) - opt.remove_listing = 0; + opt.remove_listing = false; return flag; } /* Set the "mirror" mode. It means: recursive download, timestamping, no limit on max. recursion depth, and don't remove listings. */ -static int +static bool cmd_spec_mirror (const char *com, const char *val, void *place_ignored) { int mirror; if (!cmd_boolean (com, val, &mirror)) - return 0; + return false; if (mirror) { - opt.recursive = 1; + opt.recursive = true; if (!opt.no_dirstruct) - opt.dirstruct = 1; - opt.timestamping = 1; + opt.dirstruct = true; + opt.timestamping = true; opt.reclevel = INFINITE_RECURSION; - opt.remove_listing = 0; + opt.remove_listing = false; } - return 1; + return true; } /* Validate --prefer-family and set the choice. Allowed values are "IPv4", "IPv6", and "none". */ -static int +static bool cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored) { static const struct decode_item choices[] = { @@ -1132,94 +1134,102 @@ cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored) { "IPv6", prefer_ipv6 }, { "none", prefer_none }, }; - int ok = decode_string (val, choices, countof (choices), - (int *) &opt.prefer_family); + int prefer_family = prefer_ipv4; + int ok = decode_string (val, choices, countof (choices), &prefer_family); if (!ok) fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val); + opt.prefer_family = prefer_family; return ok; } /* Set progress.type to VAL, but verify that it's a valid progress implementation before that. */ -static int +static bool cmd_spec_progress (const char *com, const char *val, void *place_ignored) { if (!valid_progress_implementation_p (val)) { fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"), exec_name, com, val); - return 0; + return false; } xfree_null (opt.progress_type); /* Don't call set_progress_implementation here. It will be called in main() when it becomes clear what the log output is. */ opt.progress_type = xstrdup (val); - return 1; + return true; } /* Set opt.recursive to VAL as with cmd_boolean. If opt.recursive is - set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct + set to true, also set opt.dirstruct to true, unless opt.no_dirstruct is specified. */ -static int +static bool cmd_spec_recursive (const char *com, const char *val, void *place_ignored) { if (!cmd_boolean (com, val, &opt.recursive)) - return 0; + return false; else { if (opt.recursive && !opt.no_dirstruct) - opt.dirstruct = 1; + opt.dirstruct = true; } - return 1; + return true; } -static int +static bool cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored) { int restrict_os = opt.restrict_files_os; int restrict_ctrl = opt.restrict_files_ctrl; + int restrict_case = opt.restrict_files_case; - const char *end = strchr (val, ','); - if (!end) - end = val + strlen (val); + const char *end; #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal) - if (VAL_IS ("unix")) - restrict_os = restrict_unix; - else if (VAL_IS ("windows")) - restrict_os = restrict_windows; - else if (VAL_IS ("nocontrol")) - restrict_ctrl = 0; - else + do { - err: - fprintf (stderr, - _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"), - exec_name, com, val); - return 0; + end = strchr (val, ','); + if (!end) + end = val + strlen (val); + + if (VAL_IS ("unix")) + restrict_os = restrict_unix; + else if (VAL_IS ("windows")) + restrict_os = restrict_windows; + else if (VAL_IS ("lowercase")) + restrict_case = restrict_lowercase; + else if (VAL_IS ("uppercase")) + restrict_case = restrict_uppercase; + else if (VAL_IS ("nocontrol")) + restrict_ctrl = false; + else + { + fprintf (stderr, + _("%s: %s: Invalid restriction `%s', use [unix|windows],[lowercase|uppercase],[nocontrol].\n"), + exec_name, com, val); + return false; + } + + if (*end) + val = end + 1; } + while (*val && *end); #undef VAL_IS - if (*end) - { - if (!strcmp (end + 1, "nocontrol")) - restrict_ctrl = 0; - else - goto err; - } - opt.restrict_files_os = restrict_os; opt.restrict_files_ctrl = restrict_ctrl; - return 1; + opt.restrict_files_case = restrict_case; + + return true; } #ifdef HAVE_SSL -static int +static bool cmd_spec_secure_protocol (const char *com, const char *val, void *place) { static const struct decode_item choices[] = { @@ -1237,45 +1247,60 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place) /* Set all three timeout values. */ -static int +static bool cmd_spec_timeout (const char *com, const char *val, void *place_ignored) { double value; if (!cmd_time (com, val, &value)) - return 0; + return false; opt.read_timeout = value; opt.connect_timeout = value; opt.dns_timeout = value; - return 1; + return true; } -static int +static bool cmd_spec_useragent (const char *com, const char *val, void *place_ignored) { - /* Just check for empty string and newline, so we don't throw total - junk to the server. */ - if (!*val || strchr (val, '\n')) + /* Disallow embedded newlines. */ + if (strchr (val, '\n')) { fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val); - return 0; + return false; } xfree_null (opt.useragent); opt.useragent = xstrdup (val); - return 1; + return true; +} + +/* The "verbose" option cannot be cmd_boolean because the variable is + not bool -- it's of type int (-1 means uninitialized because of + some random hackery for disallowing -q -v). */ + +static bool +cmd_spec_verbose (const char *com, const char *val, void *place_ignored) +{ + bool flag; + if (cmd_boolean (com, val, &flag)) + { + opt.verbose = flag; + return true; + } + return false; } /* Miscellaneous useful routines. */ /* A very simple atoi clone, more useful than atoi because it works on - delimited strings, and has error reportage. Returns 1 on success, - 0 on failure. If successful, stores result to *DEST. */ + delimited strings, and has error reportage. Returns true on success, + false on failure. If successful, stores result to *DEST. */ -static int +static bool simple_atoi (const char *beg, const char *end, int *dest) { int result = 0; - int negative = 0; + bool negative = false; const char *p = beg; while (p < end && ISSPACE (*p)) @@ -1286,7 +1311,7 @@ simple_atoi (const char *beg, const char *end, int *dest) ++p; } if (p == end) - return 0; + return false; /* Read negative numbers in a separate loop because the most negative integer cannot be represented as a positive number. */ @@ -1296,7 +1321,7 @@ simple_atoi (const char *beg, const char *end, int *dest) { int next = (10 * result) + (*p - '0'); if (next < result) - return 0; /* overflow */ + return false; /* overflow */ result = next; } else @@ -1304,29 +1329,30 @@ simple_atoi (const char *beg, const char *end, int *dest) { int next = (10 * result) - (*p - '0'); if (next > result) - return 0; /* underflow */ + return false; /* underflow */ result = next; } if (p != end) - return 0; + return false; *dest = result; - return 1; + return true; } /* Trivial atof, with error reporting. Handles "[.]", - doesn't handle exponential notation. Returns 1 on success, 0 on - failure. In case of success, stores its result to *DEST. */ + doesn't handle exponential notation. Returns true on success, + false on failure. In case of success, stores its result to + *DEST. */ -static int +static bool simple_atof (const char *beg, const char *end, double *dest) { double result = 0; - int negative = 0; - int seen_dot = 0; - int seen_digit = 0; + bool negative = false; + bool seen_dot = false; + bool seen_digit = false; double divider = 1; const char *p = beg; @@ -1348,50 +1374,51 @@ simple_atof (const char *beg, const char *end, double *dest) result = (10 * result) + (ch - '0'); else result += (ch - '0') / (divider *= 10); - seen_digit = 1; + seen_digit = true; } else if (ch == '.') { if (!seen_dot) - seen_dot = 1; + seen_dot = true; else - return 0; + return false; } else - return 0; + return false; } if (!seen_digit) - return 0; + return false; if (negative) result = -result; *dest = result; - return 1; + return true; } /* Verify that the user-specified header in S is valid. It must contain a colon preceded by non-white-space characters and must not contain newlines. */ -static int +static bool check_user_specified_header (const char *s) { const char *p; - for (p = s; *p && *p != ':' && !ISSPACE (*p); p++); + for (p = s; *p && *p != ':' && !ISSPACE (*p); p++) + ; /* The header MUST contain `:' preceded by at least one non-whitespace character. */ if (*p != ':' || p == s) - return 0; + return false; /* The header MUST NOT contain newlines. */ if (strchr (s, '\n')) - return 0; - return 1; + return false; + return true; } /* Decode VAL into a number, according to ITEMS. */ -static int +static bool decode_string (const char *val, const struct decode_item *items, int itemcount, int *place) { @@ -1400,14 +1427,13 @@ decode_string (const char *val, const struct decode_item *items, int itemcount, if (0 == strcasecmp (val, items[i].name)) { *place = items[i].code; - return 1; + return true; } - return 0; + return false; } -void cleanup_html_url PARAMS ((void)); -void http_cleanup PARAMS ((void)); +void cleanup_html_url (void); /* Free the memory allocated by global variables. */ @@ -1416,13 +1442,10 @@ cleanup (void) { /* Free external resources, close files, etc. */ - { - extern FILE *output_stream; - if (output_stream) - fclose (output_stream); - /* No need to check for error because Wget flushes its output (and - checks for errors) after any data arrives. */ - } + if (output_stream) + fclose (output_stream); + /* No need to check for error because Wget flushes its output (and + checks for errors) after any data arrives. */ /* We're exiting anyway so there's no real need to call free() hundreds of times. Skipping the frees will make Wget exit @@ -1456,7 +1479,6 @@ cleanup (void) free_vec (opt.follow_tags); free_vec (opt.ignore_tags); xfree_null (opt.progress_type); - xfree (opt.ftp_acc); xfree_null (opt.ftp_user); xfree_null (opt.ftp_passwd); xfree_null (opt.ftp_proxy); @@ -1471,6 +1493,10 @@ cleanup (void) # ifdef HAVE_SSL xfree_null (opt.cert_file); xfree_null (opt.private_key); + xfree_null (opt.ca_directory); + xfree_null (opt.ca_cert); + xfree_null (opt.random_file); + xfree_null (opt.egd_file); # endif xfree_null (opt.bind_address); xfree_null (opt.cookies_input); @@ -1479,3 +1505,50 @@ cleanup (void) xfree_null (opt.passwd); #endif /* DEBUG_MALLOC */ } + +/* Unit testing routines. */ + +#ifdef TESTING + +const char * +test_cmd_spec_restrict_file_names() +{ + int i; + struct { + char *val; + int expected_restrict_files_os; + int expected_restrict_files_ctrl; + int expected_restrict_files_case; + bool result; + } test_array[] = { + { "windows", restrict_windows, true, restrict_no_case_restriction, true }, + { "windows,", restrict_windows, true, restrict_no_case_restriction, true }, + { "windows,lowercase", restrict_windows, true, restrict_lowercase, true }, + { "unix,nocontrol,lowercase,", restrict_unix, false, restrict_lowercase, true }, + }; + + for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) + { + bool res; + + defaults(); + res = cmd_spec_restrict_file_names ("dummy", test_array[i].val, NULL); + + /* + fprintf (stderr, "test_cmd_spec_restrict_file_names: TEST %d\n", i); fflush (stderr); + fprintf (stderr, "opt.restrict_files_os: %d\n", opt.restrict_files_os); fflush (stderr); + fprintf (stderr, "opt.restrict_files_ctrl: %d\n", opt.restrict_files_ctrl); fflush (stderr); + fprintf (stderr, "opt.restrict_files_case: %d\n", opt.restrict_files_case); fflush (stderr); + */ + mu_assert ("test_cmd_spec_restrict_file_names: wrong result", + res == test_array[i].result + && opt.restrict_files_os == test_array[i].expected_restrict_files_os + && opt.restrict_files_ctrl == test_array[i].expected_restrict_files_ctrl + && opt.restrict_files_case == test_array[i].expected_restrict_files_case); + } + + return NULL; +} + +#endif /* TESTING */ +