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