]> sjero.net Git - wget/blob - src/init.c
added option --https-only
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3    2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
4    Inc.
5
6 This file is part of GNU Wget.
7
8 GNU Wget is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Wget is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
20
21 Additional permission under GNU GPL version 3 section 7
22
23 If you modify this program, or any covered work, by linking or
24 combining it with the OpenSSL project's OpenSSL library (or a
25 modified version of that library), containing parts covered by the
26 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
27 grants you additional permission to convey the resulting work.
28 Corresponding Source for a non-source form of such a combination
29 shall include the source code for the parts of OpenSSL used as well
30 as that of the covered work.  */
31
32 #include "wget.h"
33 #include "exits.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdbool.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <limits.h>
42 /* not all systems provide PATH_MAX in limits.h */
43 #ifndef PATH_MAX
44 # include <sys/param.h>
45 # ifndef PATH_MAX
46 #  define PATH_MAX MAXPATHLEN
47 # endif
48 #endif
49
50 #include <regex.h>
51 #ifdef HAVE_LIBPCRE
52 # include <pcre.h>
53 #endif
54
55 #ifdef HAVE_PWD_H
56 # include <pwd.h>
57 #endif
58 #include <assert.h>
59
60 #include "utils.h"
61 #include "init.h"
62 #include "host.h"
63 #include "netrc.h"
64 #include "progress.h"
65 #include "recur.h"              /* for INFINITE_RECURSION */
66 #include "convert.h"            /* for convert_cleanup */
67 #include "res.h"                /* for res_cleanup */
68 #include "http.h"               /* for http_cleanup */
69 #include "retr.h"               /* for output_stream */
70 #include "warc.h"               /* for warc_close */
71
72 #ifdef TESTING
73 #include "test.h"
74 #endif
75
76
77
78 #define CMD_DECLARE(func) static bool func (const char *, const char *, void *)
79
80 CMD_DECLARE (cmd_boolean);
81 CMD_DECLARE (cmd_bytes);
82 CMD_DECLARE (cmd_bytes_sum);
83 #ifdef HAVE_SSL
84 CMD_DECLARE (cmd_cert_type);
85 #endif
86 CMD_DECLARE (cmd_directory_vector);
87 CMD_DECLARE (cmd_number);
88 CMD_DECLARE (cmd_number_inf);
89 CMD_DECLARE (cmd_string);
90 CMD_DECLARE (cmd_string_uppercase);
91 CMD_DECLARE (cmd_file);
92 CMD_DECLARE (cmd_directory);
93 CMD_DECLARE (cmd_time);
94 CMD_DECLARE (cmd_vector);
95
96 CMD_DECLARE (cmd_spec_dirstruct);
97 CMD_DECLARE (cmd_spec_header);
98 CMD_DECLARE (cmd_spec_warc_header);
99 CMD_DECLARE (cmd_spec_htmlify);
100 CMD_DECLARE (cmd_spec_mirror);
101 CMD_DECLARE (cmd_spec_prefer_family);
102 CMD_DECLARE (cmd_spec_progress);
103 CMD_DECLARE (cmd_spec_recursive);
104 CMD_DECLARE (cmd_spec_regex_type);
105 CMD_DECLARE (cmd_spec_restrict_file_names);
106 CMD_DECLARE (cmd_spec_report_speed);
107 #ifdef HAVE_SSL
108 CMD_DECLARE (cmd_spec_secure_protocol);
109 #endif
110 CMD_DECLARE (cmd_spec_timeout);
111 CMD_DECLARE (cmd_spec_useragent);
112 CMD_DECLARE (cmd_spec_verbose);
113
114 /* List of recognized commands, each consisting of name, place and
115    function.  When adding a new command, simply add it to the list,
116    but be sure to keep the list sorted alphabetically, as
117    command_by_name's binary search depends on it.  Also, be sure to
118    add any entries that allocate memory (e.g. cmd_string and
119    cmd_vector) to the cleanup() function below. */
120
121 static const struct {
122   const char *name;
123   void *place;
124   bool (*action) (const char *, const char *, void *);
125 } commands[] = {
126   /* KEEP THIS LIST ALPHABETICALLY SORTED */
127   { "accept",           &opt.accepts,           cmd_vector },
128   { "acceptregex",      &opt.acceptregex_s,     cmd_string },
129   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
130   { "adjustextension",  &opt.adjust_extension,  cmd_boolean },
131   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
132   { "askpassword",      &opt.ask_passwd,        cmd_boolean },
133   { "authnochallenge",  &opt.auth_without_challenge,
134                                                 cmd_boolean },
135   { "background",       &opt.background,        cmd_boolean },
136   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
137   { "backups",          &opt.backups,           cmd_number },
138   { "base",             &opt.base_href,         cmd_string },
139   { "bindaddress",      &opt.bind_address,      cmd_string },
140   { "bodydata",         &opt.body_data,         cmd_string },
141   { "bodyfile",         &opt.body_file,         cmd_string },
142 #ifdef HAVE_SSL
143   { "cacertificate",    &opt.ca_cert,           cmd_file },
144 #endif
145   { "cache",            &opt.allow_cache,       cmd_boolean },
146 #ifdef HAVE_SSL
147   { "cadirectory",      &opt.ca_directory,      cmd_directory },
148   { "certificate",      &opt.cert_file,         cmd_file },
149   { "certificatetype",  &opt.cert_type,         cmd_cert_type },
150   { "checkcertificate", &opt.check_cert,        cmd_boolean },
151 #endif
152   { "chooseconfig",     &opt.choose_config,     cmd_file },
153   { "connecttimeout",   &opt.connect_timeout,   cmd_time },
154   { "contentdisposition", &opt.content_disposition, cmd_boolean },
155   { "contentonerror",   &opt.content_on_error,  cmd_boolean },
156   { "continue",         &opt.always_rest,       cmd_boolean },
157   { "convertlinks",     &opt.convert_links,     cmd_boolean },
158   { "cookies",          &opt.cookies,           cmd_boolean },
159   { "cutdirs",          &opt.cut_dirs,          cmd_number },
160 #ifdef ENABLE_DEBUG
161   { "debug",            &opt.debug,             cmd_boolean },
162 #endif
163   { "defaultpage",      &opt.default_page,      cmd_string },
164   { "deleteafter",      &opt.delete_after,      cmd_boolean },
165   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
166   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
167   { "dnscache",         &opt.dns_cache,         cmd_boolean },
168   { "dnstimeout",       &opt.dns_timeout,       cmd_time },
169   { "domains",          &opt.domains,           cmd_vector },
170   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
171   { "dotsinline",       &opt.dots_in_line,      cmd_number },
172   { "dotspacing",       &opt.dot_spacing,       cmd_number },
173   { "dotstyle",         &opt.dot_style,         cmd_string }, /* deprecated */
174 #ifdef HAVE_SSL
175   { "egdfile",          &opt.egd_file,          cmd_file },
176 #endif
177   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
178   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
179   { "followftp",        &opt.follow_ftp,        cmd_boolean },
180   { "followtags",       &opt.follow_tags,       cmd_vector },
181   { "forcehtml",        &opt.force_html,        cmd_boolean },
182   { "ftppasswd",        &opt.ftp_passwd,        cmd_string }, /* deprecated */
183   { "ftppassword",      &opt.ftp_passwd,        cmd_string },
184   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
185 #ifdef __VMS
186   { "ftpstmlf",         &opt.ftp_stmlf,         cmd_boolean },
187 #endif /* def __VMS */
188   { "ftpuser",          &opt.ftp_user,          cmd_string },
189   { "glob",             &opt.ftp_glob,          cmd_boolean },
190   { "header",           NULL,                   cmd_spec_header },
191   { "htmlextension",    &opt.adjust_extension,  cmd_boolean }, /* deprecated */
192   { "htmlify",          NULL,                   cmd_spec_htmlify },
193   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
194   { "httppasswd",       &opt.http_passwd,       cmd_string }, /* deprecated */
195   { "httppassword",     &opt.http_passwd,       cmd_string },
196   { "httpproxy",        &opt.http_proxy,        cmd_string },
197 #ifdef HAVE_SSL
198   { "httpsonly",        &opt.https_only,        cmd_boolean },
199 #endif
200   { "httpsproxy",       &opt.https_proxy,       cmd_string },
201   { "httpuser",         &opt.http_user,         cmd_string },
202   { "ignorecase",       &opt.ignore_case,       cmd_boolean },
203   { "ignorelength",     &opt.ignore_length,     cmd_boolean },
204   { "ignoretags",       &opt.ignore_tags,       cmd_vector },
205   { "includedirectories", &opt.includes,        cmd_directory_vector },
206 #ifdef ENABLE_IPV6
207   { "inet4only",        &opt.ipv4_only,         cmd_boolean },
208   { "inet6only",        &opt.ipv6_only,         cmd_boolean },
209 #endif
210   { "input",            &opt.input_filename,    cmd_file },
211   { "iri",              &opt.enable_iri,        cmd_boolean },
212   { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
213   { "limitrate",        &opt.limit_rate,        cmd_bytes },
214   { "loadcookies",      &opt.cookies_input,     cmd_file },
215   { "localencoding",    &opt.locale,            cmd_string },
216   { "logfile",          &opt.lfilename,         cmd_file },
217   { "login",            &opt.ftp_user,          cmd_string },/* deprecated*/
218   { "maxredirect",      &opt.max_redirect,      cmd_number },
219   { "method",           &opt.method,            cmd_string_uppercase },
220   { "mirror",           NULL,                   cmd_spec_mirror },
221   { "netrc",            &opt.netrc,             cmd_boolean },
222   { "noclobber",        &opt.noclobber,         cmd_boolean },
223   { "noparent",         &opt.no_parent,         cmd_boolean },
224   { "noproxy",          &opt.no_proxy,          cmd_vector },
225   { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
226   { "outputdocument",   &opt.output_document,   cmd_file },
227   { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
228   { "passiveftp",       &opt.ftp_pasv,          cmd_boolean },
229   { "passwd",           &opt.ftp_passwd,        cmd_string },/* deprecated*/
230   { "password",         &opt.passwd,            cmd_string },
231   { "postdata",         &opt.post_data,         cmd_string },
232   { "postfile",         &opt.post_file_name,    cmd_file },
233   { "preferfamily",     NULL,                   cmd_spec_prefer_family },
234   { "preservepermissions", &opt.preserve_perm,  cmd_boolean },
235 #ifdef HAVE_SSL
236   { "privatekey",       &opt.private_key,       cmd_file },
237   { "privatekeytype",   &opt.private_key_type,  cmd_cert_type },
238 #endif
239   { "progress",         &opt.progress_type,     cmd_spec_progress },
240   { "protocoldirectories", &opt.protocol_directories, cmd_boolean },
241   { "proxypasswd",      &opt.proxy_passwd,      cmd_string }, /* deprecated */
242   { "proxypassword",    &opt.proxy_passwd,      cmd_string },
243   { "proxyuser",        &opt.proxy_user,        cmd_string },
244   { "quiet",            &opt.quiet,             cmd_boolean },
245   { "quota",            &opt.quota,             cmd_bytes_sum },
246 #ifdef HAVE_SSL
247   { "randomfile",       &opt.random_file,       cmd_file },
248 #endif
249   { "randomwait",       &opt.random_wait,       cmd_boolean },
250   { "readtimeout",      &opt.read_timeout,      cmd_time },
251   { "reclevel",         &opt.reclevel,          cmd_number_inf },
252   { "recursive",        NULL,                   cmd_spec_recursive },
253   { "referer",          &opt.referer,           cmd_string },
254   { "regextype",        &opt.regex_type,        cmd_spec_regex_type },
255   { "reject",           &opt.rejects,           cmd_vector },
256   { "rejectregex",      &opt.rejectregex_s,     cmd_string },
257   { "relativeonly",     &opt.relative_only,     cmd_boolean },
258   { "remoteencoding",   &opt.encoding_remote,   cmd_string },
259   { "removelisting",    &opt.remove_listing,    cmd_boolean },
260   { "reportspeed",             &opt.report_bps, cmd_spec_report_speed},
261   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
262   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
263   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
264   { "robots",           &opt.use_robots,        cmd_boolean },
265   { "savecookies",      &opt.cookies_output,    cmd_file },
266   { "saveheaders",      &opt.save_headers,      cmd_boolean },
267 #ifdef HAVE_SSL
268   { "secureprotocol",   &opt.secure_protocol,   cmd_spec_secure_protocol },
269 #endif
270   { "serverresponse",   &opt.server_response,   cmd_boolean },
271   { "showalldnsentries", &opt.show_all_dns_entries, cmd_boolean },
272   { "spanhosts",        &opt.spanhost,          cmd_boolean },
273   { "spider",           &opt.spider,            cmd_boolean },
274   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
275   { "timeout",          NULL,                   cmd_spec_timeout },
276   { "timestamping",     &opt.timestamping,      cmd_boolean },
277   { "tries",            &opt.ntry,              cmd_number_inf },
278   { "trustservernames", &opt.trustservernames,  cmd_boolean },
279   { "unlink",           &opt.unlink,            cmd_boolean },
280   { "useproxy",         &opt.use_proxy,         cmd_boolean },
281   { "user",             &opt.user,              cmd_string },
282   { "useragent",        NULL,                   cmd_spec_useragent },
283   { "useservertimestamps", &opt.useservertimestamps, cmd_boolean },
284   { "verbose",          NULL,                   cmd_spec_verbose },
285   { "wait",             &opt.wait,              cmd_time },
286   { "waitretry",        &opt.waitretry,         cmd_time },
287   { "warccdx",          &opt.warc_cdx_enabled,  cmd_boolean },
288   { "warccdxdedup",     &opt.warc_cdx_dedup_filename,  cmd_file },
289 #ifdef HAVE_LIBZ
290   { "warccompression",  &opt.warc_compression_enabled, cmd_boolean },
291 #endif
292   { "warcdigests",      &opt.warc_digests_enabled, cmd_boolean },
293   { "warcfile",         &opt.warc_filename,     cmd_file },
294   { "warcheader",       NULL,                   cmd_spec_warc_header },
295   { "warckeeplog",      &opt.warc_keep_log,     cmd_boolean },
296   { "warcmaxsize",      &opt.warc_maxsize,      cmd_bytes },
297   { "warctempdir",      &opt.warc_tempdir,      cmd_directory },
298 #ifdef USE_WATT32
299   { "wdebug",           &opt.wdebug,            cmd_boolean },
300 #endif
301 };
302
303 /* Look up CMDNAME in the commands[] and return its position in the
304    array.  If CMDNAME is not found, return -1.  */
305
306 static int
307 command_by_name (const char *cmdname)
308 {
309   /* Use binary search for speed.  Wget has ~100 commands, which
310      guarantees a worst case performance of 7 string comparisons.  */
311   int lo = 0, hi = countof (commands) - 1;
312
313   while (lo <= hi)
314     {
315       int mid = (lo + hi) >> 1;
316       int cmp = strcasecmp (cmdname, commands[mid].name);
317       if (cmp < 0)
318         hi = mid - 1;
319       else if (cmp > 0)
320         lo = mid + 1;
321       else
322         return mid;
323     }
324   return -1;
325 }
326 \f
327 /* Reset the variables to default values.  */
328 void
329 defaults (void)
330 {
331   char *tmp;
332
333   /* Most of the default values are 0 (and 0.0, NULL, and false).
334      Just reset everything, and fill in the non-zero values.  Note
335      that initializing pointers to NULL this way is technically
336      illegal, but porting Wget to a machine where NULL is not all-zero
337      bit pattern will be the least of the implementors' worries.  */
338   xzero (opt);
339
340   opt.cookies = true;
341   opt.verbose = -1;
342   opt.ntry = 20;
343   opt.reclevel = 5;
344   opt.add_hostdir = true;
345   opt.netrc = true;
346   opt.ftp_glob = true;
347   opt.htmlify = true;
348   opt.http_keep_alive = true;
349   opt.use_proxy = true;
350   tmp = getenv ("no_proxy");
351   if (tmp)
352     opt.no_proxy = sepstring (tmp);
353   opt.prefer_family = prefer_none;
354   opt.allow_cache = true;
355
356   opt.read_timeout = 900;
357   opt.use_robots = true;
358
359   opt.remove_listing = true;
360
361   opt.dot_bytes = 1024;
362   opt.dot_spacing = 10;
363   opt.dots_in_line = 50;
364
365   opt.dns_cache = true;
366   opt.ftp_pasv = true;
367
368 #ifdef HAVE_SSL
369   opt.check_cert = true;
370 #endif
371
372   /* The default for file name restriction defaults to the OS type. */
373 #if defined(WINDOWS) || defined(MSDOS) || defined(__CYGWIN__)
374   opt.restrict_files_os = restrict_windows;
375 #else
376   opt.restrict_files_os = restrict_unix;
377 #endif
378   opt.restrict_files_ctrl = true;
379   opt.restrict_files_nonascii = false;
380   opt.restrict_files_case = restrict_no_case_restriction;
381
382   opt.regex_type = regex_type_posix;
383
384   opt.max_redirect = 20;
385
386   opt.waitretry = 10;
387
388 #ifdef ENABLE_IRI
389   opt.enable_iri = true;
390 #else
391   opt.enable_iri = false;
392 #endif
393   opt.locale = NULL;
394   opt.encoding_remote = NULL;
395
396   opt.useservertimestamps = true;
397   opt.show_all_dns_entries = false;
398
399   opt.warc_maxsize = 0; /* 1024 * 1024 * 1024; */
400 #ifdef HAVE_LIBZ
401   opt.warc_compression_enabled = true;
402 #else
403   opt.warc_compression_enabled = false;
404 #endif
405   opt.warc_digests_enabled = true;
406   opt.warc_cdx_enabled = false;
407   opt.warc_cdx_dedup_filename = NULL;
408   opt.warc_tempdir = NULL;
409   opt.warc_keep_log = true;
410 }
411 \f
412 /* Return the user's home directory (strdup-ed), or NULL if none is
413    found.  */
414 char *
415 home_dir (void)
416 {
417   static char *buf = NULL;
418   static char *home, *ret;
419
420   if (!home)
421     {
422       home = getenv ("HOME");
423       if (!home)
424         {
425 #if defined(MSDOS)
426           int len;
427
428           /* Under MSDOS, if $HOME isn't defined, use the directory where
429              `wget.exe' resides.  */
430           const char *_w32_get_argv0 (void); /* in libwatt.a/pcconfig.c */
431           char *p;
432
433           buff = _w32_get_argv0 ();
434
435           p = strrchr (buf, '/');            /* djgpp */
436           if (!p)
437             p = strrchr (buf, '\\');          /* others */
438           assert (p);
439
440           len = p - buff + 1;
441           buff = malloc (len + 1);
442           if (buff == NULL)
443             return NULL;
444
445           strncpy (buff, _w32_get_argv0 (), len);
446           buff[len] = '\0';
447
448           home = buf;
449 #elif !defined(WINDOWS)
450           /* If HOME is not defined, try getting it from the password
451              file.  */
452           struct passwd *pwd = getpwuid (getuid ());
453           if (!pwd || !pwd->pw_dir)
454             return NULL;
455           home = pwd->pw_dir;
456 #else  /* !WINDOWS */
457           /* Under Windows, if $HOME isn't defined, use the directory where
458              `wget.exe' resides.  */
459           home = ws_mypath ();
460 #endif /* WINDOWS */
461         }
462     }
463
464   ret = home ? xstrdup (home) : NULL;
465   if (buf)
466     free (buf);
467
468   return ret;
469 }
470
471 /* Check the 'WGETRC' environment variable and return the file name
472    if  'WGETRC' is set and is a valid file.
473    If the `WGETRC' variable exists but the file does not exist, the
474    function will exit().  */
475 char *
476 wgetrc_env_file_name (void)
477 {
478   char *env = getenv ("WGETRC");
479   if (env && *env)
480     {
481       if (!file_exists_p (env))
482         {
483           fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
484                    exec_name, env);
485           exit (1);
486         }
487       return xstrdup (env);
488     }
489   return NULL;
490 }
491
492 /* Check for the existance of '$HOME/.wgetrc' and return its path
493    if it exists and is set.  */
494 char *
495 wgetrc_user_file_name (void)
496 {
497   char *home;
498   char *file = NULL;
499   /* If that failed, try $HOME/.wgetrc (or equivalent).  */
500
501 #ifdef __VMS
502   file = "SYS$LOGIN:.wgetrc";
503 #else /* def __VMS */
504   home = home_dir ();
505   if (home)
506     file = aprintf ("%s/.wgetrc", home);
507   xfree_null (home);
508 #endif /* def __VMS [else] */
509
510   if (!file)
511     return NULL;
512   if (!file_exists_p (file))
513     {
514       xfree (file);
515       return NULL;
516     }
517   return file;
518 }
519
520 /* Return the path to the user's .wgetrc.  This is either the value of
521    `WGETRC' environment variable, or `$HOME/.wgetrc'.
522
523    Additionally, for windows, look in the directory where wget.exe
524    resides.  */
525 char *
526 wgetrc_file_name (void)
527 {
528   char *file = wgetrc_env_file_name ();
529   if (file && *file)
530     return file;
531
532   file = wgetrc_user_file_name ();
533
534 #ifdef WINDOWS
535   /* Under Windows, if we still haven't found .wgetrc, look for the file
536      `wget.ini' in the directory where `wget.exe' resides; we do this for
537      backward compatibility with previous versions of Wget.
538      SYSTEM_WGETRC should not be defined under WINDOWS.  */
539   if (!file)
540     {
541       char *home = home_dir ();
542       xfree_null (file);
543       file = NULL;
544       home = ws_mypath ();
545       if (home)
546         {
547           file = aprintf ("%s/wget.ini", home);
548           if (!file_exists_p (file))
549             {
550               xfree (file);
551               file = NULL;
552             }
553           xfree (home);
554         }
555     }
556 #endif /* WINDOWS */
557
558   return file;
559 }
560
561 /* Return values of parse_line. */
562 enum parse_line {
563   line_ok,
564   line_empty,
565   line_syntax_error,
566   line_unknown_command
567 };
568
569 static enum parse_line parse_line (const char *, char **, char **, int *);
570 static bool setval_internal (int, const char *, const char *);
571 static bool setval_internal_tilde (int, const char *, const char *);
572
573 /* Initialize variables from a wgetrc file.  Returns zero (failure) if
574    there were errors in the file.  */
575
576 bool
577 run_wgetrc (const char *file)
578 {
579   FILE *fp;
580   char *line = NULL;
581   size_t bufsize = 0;
582   int ln;
583   int errcnt = 0;
584
585   fp = fopen (file, "r");
586   if (!fp)
587     {
588       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
589                file, strerror (errno));
590       return true;                      /* not a fatal error */
591     }
592   ln = 1;
593   while (getline (&line, &bufsize, fp) > 0)
594     {
595       char *com = NULL, *val = NULL;
596       int comind;
597
598       /* Parse the line.  */
599       switch (parse_line (line, &com, &val, &comind))
600         {
601         case line_ok:
602           /* If everything is OK, set the value.  */
603           if (!setval_internal_tilde (comind, com, val))
604             {
605               fprintf (stderr, _("%s: Error in %s at line %d.\n"),
606                        exec_name, file, ln);
607               ++errcnt;
608             }
609           break;
610         case line_syntax_error:
611           fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
612                    exec_name, file, ln);
613           ++errcnt;
614           break;
615         case line_unknown_command:
616           fprintf (stderr, _("%s: Unknown command %s in %s at line %d.\n"),
617                    exec_name, quote (com), file, ln);
618           ++errcnt;
619           break;
620         case line_empty:
621           break;
622         default:
623           abort ();
624         }
625       xfree_null (com);
626       xfree_null (val);
627       ++ln;
628     }
629   xfree (line);
630   fclose (fp);
631
632   return errcnt == 0;
633 }
634
635 /* Initialize the defaults and run the system wgetrc and user's own
636    wgetrc.  */
637 void
638 initialize (void)
639 {
640   char *file, *env_sysrc;
641   bool ok = true;
642
643   /* Run a non-standard system rc file when the according environment
644      variable has been set. For internal testing purposes only!  */
645   env_sysrc = getenv ("SYSTEM_WGETRC");
646   if (env_sysrc && file_exists_p (env_sysrc))
647     {
648       ok &= run_wgetrc (env_sysrc);
649       /* If there are any problems parsing the system wgetrc file, tell
650          the user and exit */
651       if (! ok)
652         {
653           fprintf (stderr, _("\
654 Parsing system wgetrc file (env SYSTEM_WGETRC) failed.  Please check\n\
655 '%s',\n\
656 or specify a different file using --config.\n"), env_sysrc);
657           exit (2);
658         }
659     }
660   /* Otherwise, if SYSTEM_WGETRC is defined, use it.  */
661 #ifdef SYSTEM_WGETRC
662   else if (file_exists_p (SYSTEM_WGETRC))
663     ok &= run_wgetrc (SYSTEM_WGETRC);
664   /* If there are any problems parsing the system wgetrc file, tell
665      the user and exit */
666   if (! ok)
667     {
668       fprintf (stderr, _("\
669 Parsing system wgetrc file failed.  Please check\n\
670 '%s',\n\
671 or specify a different file using --config.\n"), SYSTEM_WGETRC);
672       exit (2);
673     }
674 #endif
675   /* Override it with your own, if one exists.  */
676   file = wgetrc_file_name ();
677   if (!file)
678     return;
679   /* #### We should canonicalize `file' and SYSTEM_WGETRC with
680      something like realpath() before comparing them with `strcmp'  */
681 #ifdef SYSTEM_WGETRC
682   if (!strcmp (file, SYSTEM_WGETRC))
683     {
684       fprintf (stderr, _("\
685 %s: Warning: Both system and user wgetrc point to %s.\n"),
686                exec_name, quote (file));
687     }
688   else
689 #endif
690     ok &= run_wgetrc (file);
691
692   /* If there were errors processing either `.wgetrc', abort. */
693   if (!ok)
694     exit (2);
695
696   xfree (file);
697   return;
698 }
699
700 /* Remove dashes and underscores from S, modifying S in the
701    process. */
702
703 static void
704 dehyphen (char *s)
705 {
706   char *t = s;                  /* t - tortoise */
707   char *h = s;                  /* h - hare     */
708   while (*h)
709     if (*h == '_' || *h == '-')
710       ++h;
711     else
712       *t++ = *h++;
713   *t = '\0';
714 }
715
716 /* Parse the line pointed by line, with the syntax:
717    <sp>* command <sp>* = <sp>* value <sp>*
718    Uses malloc to allocate space for command and value.
719
720    Returns one of line_ok, line_empty, line_syntax_error, or
721    line_unknown_command.
722
723    In case of line_ok, *COM and *VAL point to freshly allocated
724    strings, and *COMIND points to com's index.  In case of error or
725    empty line, their values are unmodified.  */
726
727 static enum parse_line
728 parse_line (const char *line, char **com, char **val, int *comind)
729 {
730   const char *p;
731   const char *end = line + strlen (line);
732   const char *cmdstart, *cmdend;
733   const char *valstart, *valend;
734
735   char *cmdcopy;
736   int ind;
737
738   /* Skip leading and trailing whitespace.  */
739   while (*line && c_isspace (*line))
740     ++line;
741   while (end > line && c_isspace (end[-1]))
742     --end;
743
744   /* Skip empty lines and comments.  */
745   if (!*line || *line == '#')
746     return line_empty;
747
748   p = line;
749
750   cmdstart = p;
751   while (p < end && (c_isalnum (*p) || *p == '_' || *p == '-'))
752     ++p;
753   cmdend = p;
754
755   /* Skip '=', as well as any space before or after it. */
756   while (p < end && c_isspace (*p))
757     ++p;
758   if (p == end || *p != '=')
759     return line_syntax_error;
760   ++p;
761   while (p < end && c_isspace (*p))
762     ++p;
763
764   valstart = p;
765   valend   = end;
766
767   /* The syntax is valid (even though the command might not be).  Fill
768      in the command name and value.  */
769   *com = strdupdelim (cmdstart, cmdend);
770   *val = strdupdelim (valstart, valend);
771
772   /* The line now known to be syntactically correct.  Check whether
773      the command is valid.  */
774   BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
775   dehyphen (cmdcopy);
776   ind = command_by_name (cmdcopy);
777   if (ind == -1)
778     return line_unknown_command;
779
780   /* Report success to the caller. */
781   *comind = ind;
782   return line_ok;
783 }
784
785 #if defined(WINDOWS) || defined(MSDOS)
786 # define ISSEP(c) ((c) == '/' || (c) == '\\')
787 #else
788 # define ISSEP(c) ((c) == '/')
789 #endif
790
791 /* Run commands[comind].action. */
792
793 static bool
794 setval_internal (int comind, const char *com, const char *val)
795 {
796   assert (0 <= comind && ((size_t) comind) < countof (commands));
797   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
798   return commands[comind].action (com, val, commands[comind].place);
799 }
800
801 static bool
802 setval_internal_tilde (int comind, const char *com, const char *val)
803 {
804   bool ret;
805   int homelen;
806   char *home;
807   char **pstring;
808   ret = setval_internal (comind, com, val);
809
810   /* We make tilde expansion for cmd_file and cmd_directory */
811   if (((commands[comind].action == cmd_file) ||
812        (commands[comind].action == cmd_directory))
813       && ret && (*val == '~' && ISSEP (val[1])))
814     {
815       pstring = commands[comind].place;
816       home = home_dir ();
817       if (home)
818         {
819           homelen = strlen (home);
820           while (homelen && ISSEP (home[homelen - 1]))
821             home[--homelen] = '\0';
822
823           /* Skip the leading "~/". */
824           for (++val; ISSEP (*val); val++)
825             ;
826           *pstring = concat_strings (home, "/", val, (char *)0);
827         }
828     }
829   return ret;
830 }
831
832 /* Run command COM with value VAL.  If running the command produces an
833    error, report the error and exit.
834
835    This is intended to be called from main() to modify Wget's behavior
836    through command-line switches.  Since COM is hard-coded in main(),
837    it is not canonicalized, and this aborts when COM is not found.
838
839    If COMIND's are exported to init.h, this function will be changed
840    to accept COMIND directly.  */
841
842 void
843 setoptval (const char *com, const char *val, const char *optname)
844 {
845   /* Prepend "--" to OPTNAME. */
846   char *dd_optname = (char *) alloca (2 + strlen (optname) + 1);
847   dd_optname[0] = '-';
848   dd_optname[1] = '-';
849   strcpy (dd_optname + 2, optname);
850
851   assert (val != NULL);
852   if (!setval_internal (command_by_name (com), dd_optname, val))
853     exit (2);
854 }
855
856 /* Parse OPT into command and value and run it.  For example,
857    run_command("foo=bar") is equivalent to setoptval("foo", "bar").
858    This is used by the `--execute' flag in main.c.  */
859
860 void
861 run_command (const char *opt)
862 {
863   char *com, *val;
864   int comind;
865   switch (parse_line (opt, &com, &val, &comind))
866     {
867     case line_ok:
868       if (!setval_internal (comind, com, val))
869         exit (2);
870       xfree (com);
871       xfree (val);
872       break;
873     default:
874       fprintf (stderr, _("%s: Invalid --execute command %s\n"),
875                exec_name, quote (opt));
876       exit (2);
877     }
878 }
879 \f
880 /* Generic helper functions, for use with `commands'. */
881
882 /* Forward declarations: */
883 struct decode_item {
884   const char *name;
885   int code;
886 };
887 static bool decode_string (const char *, const struct decode_item *, int, int *);
888 static bool simple_atoi (const char *, const char *, int *);
889 static bool simple_atof (const char *, const char *, double *);
890
891 #define CMP1(p, c0) (c_tolower((p)[0]) == (c0) && (p)[1] == '\0')
892
893 #define CMP2(p, c0, c1) (c_tolower((p)[0]) == (c0)        \
894                          && c_tolower((p)[1]) == (c1)     \
895                          && (p)[2] == '\0')
896
897 #define CMP3(p, c0, c1, c2) (c_tolower((p)[0]) == (c0)    \
898                      && c_tolower((p)[1]) == (c1)         \
899                      && c_tolower((p)[2]) == (c2)         \
900                      && (p)[3] == '\0')
901
902
903 /* Store the boolean value from VAL to PLACE.  COM is ignored,
904    except for error messages.  */
905 static bool
906 cmd_boolean (const char *com, const char *val, void *place)
907 {
908   bool value;
909
910   if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
911     /* "on", "yes" and "1" mean true. */
912     value = true;
913   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
914     /* "off", "no" and "0" mean false. */
915     value = false;
916   else
917     {
918       fprintf (stderr,
919                _("%s: %s: Invalid boolean %s; use `on' or `off'.\n"),
920                exec_name, com, quote (val));
921       return false;
922     }
923
924   *(bool *) place = value;
925   return true;
926 }
927
928 /* Set the non-negative integer value from VAL to PLACE.  With
929    incorrect specification, the number remains unchanged.  */
930 static bool
931 cmd_number (const char *com, const char *val, void *place)
932 {
933   if (!simple_atoi (val, val + strlen (val), place)
934       || *(int *) place < 0)
935     {
936       fprintf (stderr, _("%s: %s: Invalid number %s.\n"),
937                exec_name, com, quote (val));
938       return false;
939     }
940   return true;
941 }
942
943 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
944 static bool
945 cmd_number_inf (const char *com, const char *val, void *place)
946 {
947   if (!strcasecmp (val, "inf"))
948     {
949       *(int *) place = 0;
950       return true;
951     }
952   return cmd_number (com, val, place);
953 }
954
955 /* Copy (strdup) the string at COM to a new location and place a
956    pointer to *PLACE.  */
957 static bool
958 cmd_string (const char *com, const char *val, void *place)
959 {
960   char **pstring = (char **)place;
961
962   xfree_null (*pstring);
963   *pstring = xstrdup (val);
964   return true;
965 }
966
967 /* Like cmd_string but ensure the string is upper case.  */
968 static bool
969 cmd_string_uppercase (const char *com, const char *val, void *place)
970 {
971   char *q, **pstring;
972   pstring = (char **)place;
973   xfree_null (*pstring);
974
975   *pstring = xmalloc (strlen (val) + 1);
976
977   for (q = *pstring; *val; val++, q++)
978     *q = c_toupper (*val);
979
980   *q = '\0';
981   return true;
982 }
983
984
985 /* Like cmd_string, but handles tilde-expansion when reading a user's
986    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
987    gets expanded to the user's home directory.  */
988 static bool
989 cmd_file (const char *com, const char *val, void *place)
990 {
991   char **pstring = (char **)place;
992
993   xfree_null (*pstring);
994
995   /* #### If VAL is empty, perhaps should set *PLACE to NULL.  */
996
997   *pstring = xstrdup (val);
998
999 #if defined(WINDOWS) || defined(MSDOS)
1000   /* Convert "\" to "/". */
1001   {
1002     char *s;
1003     for (s = *pstring; *s; s++)
1004       if (*s == '\\')
1005         *s = '/';
1006   }
1007 #endif
1008   return true;
1009 }
1010
1011 /* Like cmd_file, but strips trailing '/' characters.  */
1012 static bool
1013 cmd_directory (const char *com, const char *val, void *place)
1014 {
1015   char *s, *t;
1016
1017   /* Call cmd_file() for tilde expansion and separator
1018      canonicalization (backslash -> slash under Windows).  These
1019      things should perhaps be in a separate function.  */
1020   if (!cmd_file (com, val, place))
1021     return false;
1022
1023   s = *(char **)place;
1024   t = s + strlen (s);
1025   while (t > s && *--t == '/')
1026     *t = '\0';
1027
1028   return true;
1029 }
1030
1031 /* Split VAL by space to a vector of values, and append those values
1032    to vector pointed to by the PLACE argument.  If VAL is empty, the
1033    PLACE vector is cleared instead.  */
1034
1035 static bool
1036 cmd_vector (const char *com, const char *val, void *place)
1037 {
1038   char ***pvec = (char ***)place;
1039
1040   if (*val)
1041     *pvec = merge_vecs (*pvec, sepstring (val));
1042   else
1043     {
1044       free_vec (*pvec);
1045       *pvec = NULL;
1046     }
1047   return true;
1048 }
1049
1050 static bool
1051 cmd_directory_vector (const char *com, const char *val, void *place)
1052 {
1053   char ***pvec = (char ***)place;
1054
1055   if (*val)
1056     {
1057       /* Strip the trailing slashes from directories.  */
1058       char **t, **seps;
1059
1060       seps = sepstring (val);
1061       for (t = seps; t && *t; t++)
1062         {
1063           int len = strlen (*t);
1064           /* Skip degenerate case of root directory.  */
1065           if (len > 1)
1066             {
1067               if ((*t)[len - 1] == '/')
1068                 (*t)[len - 1] = '\0';
1069             }
1070         }
1071       *pvec = merge_vecs (*pvec, seps);
1072     }
1073   else
1074     {
1075       free_vec (*pvec);
1076       *pvec = NULL;
1077     }
1078   return true;
1079 }
1080
1081 /* Engine for cmd_bytes and cmd_bytes_sum: converts a string such as
1082    "100k" or "2.5G" to a floating point number.  */
1083
1084 static bool
1085 parse_bytes_helper (const char *val, double *result)
1086 {
1087   double number, mult;
1088   const char *end = val + strlen (val);
1089
1090   /* Check for "inf".  */
1091   if (0 == strcmp (val, "inf"))
1092     {
1093       *result = 0;
1094       return true;
1095     }
1096
1097   /* Strip trailing whitespace.  */
1098   while (val < end && c_isspace (end[-1]))
1099     --end;
1100   if (val == end)
1101     return false;
1102
1103   switch (c_tolower (end[-1]))
1104     {
1105     case 'k':
1106       --end, mult = 1024.0;
1107       break;
1108     case 'm':
1109       --end, mult = 1048576.0;
1110       break;
1111     case 'g':
1112       --end, mult = 1073741824.0;
1113       break;
1114     case 't':
1115       --end, mult = 1099511627776.0;
1116       break;
1117     default:
1118       /* Not a recognized suffix: assume it's a digit.  (If not,
1119          simple_atof will raise an error.)  */
1120       mult = 1;
1121     }
1122
1123   /* Skip leading and trailing whitespace. */
1124   while (val < end && c_isspace (*val))
1125     ++val;
1126   while (val < end && c_isspace (end[-1]))
1127     --end;
1128   if (val == end)
1129     return false;
1130
1131   if (!simple_atof (val, end, &number) || number < 0)
1132     return false;
1133
1134   *result = number * mult;
1135   return true;
1136 }
1137
1138 /* Parse VAL as a number and set its value to PLACE (which should
1139    point to a wgint).
1140
1141    By default, the value is assumed to be in bytes.  If "K", "M", or
1142    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
1143    1<<30, respectively.  Floating point values are allowed and are
1144    cast to integer before use.  The idea is to be able to use things
1145    like 1.5k instead of "1536".
1146
1147    The string "inf" is returned as 0.
1148
1149    In case of error, false is returned and memory pointed to by PLACE
1150    remains unmodified.  */
1151
1152 static bool
1153 cmd_bytes (const char *com, const char *val, void *place)
1154 {
1155   double byte_value;
1156   if (!parse_bytes_helper (val, &byte_value))
1157     {
1158       fprintf (stderr, _("%s: %s: Invalid byte value %s\n"),
1159                exec_name, com, quote (val));
1160       return false;
1161     }
1162   *(wgint *)place = (wgint)byte_value;
1163   return true;
1164 }
1165
1166 /* Like cmd_bytes, but PLACE is interpreted as a pointer to
1167    SIZE_SUM.  It works by converting the string to double, therefore
1168    working with values up to 2^53-1 without loss of precision.  This
1169    value (8192 TB) is large enough to serve for a while.  */
1170
1171 static bool
1172 cmd_bytes_sum (const char *com, const char *val, void *place)
1173 {
1174   double byte_value;
1175   if (!parse_bytes_helper (val, &byte_value))
1176     {
1177       fprintf (stderr, _("%s: %s: Invalid byte value %s\n"),
1178                exec_name, com, quote (val));
1179       return false;
1180     }
1181   *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
1182   return true;
1183 }
1184
1185 /* Store the value of VAL to *OUT.  The value is a time period, by
1186    default expressed in seconds, but also accepting suffixes "m", "h",
1187    "d", and "w" for minutes, hours, days, and weeks respectively.  */
1188
1189 static bool
1190 cmd_time (const char *com, const char *val, void *place)
1191 {
1192   double number, mult;
1193   const char *end = val + strlen (val);
1194
1195   /* Strip trailing whitespace.  */
1196   while (val < end && c_isspace (end[-1]))
1197     --end;
1198
1199   if (val == end)
1200     {
1201     err:
1202       fprintf (stderr, _("%s: %s: Invalid time period %s\n"),
1203                exec_name, com, quote (val));
1204       return false;
1205     }
1206
1207   switch (c_tolower (end[-1]))
1208     {
1209     case 's':
1210       --end, mult = 1;          /* seconds */
1211       break;
1212     case 'm':
1213       --end, mult = 60;         /* minutes */
1214       break;
1215     case 'h':
1216       --end, mult = 3600;       /* hours */
1217       break;
1218     case 'd':
1219       --end, mult = 86400.0;    /* days */
1220       break;
1221     case 'w':
1222       --end, mult = 604800.0;   /* weeks */
1223       break;
1224     default:
1225       /* Not a recognized suffix: assume it belongs to the number.
1226          (If not, simple_atof will raise an error.)  */
1227       mult = 1;
1228     }
1229
1230   /* Skip leading and trailing whitespace. */
1231   while (val < end && c_isspace (*val))
1232     ++val;
1233   while (val < end && c_isspace (end[-1]))
1234     --end;
1235   if (val == end)
1236     goto err;
1237
1238   if (!simple_atof (val, end, &number))
1239     goto err;
1240
1241   *(double *)place = number * mult;
1242   return true;
1243 }
1244
1245 #ifdef HAVE_SSL
1246 static bool
1247 cmd_cert_type (const char *com, const char *val, void *place)
1248 {
1249   static const struct decode_item choices[] = {
1250     { "pem", keyfile_pem },
1251     { "der", keyfile_asn1 },
1252     { "asn1", keyfile_asn1 },
1253   };
1254   int ok = decode_string (val, choices, countof (choices), place);
1255   if (!ok)
1256     fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
1257   return ok;
1258 }
1259 #endif
1260 \f
1261 /* Specialized helper functions, used by `commands' to handle some
1262    options specially.  */
1263
1264 static bool check_user_specified_header (const char *);
1265
1266 static bool
1267 cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
1268 {
1269   if (!cmd_boolean (com, val, &opt.dirstruct))
1270     return false;
1271   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1272      must be affected inversely.  */
1273   if (opt.dirstruct)
1274     opt.no_dirstruct = false;
1275   else
1276     opt.no_dirstruct = true;
1277   return true;
1278 }
1279
1280 static bool
1281 cmd_spec_header (const char *com, const char *val, void *place_ignored)
1282 {
1283   /* Empty value means reset the list of headers. */
1284   if (*val == '\0')
1285     {
1286       free_vec (opt.user_headers);
1287       opt.user_headers = NULL;
1288       return true;
1289     }
1290
1291   if (!check_user_specified_header (val))
1292     {
1293       fprintf (stderr, _("%s: %s: Invalid header %s.\n"),
1294                exec_name, com, quote (val));
1295       return false;
1296     }
1297   opt.user_headers = vec_append (opt.user_headers, val);
1298   return true;
1299 }
1300
1301 static bool
1302 cmd_spec_warc_header (const char *com, const char *val, void *place_ignored)
1303 {
1304   /* Empty value means reset the list of headers. */
1305   if (*val == '\0')
1306     {
1307       free_vec (opt.warc_user_headers);
1308       opt.warc_user_headers = NULL;
1309       return true;
1310     }
1311
1312   if (!check_user_specified_header (val))
1313     {
1314       fprintf (stderr, _("%s: %s: Invalid WARC header %s.\n"),
1315                exec_name, com, quote (val));
1316       return false;
1317     }
1318   opt.warc_user_headers = vec_append (opt.warc_user_headers, val);
1319   return true;
1320 }
1321
1322 static bool
1323 cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
1324 {
1325   int flag = cmd_boolean (com, val, &opt.htmlify);
1326   if (flag && !opt.htmlify)
1327     opt.remove_listing = false;
1328   return flag;
1329 }
1330
1331 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1332    no limit on max. recursion depth, and don't remove listings.  */
1333
1334 static bool
1335 cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
1336 {
1337   int mirror;
1338
1339   if (!cmd_boolean (com, val, &mirror))
1340     return false;
1341   if (mirror)
1342     {
1343       opt.recursive = true;
1344       if (!opt.no_dirstruct)
1345         opt.dirstruct = true;
1346       opt.timestamping = true;
1347       opt.reclevel = INFINITE_RECURSION;
1348       opt.remove_listing = false;
1349     }
1350   return true;
1351 }
1352
1353 /* Validate --prefer-family and set the choice.  Allowed values are
1354    "IPv4", "IPv6", and "none".  */
1355
1356 static bool
1357 cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
1358 {
1359   static const struct decode_item choices[] = {
1360     { "IPv4", prefer_ipv4 },
1361     { "IPv6", prefer_ipv6 },
1362     { "none", prefer_none },
1363   };
1364   int prefer_family = prefer_none;
1365   int ok = decode_string (val, choices, countof (choices), &prefer_family);
1366   if (!ok)
1367     fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
1368   opt.prefer_family = prefer_family;
1369   return ok;
1370 }
1371
1372 /* Set progress.type to VAL, but verify that it's a valid progress
1373    implementation before that.  */
1374
1375 static bool
1376 cmd_spec_progress (const char *com, const char *val, void *place_ignored)
1377 {
1378   if (!valid_progress_implementation_p (val))
1379     {
1380       fprintf (stderr, _("%s: %s: Invalid progress type %s.\n"),
1381                exec_name, com, quote (val));
1382       return false;
1383     }
1384   xfree_null (opt.progress_type);
1385
1386   /* Don't call set_progress_implementation here.  It will be called
1387      in main() when it becomes clear what the log output is.  */
1388   opt.progress_type = xstrdup (val);
1389   return true;
1390 }
1391
1392 /* Set opt.recursive to VAL as with cmd_boolean.  If opt.recursive is
1393    set to true, also set opt.dirstruct to true, unless opt.no_dirstruct
1394    is specified.  */
1395
1396 static bool
1397 cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
1398 {
1399   if (!cmd_boolean (com, val, &opt.recursive))
1400     return false;
1401   else
1402     {
1403       if (opt.recursive && !opt.no_dirstruct)
1404         opt.dirstruct = true;
1405     }
1406   return true;
1407 }
1408
1409 /* Validate --regex-type and set the choice.  */
1410
1411 static bool
1412 cmd_spec_regex_type (const char *com, const char *val, void *place_ignored)
1413 {
1414   static const struct decode_item choices[] = {
1415     { "posix", regex_type_posix },
1416 #ifdef HAVE_LIBPCRE
1417     { "pcre",  regex_type_pcre },
1418 #endif
1419   };
1420   int regex_type = regex_type_posix;
1421   int ok = decode_string (val, choices, countof (choices), &regex_type);
1422   if (!ok)
1423     fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
1424   opt.regex_type = regex_type;
1425   return ok;
1426 }
1427
1428 static bool
1429 cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
1430 {
1431   int restrict_os = opt.restrict_files_os;
1432   int restrict_ctrl = opt.restrict_files_ctrl;
1433   int restrict_case = opt.restrict_files_case;
1434   int restrict_nonascii = opt.restrict_files_nonascii;
1435
1436   const char *end;
1437
1438 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1439
1440   do
1441     {
1442       end = strchr (val, ',');
1443       if (!end)
1444         end = val + strlen (val);
1445
1446       if (VAL_IS ("unix"))
1447         restrict_os = restrict_unix;
1448       else if (VAL_IS ("windows"))
1449         restrict_os = restrict_windows;
1450       else if (VAL_IS ("lowercase"))
1451         restrict_case = restrict_lowercase;
1452       else if (VAL_IS ("uppercase"))
1453         restrict_case = restrict_uppercase;
1454       else if (VAL_IS ("nocontrol"))
1455         restrict_ctrl = false;
1456       else if (VAL_IS ("ascii"))
1457         restrict_nonascii = true;
1458       else
1459         {
1460           fprintf (stderr, _("\
1461 %s: %s: Invalid restriction %s,\n\
1462     use [unix|windows],[lowercase|uppercase],[nocontrol],[ascii].\n"),
1463                    exec_name, com, quote (val));
1464           return false;
1465         }
1466
1467       if (*end)
1468         val = end + 1;
1469     }
1470   while (*val && *end);
1471
1472 #undef VAL_IS
1473
1474   opt.restrict_files_os = restrict_os;
1475   opt.restrict_files_ctrl = restrict_ctrl;
1476   opt.restrict_files_case = restrict_case;
1477   opt.restrict_files_nonascii = restrict_nonascii;
1478
1479   return true;
1480 }
1481
1482 static bool
1483 cmd_spec_report_speed (const char *com, const char *val, void *place_ignored)
1484 {
1485   opt.report_bps = strcasecmp (val, "bits") == 0;
1486   if (!opt.report_bps)
1487     fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
1488   return opt.report_bps;
1489 }
1490
1491 #ifdef HAVE_SSL
1492 static bool
1493 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
1494 {
1495   static const struct decode_item choices[] = {
1496     { "auto", secure_protocol_auto },
1497     { "sslv2", secure_protocol_sslv2 },
1498     { "sslv3", secure_protocol_sslv3 },
1499     { "tlsv1", secure_protocol_tlsv1 },
1500   };
1501   int ok = decode_string (val, choices, countof (choices), place);
1502   if (!ok)
1503     fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
1504   return ok;
1505 }
1506 #endif
1507
1508 /* Set all three timeout values. */
1509
1510 static bool
1511 cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
1512 {
1513   double value;
1514   if (!cmd_time (com, val, &value))
1515     return false;
1516   opt.read_timeout = value;
1517   opt.connect_timeout = value;
1518   opt.dns_timeout = value;
1519   return true;
1520 }
1521
1522 static bool
1523 cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
1524 {
1525   /* Disallow embedded newlines.  */
1526   if (strchr (val, '\n'))
1527     {
1528       fprintf (stderr, _("%s: %s: Invalid value %s.\n"),
1529                exec_name, com, quote (val));
1530       return false;
1531     }
1532   xfree_null (opt.useragent);
1533   opt.useragent = xstrdup (val);
1534   return true;
1535 }
1536
1537 /* The "verbose" option cannot be cmd_boolean because the variable is
1538    not bool -- it's of type int (-1 means uninitialized because of
1539    some random hackery for disallowing -q -v).  */
1540
1541 static bool
1542 cmd_spec_verbose (const char *com, const char *val, void *place_ignored)
1543 {
1544   bool flag;
1545   if (cmd_boolean (com, val, &flag))
1546     {
1547       opt.verbose = flag;
1548       return true;
1549     }
1550   return false;
1551 }
1552 \f
1553 /* Miscellaneous useful routines.  */
1554
1555 /* A very simple atoi clone, more useful than atoi because it works on
1556    delimited strings, and has error reportage.  Returns true on success,
1557    false on failure.  If successful, stores result to *DEST.  */
1558
1559 static bool
1560 simple_atoi (const char *beg, const char *end, int *dest)
1561 {
1562   int result = 0;
1563   bool negative = false;
1564   const char *p = beg;
1565
1566   while (p < end && c_isspace (*p))
1567     ++p;
1568   if (p < end && (*p == '-' || *p == '+'))
1569     {
1570       negative = (*p == '-');
1571       ++p;
1572     }
1573   if (p == end)
1574     return false;
1575
1576   /* Read negative numbers in a separate loop because the most
1577      negative integer cannot be represented as a positive number.  */
1578
1579   if (!negative)
1580     for (; p < end && c_isdigit (*p); p++)
1581       {
1582         int next = (10 * result) + (*p - '0');
1583         if (next < result)
1584           return false;         /* overflow */
1585         result = next;
1586       }
1587   else
1588     for (; p < end && c_isdigit (*p); p++)
1589       {
1590         int next = (10 * result) - (*p - '0');
1591         if (next > result)
1592           return false;         /* underflow */
1593         result = next;
1594       }
1595
1596   if (p != end)
1597     return false;
1598
1599   *dest = result;
1600   return true;
1601 }
1602
1603 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1604    doesn't handle exponential notation.  Returns true on success,
1605    false on failure.  In case of success, stores its result to
1606    *DEST.  */
1607
1608 static bool
1609 simple_atof (const char *beg, const char *end, double *dest)
1610 {
1611   double result = 0;
1612
1613   bool negative = false;
1614   bool seen_dot = false;
1615   bool seen_digit = false;
1616   double divider = 1;
1617
1618   const char *p = beg;
1619
1620   while (p < end && c_isspace (*p))
1621     ++p;
1622   if (p < end && (*p == '-' || *p == '+'))
1623     {
1624       negative = (*p == '-');
1625       ++p;
1626     }
1627
1628   for (; p < end; p++)
1629     {
1630       char ch = *p;
1631       if (c_isdigit (ch))
1632         {
1633           if (!seen_dot)
1634             result = (10 * result) + (ch - '0');
1635           else
1636             result += (ch - '0') / (divider *= 10);
1637           seen_digit = true;
1638         }
1639       else if (ch == '.')
1640         {
1641           if (!seen_dot)
1642             seen_dot = true;
1643           else
1644             return false;
1645         }
1646       else
1647         return false;
1648     }
1649   if (!seen_digit)
1650     return false;
1651   if (negative)
1652     result = -result;
1653
1654   *dest = result;
1655   return true;
1656 }
1657
1658 /* Verify that the user-specified header in S is valid.  It must
1659    contain a colon preceded by non-white-space characters and must not
1660    contain newlines.  */
1661
1662 static bool
1663 check_user_specified_header (const char *s)
1664 {
1665   const char *p;
1666
1667   for (p = s; *p && *p != ':' && !c_isspace (*p); p++)
1668     ;
1669   /* The header MUST contain `:' preceded by at least one
1670      non-whitespace character.  */
1671   if (*p != ':' || p == s)
1672     return false;
1673   /* The header MUST NOT contain newlines.  */
1674   if (strchr (s, '\n'))
1675     return false;
1676   return true;
1677 }
1678
1679 /* Decode VAL into a number, according to ITEMS. */
1680
1681 static bool
1682 decode_string (const char *val, const struct decode_item *items, int itemcount,
1683                int *place)
1684 {
1685   int i;
1686   for (i = 0; i < itemcount; i++)
1687     if (0 == strcasecmp (val, items[i].name))
1688       {
1689         *place = items[i].code;
1690         return true;
1691       }
1692   return false;
1693 }
1694
1695 \f
1696 void cleanup_html_url (void);
1697 void spider_cleanup (void);
1698
1699
1700 /* Free the memory allocated by global variables.  */
1701 void
1702 cleanup (void)
1703 {
1704   /* Free external resources, close files, etc. */
1705
1706   /* Close WARC file. */
1707   if (opt.warc_filename != 0)
1708     warc_close ();
1709
1710   log_close ();
1711
1712   if (output_stream)
1713     if (fclose (output_stream) == EOF)
1714       inform_exit_status (CLOSEFAILED);
1715
1716   /* No need to check for error because Wget flushes its output (and
1717      checks for errors) after any data arrives.  */
1718
1719   /* We're exiting anyway so there's no real need to call free()
1720      hundreds of times.  Skipping the frees will make Wget exit
1721      faster.
1722
1723      However, when detecting leaks, it's crucial to free() everything
1724      because then you can find the real leaks, i.e. the allocated
1725      memory which grows with the size of the program.  */
1726
1727 #ifdef DEBUG_MALLOC
1728   convert_cleanup ();
1729   res_cleanup ();
1730   http_cleanup ();
1731   cleanup_html_url ();
1732   spider_cleanup ();
1733   host_cleanup ();
1734   log_cleanup ();
1735
1736   for (i = 0; i < nurl; i++)
1737     xfree (url[i]);
1738
1739   {
1740     extern acc_t *netrc_list;
1741     free_netrc (netrc_list);
1742   }
1743   xfree_null (opt.choose_config);
1744   xfree_null (opt.lfilename);
1745   xfree_null (opt.dir_prefix);
1746   xfree_null (opt.input_filename);
1747   xfree_null (opt.output_document);
1748   free_vec (opt.accepts);
1749   free_vec (opt.rejects);
1750   free_vec (opt.excludes);
1751   free_vec (opt.includes);
1752   free_vec (opt.domains);
1753   free_vec (opt.follow_tags);
1754   free_vec (opt.ignore_tags);
1755   xfree_null (opt.progress_type);
1756   xfree_null (opt.ftp_user);
1757   xfree_null (opt.ftp_passwd);
1758   xfree_null (opt.ftp_proxy);
1759   xfree_null (opt.https_proxy);
1760   xfree_null (opt.http_proxy);
1761   free_vec (opt.no_proxy);
1762   xfree_null (opt.useragent);
1763   xfree_null (opt.referer);
1764   xfree_null (opt.http_user);
1765   xfree_null (opt.http_passwd);
1766   free_vec (opt.user_headers);
1767   free_vec (opt.warc_user_headers);
1768 # ifdef HAVE_SSL
1769   xfree_null (opt.cert_file);
1770   xfree_null (opt.private_key);
1771   xfree_null (opt.ca_directory);
1772   xfree_null (opt.ca_cert);
1773   xfree_null (opt.random_file);
1774   xfree_null (opt.egd_file);
1775 # endif
1776   xfree_null (opt.bind_address);
1777   xfree_null (opt.cookies_input);
1778   xfree_null (opt.cookies_output);
1779   xfree_null (opt.user);
1780   xfree_null (opt.passwd);
1781   xfree_null (opt.base_href);
1782   xfree_null (opt.method);
1783
1784 #endif /* DEBUG_MALLOC */
1785 }
1786 \f
1787 /* Unit testing routines.  */
1788
1789 #ifdef TESTING
1790
1791 const char *
1792 test_commands_sorted()
1793 {
1794   int prev_idx = 0, next_idx = 1;
1795   int command_count = countof (commands) - 1;
1796   int cmp = 0;
1797   while (next_idx <= command_count)
1798     {
1799       cmp = strcasecmp (commands[prev_idx].name, commands[next_idx].name);
1800       if (cmp > 0)
1801         {
1802           mu_assert ("FAILED", false);
1803           break;
1804         }
1805       else
1806         {
1807           prev_idx ++;
1808           next_idx ++;
1809         }
1810     }
1811   return NULL;
1812 }
1813
1814 const char *
1815 test_cmd_spec_restrict_file_names()
1816 {
1817   int i;
1818   struct {
1819     char *val;
1820     int expected_restrict_files_os;
1821     int expected_restrict_files_ctrl;
1822     int expected_restrict_files_case;
1823     bool result;
1824   } test_array[] = {
1825     { "windows", restrict_windows, true, restrict_no_case_restriction, true },
1826     { "windows,", restrict_windows, true, restrict_no_case_restriction, true },
1827     { "windows,lowercase", restrict_windows, true, restrict_lowercase, true },
1828     { "unix,nocontrol,lowercase,", restrict_unix, false, restrict_lowercase, true },
1829   };
1830
1831   for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
1832     {
1833       bool res;
1834
1835       defaults();
1836       res = cmd_spec_restrict_file_names ("dummy", test_array[i].val, NULL);
1837
1838       /*
1839       fprintf (stderr, "test_cmd_spec_restrict_file_names: TEST %d\n", i); fflush (stderr);
1840       fprintf (stderr, "opt.restrict_files_os: %d\n",   opt.restrict_files_os); fflush (stderr);
1841       fprintf (stderr, "opt.restrict_files_ctrl: %d\n", opt.restrict_files_ctrl); fflush (stderr);
1842       fprintf (stderr, "opt.restrict_files_case: %d\n", opt.restrict_files_case); fflush (stderr);
1843       */
1844       mu_assert ("test_cmd_spec_restrict_file_names: wrong result",
1845                  res == test_array[i].result
1846                  && opt.restrict_files_os   == test_array[i].expected_restrict_files_os
1847                  && opt.restrict_files_ctrl == test_array[i].expected_restrict_files_ctrl
1848                  && opt.restrict_files_case == test_array[i].expected_restrict_files_case);
1849     }
1850
1851   return NULL;
1852 }
1853
1854 #endif /* TESTING */
1855