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