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