]> sjero.net Git - wget/blob - src/init.c
8cc77bc7980afe56edf53d2130b82ea692c2d583
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003
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 #include <assert.h>
60
61 #include "wget.h"
62 #include "utils.h"
63 #include "init.h"
64 #include "host.h"
65 #include "netrc.h"
66 #include "cookies.h"            /* for cookie_jar_delete */
67 #include "progress.h"
68 #include "recur.h"              /* for INFINITE_RECURSION */
69
70 #ifndef errno
71 extern int errno;
72 #endif
73
74 extern struct cookie_jar *wget_cookie_jar;
75
76 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
77    otherwise, it will be performed by the shell.  This variable will
78    be set by the wgetrc-reading function.  */
79
80 static int enable_tilde_expansion;
81
82
83 #define CMD_DECLARE(func) static int func \
84   PARAMS ((const char *, const char *, void *))
85
86 CMD_DECLARE (cmd_boolean);
87 CMD_DECLARE (cmd_bytes);
88 CMD_DECLARE (cmd_bytes_large);
89 CMD_DECLARE (cmd_directory_vector);
90 CMD_DECLARE (cmd_lockable_boolean);
91 CMD_DECLARE (cmd_number);
92 CMD_DECLARE (cmd_number_inf);
93 CMD_DECLARE (cmd_string);
94 CMD_DECLARE (cmd_file);
95 CMD_DECLARE (cmd_directory);
96 CMD_DECLARE (cmd_time);
97 CMD_DECLARE (cmd_vector);
98
99 CMD_DECLARE (cmd_spec_dirstruct);
100 CMD_DECLARE (cmd_spec_header);
101 CMD_DECLARE (cmd_spec_htmlify);
102 CMD_DECLARE (cmd_spec_mirror);
103 CMD_DECLARE (cmd_spec_progress);
104 CMD_DECLARE (cmd_spec_recursive);
105 CMD_DECLARE (cmd_spec_restrict_file_names);
106 CMD_DECLARE (cmd_spec_timeout);
107 CMD_DECLARE (cmd_spec_useragent);
108
109 /* List of recognized commands, each consisting of name, closure and
110    function.  When adding a new command, simply add it to the list,
111    but be sure to keep the list sorted alphabetically, as
112    command_by_name depends on it.  Also, be sure to add any entries
113    that allocate memory (e.g. cmd_string and cmd_vector guys) to the
114    cleanup() function below. */
115
116 static struct {
117   char *name;
118   void *closure;
119   int (*action) PARAMS ((const char *, const char *, void *));
120 } commands[] = {
121   { "accept",           &opt.accepts,           cmd_vector },
122   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
123   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
124   { "background",       &opt.background,        cmd_boolean },
125   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
126   { "backups",          &opt.backups,           cmd_number },
127   { "base",             &opt.base_href,         cmd_string },
128   { "bindaddress",      &opt.bind_address,      cmd_string },
129   { "cache",            &opt.allow_cache,       cmd_boolean },
130   { "connecttimeout",   &opt.connect_timeout,   cmd_time },
131   { "continue",         &opt.always_rest,       cmd_boolean },
132   { "convertlinks",     &opt.convert_links,     cmd_boolean },
133   { "cookies",          &opt.cookies,           cmd_boolean },
134   { "cutdirs",          &opt.cut_dirs,          cmd_number },
135 #ifdef ENABLE_DEBUG
136   { "debug",            &opt.debug,             cmd_boolean },
137 #endif
138   { "deleteafter",      &opt.delete_after,      cmd_boolean },
139   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
140   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
141   { "dnscache",         &opt.dns_cache,         cmd_boolean },
142   { "dnstimeout",       &opt.dns_timeout,       cmd_time },
143   { "domains",          &opt.domains,           cmd_vector },
144   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
145   { "dotsinline",       &opt.dots_in_line,      cmd_number },
146   { "dotspacing",       &opt.dot_spacing,       cmd_number },
147   { "dotstyle",         &opt.dot_style,         cmd_string },
148 #ifdef HAVE_SSL
149   { "egdfile",          &opt.sslegdsock,        cmd_file },
150 #endif
151   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
152   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
153   { "followftp",        &opt.follow_ftp,        cmd_boolean },
154   { "followtags",       &opt.follow_tags,       cmd_vector },
155   { "forcehtml",        &opt.force_html,        cmd_boolean },
156   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
157   { "glob",             &opt.ftp_glob,          cmd_boolean },
158   { "header",           NULL,                   cmd_spec_header },
159   { "htmlextension",    &opt.html_extension,    cmd_boolean },
160   { "htmlify",          NULL,                   cmd_spec_htmlify },
161   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
162   { "httppasswd",       &opt.http_passwd,       cmd_string },
163   { "httpproxy",        &opt.http_proxy,        cmd_string },
164   { "httpsproxy",       &opt.https_proxy,       cmd_string },
165   { "httpuser",         &opt.http_user,         cmd_string },
166   { "ignorelength",     &opt.ignore_length,     cmd_boolean },
167   { "ignoretags",       &opt.ignore_tags,       cmd_vector },
168   { "includedirectories", &opt.includes,        cmd_directory_vector },
169   { "input",            &opt.input_filename,    cmd_file },
170   { "killlonger",       &opt.kill_longer,       cmd_boolean },
171   { "limitrate",        &opt.limit_rate,        cmd_bytes },
172   { "loadcookies",      &opt.cookies_input,     cmd_file },
173   { "logfile",          &opt.lfilename,         cmd_file },
174   { "login",            &opt.ftp_acc,           cmd_string },
175   { "mirror",           NULL,                   cmd_spec_mirror },
176   { "netrc",            &opt.netrc,             cmd_boolean },
177   { "noclobber",        &opt.noclobber,         cmd_boolean },
178   { "noparent",         &opt.no_parent,         cmd_boolean },
179   { "noproxy",          &opt.no_proxy,          cmd_vector },
180   { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
181   { "outputdocument",   &opt.output_document,   cmd_file },
182   { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
183   { "passiveftp",       &opt.ftp_pasv,          cmd_lockable_boolean },
184   { "passwd",           &opt.ftp_pass,          cmd_string },
185   { "postdata",         &opt.post_data,         cmd_string },
186   { "postfile",         &opt.post_file_name,    cmd_file },
187   { "progress",         &opt.progress_type,     cmd_spec_progress },
188   { "proxypasswd",      &opt.proxy_passwd,      cmd_string },
189   { "proxyuser",        &opt.proxy_user,        cmd_string },
190   { "quiet",            &opt.quiet,             cmd_boolean },
191   { "quota",            &opt.quota,             cmd_bytes_large },
192   { "randomwait",       &opt.random_wait,       cmd_boolean },
193   { "readtimeout",      &opt.read_timeout,      cmd_time },
194   { "reclevel",         &opt.reclevel,          cmd_number_inf },
195   { "recursive",        NULL,                   cmd_spec_recursive },
196   { "referer",          &opt.referer,           cmd_string },
197   { "reject",           &opt.rejects,           cmd_vector },
198   { "relativeonly",     &opt.relative_only,     cmd_boolean },
199   { "removelisting",    &opt.remove_listing,    cmd_boolean },
200   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
201   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
202   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
203   { "robots",           &opt.use_robots,        cmd_boolean },
204   { "savecookies",      &opt.cookies_output,    cmd_file },
205   { "saveheaders",      &opt.save_headers,      cmd_boolean },
206   { "serverresponse",   &opt.server_response,   cmd_boolean },
207   { "spanhosts",        &opt.spanhost,          cmd_boolean },
208   { "spider",           &opt.spider,            cmd_boolean },
209 #ifdef HAVE_SSL
210   { "sslcadir",         &opt.sslcadir,          cmd_directory },
211   { "sslcafile",        &opt.sslcafile,         cmd_file },
212   { "sslcertfile",      &opt.sslcertfile,       cmd_file },
213   { "sslcertkey",       &opt.sslcertkey,        cmd_file },
214   { "sslcerttype",      &opt.sslcerttype,       cmd_number },
215   { "sslcheckcert",     &opt.sslcheckcert,      cmd_number },
216   { "sslprotocol",      &opt.sslprotocol,       cmd_number },
217 #endif /* HAVE_SSL */
218   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
219   { "timeout",          NULL,                   cmd_spec_timeout },
220   { "timestamping",     &opt.timestamping,      cmd_boolean },
221   { "tries",            &opt.ntry,              cmd_number_inf },
222   { "useproxy",         &opt.use_proxy,         cmd_boolean },
223   { "useragent",        NULL,                   cmd_spec_useragent },
224   { "verbose",          &opt.verbose,           cmd_boolean },
225   { "wait",             &opt.wait,              cmd_time },
226   { "waitretry",        &opt.waitretry,         cmd_time }
227 };
228
229 /* Look up CMDNAME in the commands[] and return its position in the
230    array.  If CMDNAME is not found, return -1.  */
231
232 static int
233 command_by_name (const char *cmdname)
234 {
235   /* Use binary search for speed.  Wget has ~100 commands, which
236      guarantees a worst case performance of 7 string comparisons.  */
237   int lo = 0, hi = countof (commands) - 1;
238
239   while (lo <= hi)
240     {
241       int mid = (lo + hi) >> 1;
242       int cmp = strcasecmp (cmdname, commands[mid].name);
243       if (cmp < 0)
244         hi = mid - 1;
245       else if (cmp > 0)
246         lo = mid + 1;
247       else
248         return mid;
249     }
250   return -1;
251 }
252 \f
253 /* Reset the variables to default values.  */
254 static void
255 defaults (void)
256 {
257   char *tmp;
258
259   /* Most of the default values are 0.  Just reset everything, and
260      fill in the non-zero values.  Note that initializing pointers to
261      NULL this way is technically illegal, but porting Wget to a
262      machine where NULL is not all-zero bit pattern will be the least
263      of the implementors' worries.  */
264   xzero (opt);
265
266   opt.cookies = 1;
267   opt.verbose = -1;
268   opt.ntry = 20;
269   opt.reclevel = 5;
270   opt.add_hostdir = 1;
271   opt.ftp_acc  = xstrdup ("anonymous");
272   opt.ftp_pass = xstrdup ("-wget@");
273   opt.netrc = 1;
274   opt.ftp_glob = 1;
275   opt.htmlify = 1;
276   opt.http_keep_alive = 1;
277   opt.use_proxy = 1;
278   tmp = getenv ("no_proxy");
279   if (tmp)
280     opt.no_proxy = sepstring (tmp);
281   opt.allow_cache = 1;
282
283   opt.read_timeout = 900;
284   opt.use_robots = 1;
285
286   opt.remove_listing = 1;
287
288   opt.dot_bytes = 1024;
289   opt.dot_spacing = 10;
290   opt.dots_in_line = 50;
291
292   opt.dns_cache = 1;
293
294   /* The default for file name restriction defaults to the OS type. */
295 #if !defined(WINDOWS) && !defined(__CYGWIN__)
296   opt.restrict_files_os = restrict_unix;
297 #else
298   opt.restrict_files_os = restrict_windows;
299 #endif
300   opt.restrict_files_ctrl = 1;
301 }
302 \f
303 /* Return the user's home directory (strdup-ed), or NULL if none is
304    found.  */
305 char *
306 home_dir (void)
307 {
308   char *home = getenv ("HOME");
309
310   if (!home)
311     {
312 #ifndef WINDOWS
313       /* If HOME is not defined, try getting it from the password
314          file.  */
315       struct passwd *pwd = getpwuid (getuid ());
316       if (!pwd || !pwd->pw_dir)
317         return NULL;
318       home = pwd->pw_dir;
319 #else  /* WINDOWS */
320       home = "C:\\";
321       /* #### Maybe I should grab home_dir from registry, but the best
322          that I could get from there is user's Start menu.  It sucks!  */
323 #endif /* WINDOWS */
324     }
325
326   return home ? xstrdup (home) : NULL;
327 }
328
329 /* Return the path to the user's .wgetrc.  This is either the value of
330    `WGETRC' environment variable, or `$HOME/.wgetrc'.
331
332    If the `WGETRC' variable exists but the file does not exist, the
333    function will exit().  */
334 static char *
335 wgetrc_file_name (void)
336 {
337   char *env, *home;
338   char *file = NULL;
339
340   /* Try the environment.  */
341   env = getenv ("WGETRC");
342   if (env && *env)
343     {
344       if (!file_exists_p (env))
345         {
346           fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
347                    exec_name, env);
348           exit (1);
349         }
350       return xstrdup (env);
351     }
352
353 #ifndef WINDOWS
354   /* If that failed, try $HOME/.wgetrc.  */
355   home = home_dir ();
356   if (home)
357     {
358       file = (char *)xmalloc (strlen (home) + 1 + strlen (".wgetrc") + 1);
359       sprintf (file, "%s/.wgetrc", home);
360     }
361   xfree_null (home);
362 #else  /* WINDOWS */
363   /* Under Windows, "home" is (for the purposes of this function) the
364      directory where `wget.exe' resides, and `wget.ini' will be used
365      as file name.  SYSTEM_WGETRC should not be defined under WINDOWS.
366
367      It is not as trivial as I assumed, because on 95 argv[0] is full
368      path, but on NT you get what you typed in command line.  --dbudor */
369   home = ws_mypath ();
370   if (home)
371     {
372       file = (char *)xmalloc (strlen (home) + strlen ("wget.ini") + 1);
373       sprintf (file, "%swget.ini", home);
374     }
375 #endif /* WINDOWS */
376
377   if (!file)
378     return NULL;
379   if (!file_exists_p (file))
380     {
381       xfree (file);
382       return NULL;
383     }
384   return file;
385 }
386
387 static int parse_line PARAMS ((const char *, char **, char **, int *));
388 static int setval_internal PARAMS ((int, const char *, const char *));
389
390 /* Initialize variables from a wgetrc file.  */
391
392 static void
393 run_wgetrc (const char *file)
394 {
395   FILE *fp;
396   char *line;
397   int ln;
398
399   fp = fopen (file, "rb");
400   if (!fp)
401     {
402       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
403                file, strerror (errno));
404       return;
405     }
406   enable_tilde_expansion = 1;
407   ln = 1;
408   while ((line = read_whole_line (fp)))
409     {
410       char *com, *val;
411       int comind, status;
412
413       /* Parse the line.  */
414       status = parse_line (line, &com, &val, &comind);
415       xfree (line);
416       /* If everything is OK, set the value.  */
417       if (status == 1)
418         {
419           if (!setval_internal (comind, com, val))
420             fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
421                      file, ln);
422           xfree (com);
423           xfree (val);
424         }
425       else if (status == 0)
426         fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
427                  file, ln);
428       ++ln;
429     }
430   enable_tilde_expansion = 0;
431   fclose (fp);
432 }
433
434 /* Initialize the defaults and run the system wgetrc and user's own
435    wgetrc.  */
436 void
437 initialize (void)
438 {
439   char *file;
440
441   /* Load the hard-coded defaults.  */
442   defaults ();
443
444   /* If SYSTEM_WGETRC is defined, use it.  */
445 #ifdef SYSTEM_WGETRC
446   if (file_exists_p (SYSTEM_WGETRC))
447     run_wgetrc (SYSTEM_WGETRC);
448 #endif
449   /* Override it with your own, if one exists.  */
450   file = wgetrc_file_name ();
451   if (!file)
452     return;
453   /* #### We should canonicalize `file' and SYSTEM_WGETRC with
454      something like realpath() before comparing them with `strcmp'  */
455 #ifdef SYSTEM_WGETRC
456   if (!strcmp (file, SYSTEM_WGETRC))
457     {
458       fprintf (stderr, _("\
459 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
460                exec_name, file);
461     }
462   else
463 #endif
464     run_wgetrc (file);
465   xfree (file);
466   return;
467 }
468 \f
469 /* Remove dashes and underscores from S, modifying S in the
470    process. */
471
472 static void
473 dehyphen (char *s)
474 {
475   char *t = s;                  /* t - tortoise */
476   char *h = s;                  /* h - hare     */
477   while (*h)
478     if (*h == '_' || *h == '-')
479       ++h;
480     else
481       *t++ = *h++;
482   *t = '\0';
483 }
484
485 /* Parse the line pointed by line, with the syntax:
486    <sp>* command <sp>* = <sp>* value <sp>*
487    Uses malloc to allocate space for command and value.
488    If the line is invalid, data is freed and 0 is returned.
489
490    Return values:
491     1 - success
492     0 - error
493    -1 - empty
494
495    In case of success, *COM and *VAL point to freshly allocated
496    strings, and *COMIND points to com's index.  In case of error or
497    empty line, those values are unaffected.  */
498
499 static int
500 parse_line (const char *line, char **com, char **val, int *comind)
501 {
502   const char *p;
503   const char *end = line + strlen (line);
504   const char *cmdstart, *cmdend;
505   const char *valstart, *valend;
506
507   char *cmdcopy;
508   int ind;
509
510   /* Skip leading and trailing whitespace.  */
511   while (*line && ISSPACE (*line))
512     ++line;
513   while (end > line && ISSPACE (end[-1]))
514     --end;
515
516   /* Skip empty lines and comments.  */
517   if (!*line || *line == '#')
518     return -1;
519
520   p = line;
521
522   cmdstart = p;
523   while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-'))
524     ++p;
525   cmdend = p;
526
527   /* Skip '=', as well as any space before or after it. */
528   while (p < end && ISSPACE (*p))
529     ++p;
530   if (p == end || *p != '=')
531     return 0;
532   ++p;
533   while (p < end && ISSPACE (*p))
534     ++p;
535
536   valstart = p;
537   valend   = end;
538
539   /* The line now known to be syntactically correct.  Check whether
540      the command is valid.  */
541   BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
542   dehyphen (cmdcopy);
543   ind = command_by_name (cmdcopy);
544   if (ind == -1)
545     return 0;
546
547   /* The command is valid.  Now fill in the values and report success
548      to the caller.  */
549   *comind = ind;
550   *com = strdupdelim (cmdstart, cmdend);
551   *val = strdupdelim (valstart, valend);
552   return 1;
553 }
554
555 /* Run commands[comind].action. */
556
557 static int
558 setval_internal (int comind, const char *com, const char *val)
559 {
560   assert (0 <= comind && comind < countof (commands));
561   return ((*commands[comind].action) (com, val, commands[comind].closure));
562 }
563
564 /* Run command COM with value VAL.  If running the command produces an
565    error, report the error and exit.
566
567    This is intended to be called from main() to modify Wget's behavior
568    through command-line switches.  Since COM is hard-coded in main(),
569    it is not canonicalized, and this aborts when COM is not found.
570
571    If COMIND's are exported to init.h, this function will be changed
572    to accept COMIND directly.  */
573
574 void
575 setoptval (const char *com, const char *val)
576 {
577   if (!setval_internal (command_by_name (com), com, val))
578     exit (2);
579 }
580
581 /* Parse OPT into command and value and run it.  For example,
582    run_command("foo=bar") is equivalent to setoptval("foo", "bar").
583    This is used by the `--execute' flag in main.c.  */
584
585 void
586 run_command (const char *opt)
587 {
588   char *com, *val;
589   int comind;
590   int status = parse_line (opt, &com, &val, &comind);
591   if (status == 1)
592     {
593       if (!setval_internal (comind, com, val))
594         exit (2);
595       xfree (com);
596       xfree (val);
597     }
598   else if (status == 0)
599     {
600       fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
601                exec_name, opt);
602       exit (2);
603     }
604 }
605 \f
606 /* Generic helper functions, for use with `commands'. */
607
608 #define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
609
610 #define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0)        \
611                          && TOLOWER((p)[1]) == (c1)     \
612                          && (p)[2] == '\0')
613
614 #define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0)    \
615                      && TOLOWER((p)[1]) == (c1)         \
616                      && TOLOWER((p)[2]) == (c2)         \
617                      && (p)[3] == '\0')
618
619
620 /* Store the boolean value from VAL to CLOSURE.  COM is ignored,
621    except for error messages.  */
622 static int
623 cmd_boolean (const char *com, const char *val, void *closure)
624 {
625   int bool_value;
626
627   if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
628     /* "on", "yes" and "1" mean true. */
629     bool_value = 1;
630   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
631     /* "off", "no" and "0" mean false. */
632     bool_value = 0;
633   else
634     {
635       fprintf (stderr,
636                _("%s: %s: Invalid boolean `%s', use `on' or `off'.\n"),
637                exec_name, com, val);
638       return 0;
639     }
640
641   *(int *)closure = bool_value;
642   return 1;
643 }
644
645 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to CLOSURE.
646    COM is ignored, except for error messages.  Values 2 and -1
647    indicate that once defined, the value may not be changed by
648    successive wgetrc files or command-line arguments.
649
650    Values: 2 - Enable a particular option for good ("always")
651            1 - Enable an option ("on")
652            0 - Disable an option ("off")
653           -1 - Disable an option for good ("never") */
654 static int
655 cmd_lockable_boolean (const char *com, const char *val, void *closure)
656 {
657   int lockable_boolean_value;
658
659   int oldval = *(int *)closure;
660
661   /*
662    * If a config file said "always" or "never", don't allow command line
663    * arguments to override the config file.
664    */
665   if (oldval == -1 || oldval == 2)
666     return 1;
667
668   if (0 == strcasecmp (val, "always") || CMP1 (val, '2'))
669     lockable_boolean_value = 2;
670   else if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
671     lockable_boolean_value = 1;
672   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
673     lockable_boolean_value = 0;
674   else if (0 == strcasecmp (val, "never") || CMP2 (val, '-', '1'))
675     lockable_boolean_value = -1;
676   else
677     {
678       fprintf (stderr,
679                _("%s: %s: Invalid boolean `%s', use always, on, off, or never.\n"),
680                exec_name, com, val);
681       return 0;
682     }
683
684   *(int *)closure = lockable_boolean_value;
685   return 1;
686 }
687
688 static int simple_atoi PARAMS ((const char *, const char *, int *));
689
690 /* Set the non-negative integer value from VAL to CLOSURE.  With
691    incorrect specification, the number remains unchanged.  */
692 static int
693 cmd_number (const char *com, const char *val, void *closure)
694 {
695   if (!simple_atoi (val, val + strlen (val), closure))
696     {
697       fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
698                exec_name, com, val);
699       return 0;
700     }
701   return 1;
702 }
703
704 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
705 static int
706 cmd_number_inf (const char *com, const char *val, void *closure)
707 {
708   if (!strcasecmp (val, "inf"))
709     {
710       *(int *)closure = 0;
711       return 1;
712     }
713   return cmd_number (com, val, closure);
714 }
715
716 /* Copy (strdup) the string at COM to a new location and place a
717    pointer to *CLOSURE.  */
718 static int
719 cmd_string (const char *com, const char *val, void *closure)
720 {
721   char **pstring = (char **)closure;
722
723   xfree_null (*pstring);
724   *pstring = xstrdup (val);
725   return 1;
726 }
727
728 #ifndef WINDOWS
729 # define ISSEP(c) ((c) == '/')
730 #else
731 # define ISSEP(c) ((c) == '/' || (c) == '\\')
732 #endif
733
734 /* Like the above, but handles tilde-expansion when reading a user's
735    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
736    gets expanded to the user's home directory.  */
737 static int
738 cmd_file (const char *com, const char *val, void *closure)
739 {
740   char **pstring = (char **)closure;
741
742   xfree_null (*pstring);
743
744   /* #### If VAL is empty, perhaps should set *CLOSURE to NULL.  */
745
746   if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
747     {
748     noexpand:
749       *pstring = xstrdup (val);
750     }
751   else
752     {
753       char *result;
754       int homelen;
755       char *home = home_dir ();
756       if (!home)
757         goto noexpand;
758
759       homelen = strlen (home);
760       while (homelen && ISSEP (home[homelen - 1]))
761         home[--homelen] = '\0';
762
763       /* Skip the leading "~/". */
764       for (++val; ISSEP (*val); val++)
765         ;
766
767       result = xmalloc (homelen + 1 + strlen (val) + 1);
768       memcpy (result, home, homelen);
769       result[homelen] = '/';
770       strcpy (result + homelen + 1, val);
771
772       *pstring = result;
773     }
774
775 #ifdef WINDOWS
776   /* Convert "\" to "/". */
777   {
778     char *s;
779     for (s = *pstring; *s; s++)
780       if (*s == '\\')
781         *s = '/';
782   }
783 #endif
784   return 1;
785 }
786
787 /* Like cmd_file, but strips trailing '/' characters.  */
788 static int
789 cmd_directory (const char *com, const char *val, void *closure)
790 {
791   char *s, *t;
792
793   /* Call cmd_file() for tilde expansion and separator
794      canonicalization (backslash -> slash under Windows).  These
795      things should perhaps be in a separate function.  */
796   if (!cmd_file (com, val, closure))
797     return 0;
798
799   s = *(char **)closure;
800   t = s + strlen (s);
801   while (t > s && *--t == '/')
802     *t = '\0';
803
804   return 1;
805 }
806
807 /* Split VAL by space to a vector of values, and append those values
808    to vector pointed to by the CLOSURE argument.  If VAL is empty, the
809    CLOSURE vector is cleared instead.  */
810
811 static int
812 cmd_vector (const char *com, const char *val, void *closure)
813 {
814   char ***pvec = (char ***)closure;
815
816   if (*val)
817     *pvec = merge_vecs (*pvec, sepstring (val));
818   else
819     {
820       free_vec (*pvec);
821       *pvec = NULL;
822     }
823   return 1;
824 }
825
826 static int
827 cmd_directory_vector (const char *com, const char *val, void *closure)
828 {
829   char ***pvec = (char ***)closure;
830
831   if (*val)
832     {
833       /* Strip the trailing slashes from directories.  */
834       char **t, **seps;
835
836       seps = sepstring (val);
837       for (t = seps; t && *t; t++)
838         {
839           int len = strlen (*t);
840           /* Skip degenerate case of root directory.  */
841           if (len > 1)
842             {
843               if ((*t)[len - 1] == '/')
844                 (*t)[len - 1] = '\0';
845             }
846         }
847       *pvec = merge_vecs (*pvec, seps);
848     }
849   else
850     {
851       free_vec (*pvec);
852       *pvec = NULL;
853     }
854   return 1;
855 }
856
857 static int simple_atof PARAMS ((const char *, const char *, double *));
858
859 /* Enginge for cmd_bytes and cmd_bytes_large: converts a string such
860    as "100k" or "2.5G" to a floating point number.  */
861
862 static int
863 parse_bytes_helper (const char *val, double *result)
864 {
865   double number, mult;
866   const char *end = val + strlen (val);
867
868   /* Check for "inf".  */
869   if (0 == strcmp (val, "inf"))
870     {
871       *result = 0;
872       return 1;
873     }
874
875   /* Strip trailing whitespace.  */
876   while (val < end && ISSPACE (end[-1]))
877     --end;
878   if (val == end)
879     return 0;
880
881   switch (TOLOWER (end[-1]))
882     {
883     case 'k':
884       --end, mult = 1024.0;
885       break;
886     case 'm':
887       --end, mult = 1048576.0;
888       break;
889     case 'g':
890       --end, mult = 1073741824.0;
891       break;
892     case 't':
893       --end, mult = 1099511627776.0;
894       break;
895     default:
896       /* Not a recognized suffix: assume it's a digit.  (If not,
897          simple_atof will raise an error.)  */
898       mult = 1;
899     }
900
901   /* Skip leading and trailing whitespace. */
902   while (val < end && ISSPACE (*val))
903     ++val;
904   while (val < end && ISSPACE (end[-1]))
905     --end;
906   if (val == end)
907     return 0;
908
909   if (!simple_atof (val, end, &number))
910     return 0;
911
912   *result = number * mult;
913   return 1;
914 }
915
916 /* Parse VAL as a number and set its value to CLOSURE (which should
917    point to a long int).
918
919    By default, the value is assumed to be in bytes.  If "K", "M", or
920    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
921    1<<30, respectively.  Floating point values are allowed and are
922    cast to integer before use.  The idea is to be able to use things
923    like 1.5k instead of "1536".
924
925    The string "inf" is returned as 0.
926
927    In case of error, 0 is returned and memory pointed to by CLOSURE
928    remains unmodified.  */
929
930 static int
931 cmd_bytes (const char *com, const char *val, void *closure)
932 {
933   double byte_value;
934   if (!parse_bytes_helper (val, &byte_value))
935     {
936       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
937                exec_name, com, val);
938       return 0;
939     }
940   *(long *)closure = (long)byte_value;
941   return 1;
942 }
943
944 /* Like cmd_bytes, but CLOSURE is interpreted as a pointer to
945    LARGE_INT.  It works by converting the string to double, therefore
946    working with values up to 2^53-1 without loss of precision.  This
947    value (8192 TB) is large enough to serve for a while.  */
948
949 static int
950 cmd_bytes_large (const char *com, const char *val, void *closure)
951 {
952   double byte_value;
953   if (!parse_bytes_helper (val, &byte_value))
954     {
955       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
956                exec_name, com, val);
957       return 0;
958     }
959   *(LARGE_INT *)closure = (LARGE_INT)byte_value;
960   return 1;
961 }
962
963 /* Store the value of VAL to *OUT.  The value is a time period, by
964    default expressed in seconds, but also accepting suffixes "m", "h",
965    "d", and "w" for minutes, hours, days, and weeks respectively.  */
966
967 static int
968 cmd_time (const char *com, const char *val, void *closure)
969 {
970   double number, mult;
971   const char *end = val + strlen (val);
972
973   /* Strip trailing whitespace.  */
974   while (val < end && ISSPACE (end[-1]))
975     --end;
976
977   if (val == end)
978     {
979     err:
980       fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
981                exec_name, com, val);
982       return 0;
983     }
984
985   switch (TOLOWER (end[-1]))
986     {
987     case 's':
988       --end, mult = 1;          /* seconds */
989       break;
990     case 'm':
991       --end, mult = 60;         /* minutes */
992       break;
993     case 'h':
994       --end, mult = 3600;       /* hours */
995       break;
996     case 'd':
997       --end, mult = 86400.0;    /* days */
998       break;
999     case 'w':
1000       --end, mult = 604800.0;   /* weeks */
1001       break;
1002     default:
1003       /* Not a recognized suffix: assume it belongs to the number.
1004          (If not, atof simple_atof will raise an error.)  */
1005       mult = 1;
1006     }
1007
1008   /* Skip leading and trailing whitespace. */
1009   while (val < end && ISSPACE (*val))
1010     ++val;
1011   while (val < end && ISSPACE (end[-1]))
1012     --end;
1013   if (val == end)
1014     goto err;
1015
1016   if (!simple_atof (val, end, &number))
1017     goto err;
1018
1019   *(double *)closure = number * mult;
1020   return 1;
1021 }
1022 \f
1023 /* Specialized helper functions, used by `commands' to handle some
1024    options specially.  */
1025
1026 static int check_user_specified_header PARAMS ((const char *));
1027
1028 static int
1029 cmd_spec_dirstruct (const char *com, const char *val, void *closure)
1030 {
1031   if (!cmd_boolean (com, val, &opt.dirstruct))
1032     return 0;
1033   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1034      must be affected inversely.  */
1035   if (opt.dirstruct)
1036     opt.no_dirstruct = 0;
1037   else
1038     opt.no_dirstruct = 1;
1039   return 1;
1040 }
1041
1042 static int
1043 cmd_spec_header (const char *com, const char *val, void *closure)
1044 {
1045   if (!*val)
1046     {
1047       /* Empty header means reset headers.  */
1048       xfree_null (opt.user_header);
1049       opt.user_header = NULL;
1050     }
1051   else
1052     {
1053       int i;
1054
1055       if (!check_user_specified_header (val))
1056         {
1057           fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1058                    exec_name, com, val);
1059           return 0;
1060         }
1061       i = opt.user_header ? strlen (opt.user_header) : 0;
1062       opt.user_header = (char *)xrealloc (opt.user_header, i + strlen (val)
1063                                           + 2 + 1);
1064       strcpy (opt.user_header + i, val);
1065       i += strlen (val);
1066       opt.user_header[i++] = '\r';
1067       opt.user_header[i++] = '\n';
1068       opt.user_header[i] = '\0';
1069     }
1070   return 1;
1071 }
1072
1073 static int
1074 cmd_spec_htmlify (const char *com, const char *val, void *closure)
1075 {
1076   int flag = cmd_boolean (com, val, &opt.htmlify);
1077   if (flag && !opt.htmlify)
1078     opt.remove_listing = 0;
1079   return flag;
1080 }
1081
1082 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1083    no limit on max. recursion depth, and don't remove listings.  */
1084
1085 static int
1086 cmd_spec_mirror (const char *com, const char *val, void *closure)
1087 {
1088   int mirror;
1089
1090   if (!cmd_boolean (com, val, &mirror))
1091     return 0;
1092   if (mirror)
1093     {
1094       opt.recursive = 1;
1095       if (!opt.no_dirstruct)
1096         opt.dirstruct = 1;
1097       opt.timestamping = 1;
1098       opt.reclevel = INFINITE_RECURSION;
1099       opt.remove_listing = 0;
1100     }
1101   return 1;
1102 }
1103
1104 /* Set progress.type to VAL, but verify that it's a valid progress
1105    implementation before that.  */
1106
1107 static int
1108 cmd_spec_progress (const char *com, const char *val, void *closure)
1109 {
1110   if (!valid_progress_implementation_p (val))
1111     {
1112       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1113                exec_name, com, val);
1114       return 0;
1115     }
1116   xfree_null (opt.progress_type);
1117
1118   /* Don't call set_progress_implementation here.  It will be called
1119      in main() when it becomes clear what the log output is.  */
1120   opt.progress_type = xstrdup (val);
1121   return 1;
1122 }
1123
1124 /* Set opt.recursive to VAL as with cmd_boolean.  If opt.recursive is
1125    set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct
1126    is specified.  */
1127
1128 static int
1129 cmd_spec_recursive (const char *com, const char *val, void *closure)
1130 {
1131   if (!cmd_boolean (com, val, &opt.recursive))
1132     return 0;
1133   else
1134     {
1135       if (opt.recursive && !opt.no_dirstruct)
1136         opt.dirstruct = 1;
1137     }
1138   return 1;
1139 }
1140
1141 static int
1142 cmd_spec_restrict_file_names (const char *com, const char *val, void *closure)
1143 {
1144   int restrict_os = opt.restrict_files_os;
1145   int restrict_ctrl = opt.restrict_files_ctrl;
1146
1147   const char *end = strchr (val, ',');
1148   if (!end)
1149     end = val + strlen (val);
1150
1151 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1152
1153   if (VAL_IS ("unix"))
1154     restrict_os = restrict_unix;
1155   else if (VAL_IS ("windows"))
1156     restrict_os = restrict_windows;
1157   else if (VAL_IS ("nocontrol"))
1158     restrict_ctrl = 0;
1159   else
1160     {
1161     err:
1162       fprintf (stderr,
1163                _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
1164                exec_name, com, val);
1165       return 0;
1166     }
1167
1168 #undef VAL_IS
1169
1170   if (*end)
1171     {
1172       if (!strcmp (end + 1, "nocontrol"))
1173         restrict_ctrl = 0;
1174       else
1175         goto err;
1176     }
1177
1178   opt.restrict_files_os = restrict_os;
1179   opt.restrict_files_ctrl = restrict_ctrl;
1180   return 1;
1181 }
1182
1183 /* Set all three timeout values. */
1184
1185 static int
1186 cmd_spec_timeout (const char *com, const char *val, void *closure)
1187 {
1188   double value;
1189   if (!cmd_time (com, val, &value))
1190     return 0;
1191   opt.read_timeout = value;
1192   opt.connect_timeout = value;
1193   opt.dns_timeout = value;
1194   return 1;
1195 }
1196
1197 static int
1198 cmd_spec_useragent (const char *com, const char *val, void *closure)
1199 {
1200   /* Just check for empty string and newline, so we don't throw total
1201      junk to the server.  */
1202   if (!*val || strchr (val, '\n'))
1203     {
1204       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1205                exec_name, com, val);
1206       return 0;
1207     }
1208   opt.useragent = xstrdup (val);
1209   return 1;
1210 }
1211 \f
1212 /* Miscellaneous useful routines.  */
1213
1214 /* A very simple atoi clone, more portable than strtol and friends,
1215    but reports errors, unlike atoi.  Returns 1 on success, 0 on
1216    failure.  In case of success, stores result to *DEST.  */
1217
1218 static int
1219 simple_atoi (const char *beg, const char *end, int *dest)
1220 {
1221   int result = 0;
1222   const char *p;
1223
1224   if (beg == end)
1225     return 0;
1226
1227   for (p = beg; p < end && ISDIGIT (*p); p++)
1228     result = (10 * result) + (*p - '0');
1229
1230   if (p != end)
1231     return 0;
1232
1233   *dest = result;
1234   return 1;
1235 }
1236
1237 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1238    doesn't handle exponential notation.  Returns 1 on success, 0 on
1239    failure.  In case of success, stores its result to *DEST.  */
1240
1241 static int
1242 simple_atof (const char *beg, const char *end, double *dest)
1243 {
1244   double result = 0;
1245
1246   int seen_dot = 0;
1247   int seen_digit = 0;
1248   double divider = 1;
1249
1250   const char *p;
1251
1252   for (p = beg; p < end; p++)
1253     {
1254       char ch = *p;
1255       if (ISDIGIT (ch))
1256         {
1257           if (!seen_dot)
1258             result = (10 * result) + (ch - '0');
1259           else
1260             result += (ch - '0') / (divider *= 10);
1261           seen_digit = 1;
1262         }
1263       else if (ch == '.')
1264         {
1265           if (!seen_dot)
1266             seen_dot = 1;
1267           else
1268             return 0;
1269         }
1270       else
1271         return 0;
1272     }
1273   if (!seen_digit)
1274     return 0;
1275
1276   *dest = result;
1277   return 1;
1278 }
1279
1280 static int
1281 check_user_specified_header (const char *s)
1282 {
1283   const char *p;
1284
1285   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1286   /* The header MUST contain `:' preceded by at least one
1287      non-whitespace character.  */
1288   if (*p != ':' || p == s)
1289     return 0;
1290   /* The header MUST NOT contain newlines.  */
1291   if (strchr (s, '\n'))
1292     return 0;
1293   return 1;
1294 }
1295 \f
1296 void cleanup_html_url PARAMS ((void));
1297 void res_cleanup PARAMS ((void));
1298 void downloaded_files_free PARAMS ((void));
1299 void http_cleanup PARAMS ((void));
1300
1301
1302 /* Free the memory allocated by global variables.  */
1303 void
1304 cleanup (void)
1305 {
1306   /* Free external resources, close files, etc. */
1307
1308   if (opt.dfp)
1309     fclose (opt.dfp);
1310
1311   /* We're exiting anyway so there's no real need to call free()
1312      hundreds of times.  Skipping the frees will make Wget exit
1313      faster.
1314
1315      However, when detecting leaks, it's crucial to free() everything
1316      because then you can find the real leaks, i.e. the allocated
1317      memory which grows with the size of the program.  */
1318
1319 #ifdef DEBUG_MALLOC
1320   convert_cleanup ();
1321   res_cleanup ();
1322   http_cleanup ();
1323   cleanup_html_url ();
1324   downloaded_files_free ();
1325   host_cleanup ();
1326   if (wget_cookie_jar)
1327     cookie_jar_delete (wget_cookie_jar);
1328
1329   {
1330     extern acc_t *netrc_list;
1331     free_netrc (netrc_list);
1332   }
1333   xfree_null (opt.lfilename);
1334   xfree_null (opt.dir_prefix);
1335   xfree_null (opt.input_filename);
1336   xfree_null (opt.output_document);
1337   free_vec (opt.accepts);
1338   free_vec (opt.rejects);
1339   free_vec (opt.excludes);
1340   free_vec (opt.includes);
1341   free_vec (opt.domains);
1342   free_vec (opt.follow_tags);
1343   free_vec (opt.ignore_tags);
1344   xfree_null (opt.progress_type);
1345   xfree (opt.ftp_acc);
1346   xfree_null (opt.ftp_pass);
1347   xfree_null (opt.ftp_proxy);
1348   xfree_null (opt.https_proxy);
1349   xfree_null (opt.http_proxy);
1350   free_vec (opt.no_proxy);
1351   xfree_null (opt.useragent);
1352   xfree_null (opt.referer);
1353   xfree_null (opt.http_user);
1354   xfree_null (opt.http_passwd);
1355   xfree_null (opt.user_header);
1356 #ifdef HAVE_SSL
1357   xfree_null (opt.sslcertkey);
1358   xfree_null (opt.sslcertfile);
1359 #endif /* HAVE_SSL */
1360   xfree_null (opt.bind_address);
1361   xfree_null (opt.cookies_input);
1362   xfree_null (opt.cookies_output);
1363 #endif
1364 }