]> sjero.net Git - wget/blob - src/init.c
[svn] Commit IPv6 support by Thomas Lussnig.
[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   wget_sockaddr sa;
531   wget_sockaddr **target = (wget_sockaddr **)closure;
532
533   memset (&sa, '\0', sizeof (sa));
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   sa.sa.sa_family = ip_default_family;
543   wget_sockaddr_set_port (&sa, 0);
544   address_list_copy_one (al, 0, wget_sockaddr_get_addr (&sa));
545   address_list_release (al);
546
547   FREE_MAYBE (*target);
548
549   *target = xmalloc (sizeof (sa));
550   memcpy (*target, &sa, sizeof (sa));
551
552   return 1;
553 }
554
555 /* Store the boolean value from VAL to CLOSURE.  COM is ignored,
556    except for error messages.  */
557 static int
558 cmd_boolean (const char *com, const char *val, void *closure)
559 {
560   int bool_value;
561
562   if (!strcasecmp (val, "on")
563       || (*val == '1' && !*(val + 1)))
564     bool_value = 1;
565   else if (!strcasecmp (val, "off")
566            || (*val == '0' && !*(val + 1)))
567     bool_value = 0;
568   else
569     {
570       fprintf (stderr, _("%s: %s: Please specify on or off.\n"),
571                exec_name, com);
572       return 0;
573     }
574
575   *(int *)closure = bool_value;
576   return 1;
577 }
578
579 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to CLOSURE.  COM is
580    ignored, except for error messages.  Values 2 and -1 indicate that once
581    defined, the value may not be changed by successive wgetrc files or
582    command-line arguments.
583
584    Values: 2 - Enable a particular option for good ("always")
585            1 - Enable an option ("on")
586            0 - Disable an option ("off")
587           -1 - Disable an option for good ("never") */
588 static int
589 cmd_lockable_boolean (const char *com, const char *val, void *closure)
590 {
591   int lockable_boolean_value;
592
593   /*
594    * If a config file said "always" or "never", don't allow command line
595    * arguments to override the config file.
596    */
597   if (*(int *)closure == -1 || *(int *)closure == 2)
598     return 1;
599
600   if (!strcasecmp (val, "always")
601       || (*val == '2' && !*(val + 1)))
602     lockable_boolean_value = 2;
603   else if (!strcasecmp (val, "on")
604       || (*val == '1' && !*(val + 1)))
605     lockable_boolean_value = 1;
606   else if (!strcasecmp (val, "off")
607           || (*val == '0' && !*(val + 1)))
608     lockable_boolean_value = 0;
609   else if (!strcasecmp (val, "never")
610       || (*val == '-' && *(val + 1) == '1' && !*(val + 2)))
611     lockable_boolean_value = -1;
612   else
613     {
614       fprintf (stderr, _("%s: %s: Please specify always, on, off, "
615                          "or never.\n"),
616                exec_name, com);
617       return 0;
618     }
619
620   *(int *)closure = lockable_boolean_value;
621   return 1;
622 }
623
624 /* Set the non-negative integer value from VAL to CLOSURE.  With
625    incorrect specification, the number remains unchanged.  */
626 static int
627 cmd_number (const char *com, const char *val, void *closure)
628 {
629   int num = myatoi (val);
630
631   if (num == -1)
632     {
633       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
634                exec_name, com, val);
635       return 0;
636     }
637   *(int *)closure = num;
638   return 1;
639 }
640
641 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
642 static int
643 cmd_number_inf (const char *com, const char *val, void *closure)
644 {
645   if (!strcasecmp (val, "inf"))
646     {
647       *(int *)closure = 0;
648       return 1;
649     }
650   return cmd_number (com, val, closure);
651 }
652
653 /* Copy (strdup) the string at COM to a new location and place a
654    pointer to *CLOSURE.  */
655 static int
656 cmd_string (const char *com, const char *val, void *closure)
657 {
658   char **pstring = (char **)closure;
659
660   FREE_MAYBE (*pstring);
661   *pstring = xstrdup (val);
662   return 1;
663 }
664
665 /* Like the above, but handles tilde-expansion when reading a user's
666    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
667    gets expanded to the user's home directory.  */
668 static int
669 cmd_file (const char *com, const char *val, void *closure)
670 {
671   char **pstring = (char **)closure;
672
673   FREE_MAYBE (*pstring);
674
675   /* #### If VAL is empty, perhaps should set *CLOSURE to NULL.  */
676
677   if (!enable_tilde_expansion || !(*val == '~' && (*(val + 1) == '/'
678 #ifdef WINDOWS
679           || *(val + 1) == '\\'
680 #endif
681           )))
682     {
683     noexpand:
684       *pstring = xstrdup (val);
685     }
686   else
687     {
688       char *result;
689       int homelen;
690       char *home = home_dir ();
691       if (!home)
692         goto noexpand;
693
694       homelen = strlen (home);
695       while (homelen && (home[homelen - 1] == '/'
696 #ifdef WINDOWS
697             || home[homelen - 1] == '\\'
698 #endif
699             ))
700         home[--homelen] = '\0';
701
702       /* Skip the leading "~/". */
703 #ifdef WINDOWS
704       for (++val; *val == '/' || *val == '\\'; val++)
705         ;
706 #else
707       for (++val; *val == '/'; val++)
708         ;
709 #endif
710
711       result = xmalloc (homelen + 1 + strlen (val));
712       memcpy (result, home, homelen);
713       result[homelen] = '/';
714       strcpy (result + homelen + 1, val);
715
716       *pstring = result;
717     }
718 #ifdef WINDOWS
719   /* Convert "\" to "/". */
720   {
721     char *s;
722     for (s = *pstring; *s; s++)
723       if (*s == '\\')
724         *s = '/';
725   }
726 #endif
727   return 1;
728 }
729
730 /* Like cmd_file, but strips trailing '/' characters.  */
731 static int
732 cmd_directory (const char *com, const char *val, void *closure)
733 {
734   char *s, *t;
735
736   /* Call cmd_file() for tilde expansion and separator
737      canonicalization (backslash -> slash under Windows).  These
738      things should perhaps be in a separate function.  */
739   if (!cmd_file (com, val, closure))
740     return 0;
741
742   s = *(char **)closure;
743   t = s + strlen (s);
744   while (t > s && *--t == '/')
745     *t = '\0';
746
747   return 1;
748 }
749
750 /* Merge the vector (array of strings separated with `,') in COM with
751    the vector (NULL-terminated array of strings) pointed to by
752    CLOSURE.  */
753 static int
754 cmd_vector (const char *com, const char *val, void *closure)
755 {
756   char ***pvec = (char ***)closure;
757
758   if (*val)
759     *pvec = merge_vecs (*pvec, sepstring (val));
760   else
761     {
762       free_vec (*pvec);
763       *pvec = NULL;
764     }
765   return 1;
766 }
767
768 static int
769 cmd_directory_vector (const char *com, const char *val, void *closure)
770 {
771   char ***pvec = (char ***)closure;
772
773   if (*val)
774     {
775       /* Strip the trailing slashes from directories.  */
776       char **t, **seps;
777
778       seps = sepstring (val);
779       for (t = seps; t && *t; t++)
780         {
781           int len = strlen (*t);
782           /* Skip degenerate case of root directory.  */
783           if (len > 1)
784             {
785               if ((*t)[len - 1] == '/')
786                 (*t)[len - 1] = '\0';
787             }
788         }
789       *pvec = merge_vecs (*pvec, seps);
790     }
791   else
792     {
793       free_vec (*pvec);
794       *pvec = NULL;
795     }
796   return 1;
797 }
798
799 /* Set the value stored in VAL to CLOSURE (which should point to a
800    long int), allowing several postfixes, with the following syntax
801    (regexp):
802
803    [0-9]+       -> bytes
804    [0-9]+[kK]   -> bytes * 1024
805    [0-9]+[mM]   -> bytes * 1024 * 1024
806    inf          -> 0
807
808    Anything else is flagged as incorrect, and CLOSURE is unchanged.  */
809 static int
810 cmd_bytes (const char *com, const char *val, void *closure)
811 {
812   long result;
813   long *out = (long *)closure;
814   const char *p;
815
816   result = 0;
817   p = val;
818   /* Check for "inf".  */
819   if (p[0] == 'i' && p[1] == 'n' && p[2] == 'f' && p[3] == '\0')
820     {
821       *out = 0;
822       return 1;
823     }
824   /* Search for digits and construct result.  */
825   for (; *p && ISDIGIT (*p); p++)
826     result = (10 * result) + (*p - '0');
827   /* If no digits were found, or more than one character is following
828      them, bail out.  */
829   if (p == val || (*p != '\0' && *(p + 1) != '\0'))
830     {
831       printf (_("%s: Invalid specification `%s'\n"), com, val);
832       return 0;
833     }
834   /* Search for a designator.  */
835   switch (TOLOWER (*p))
836     {
837     case '\0':
838       /* None */
839       break;
840     case 'k':
841       /* Kilobytes */
842       result *= 1024;
843       break;
844     case 'm':
845       /* Megabytes */
846       result *= (long)1024 * 1024;
847       break;
848     case 'g':
849       /* Gigabytes */
850       result *= (long)1024 * 1024 * 1024;
851       break;
852     default:
853       printf (_("%s: Invalid specification `%s'\n"), com, val);
854       return 0;
855     }
856   *out = result;
857   return 1;
858 }
859
860 /* Store the value of VAL to *OUT, allowing suffixes for minutes and
861    hours.  */
862 static int
863 cmd_time (const char *com, const char *val, void *closure)
864 {
865   long result = 0;
866   const char *p = val;
867
868   /* Search for digits and construct result.  */
869   for (; *p && ISDIGIT (*p); p++)
870     result = (10 * result) + (*p - '0');
871   /* If no digits were found, or more than one character is following
872      them, bail out.  */
873   if (p == val || (*p != '\0' && *(p + 1) != '\0'))
874     {
875       printf (_("%s: Invalid specification `%s'\n"), com, val);
876       return 0;
877     }
878   /* Search for a suffix.  */
879   switch (TOLOWER (*p))
880     {
881     case '\0':
882       /* None */
883       break;
884     case 'm':
885       /* Minutes */
886       result *= 60;
887       break;
888     case 'h':
889       /* Seconds */
890       result *= 3600;
891       break;
892     case 'd':
893       /* Days (overflow on 16bit machines) */
894       result *= 86400L;
895       break;
896     case 'w':
897       /* Weeks :-) */
898       result *= 604800L;
899       break;
900     default:
901       printf (_("%s: Invalid specification `%s'\n"), com, val);
902       return 0;
903     }
904   *(long *)closure = result;
905   return 1;
906 }
907 \f
908 /* Specialized helper functions, used by `commands' to handle some
909    options specially.  */
910
911 static int check_user_specified_header PARAMS ((const char *));
912
913 static int
914 cmd_spec_dirstruct (const char *com, const char *val, void *closure)
915 {
916   if (!cmd_boolean (com, val, &opt.dirstruct))
917     return 0;
918   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
919      must be affected inversely.  */
920   if (opt.dirstruct)
921     opt.no_dirstruct = 0;
922   else
923     opt.no_dirstruct = 1;
924   return 1;
925 }
926
927 static int
928 cmd_spec_header (const char *com, const char *val, void *closure)
929 {
930   if (!*val)
931     {
932       /* Empty header means reset headers.  */
933       FREE_MAYBE (opt.user_header);
934       opt.user_header = NULL;
935     }
936   else
937     {
938       int i;
939
940       if (!check_user_specified_header (val))
941         {
942           fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
943                    exec_name, com, val);
944           return 0;
945         }
946       i = opt.user_header ? strlen (opt.user_header) : 0;
947       opt.user_header = (char *)xrealloc (opt.user_header, i + strlen (val)
948                                           + 2 + 1);
949       strcpy (opt.user_header + i, val);
950       i += strlen (val);
951       opt.user_header[i++] = '\r';
952       opt.user_header[i++] = '\n';
953       opt.user_header[i] = '\0';
954     }
955   return 1;
956 }
957
958 static int
959 cmd_spec_htmlify (const char *com, const char *val, void *closure)
960 {
961   int flag = cmd_boolean (com, val, &opt.htmlify);
962   if (flag && !opt.htmlify)
963     opt.remove_listing = 0;
964   return flag;
965 }
966
967 static int
968 cmd_spec_mirror (const char *com, const char *val, void *closure)
969 {
970   int mirror;
971
972   if (!cmd_boolean (com, val, &mirror))
973     return 0;
974   if (mirror)
975     {
976       opt.recursive = 1;
977       if (!opt.no_dirstruct)
978         opt.dirstruct = 1;
979       opt.timestamping = 1;
980       opt.reclevel = INFINITE_RECURSION;
981       opt.remove_listing = 0;
982     }
983   return 1;
984 }
985
986 static int
987 cmd_spec_progress (const char *com, const char *val, void *closure)
988 {
989   if (!valid_progress_implementation_p (val))
990     {
991       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
992                exec_name, com, val);
993       return 0;
994     }
995   FREE_MAYBE (opt.progress_type);
996
997   /* Don't call set_progress_implementation here.  It will be called
998      in main() when it becomes clear what the log output is.  */
999   opt.progress_type = xstrdup (val);
1000   return 1;
1001 }
1002
1003 static int
1004 cmd_spec_recursive (const char *com, const char *val, void *closure)
1005 {
1006   if (!cmd_boolean (com, val, &opt.recursive))
1007     return 0;
1008   else
1009     {
1010       if (opt.recursive && !opt.no_dirstruct)
1011         opt.dirstruct = 1;
1012     }
1013   return 1;
1014 }
1015
1016 static int
1017 cmd_spec_useragent (const char *com, const char *val, void *closure)
1018 {
1019   /* Just check for empty string and newline, so we don't throw total
1020      junk to the server.  */
1021   if (!*val || strchr (val, '\n'))
1022     {
1023       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1024                exec_name, com, val);
1025       return 0;
1026     }
1027   opt.useragent = xstrdup (val);
1028   return 1;
1029 }
1030 \f
1031 /* Miscellaneous useful routines.  */
1032
1033 /* Return the integer value of a positive integer written in S, or -1
1034    if an error was encountered.  */
1035 static int
1036 myatoi (const char *s)
1037 {
1038   int res;
1039   const char *orig = s;
1040
1041   for (res = 0; *s && ISDIGIT (*s); s++)
1042     res = 10 * res + (*s - '0');
1043   if (*s || orig == s)
1044     return -1;
1045   else
1046     return res;
1047 }
1048
1049 #define ISODIGIT(x) ((x) >= '0' && (x) <= '7')
1050
1051 static int
1052 check_user_specified_header (const char *s)
1053 {
1054   const char *p;
1055
1056   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1057   /* The header MUST contain `:' preceded by at least one
1058      non-whitespace character.  */
1059   if (*p != ':' || p == s)
1060     return 0;
1061   /* The header MUST NOT contain newlines.  */
1062   if (strchr (s, '\n'))
1063     return 0;
1064   return 1;
1065 }
1066 \f
1067 void cleanup_html_url PARAMS ((void));
1068 void res_cleanup PARAMS ((void));
1069 void downloaded_files_free PARAMS ((void));
1070 void http_cleanup PARAMS ((void));
1071
1072
1073 /* Free the memory allocated by global variables.  */
1074 void
1075 cleanup (void)
1076 {
1077   /* Free external resources, close files, etc. */
1078
1079   if (opt.dfp)
1080     fclose (opt.dfp);
1081
1082   /* We're exiting anyway so there's no real need to call free()
1083      hundreds of times.  Skipping the frees will make Wget exit
1084      faster.
1085
1086      However, when detecting leaks, it's crucial to free() everything
1087      because then you can find the real leaks, i.e. the allocated
1088      memory which grows with the size of the program.  */
1089
1090 #ifdef DEBUG_MALLOC
1091   recursive_cleanup ();
1092   res_cleanup ();
1093   http_cleanup ();
1094   cleanup_html_url ();
1095   downloaded_files_free ();
1096   cookies_cleanup ();
1097   host_cleanup ();
1098
1099   {
1100     extern acc_t *netrc_list;
1101     free_netrc (netrc_list);
1102   }
1103   FREE_MAYBE (opt.lfilename);
1104   xfree (opt.dir_prefix);
1105   FREE_MAYBE (opt.input_filename);
1106   FREE_MAYBE (opt.output_document);
1107   free_vec (opt.accepts);
1108   free_vec (opt.rejects);
1109   free_vec (opt.excludes);
1110   free_vec (opt.includes);
1111   free_vec (opt.domains);
1112   free_vec (opt.follow_tags);
1113   free_vec (opt.ignore_tags);
1114   FREE_MAYBE (opt.progress_type);
1115   xfree (opt.ftp_acc);
1116   FREE_MAYBE (opt.ftp_pass);
1117   FREE_MAYBE (opt.ftp_proxy);
1118   FREE_MAYBE (opt.https_proxy);
1119   FREE_MAYBE (opt.http_proxy);
1120   free_vec (opt.no_proxy);
1121   FREE_MAYBE (opt.useragent);
1122   FREE_MAYBE (opt.referer);
1123   FREE_MAYBE (opt.http_user);
1124   FREE_MAYBE (opt.http_passwd);
1125   FREE_MAYBE (opt.user_header);
1126 #ifdef HAVE_SSL
1127   FREE_MAYBE (opt.sslcertkey);
1128   FREE_MAYBE (opt.sslcertfile);
1129 #endif /* HAVE_SSL */
1130   FREE_MAYBE (opt.bind_address);
1131   FREE_MAYBE (opt.cookies_input);
1132   FREE_MAYBE (opt.cookies_output);
1133 #endif
1134 }