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