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