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