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