]> sjero.net Git - wget/blob - src/init.c
[svn] Report exact command name alongside the "display name".
[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   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
163   { "ftpuser",          &opt.ftp_user,          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 (%s) to %s\n", com, commands[comind].name, 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   switch (parse_line (opt, &com, &val, &comind))
653     {
654     case line_ok:
655       if (!setval_internal (comind, com, val))
656         exit (2);
657       xfree (com);
658       xfree (val);
659       break;
660     default:
661       fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
662                exec_name, opt);
663       exit (2);
664     }
665 }
666 \f
667 /* Generic helper functions, for use with `commands'. */
668
669 /* Forward declarations: */
670 struct decode_item {
671   const char *name;
672   int code;
673 };
674 static int decode_string PARAMS ((const char *, const struct decode_item *,
675                                   int, int *));
676 static int simple_atoi PARAMS ((const char *, const char *, int *));
677 static int simple_atof PARAMS ((const char *, const char *, double *));
678
679 #define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
680
681 #define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0)        \
682                          && TOLOWER((p)[1]) == (c1)     \
683                          && (p)[2] == '\0')
684
685 #define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0)    \
686                      && TOLOWER((p)[1]) == (c1)         \
687                      && TOLOWER((p)[2]) == (c2)         \
688                      && (p)[3] == '\0')
689
690
691 /* Store the boolean value from VAL to PLACE.  COM is ignored,
692    except for error messages.  */
693 static int
694 cmd_boolean (const char *com, const char *val, void *place)
695 {
696   int bool_value;
697
698   if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
699     /* "on", "yes" and "1" mean true. */
700     bool_value = 1;
701   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
702     /* "off", "no" and "0" mean false. */
703     bool_value = 0;
704   else
705     {
706       fprintf (stderr,
707                _("%s: %s: Invalid boolean `%s', use `on' or `off'.\n"),
708                exec_name, com, val);
709       return 0;
710     }
711
712   *(int *)place = bool_value;
713   return 1;
714 }
715
716 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to PLACE.
717    COM is ignored, except for error messages.  Values 2 and -1
718    indicate that once defined, the value may not be changed by
719    successive wgetrc files or command-line arguments.
720
721    Values: 2 - Enable a particular option for good ("always")
722            1 - Enable an option ("on")
723            0 - Disable an option ("off")
724           -1 - Disable an option for good ("never") */
725 static int
726 cmd_lockable_boolean (const char *com, const char *val, void *place)
727 {
728   int lockable_boolean_value;
729
730   int oldval = *(int *)place;
731
732   /*
733    * If a config file said "always" or "never", don't allow command line
734    * arguments to override the config file.
735    */
736   if (oldval == -1 || oldval == 2)
737     return 1;
738
739   if (0 == strcasecmp (val, "always") || CMP1 (val, '2'))
740     lockable_boolean_value = 2;
741   else if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
742     lockable_boolean_value = 1;
743   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
744     lockable_boolean_value = 0;
745   else if (0 == strcasecmp (val, "never") || CMP2 (val, '-', '1'))
746     lockable_boolean_value = -1;
747   else
748     {
749       fprintf (stderr,
750                _("%s: %s: Invalid boolean `%s', use always, on, off, or never.\n"),
751                exec_name, com, val);
752       return 0;
753     }
754
755   *(int *)place = lockable_boolean_value;
756   return 1;
757 }
758
759 /* Set the non-negative integer value from VAL to PLACE.  With
760    incorrect specification, the number remains unchanged.  */
761 static int
762 cmd_number (const char *com, const char *val, void *place)
763 {
764   if (!simple_atoi (val, val + strlen (val), place)
765       || *(int *) place < 0)
766     {
767       fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
768                exec_name, com, val);
769       return 0;
770     }
771   return 1;
772 }
773
774 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
775 static int
776 cmd_number_inf (const char *com, const char *val, void *place)
777 {
778   if (!strcasecmp (val, "inf"))
779     {
780       *(int *)place = 0;
781       return 1;
782     }
783   return cmd_number (com, val, place);
784 }
785
786 /* Copy (strdup) the string at COM to a new location and place a
787    pointer to *PLACE.  */
788 static int
789 cmd_string (const char *com, const char *val, void *place)
790 {
791   char **pstring = (char **)place;
792
793   xfree_null (*pstring);
794   *pstring = xstrdup (val);
795   return 1;
796 }
797
798 #ifndef WINDOWS
799 # define ISSEP(c) ((c) == '/')
800 #else
801 # define ISSEP(c) ((c) == '/' || (c) == '\\')
802 #endif
803
804 /* Like the above, but handles tilde-expansion when reading a user's
805    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
806    gets expanded to the user's home directory.  */
807 static int
808 cmd_file (const char *com, const char *val, void *place)
809 {
810   char **pstring = (char **)place;
811
812   xfree_null (*pstring);
813
814   /* #### If VAL is empty, perhaps should set *PLACE to NULL.  */
815
816   if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
817     {
818     noexpand:
819       *pstring = xstrdup (val);
820     }
821   else
822     {
823       int homelen;
824       char *home = home_dir ();
825       if (!home)
826         goto noexpand;
827
828       homelen = strlen (home);
829       while (homelen && ISSEP (home[homelen - 1]))
830         home[--homelen] = '\0';
831
832       /* Skip the leading "~/". */
833       for (++val; ISSEP (*val); val++)
834         ;
835
836       *pstring = concat_strings (home, "/", val, (char *) 0);
837     }
838
839 #ifdef WINDOWS
840   /* Convert "\" to "/". */
841   {
842     char *s;
843     for (s = *pstring; *s; s++)
844       if (*s == '\\')
845         *s = '/';
846   }
847 #endif
848   return 1;
849 }
850
851 /* Like cmd_file, but strips trailing '/' characters.  */
852 static int
853 cmd_directory (const char *com, const char *val, void *place)
854 {
855   char *s, *t;
856
857   /* Call cmd_file() for tilde expansion and separator
858      canonicalization (backslash -> slash under Windows).  These
859      things should perhaps be in a separate function.  */
860   if (!cmd_file (com, val, place))
861     return 0;
862
863   s = *(char **)place;
864   t = s + strlen (s);
865   while (t > s && *--t == '/')
866     *t = '\0';
867
868   return 1;
869 }
870
871 /* Split VAL by space to a vector of values, and append those values
872    to vector pointed to by the PLACE argument.  If VAL is empty, the
873    PLACE vector is cleared instead.  */
874
875 static int
876 cmd_vector (const char *com, const char *val, void *place)
877 {
878   char ***pvec = (char ***)place;
879
880   if (*val)
881     *pvec = merge_vecs (*pvec, sepstring (val));
882   else
883     {
884       free_vec (*pvec);
885       *pvec = NULL;
886     }
887   return 1;
888 }
889
890 static int
891 cmd_directory_vector (const char *com, const char *val, void *place)
892 {
893   char ***pvec = (char ***)place;
894
895   if (*val)
896     {
897       /* Strip the trailing slashes from directories.  */
898       char **t, **seps;
899
900       seps = sepstring (val);
901       for (t = seps; t && *t; t++)
902         {
903           int len = strlen (*t);
904           /* Skip degenerate case of root directory.  */
905           if (len > 1)
906             {
907               if ((*t)[len - 1] == '/')
908                 (*t)[len - 1] = '\0';
909             }
910         }
911       *pvec = merge_vecs (*pvec, seps);
912     }
913   else
914     {
915       free_vec (*pvec);
916       *pvec = NULL;
917     }
918   return 1;
919 }
920
921 /* Engine for cmd_bytes and cmd_bytes_large: converts a string such as
922    "100k" or "2.5G" to a floating point number.  */
923
924 static int
925 parse_bytes_helper (const char *val, double *result)
926 {
927   double number, mult;
928   const char *end = val + strlen (val);
929
930   /* Check for "inf".  */
931   if (0 == strcmp (val, "inf"))
932     {
933       *result = 0;
934       return 1;
935     }
936
937   /* Strip trailing whitespace.  */
938   while (val < end && ISSPACE (end[-1]))
939     --end;
940   if (val == end)
941     return 0;
942
943   switch (TOLOWER (end[-1]))
944     {
945     case 'k':
946       --end, mult = 1024.0;
947       break;
948     case 'm':
949       --end, mult = 1048576.0;
950       break;
951     case 'g':
952       --end, mult = 1073741824.0;
953       break;
954     case 't':
955       --end, mult = 1099511627776.0;
956       break;
957     default:
958       /* Not a recognized suffix: assume it's a digit.  (If not,
959          simple_atof will raise an error.)  */
960       mult = 1;
961     }
962
963   /* Skip leading and trailing whitespace. */
964   while (val < end && ISSPACE (*val))
965     ++val;
966   while (val < end && ISSPACE (end[-1]))
967     --end;
968   if (val == end)
969     return 0;
970
971   if (!simple_atof (val, end, &number) || number < 0)
972     return 0;
973
974   *result = number * mult;
975   return 1;
976 }
977
978 /* Parse VAL as a number and set its value to PLACE (which should
979    point to a wgint).
980
981    By default, the value is assumed to be in bytes.  If "K", "M", or
982    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
983    1<<30, respectively.  Floating point values are allowed and are
984    cast to integer before use.  The idea is to be able to use things
985    like 1.5k instead of "1536".
986
987    The string "inf" is returned as 0.
988
989    In case of error, 0 is returned and memory pointed to by PLACE
990    remains unmodified.  */
991
992 static int
993 cmd_bytes (const char *com, const char *val, void *place)
994 {
995   double byte_value;
996   if (!parse_bytes_helper (val, &byte_value))
997     {
998       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
999                exec_name, com, val);
1000       return 0;
1001     }
1002   *(wgint *)place = (wgint)byte_value;
1003   return 1;
1004 }
1005
1006 /* Like cmd_bytes, but PLACE is interpreted as a pointer to
1007    LARGE_INT.  It works by converting the string to double, therefore
1008    working with values up to 2^53-1 without loss of precision.  This
1009    value (8192 TB) is large enough to serve for a while.  */
1010
1011 static int
1012 cmd_bytes_large (const char *com, const char *val, void *place)
1013 {
1014   double byte_value;
1015   if (!parse_bytes_helper (val, &byte_value))
1016     {
1017       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
1018                exec_name, com, val);
1019       return 0;
1020     }
1021   *(LARGE_INT *)place = (LARGE_INT)byte_value;
1022   return 1;
1023 }
1024
1025 /* Store the value of VAL to *OUT.  The value is a time period, by
1026    default expressed in seconds, but also accepting suffixes "m", "h",
1027    "d", and "w" for minutes, hours, days, and weeks respectively.  */
1028
1029 static int
1030 cmd_time (const char *com, const char *val, void *place)
1031 {
1032   double number, mult;
1033   const char *end = val + strlen (val);
1034
1035   /* Strip trailing whitespace.  */
1036   while (val < end && ISSPACE (end[-1]))
1037     --end;
1038
1039   if (val == end)
1040     {
1041     err:
1042       fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
1043                exec_name, com, val);
1044       return 0;
1045     }
1046
1047   switch (TOLOWER (end[-1]))
1048     {
1049     case 's':
1050       --end, mult = 1;          /* seconds */
1051       break;
1052     case 'm':
1053       --end, mult = 60;         /* minutes */
1054       break;
1055     case 'h':
1056       --end, mult = 3600;       /* hours */
1057       break;
1058     case 'd':
1059       --end, mult = 86400.0;    /* days */
1060       break;
1061     case 'w':
1062       --end, mult = 604800.0;   /* weeks */
1063       break;
1064     default:
1065       /* Not a recognized suffix: assume it belongs to the number.
1066          (If not, simple_atof will raise an error.)  */
1067       mult = 1;
1068     }
1069
1070   /* Skip leading and trailing whitespace. */
1071   while (val < end && ISSPACE (*val))
1072     ++val;
1073   while (val < end && ISSPACE (end[-1]))
1074     --end;
1075   if (val == end)
1076     goto err;
1077
1078   if (!simple_atof (val, end, &number))
1079     goto err;
1080
1081   *(double *)place = number * mult;
1082   return 1;
1083 }
1084
1085 #ifdef HAVE_SSL
1086 static int
1087 cmd_cert_type (const char *com, const char *val, void *place)
1088 {
1089   static const struct decode_item choices[] = {
1090     { "pem", keyfile_pem },
1091     { "der", keyfile_asn1 },
1092     { "asn1", keyfile_asn1 },
1093   };
1094   int ok = decode_string (val, choices, countof (choices), place);
1095   if (!ok)
1096     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1097   return ok;
1098 }
1099 #endif
1100 \f
1101 /* Specialized helper functions, used by `commands' to handle some
1102    options specially.  */
1103
1104 static int check_user_specified_header PARAMS ((const char *));
1105
1106 static int
1107 cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
1108 {
1109   if (!cmd_boolean (com, val, &opt.dirstruct))
1110     return 0;
1111   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1112      must be affected inversely.  */
1113   if (opt.dirstruct)
1114     opt.no_dirstruct = 0;
1115   else
1116     opt.no_dirstruct = 1;
1117   return 1;
1118 }
1119
1120 static int
1121 cmd_spec_header (const char *com, const char *val, void *place)
1122 {
1123   if (!check_user_specified_header (val))
1124     {
1125       fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1126                exec_name, com, val);
1127       return 0;
1128     }
1129   return cmd_vector (com, val, place);
1130 }
1131
1132 static int
1133 cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
1134 {
1135   int flag = cmd_boolean (com, val, &opt.htmlify);
1136   if (flag && !opt.htmlify)
1137     opt.remove_listing = 0;
1138   return flag;
1139 }
1140
1141 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1142    no limit on max. recursion depth, and don't remove listings.  */
1143
1144 static int
1145 cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
1146 {
1147   int mirror;
1148
1149   if (!cmd_boolean (com, val, &mirror))
1150     return 0;
1151   if (mirror)
1152     {
1153       opt.recursive = 1;
1154       if (!opt.no_dirstruct)
1155         opt.dirstruct = 1;
1156       opt.timestamping = 1;
1157       opt.reclevel = INFINITE_RECURSION;
1158       opt.remove_listing = 0;
1159     }
1160   return 1;
1161 }
1162
1163 /* Validate --prefer-family and set the choice.  Allowed values are
1164    "IPv4", "IPv6", and "none".  */
1165
1166 static int
1167 cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
1168 {
1169   static const struct decode_item choices[] = {
1170     { "IPv4", prefer_ipv4 },
1171     { "IPv6", prefer_ipv6 },
1172     { "none", prefer_none },
1173   };
1174   int ok = decode_string (val, choices, countof (choices),
1175                           (int *) &opt.prefer_family);
1176   if (!ok)
1177     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1178   return ok;
1179 }
1180
1181 /* Set progress.type to VAL, but verify that it's a valid progress
1182    implementation before that.  */
1183
1184 static int
1185 cmd_spec_progress (const char *com, const char *val, void *place_ignored)
1186 {
1187   if (!valid_progress_implementation_p (val))
1188     {
1189       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1190                exec_name, com, val);
1191       return 0;
1192     }
1193   xfree_null (opt.progress_type);
1194
1195   /* Don't call set_progress_implementation here.  It will be called
1196      in main() when it becomes clear what the log output is.  */
1197   opt.progress_type = xstrdup (val);
1198   return 1;
1199 }
1200
1201 /* Set opt.recursive to VAL as with cmd_boolean.  If opt.recursive is
1202    set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct
1203    is specified.  */
1204
1205 static int
1206 cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
1207 {
1208   if (!cmd_boolean (com, val, &opt.recursive))
1209     return 0;
1210   else
1211     {
1212       if (opt.recursive && !opt.no_dirstruct)
1213         opt.dirstruct = 1;
1214     }
1215   return 1;
1216 }
1217
1218 static int
1219 cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
1220 {
1221   int restrict_os = opt.restrict_files_os;
1222   int restrict_ctrl = opt.restrict_files_ctrl;
1223
1224   const char *end = strchr (val, ',');
1225   if (!end)
1226     end = val + strlen (val);
1227
1228 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1229
1230   if (VAL_IS ("unix"))
1231     restrict_os = restrict_unix;
1232   else if (VAL_IS ("windows"))
1233     restrict_os = restrict_windows;
1234   else if (VAL_IS ("nocontrol"))
1235     restrict_ctrl = 0;
1236   else
1237     {
1238     err:
1239       fprintf (stderr,
1240                _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
1241                exec_name, com, val);
1242       return 0;
1243     }
1244
1245 #undef VAL_IS
1246
1247   if (*end)
1248     {
1249       if (!strcmp (end + 1, "nocontrol"))
1250         restrict_ctrl = 0;
1251       else
1252         goto err;
1253     }
1254
1255   opt.restrict_files_os = restrict_os;
1256   opt.restrict_files_ctrl = restrict_ctrl;
1257   return 1;
1258 }
1259
1260 #ifdef HAVE_SSL
1261 static int
1262 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
1263 {
1264   static const struct decode_item choices[] = {
1265     { "auto", secure_protocol_auto },
1266     { "sslv2", secure_protocol_sslv2 },
1267     { "sslv3", secure_protocol_sslv3 },
1268     { "tlsv1", secure_protocol_tlsv1 },
1269   };
1270   int ok = decode_string (val, choices, countof (choices), place);
1271   if (!ok)
1272     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1273   return ok;
1274 }
1275 #endif
1276
1277 /* Set all three timeout values. */
1278
1279 static int
1280 cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
1281 {
1282   double value;
1283   if (!cmd_time (com, val, &value))
1284     return 0;
1285   opt.read_timeout = value;
1286   opt.connect_timeout = value;
1287   opt.dns_timeout = value;
1288   return 1;
1289 }
1290
1291 static int
1292 cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
1293 {
1294   /* Disallow embedded newlines.  */
1295   if (strchr (val, '\n'))
1296     {
1297       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1298                exec_name, com, val);
1299       return 0;
1300     }
1301   xfree_null (opt.useragent);
1302   opt.useragent = xstrdup (val);
1303   return 1;
1304 }
1305 \f
1306 /* Miscellaneous useful routines.  */
1307
1308 /* A very simple atoi clone, more useful than atoi because it works on
1309    delimited strings, and has error reportage.  Returns 1 on success,
1310    0 on failure.  If successful, stores result to *DEST.  */
1311
1312 static int
1313 simple_atoi (const char *beg, const char *end, int *dest)
1314 {
1315   int result = 0;
1316   int negative = 0;
1317   const char *p = beg;
1318
1319   while (p < end && ISSPACE (*p))
1320     ++p;
1321   if (p < end && (*p == '-' || *p == '+'))
1322     {
1323       negative = (*p == '-');
1324       ++p;
1325     }
1326   if (p == end)
1327     return 0;
1328
1329   /* Read negative numbers in a separate loop because the most
1330      negative integer cannot be represented as a positive number.  */
1331
1332   if (!negative)
1333     for (; p < end && ISDIGIT (*p); p++)
1334       {
1335         int next = (10 * result) + (*p - '0');
1336         if (next < result)
1337           return 0;             /* overflow */
1338         result = next;
1339       }
1340   else
1341     for (; p < end && ISDIGIT (*p); p++)
1342       {
1343         int next = (10 * result) - (*p - '0');
1344         if (next > result)
1345           return 0;             /* underflow */
1346         result = next;
1347       }
1348
1349   if (p != end)
1350     return 0;
1351
1352   *dest = result;
1353   return 1;
1354 }
1355
1356 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1357    doesn't handle exponential notation.  Returns 1 on success, 0 on
1358    failure.  In case of success, stores its result to *DEST.  */
1359
1360 static int
1361 simple_atof (const char *beg, const char *end, double *dest)
1362 {
1363   double result = 0;
1364
1365   int negative = 0;
1366   int seen_dot = 0;
1367   int seen_digit = 0;
1368   double divider = 1;
1369
1370   const char *p = beg;
1371
1372   while (p < end && ISSPACE (*p))
1373     ++p;
1374   if (p < end && (*p == '-' || *p == '+'))
1375     {
1376       negative = (*p == '-');
1377       ++p;
1378     }
1379
1380   for (; p < end; p++)
1381     {
1382       char ch = *p;
1383       if (ISDIGIT (ch))
1384         {
1385           if (!seen_dot)
1386             result = (10 * result) + (ch - '0');
1387           else
1388             result += (ch - '0') / (divider *= 10);
1389           seen_digit = 1;
1390         }
1391       else if (ch == '.')
1392         {
1393           if (!seen_dot)
1394             seen_dot = 1;
1395           else
1396             return 0;
1397         }
1398       else
1399         return 0;
1400     }
1401   if (!seen_digit)
1402     return 0;
1403   if (negative)
1404     result = -result;
1405
1406   *dest = result;
1407   return 1;
1408 }
1409
1410 /* Verify that the user-specified header in S is valid.  It must
1411    contain a colon preceded by non-white-space characters and must not
1412    contain newlines.  */
1413
1414 static int
1415 check_user_specified_header (const char *s)
1416 {
1417   const char *p;
1418
1419   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1420   /* The header MUST contain `:' preceded by at least one
1421      non-whitespace character.  */
1422   if (*p != ':' || p == s)
1423     return 0;
1424   /* The header MUST NOT contain newlines.  */
1425   if (strchr (s, '\n'))
1426     return 0;
1427   return 1;
1428 }
1429
1430 /* Decode VAL into a number, according to ITEMS. */
1431
1432 static int
1433 decode_string (const char *val, const struct decode_item *items, int itemcount,
1434                int *place)
1435 {
1436   int i;
1437   for (i = 0; i < itemcount; i++)
1438     if (0 == strcasecmp (val, items[i].name))
1439       {
1440         *place = items[i].code;
1441         return 1;
1442       }
1443   return 0;
1444 }
1445
1446 \f
1447 void cleanup_html_url PARAMS ((void));
1448 void http_cleanup PARAMS ((void));
1449
1450
1451 /* Free the memory allocated by global variables.  */
1452 void
1453 cleanup (void)
1454 {
1455   /* Free external resources, close files, etc. */
1456
1457   {
1458     extern FILE *output_stream;
1459     if (output_stream)
1460       fclose (output_stream);
1461     /* No need to check for error because Wget flushes its output (and
1462        checks for errors) after any data arrives.  */
1463   }
1464
1465   /* We're exiting anyway so there's no real need to call free()
1466      hundreds of times.  Skipping the frees will make Wget exit
1467      faster.
1468
1469      However, when detecting leaks, it's crucial to free() everything
1470      because then you can find the real leaks, i.e. the allocated
1471      memory which grows with the size of the program.  */
1472
1473 #ifdef DEBUG_MALLOC
1474   convert_cleanup ();
1475   res_cleanup ();
1476   http_cleanup ();
1477   cleanup_html_url ();
1478   host_cleanup ();
1479   log_cleanup ();
1480
1481   {
1482     extern acc_t *netrc_list;
1483     free_netrc (netrc_list);
1484   }
1485   xfree_null (opt.lfilename);
1486   xfree_null (opt.dir_prefix);
1487   xfree_null (opt.input_filename);
1488   xfree_null (opt.output_document);
1489   free_vec (opt.accepts);
1490   free_vec (opt.rejects);
1491   free_vec (opt.excludes);
1492   free_vec (opt.includes);
1493   free_vec (opt.domains);
1494   free_vec (opt.follow_tags);
1495   free_vec (opt.ignore_tags);
1496   xfree_null (opt.progress_type);
1497   xfree_null (opt.ftp_user);
1498   xfree_null (opt.ftp_passwd);
1499   xfree_null (opt.ftp_proxy);
1500   xfree_null (opt.https_proxy);
1501   xfree_null (opt.http_proxy);
1502   free_vec (opt.no_proxy);
1503   xfree_null (opt.useragent);
1504   xfree_null (opt.referer);
1505   xfree_null (opt.http_user);
1506   xfree_null (opt.http_passwd);
1507   free_vec (opt.user_headers);
1508 # ifdef HAVE_SSL
1509   xfree_null (opt.cert_file);
1510   xfree_null (opt.private_key);
1511   xfree_null (opt.ca_directory);
1512   xfree_null (opt.ca_cert);
1513   xfree_null (opt.random_file);
1514   xfree_null (opt.egd_file);
1515 # endif
1516   xfree_null (opt.bind_address);
1517   xfree_null (opt.cookies_input);
1518   xfree_null (opt.cookies_output);
1519   xfree_null (opt.user);
1520   xfree_null (opt.passwd);
1521 #endif /* DEBUG_MALLOC */
1522 }