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