]> sjero.net Git - wget/blob - src/init.c
[svn] Allow --header to contain ",".
[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) 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",           NULL,                   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_ignored)
1122 {
1123   /* Empty value means reset the list of headers. */
1124   if (*val == '\0')
1125     {
1126       free_vec (opt.user_headers);
1127       opt.user_headers = NULL;
1128       return 1;
1129     }
1130
1131   if (!check_user_specified_header (val))
1132     {
1133       fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1134                exec_name, com, val);
1135       return 0;
1136     }
1137   opt.user_headers = vec_append (opt.user_headers, val);
1138   return 1;
1139 }
1140
1141 static int
1142 cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
1143 {
1144   int flag = cmd_boolean (com, val, &opt.htmlify);
1145   if (flag && !opt.htmlify)
1146     opt.remove_listing = 0;
1147   return flag;
1148 }
1149
1150 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1151    no limit on max. recursion depth, and don't remove listings.  */
1152
1153 static int
1154 cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
1155 {
1156   int mirror;
1157
1158   if (!cmd_boolean (com, val, &mirror))
1159     return 0;
1160   if (mirror)
1161     {
1162       opt.recursive = 1;
1163       if (!opt.no_dirstruct)
1164         opt.dirstruct = 1;
1165       opt.timestamping = 1;
1166       opt.reclevel = INFINITE_RECURSION;
1167       opt.remove_listing = 0;
1168     }
1169   return 1;
1170 }
1171
1172 /* Validate --prefer-family and set the choice.  Allowed values are
1173    "IPv4", "IPv6", and "none".  */
1174
1175 static int
1176 cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
1177 {
1178   static const struct decode_item choices[] = {
1179     { "IPv4", prefer_ipv4 },
1180     { "IPv6", prefer_ipv6 },
1181     { "none", prefer_none },
1182   };
1183   int ok = decode_string (val, choices, countof (choices),
1184                           (int *) &opt.prefer_family);
1185   if (!ok)
1186     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1187   return ok;
1188 }
1189
1190 /* Set progress.type to VAL, but verify that it's a valid progress
1191    implementation before that.  */
1192
1193 static int
1194 cmd_spec_progress (const char *com, const char *val, void *place_ignored)
1195 {
1196   if (!valid_progress_implementation_p (val))
1197     {
1198       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1199                exec_name, com, val);
1200       return 0;
1201     }
1202   xfree_null (opt.progress_type);
1203
1204   /* Don't call set_progress_implementation here.  It will be called
1205      in main() when it becomes clear what the log output is.  */
1206   opt.progress_type = xstrdup (val);
1207   return 1;
1208 }
1209
1210 /* Set opt.recursive to VAL as with cmd_boolean.  If opt.recursive is
1211    set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct
1212    is specified.  */
1213
1214 static int
1215 cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
1216 {
1217   if (!cmd_boolean (com, val, &opt.recursive))
1218     return 0;
1219   else
1220     {
1221       if (opt.recursive && !opt.no_dirstruct)
1222         opt.dirstruct = 1;
1223     }
1224   return 1;
1225 }
1226
1227 static int
1228 cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
1229 {
1230   int restrict_os = opt.restrict_files_os;
1231   int restrict_ctrl = opt.restrict_files_ctrl;
1232
1233   const char *end = strchr (val, ',');
1234   if (!end)
1235     end = val + strlen (val);
1236
1237 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1238
1239   if (VAL_IS ("unix"))
1240     restrict_os = restrict_unix;
1241   else if (VAL_IS ("windows"))
1242     restrict_os = restrict_windows;
1243   else if (VAL_IS ("nocontrol"))
1244     restrict_ctrl = 0;
1245   else
1246     {
1247     err:
1248       fprintf (stderr,
1249                _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
1250                exec_name, com, val);
1251       return 0;
1252     }
1253
1254 #undef VAL_IS
1255
1256   if (*end)
1257     {
1258       if (!strcmp (end + 1, "nocontrol"))
1259         restrict_ctrl = 0;
1260       else
1261         goto err;
1262     }
1263
1264   opt.restrict_files_os = restrict_os;
1265   opt.restrict_files_ctrl = restrict_ctrl;
1266   return 1;
1267 }
1268
1269 #ifdef HAVE_SSL
1270 static int
1271 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
1272 {
1273   static const struct decode_item choices[] = {
1274     { "auto", secure_protocol_auto },
1275     { "sslv2", secure_protocol_sslv2 },
1276     { "sslv3", secure_protocol_sslv3 },
1277     { "tlsv1", secure_protocol_tlsv1 },
1278   };
1279   int ok = decode_string (val, choices, countof (choices), place);
1280   if (!ok)
1281     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1282   return ok;
1283 }
1284 #endif
1285
1286 /* Set all three timeout values. */
1287
1288 static int
1289 cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
1290 {
1291   double value;
1292   if (!cmd_time (com, val, &value))
1293     return 0;
1294   opt.read_timeout = value;
1295   opt.connect_timeout = value;
1296   opt.dns_timeout = value;
1297   return 1;
1298 }
1299
1300 static int
1301 cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
1302 {
1303   /* Disallow embedded newlines.  */
1304   if (strchr (val, '\n'))
1305     {
1306       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1307                exec_name, com, val);
1308       return 0;
1309     }
1310   xfree_null (opt.useragent);
1311   opt.useragent = xstrdup (val);
1312   return 1;
1313 }
1314 \f
1315 /* Miscellaneous useful routines.  */
1316
1317 /* A very simple atoi clone, more useful than atoi because it works on
1318    delimited strings, and has error reportage.  Returns 1 on success,
1319    0 on failure.  If successful, stores result to *DEST.  */
1320
1321 static int
1322 simple_atoi (const char *beg, const char *end, int *dest)
1323 {
1324   int result = 0;
1325   int negative = 0;
1326   const char *p = beg;
1327
1328   while (p < end && ISSPACE (*p))
1329     ++p;
1330   if (p < end && (*p == '-' || *p == '+'))
1331     {
1332       negative = (*p == '-');
1333       ++p;
1334     }
1335   if (p == end)
1336     return 0;
1337
1338   /* Read negative numbers in a separate loop because the most
1339      negative integer cannot be represented as a positive number.  */
1340
1341   if (!negative)
1342     for (; p < end && ISDIGIT (*p); p++)
1343       {
1344         int next = (10 * result) + (*p - '0');
1345         if (next < result)
1346           return 0;             /* overflow */
1347         result = next;
1348       }
1349   else
1350     for (; p < end && ISDIGIT (*p); p++)
1351       {
1352         int next = (10 * result) - (*p - '0');
1353         if (next > result)
1354           return 0;             /* underflow */
1355         result = next;
1356       }
1357
1358   if (p != end)
1359     return 0;
1360
1361   *dest = result;
1362   return 1;
1363 }
1364
1365 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1366    doesn't handle exponential notation.  Returns 1 on success, 0 on
1367    failure.  In case of success, stores its result to *DEST.  */
1368
1369 static int
1370 simple_atof (const char *beg, const char *end, double *dest)
1371 {
1372   double result = 0;
1373
1374   int negative = 0;
1375   int seen_dot = 0;
1376   int seen_digit = 0;
1377   double divider = 1;
1378
1379   const char *p = beg;
1380
1381   while (p < end && ISSPACE (*p))
1382     ++p;
1383   if (p < end && (*p == '-' || *p == '+'))
1384     {
1385       negative = (*p == '-');
1386       ++p;
1387     }
1388
1389   for (; p < end; p++)
1390     {
1391       char ch = *p;
1392       if (ISDIGIT (ch))
1393         {
1394           if (!seen_dot)
1395             result = (10 * result) + (ch - '0');
1396           else
1397             result += (ch - '0') / (divider *= 10);
1398           seen_digit = 1;
1399         }
1400       else if (ch == '.')
1401         {
1402           if (!seen_dot)
1403             seen_dot = 1;
1404           else
1405             return 0;
1406         }
1407       else
1408         return 0;
1409     }
1410   if (!seen_digit)
1411     return 0;
1412   if (negative)
1413     result = -result;
1414
1415   *dest = result;
1416   return 1;
1417 }
1418
1419 /* Verify that the user-specified header in S is valid.  It must
1420    contain a colon preceded by non-white-space characters and must not
1421    contain newlines.  */
1422
1423 static int
1424 check_user_specified_header (const char *s)
1425 {
1426   const char *p;
1427
1428   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1429   /* The header MUST contain `:' preceded by at least one
1430      non-whitespace character.  */
1431   if (*p != ':' || p == s)
1432     return 0;
1433   /* The header MUST NOT contain newlines.  */
1434   if (strchr (s, '\n'))
1435     return 0;
1436   return 1;
1437 }
1438
1439 /* Decode VAL into a number, according to ITEMS. */
1440
1441 static int
1442 decode_string (const char *val, const struct decode_item *items, int itemcount,
1443                int *place)
1444 {
1445   int i;
1446   for (i = 0; i < itemcount; i++)
1447     if (0 == strcasecmp (val, items[i].name))
1448       {
1449         *place = items[i].code;
1450         return 1;
1451       }
1452   return 0;
1453 }
1454
1455 \f
1456 void cleanup_html_url PARAMS ((void));
1457 void http_cleanup PARAMS ((void));
1458
1459
1460 /* Free the memory allocated by global variables.  */
1461 void
1462 cleanup (void)
1463 {
1464   /* Free external resources, close files, etc. */
1465
1466   {
1467     extern FILE *output_stream;
1468     if (output_stream)
1469       fclose (output_stream);
1470     /* No need to check for error because Wget flushes its output (and
1471        checks for errors) after any data arrives.  */
1472   }
1473
1474   /* We're exiting anyway so there's no real need to call free()
1475      hundreds of times.  Skipping the frees will make Wget exit
1476      faster.
1477
1478      However, when detecting leaks, it's crucial to free() everything
1479      because then you can find the real leaks, i.e. the allocated
1480      memory which grows with the size of the program.  */
1481
1482 #ifdef DEBUG_MALLOC
1483   convert_cleanup ();
1484   res_cleanup ();
1485   http_cleanup ();
1486   cleanup_html_url ();
1487   host_cleanup ();
1488   log_cleanup ();
1489
1490   {
1491     extern acc_t *netrc_list;
1492     free_netrc (netrc_list);
1493   }
1494   xfree_null (opt.lfilename);
1495   xfree_null (opt.dir_prefix);
1496   xfree_null (opt.input_filename);
1497   xfree_null (opt.output_document);
1498   free_vec (opt.accepts);
1499   free_vec (opt.rejects);
1500   free_vec (opt.excludes);
1501   free_vec (opt.includes);
1502   free_vec (opt.domains);
1503   free_vec (opt.follow_tags);
1504   free_vec (opt.ignore_tags);
1505   xfree_null (opt.progress_type);
1506   xfree_null (opt.ftp_user);
1507   xfree_null (opt.ftp_passwd);
1508   xfree_null (opt.ftp_proxy);
1509   xfree_null (opt.https_proxy);
1510   xfree_null (opt.http_proxy);
1511   free_vec (opt.no_proxy);
1512   xfree_null (opt.useragent);
1513   xfree_null (opt.referer);
1514   xfree_null (opt.http_user);
1515   xfree_null (opt.http_passwd);
1516   free_vec (opt.user_headers);
1517 # ifdef HAVE_SSL
1518   xfree_null (opt.cert_file);
1519   xfree_null (opt.private_key);
1520   xfree_null (opt.ca_directory);
1521   xfree_null (opt.ca_cert);
1522   xfree_null (opt.random_file);
1523   xfree_null (opt.egd_file);
1524 # endif
1525   xfree_null (opt.bind_address);
1526   xfree_null (opt.cookies_input);
1527   xfree_null (opt.cookies_output);
1528   xfree_null (opt.user);
1529   xfree_null (opt.passwd);
1530 #endif /* DEBUG_MALLOC */
1531 }