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