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