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