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