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