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