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