source: trunk/essentials/net-misc/wget/src/init.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

File size: 40.1 KB
Line 
1/* Reading/parsing the initialization file.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3
4This file is part of GNU Wget.
5
6GNU Wget is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11GNU Wget is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with Wget; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20In addition, as a special exception, the Free Software Foundation
21gives permission to link the code of its release of Wget with the
22OpenSSL project's "OpenSSL" library (or with modified versions of it
23that use the same license as the "OpenSSL" library), and distribute
24the linked executables. You must obey the GNU General Public License
25in all respects for all of the code used other than "OpenSSL". If you
26modify this file, you may extend this exception to your version of the
27file, but you are not obligated to do so. If you do not wish to do
28so, delete this exception statement from your version. */
29
30#include <config.h>
31
32#include <stdio.h>
33#include <sys/types.h>
34#include <stdlib.h>
35#ifdef HAVE_UNISTD_H
36# include <unistd.h>
37#endif
38#ifdef HAVE_STRING_H
39# include <string.h>
40#else
41# include <strings.h>
42#endif
43#include <errno.h>
44
45#ifdef HAVE_PWD_H
46# include <pwd.h>
47#endif
48#include <assert.h>
49
50#include "wget.h"
51#include "utils.h"
52#include "init.h"
53#include "host.h"
54#include "netrc.h"
55#include "progress.h"
56#include "recur.h" /* for INFINITE_RECURSION */
57#include "convert.h" /* for convert_cleanup */
58#include "res.h" /* for res_cleanup */
59
60#ifndef errno
61extern int errno;
62#endif
63
64/* We want tilde expansion enabled only when reading `.wgetrc' lines;
65 otherwise, it will be performed by the shell. This variable will
66 be set by the wgetrc-reading function. */
67
68static int enable_tilde_expansion;
69
70
71#define CMD_DECLARE(func) static int func \
72 PARAMS ((const char *, const char *, void *))
73
74CMD_DECLARE (cmd_boolean);
75CMD_DECLARE (cmd_bytes);
76CMD_DECLARE (cmd_bytes_sum);
77#ifdef HAVE_SSL
78CMD_DECLARE (cmd_cert_type);
79#endif
80CMD_DECLARE (cmd_directory_vector);
81CMD_DECLARE (cmd_lockable_boolean);
82CMD_DECLARE (cmd_number);
83CMD_DECLARE (cmd_number_inf);
84CMD_DECLARE (cmd_string);
85CMD_DECLARE (cmd_file);
86CMD_DECLARE (cmd_directory);
87CMD_DECLARE (cmd_time);
88CMD_DECLARE (cmd_vector);
89
90CMD_DECLARE (cmd_spec_dirstruct);
91CMD_DECLARE (cmd_spec_header);
92CMD_DECLARE (cmd_spec_htmlify);
93CMD_DECLARE (cmd_spec_mirror);
94CMD_DECLARE (cmd_spec_prefer_family);
95CMD_DECLARE (cmd_spec_progress);
96CMD_DECLARE (cmd_spec_recursive);
97CMD_DECLARE (cmd_spec_restrict_file_names);
98#ifdef HAVE_SSL
99CMD_DECLARE (cmd_spec_secure_protocol);
100#endif
101CMD_DECLARE (cmd_spec_timeout);
102CMD_DECLARE (cmd_spec_useragent);
103
104/* List of recognized commands, each consisting of name, place and
105 function. When adding a new command, simply add it to the list,
106 but be sure to keep the list sorted alphabetically, as
107 command_by_name depends on it. Also, be sure to add any entries
108 that allocate memory (e.g. cmd_string and cmd_vector) to the
109 cleanup() function below. */
110
111static struct {
112 const char *name;
113 void *place;
114 int (*action) PARAMS ((const char *, const char *, void *));
115} commands[] = {
116 { "accept", &opt.accepts, cmd_vector },
117 { "addhostdir", &opt.add_hostdir, cmd_boolean },
118 { "alwaysrest", &opt.always_rest, cmd_boolean }, /* deprecated */
119 { "background", &opt.background, cmd_boolean },
120 { "backupconverted", &opt.backup_converted, cmd_boolean },
121 { "backups", &opt.backups, cmd_number },
122 { "base", &opt.base_href, cmd_string },
123 { "bindaddress", &opt.bind_address, cmd_string },
124#ifdef HAVE_SSL
125 { "cacertificate", &opt.ca_cert, cmd_file },
126#endif
127 { "cache", &opt.allow_cache, cmd_boolean },
128#ifdef HAVE_SSL
129 { "cadirectory", &opt.ca_directory, cmd_directory },
130 { "certificate", &opt.cert_file, cmd_file },
131 { "certificatetype", &opt.cert_type, cmd_cert_type },
132 { "checkcertificate", &opt.check_cert, cmd_boolean },
133#endif
134 { "connecttimeout", &opt.connect_timeout, cmd_time },
135 { "continue", &opt.always_rest, cmd_boolean },
136 { "convertlinks", &opt.convert_links, cmd_boolean },
137 { "cookies", &opt.cookies, cmd_boolean },
138 { "cutdirs", &opt.cut_dirs, cmd_number },
139#ifdef ENABLE_DEBUG
140 { "debug", &opt.debug, cmd_boolean },
141#endif
142 { "deleteafter", &opt.delete_after, cmd_boolean },
143 { "dirprefix", &opt.dir_prefix, cmd_directory },
144 { "dirstruct", NULL, cmd_spec_dirstruct },
145 { "dnscache", &opt.dns_cache, cmd_boolean },
146 { "dnstimeout", &opt.dns_timeout, cmd_time },
147 { "domains", &opt.domains, cmd_vector },
148 { "dotbytes", &opt.dot_bytes, cmd_bytes },
149 { "dotsinline", &opt.dots_in_line, cmd_number },
150 { "dotspacing", &opt.dot_spacing, cmd_number },
151 { "dotstyle", &opt.dot_style, cmd_string },
152#ifdef HAVE_SSL
153 { "egdfile", &opt.egd_file, cmd_file },
154#endif
155 { "excludedirectories", &opt.excludes, cmd_directory_vector },
156 { "excludedomains", &opt.exclude_domains, cmd_vector },
157 { "followftp", &opt.follow_ftp, cmd_boolean },
158 { "followtags", &opt.follow_tags, cmd_vector },
159 { "forcehtml", &opt.force_html, cmd_boolean },
160 { "ftppasswd", &opt.ftp_passwd, cmd_string }, /* deprecated */
161 { "ftppassword", &opt.ftp_passwd, cmd_string },
162 { "ftpproxy", &opt.ftp_proxy, cmd_string },
163 { "ftpuser", &opt.ftp_user, cmd_string },
164 { "glob", &opt.ftp_glob, cmd_boolean },
165 { "header", NULL, cmd_spec_header },
166 { "htmlextension", &opt.html_extension, cmd_boolean },
167 { "htmlify", NULL, cmd_spec_htmlify },
168 { "httpkeepalive", &opt.http_keep_alive, cmd_boolean },
169 { "httppasswd", &opt.http_passwd, cmd_string }, /* deprecated */
170 { "httppassword", &opt.http_passwd, cmd_string },
171 { "httpproxy", &opt.http_proxy, cmd_string },
172 { "httpsproxy", &opt.https_proxy, cmd_string },
173 { "httpuser", &opt.http_user, cmd_string },
174 { "ignorelength", &opt.ignore_length, cmd_boolean },
175 { "ignoretags", &opt.ignore_tags, cmd_vector },
176 { "includedirectories", &opt.includes, cmd_directory_vector },
177#ifdef ENABLE_IPV6
178 { "inet4only", &opt.ipv4_only, cmd_boolean },
179 { "inet6only", &opt.ipv6_only, cmd_boolean },
180#endif
181 { "input", &opt.input_filename, cmd_file },
182 { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
183 { "limitrate", &opt.limit_rate, cmd_bytes },
184 { "loadcookies", &opt.cookies_input, cmd_file },
185 { "logfile", &opt.lfilename, cmd_file },
186 { "login", &opt.ftp_user, cmd_string },/* deprecated*/
187 { "mirror", NULL, cmd_spec_mirror },
188 { "netrc", &opt.netrc, cmd_boolean },
189 { "noclobber", &opt.noclobber, cmd_boolean },
190 { "noparent", &opt.no_parent, cmd_boolean },
191 { "noproxy", &opt.no_proxy, cmd_vector },
192 { "numtries", &opt.ntry, cmd_number_inf },/* deprecated*/
193 { "outputdocument", &opt.output_document, cmd_file },
194 { "pagerequisites", &opt.page_requisites, cmd_boolean },
195 { "passiveftp", &opt.ftp_pasv, cmd_lockable_boolean },
196 { "passwd", &opt.ftp_passwd, cmd_string },/* deprecated*/
197 { "password", &opt.passwd, cmd_string },
198 { "postdata", &opt.post_data, cmd_string },
199 { "postfile", &opt.post_file_name, cmd_file },
200 { "preferfamily", NULL, cmd_spec_prefer_family },
201 { "preservepermissions", &opt.preserve_perm, cmd_boolean },
202#ifdef HAVE_SSL
203 { "privatekey", &opt.private_key, cmd_file },
204 { "privatekeytype", &opt.private_key_type, cmd_cert_type },
205#endif
206 { "progress", &opt.progress_type, cmd_spec_progress },
207 { "protocoldirectories", &opt.protocol_directories, cmd_boolean },
208 { "proxypasswd", &opt.proxy_passwd, cmd_string }, /* deprecated */
209 { "proxypassword", &opt.proxy_passwd, cmd_string },
210 { "proxyuser", &opt.proxy_user, cmd_string },
211 { "quiet", &opt.quiet, cmd_boolean },
212 { "quota", &opt.quota, cmd_bytes_sum },
213#ifdef HAVE_SSL
214 { "randomfile", &opt.random_file, cmd_file },
215#endif
216 { "randomwait", &opt.random_wait, cmd_boolean },
217 { "readtimeout", &opt.read_timeout, cmd_time },
218 { "reclevel", &opt.reclevel, cmd_number_inf },
219 { "recursive", NULL, cmd_spec_recursive },
220 { "referer", &opt.referer, cmd_string },
221 { "reject", &opt.rejects, cmd_vector },
222 { "relativeonly", &opt.relative_only, cmd_boolean },
223 { "removelisting", &opt.remove_listing, cmd_boolean },
224 { "restrictfilenames", NULL, cmd_spec_restrict_file_names },
225 { "retrsymlinks", &opt.retr_symlinks, cmd_boolean },
226 { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
227 { "robots", &opt.use_robots, cmd_boolean },
228 { "savecookies", &opt.cookies_output, cmd_file },
229 { "saveheaders", &opt.save_headers, cmd_boolean },
230#ifdef HAVE_SSL
231 { "secureprotocol", &opt.secure_protocol, cmd_spec_secure_protocol },
232#endif
233 { "serverresponse", &opt.server_response, cmd_boolean },
234 { "spanhosts", &opt.spanhost, cmd_boolean },
235 { "spider", &opt.spider, cmd_boolean },
236 { "strictcomments", &opt.strict_comments, cmd_boolean },
237 { "timeout", NULL, cmd_spec_timeout },
238 { "timestamping", &opt.timestamping, cmd_boolean },
239 { "tries", &opt.ntry, cmd_number_inf },
240 { "useproxy", &opt.use_proxy, cmd_boolean },
241 { "user", &opt.user, cmd_string },
242 { "useragent", NULL, cmd_spec_useragent },
243 { "verbose", &opt.verbose, cmd_boolean },
244 { "wait", &opt.wait, cmd_time },
245 { "waitretry", &opt.waitretry, cmd_time }
246};
247
248/* Look up CMDNAME in the commands[] and return its position in the
249 array. If CMDNAME is not found, return -1. */
250
251static int
252command_by_name (const char *cmdname)
253{
254 /* Use binary search for speed. Wget has ~100 commands, which
255 guarantees a worst case performance of 7 string comparisons. */
256 int lo = 0, hi = countof (commands) - 1;
257
258 while (lo <= hi)
259 {
260 int mid = (lo + hi) >> 1;
261 int cmp = strcasecmp (cmdname, commands[mid].name);
262 if (cmp < 0)
263 hi = mid - 1;
264 else if (cmp > 0)
265 lo = mid + 1;
266 else
267 return mid;
268 }
269 return -1;
270}
271
272
273/* Reset the variables to default values. */
274static void
275defaults (void)
276{
277 char *tmp;
278
279 /* Most of the default values are 0. Just reset everything, and
280 fill in the non-zero values. Note that initializing pointers to
281 NULL this way is technically illegal, but porting Wget to a
282 machine where NULL is not all-zero bit pattern will be the least
283 of the implementors' worries. */
284 xzero (opt);
285
286 opt.cookies = 1;
287 opt.verbose = -1;
288 opt.ntry = 20;
289 opt.reclevel = 5;
290 opt.add_hostdir = 1;
291 opt.netrc = 1;
292 opt.ftp_glob = 1;
293 opt.htmlify = 1;
294 opt.http_keep_alive = 1;
295 opt.use_proxy = 1;
296 tmp = getenv ("no_proxy");
297 if (tmp)
298 opt.no_proxy = sepstring (tmp);
299 opt.allow_cache = 1;
300
301 opt.read_timeout = 900;
302 opt.use_robots = 1;
303
304 opt.remove_listing = 1;
305
306 opt.dot_bytes = 1024;
307 opt.dot_spacing = 10;
308 opt.dots_in_line = 50;
309
310 opt.dns_cache = 1;
311 opt.ftp_pasv = 1;
312
313#ifdef HAVE_SSL
314 opt.check_cert = 1;
315#endif
316
317 /* The default for file name restriction defaults to the OS type. */
318#if !defined(WINDOWS) && !defined(__CYGWIN__)
319 opt.restrict_files_os = restrict_unix;
320#else
321 opt.restrict_files_os = restrict_windows;
322#endif
323 opt.restrict_files_ctrl = 1;
324}
325
326
327/* Return the user's home directory (strdup-ed), or NULL if none is
328 found. */
329char *
330home_dir (void)
331{
332 char *home = getenv ("HOME");
333
334 if (!home)
335 {
336#ifndef WINDOWS
337 /* If HOME is not defined, try getting it from the password
338 file. */
339 struct passwd *pwd = getpwuid (getuid ());
340 if (!pwd || !pwd->pw_dir)
341 return NULL;
342 home = pwd->pw_dir;
343#else /* WINDOWS */
344 /* Under Windows, if $HOME isn't defined, use the directory where
345 `wget.exe' resides. */
346 home = ws_mypath ();
347#endif /* WINDOWS */
348 }
349
350 return home ? xstrdup (home) : NULL;
351}
352
353/* Return the path to the user's .wgetrc. This is either the value of
354 `WGETRC' environment variable, or `$HOME/.wgetrc'.
355
356 If the `WGETRC' variable exists but the file does not exist, the
357 function will exit(). */
358static char *
359wgetrc_file_name (void)
360{
361 char *env, *home;
362 char *file = NULL;
363
364 /* Try the environment. */
365 env = getenv ("WGETRC");
366 if (env && *env)
367 {
368 if (!file_exists_p (env))
369 {
370 fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
371 exec_name, env);
372 exit (1);
373 }
374 return xstrdup (env);
375 }
376
377 /* If that failed, try $HOME/.wgetrc. */
378 home = home_dir ();
379 if (home)
380 file = aprintf ("%s/.wgetrc", home);
381 xfree_null (home);
382
383#ifdef WINDOWS
384 /* Under Windows, if we still haven't found .wgetrc, look for the file
385 `wget.ini' in the directory where `wget.exe' resides; we do this for
386 backward compatibility with previous versions of Wget.
387 SYSTEM_WGETRC should not be defined under WINDOWS. */
388 if (!file || !file_exists_p (file))
389 {
390 xfree_null (file);
391 file = NULL;
392 home = ws_mypath ();
393 if (home)
394 file = aprintf ("%s/wget.ini", home);
395 }
396#endif /* WINDOWS */
397
398 if (!file)
399 return NULL;
400 if (!file_exists_p (file))
401 {
402 xfree (file);
403 return NULL;
404 }
405 return file;
406}
407
408/* Return values of parse_line. */
409enum parse_line {
410 line_ok,
411 line_empty,
412 line_syntax_error,
413 line_unknown_command
414};
415
416static enum parse_line parse_line PARAMS ((const char *, char **,
417 char **, int *));
418static int setval_internal PARAMS ((int, const char *, const char *));
419
420/* Initialize variables from a wgetrc file. Returns zero (failure) if
421 there were errors in the file. */
422
423static int
424run_wgetrc (const char *file)
425{
426 FILE *fp;
427 char *line;
428 int ln;
429 int errcnt = 0;
430
431 fp = fopen (file, "rb");
432 if (!fp)
433 {
434 fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
435 file, strerror (errno));
436 return 1; /* not a fatal error */
437 }
438 enable_tilde_expansion = 1;
439 ln = 1;
440 while ((line = read_whole_line (fp)) != NULL)
441 {
442 char *com = NULL, *val = NULL;
443 int comind;
444
445 /* Parse the line. */
446 switch (parse_line (line, &com, &val, &comind))
447 {
448 case line_ok:
449 /* If everything is OK, set the value. */
450 if (!setval_internal (comind, com, val))
451 {
452 fprintf (stderr, _("%s: Error in %s at line %d.\n"),
453 exec_name, file, ln);
454 ++errcnt;
455 }
456 break;
457 case line_syntax_error:
458 fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
459 exec_name, file, ln);
460 ++errcnt;
461 break;
462 case line_unknown_command:
463 fprintf (stderr, _("%s: Unknown command `%s' in %s at line %d.\n"),
464 exec_name, com, file, ln);
465 ++errcnt;
466 break;
467 case line_empty:
468 break;
469 default:
470 abort ();
471 }
472 xfree_null (com);
473 xfree_null (val);
474 xfree (line);
475 ++ln;
476 }
477 enable_tilde_expansion = 0;
478 fclose (fp);
479
480 return errcnt == 0;
481}
482
483/* Initialize the defaults and run the system wgetrc and user's own
484 wgetrc. */
485void
486initialize (void)
487{
488 char *file;
489 int ok = 1;
490
491 /* Load the hard-coded defaults. */
492 defaults ();
493
494 /* If SYSTEM_WGETRC is defined, use it. */
495#ifdef SYSTEM_WGETRC
496 if (file_exists_p (SYSTEM_WGETRC))
497 ok &= run_wgetrc (SYSTEM_WGETRC);
498#endif
499 /* Override it with your own, if one exists. */
500 file = wgetrc_file_name ();
501 if (!file)
502 return;
503 /* #### We should canonicalize `file' and SYSTEM_WGETRC with
504 something like realpath() before comparing them with `strcmp' */
505#ifdef SYSTEM_WGETRC
506 if (!strcmp (file, SYSTEM_WGETRC))
507 {
508 fprintf (stderr, _("\
509%s: Warning: Both system and user wgetrc point to `%s'.\n"),
510 exec_name, file);
511 }
512 else
513#endif
514 ok &= run_wgetrc (file);
515
516 /* If there were errors processing either `.wgetrc', abort. */
517 if (!ok)
518 exit (2);
519
520 xfree (file);
521 return;
522}
523
524
525/* Remove dashes and underscores from S, modifying S in the
526 process. */
527
528static void
529dehyphen (char *s)
530{
531 char *t = s; /* t - tortoise */
532 char *h = s; /* h - hare */
533 while (*h)
534 if (*h == '_' || *h == '-')
535 ++h;
536 else
537 *t++ = *h++;
538 *t = '\0';
539}
540
541/* Parse the line pointed by line, with the syntax:
542 <sp>* command <sp>* = <sp>* value <sp>*
543 Uses malloc to allocate space for command and value.
544 If the line is invalid, data is freed and 0 is returned.
545
546 Returns one of line_ok, line_empty, line_syntax_error, or
547 line_unknown_command.
548
549 In case of line_ok, *COM and *VAL point to freshly allocated
550 strings, and *COMIND points to com's index. In case of error or
551 empty line, their values are unmodified. */
552
553static enum parse_line
554parse_line (const char *line, char **com, char **val, int *comind)
555{
556 const char *p;
557 const char *end = line + strlen (line);
558 const char *cmdstart, *cmdend;
559 const char *valstart, *valend;
560
561 char *cmdcopy;
562 int ind;
563
564 /* Skip leading and trailing whitespace. */
565 while (*line && ISSPACE (*line))
566 ++line;
567 while (end > line && ISSPACE (end[-1]))
568 --end;
569
570 /* Skip empty lines and comments. */
571 if (!*line || *line == '#')
572 return line_empty;
573
574 p = line;
575
576 cmdstart = p;
577 while (p < end && (ISALNUM (*p) || *p == '_' || *p == '-'))
578 ++p;
579 cmdend = p;
580
581 /* Skip '=', as well as any space before or after it. */
582 while (p < end && ISSPACE (*p))
583 ++p;
584 if (p == end || *p != '=')
585 return line_syntax_error;
586 ++p;
587 while (p < end && ISSPACE (*p))
588 ++p;
589
590 valstart = p;
591 valend = end;
592
593 /* The syntax is valid (even though the command might not be). Fill
594 in the command name and value. */
595 *com = strdupdelim (cmdstart, cmdend);
596 *val = strdupdelim (valstart, valend);
597
598 /* The line now known to be syntactically correct. Check whether
599 the command is valid. */
600 BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
601 dehyphen (cmdcopy);
602 ind = command_by_name (cmdcopy);
603 if (ind == -1)
604 return line_unknown_command;
605
606 /* Report success to the caller. */
607 *comind = ind;
608 return line_ok;
609}
610
611/* Run commands[comind].action. */
612
613static int
614setval_internal (int comind, const char *com, const char *val)
615{
616 assert (0 <= comind && comind < countof (commands));
617 DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
618 return ((*commands[comind].action) (com, val, commands[comind].place));
619}
620
621/* Run command COM with value VAL. If running the command produces an
622 error, report the error and exit.
623
624 This is intended to be called from main() to modify Wget's behavior
625 through command-line switches. Since COM is hard-coded in main(),
626 it is not canonicalized, and this aborts when COM is not found.
627
628 If COMIND's are exported to init.h, this function will be changed
629 to accept COMIND directly. */
630
631void
632setoptval (const char *com, const char *val, const char *optname)
633{
634 /* Prepend "--" to OPTNAME. */
635 char *dd_optname = (char *) alloca (2 + strlen (optname) + 1);
636 dd_optname[0] = '-';
637 dd_optname[1] = '-';
638 strcpy (dd_optname + 2, optname);
639
640 assert (val != NULL);
641 if (!setval_internal (command_by_name (com), dd_optname, val))
642 exit (2);
643}
644
645/* Parse OPT into command and value and run it. For example,
646 run_command("foo=bar") is equivalent to setoptval("foo", "bar").
647 This is used by the `--execute' flag in main.c. */
648
649void
650run_command (const char *opt)
651{
652 char *com, *val;
653 int comind;
654 switch (parse_line (opt, &com, &val, &comind))
655 {
656 case line_ok:
657 if (!setval_internal (comind, com, val))
658 exit (2);
659 xfree (com);
660 xfree (val);
661 break;
662 default:
663 fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
664 exec_name, opt);
665 exit (2);
666 }
667}
668
669
670/* Generic helper functions, for use with `commands'. */
671
672/* Forward declarations: */
673struct decode_item {
674 const char *name;
675 int code;
676};
677static int decode_string PARAMS ((const char *, const struct decode_item *,
678 int, int *));
679static int simple_atoi PARAMS ((const char *, const char *, int *));
680static int simple_atof PARAMS ((const char *, const char *, double *));
681
682#define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
683
684#define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0) \
685 && TOLOWER((p)[1]) == (c1) \
686 && (p)[2] == '\0')
687
688#define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0) \
689 && TOLOWER((p)[1]) == (c1) \
690 && TOLOWER((p)[2]) == (c2) \
691 && (p)[3] == '\0')
692
693
694/* Store the boolean value from VAL to PLACE. COM is ignored,
695 except for error messages. */
696static int
697cmd_boolean (const char *com, const char *val, void *place)
698{
699 int bool_value;
700
701 if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
702 /* "on", "yes" and "1" mean true. */
703 bool_value = 1;
704 else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
705 /* "off", "no" and "0" mean false. */
706 bool_value = 0;
707 else
708 {
709 fprintf (stderr,
710 _("%s: %s: Invalid boolean `%s'; use `on' or `off'.\n"),
711 exec_name, com, val);
712 return 0;
713 }
714
715 *(int *)place = bool_value;
716 return 1;
717}
718
719/* Store the lockable_boolean {2, 1, 0, -1} value from VAL to PLACE.
720 COM is ignored, except for error messages. Values 2 and -1
721 indicate that once defined, the value may not be changed by
722 successive wgetrc files or command-line arguments.
723
724 Values: 2 - Enable a particular option for good ("always")
725 1 - Enable an option ("on")
726 0 - Disable an option ("off")
727 -1 - Disable an option for good ("never")
728
729 #### This hack is currently only used for passive FTP because a
730 contributor had broken scripts specify --passive-ftp where he
731 didn't want it. It should be removed because the same can now be
732 achieved by replacing the wget executable with a script containing:
733
734 exec wget "$@" --no-passive-ftp
735*/
736
737static int
738cmd_lockable_boolean (const char *com, const char *val, void *place)
739{
740 int lockable_boolean_value;
741
742 int oldval = *(int *)place;
743
744 /*
745 * If a config file said "always" or "never", don't allow command line
746 * arguments to override the config file.
747 */
748 if (oldval == -1 || oldval == 2)
749 return 1;
750
751 if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
752 lockable_boolean_value = 1;
753 else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
754 lockable_boolean_value = 0;
755 else if (0 == strcasecmp (val, "always"))
756 lockable_boolean_value = 2;
757 else if (0 == strcasecmp (val, "never"))
758 lockable_boolean_value = -1;
759 else
760 {
761 fprintf (stderr,
762 _("%s: %s: Invalid extended boolean `%s';\n\
763use one of `on', `off', `always', or `never'.\n"),
764 exec_name, com, val);
765 return 0;
766 }
767
768 *(int *)place = lockable_boolean_value;
769 return 1;
770}
771
772/* Set the non-negative integer value from VAL to PLACE. With
773 incorrect specification, the number remains unchanged. */
774static int
775cmd_number (const char *com, const char *val, void *place)
776{
777 if (!simple_atoi (val, val + strlen (val), place)
778 || *(int *) place < 0)
779 {
780 fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
781 exec_name, com, val);
782 return 0;
783 }
784 return 1;
785}
786
787/* Similar to cmd_number(), only accepts `inf' as a synonym for 0. */
788static int
789cmd_number_inf (const char *com, const char *val, void *place)
790{
791 if (!strcasecmp (val, "inf"))
792 {
793 *(int *)place = 0;
794 return 1;
795 }
796 return cmd_number (com, val, place);
797}
798
799/* Copy (strdup) the string at COM to a new location and place a
800 pointer to *PLACE. */
801static int
802cmd_string (const char *com, const char *val, void *place)
803{
804 char **pstring = (char **)place;
805
806 xfree_null (*pstring);
807 *pstring = xstrdup (val);
808 return 1;
809}
810
811#ifndef WINDOWS
812# define ISSEP(c) ((c) == '/')
813#else
814# define ISSEP(c) ((c) == '/' || (c) == '\\')
815#endif
816
817/* Like the above, but handles tilde-expansion when reading a user's
818 `.wgetrc'. In that case, and if VAL begins with `~', the tilde
819 gets expanded to the user's home directory. */
820static int
821cmd_file (const char *com, const char *val, void *place)
822{
823 char **pstring = (char **)place;
824
825 xfree_null (*pstring);
826
827 /* #### If VAL is empty, perhaps should set *PLACE to NULL. */
828
829 if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
830 {
831 noexpand:
832 *pstring = xstrdup (val);
833 }
834 else
835 {
836 int homelen;
837 char *home = home_dir ();
838 if (!home)
839 goto noexpand;
840
841 homelen = strlen (home);
842 while (homelen && ISSEP (home[homelen - 1]))
843 home[--homelen] = '\0';
844
845 /* Skip the leading "~/". */
846 for (++val; ISSEP (*val); val++)
847 ;
848
849 *pstring = concat_strings (home, "/", val, (char *) 0);
850 }
851
852#ifdef WINDOWS
853 /* Convert "\" to "/". */
854 {
855 char *s;
856 for (s = *pstring; *s; s++)
857 if (*s == '\\')
858 *s = '/';
859 }
860#endif
861 return 1;
862}
863
864/* Like cmd_file, but strips trailing '/' characters. */
865static int
866cmd_directory (const char *com, const char *val, void *place)
867{
868 char *s, *t;
869
870 /* Call cmd_file() for tilde expansion and separator
871 canonicalization (backslash -> slash under Windows). These
872 things should perhaps be in a separate function. */
873 if (!cmd_file (com, val, place))
874 return 0;
875
876 s = *(char **)place;
877 t = s + strlen (s);
878 while (t > s && *--t == '/')
879 *t = '\0';
880
881 return 1;
882}
883
884/* Split VAL by space to a vector of values, and append those values
885 to vector pointed to by the PLACE argument. If VAL is empty, the
886 PLACE vector is cleared instead. */
887
888static int
889cmd_vector (const char *com, const char *val, void *place)
890{
891 char ***pvec = (char ***)place;
892
893 if (*val)
894 *pvec = merge_vecs (*pvec, sepstring (val));
895 else
896 {
897 free_vec (*pvec);
898 *pvec = NULL;
899 }
900 return 1;
901}
902
903static int
904cmd_directory_vector (const char *com, const char *val, void *place)
905{
906 char ***pvec = (char ***)place;
907
908 if (*val)
909 {
910 /* Strip the trailing slashes from directories. */
911 char **t, **seps;
912
913 seps = sepstring (val);
914 for (t = seps; t && *t; t++)
915 {
916 int len = strlen (*t);
917 /* Skip degenerate case of root directory. */
918 if (len > 1)
919 {
920 if ((*t)[len - 1] == '/')
921 (*t)[len - 1] = '\0';
922 }
923 }
924 *pvec = merge_vecs (*pvec, seps);
925 }
926 else
927 {
928 free_vec (*pvec);
929 *pvec = NULL;
930 }
931 return 1;
932}
933
934/* Engine for cmd_bytes and cmd_bytes_sum: converts a string such as
935 "100k" or "2.5G" to a floating point number. */
936
937static int
938parse_bytes_helper (const char *val, double *result)
939{
940 double number, mult;
941 const char *end = val + strlen (val);
942
943 /* Check for "inf". */
944 if (0 == strcmp (val, "inf"))
945 {
946 *result = 0;
947 return 1;
948 }
949
950 /* Strip trailing whitespace. */
951 while (val < end && ISSPACE (end[-1]))
952 --end;
953 if (val == end)
954 return 0;
955
956 switch (TOLOWER (end[-1]))
957 {
958 case 'k':
959 --end, mult = 1024.0;
960 break;
961 case 'm':
962 --end, mult = 1048576.0;
963 break;
964 case 'g':
965 --end, mult = 1073741824.0;
966 break;
967 case 't':
968 --end, mult = 1099511627776.0;
969 break;
970 default:
971 /* Not a recognized suffix: assume it's a digit. (If not,
972 simple_atof will raise an error.) */
973 mult = 1;
974 }
975
976 /* Skip leading and trailing whitespace. */
977 while (val < end && ISSPACE (*val))
978 ++val;
979 while (val < end && ISSPACE (end[-1]))
980 --end;
981 if (val == end)
982 return 0;
983
984 if (!simple_atof (val, end, &number) || number < 0)
985 return 0;
986
987 *result = number * mult;
988 return 1;
989}
990
991/* Parse VAL as a number and set its value to PLACE (which should
992 point to a wgint).
993
994 By default, the value is assumed to be in bytes. If "K", "M", or
995 "G" are appended, the value is multiplied with 1<<10, 1<<20, or
996 1<<30, respectively. Floating point values are allowed and are
997 cast to integer before use. The idea is to be able to use things
998 like 1.5k instead of "1536".
999
1000 The string "inf" is returned as 0.
1001
1002 In case of error, 0 is returned and memory pointed to by PLACE
1003 remains unmodified. */
1004
1005static int
1006cmd_bytes (const char *com, const char *val, void *place)
1007{
1008 double byte_value;
1009 if (!parse_bytes_helper (val, &byte_value))
1010 {
1011 fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
1012 exec_name, com, val);
1013 return 0;
1014 }
1015 *(wgint *)place = (wgint)byte_value;
1016 return 1;
1017}
1018
1019/* Like cmd_bytes, but PLACE is interpreted as a pointer to
1020 SIZE_SUM. It works by converting the string to double, therefore
1021 working with values up to 2^53-1 without loss of precision. This
1022 value (8192 TB) is large enough to serve for a while. */
1023
1024static int
1025cmd_bytes_sum (const char *com, const char *val, void *place)
1026{
1027 double byte_value;
1028 if (!parse_bytes_helper (val, &byte_value))
1029 {
1030 fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
1031 exec_name, com, val);
1032 return 0;
1033 }
1034 *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
1035 return 1;
1036}
1037
1038/* Store the value of VAL to *OUT. The value is a time period, by
1039 default expressed in seconds, but also accepting suffixes "m", "h",
1040 "d", and "w" for minutes, hours, days, and weeks respectively. */
1041
1042static int
1043cmd_time (const char *com, const char *val, void *place)
1044{
1045 double number, mult;
1046 const char *end = val + strlen (val);
1047
1048 /* Strip trailing whitespace. */
1049 while (val < end && ISSPACE (end[-1]))
1050 --end;
1051
1052 if (val == end)
1053 {
1054 err:
1055 fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
1056 exec_name, com, val);
1057 return 0;
1058 }
1059
1060 switch (TOLOWER (end[-1]))
1061 {
1062 case 's':
1063 --end, mult = 1; /* seconds */
1064 break;
1065 case 'm':
1066 --end, mult = 60; /* minutes */
1067 break;
1068 case 'h':
1069 --end, mult = 3600; /* hours */
1070 break;
1071 case 'd':
1072 --end, mult = 86400.0; /* days */
1073 break;
1074 case 'w':
1075 --end, mult = 604800.0; /* weeks */
1076 break;
1077 default:
1078 /* Not a recognized suffix: assume it belongs to the number.
1079 (If not, simple_atof will raise an error.) */
1080 mult = 1;
1081 }
1082
1083 /* Skip leading and trailing whitespace. */
1084 while (val < end && ISSPACE (*val))
1085 ++val;
1086 while (val < end && ISSPACE (end[-1]))
1087 --end;
1088 if (val == end)
1089 goto err;
1090
1091 if (!simple_atof (val, end, &number))
1092 goto err;
1093
1094 *(double *)place = number * mult;
1095 return 1;
1096}
1097
1098#ifdef HAVE_SSL
1099static int
1100cmd_cert_type (const char *com, const char *val, void *place)
1101{
1102 static const struct decode_item choices[] = {
1103 { "pem", keyfile_pem },
1104 { "der", keyfile_asn1 },
1105 { "asn1", keyfile_asn1 },
1106 };
1107 int ok = decode_string (val, choices, countof (choices), place);
1108 if (!ok)
1109 fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1110 return ok;
1111}
1112#endif
1113
1114
1115/* Specialized helper functions, used by `commands' to handle some
1116 options specially. */
1117
1118static int check_user_specified_header PARAMS ((const char *));
1119
1120static int
1121cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
1122{
1123 if (!cmd_boolean (com, val, &opt.dirstruct))
1124 return 0;
1125 /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1126 must be affected inversely. */
1127 if (opt.dirstruct)
1128 opt.no_dirstruct = 0;
1129 else
1130 opt.no_dirstruct = 1;
1131 return 1;
1132}
1133
1134static int
1135cmd_spec_header (const char *com, const char *val, void *place_ignored)
1136{
1137 /* Empty value means reset the list of headers. */
1138 if (*val == '\0')
1139 {
1140 free_vec (opt.user_headers);
1141 opt.user_headers = NULL;
1142 return 1;
1143 }
1144
1145 if (!check_user_specified_header (val))
1146 {
1147 fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1148 exec_name, com, val);
1149 return 0;
1150 }
1151 opt.user_headers = vec_append (opt.user_headers, val);
1152 return 1;
1153}
1154
1155static int
1156cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
1157{
1158 int flag = cmd_boolean (com, val, &opt.htmlify);
1159 if (flag && !opt.htmlify)
1160 opt.remove_listing = 0;
1161 return flag;
1162}
1163
1164/* Set the "mirror" mode. It means: recursive download, timestamping,
1165 no limit on max. recursion depth, and don't remove listings. */
1166
1167static int
1168cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
1169{
1170 int mirror;
1171
1172 if (!cmd_boolean (com, val, &mirror))
1173 return 0;
1174 if (mirror)
1175 {
1176 opt.recursive = 1;
1177 if (!opt.no_dirstruct)
1178 opt.dirstruct = 1;
1179 opt.timestamping = 1;
1180 opt.reclevel = INFINITE_RECURSION;
1181 opt.remove_listing = 0;
1182 }
1183 return 1;
1184}
1185
1186/* Validate --prefer-family and set the choice. Allowed values are
1187 "IPv4", "IPv6", and "none". */
1188
1189static int
1190cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
1191{
1192 static const struct decode_item choices[] = {
1193 { "IPv4", prefer_ipv4 },
1194 { "IPv6", prefer_ipv6 },
1195 { "none", prefer_none },
1196 };
1197 int ok = decode_string (val, choices, countof (choices),
1198 (int *) &opt.prefer_family);
1199 if (!ok)
1200 fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1201 return ok;
1202}
1203
1204/* Set progress.type to VAL, but verify that it's a valid progress
1205 implementation before that. */
1206
1207static int
1208cmd_spec_progress (const char *com, const char *val, void *place_ignored)
1209{
1210 if (!valid_progress_implementation_p (val))
1211 {
1212 fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1213 exec_name, com, val);
1214 return 0;
1215 }
1216 xfree_null (opt.progress_type);
1217
1218 /* Don't call set_progress_implementation here. It will be called
1219 in main() when it becomes clear what the log output is. */
1220 opt.progress_type = xstrdup (val);
1221 return 1;
1222}
1223
1224/* Set opt.recursive to VAL as with cmd_boolean. If opt.recursive is
1225 set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct
1226 is specified. */
1227
1228static int
1229cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
1230{
1231 if (!cmd_boolean (com, val, &opt.recursive))
1232 return 0;
1233 else
1234 {
1235 if (opt.recursive && !opt.no_dirstruct)
1236 opt.dirstruct = 1;
1237 }
1238 return 1;
1239}
1240
1241static int
1242cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
1243{
1244 int restrict_os = opt.restrict_files_os;
1245 int restrict_ctrl = opt.restrict_files_ctrl;
1246
1247 const char *end = strchr (val, ',');
1248 if (!end)
1249 end = val + strlen (val);
1250
1251#define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1252
1253 if (VAL_IS ("unix"))
1254 restrict_os = restrict_unix;
1255 else if (VAL_IS ("windows"))
1256 restrict_os = restrict_windows;
1257 else if (VAL_IS ("nocontrol"))
1258 restrict_ctrl = 0;
1259 else
1260 {
1261 err:
1262 fprintf (stderr,
1263 _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
1264 exec_name, com, val);
1265 return 0;
1266 }
1267
1268#undef VAL_IS
1269
1270 if (*end)
1271 {
1272 if (!strcmp (end + 1, "nocontrol"))
1273 restrict_ctrl = 0;
1274 else
1275 goto err;
1276 }
1277
1278 opt.restrict_files_os = restrict_os;
1279 opt.restrict_files_ctrl = restrict_ctrl;
1280 return 1;
1281}
1282
1283#ifdef HAVE_SSL
1284static int
1285cmd_spec_secure_protocol (const char *com, const char *val, void *place)
1286{
1287 static const struct decode_item choices[] = {
1288 { "auto", secure_protocol_auto },
1289 { "sslv2", secure_protocol_sslv2 },
1290 { "sslv3", secure_protocol_sslv3 },
1291 { "tlsv1", secure_protocol_tlsv1 },
1292 };
1293 int ok = decode_string (val, choices, countof (choices), place);
1294 if (!ok)
1295 fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1296 return ok;
1297}
1298#endif
1299
1300/* Set all three timeout values. */
1301
1302static int
1303cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
1304{
1305 double value;
1306 if (!cmd_time (com, val, &value))
1307 return 0;
1308 opt.read_timeout = value;
1309 opt.connect_timeout = value;
1310 opt.dns_timeout = value;
1311 return 1;
1312}
1313
1314static int
1315cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
1316{
1317 /* Disallow embedded newlines. */
1318 if (strchr (val, '\n'))
1319 {
1320 fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1321 exec_name, com, val);
1322 return 0;
1323 }
1324 xfree_null (opt.useragent);
1325 opt.useragent = xstrdup (val);
1326 return 1;
1327}
1328
1329
1330/* Miscellaneous useful routines. */
1331
1332/* A very simple atoi clone, more useful than atoi because it works on
1333 delimited strings, and has error reportage. Returns 1 on success,
1334 0 on failure. If successful, stores result to *DEST. */
1335
1336static int
1337simple_atoi (const char *beg, const char *end, int *dest)
1338{
1339 int result = 0;
1340 int negative = 0;
1341 const char *p = beg;
1342
1343 while (p < end && ISSPACE (*p))
1344 ++p;
1345 if (p < end && (*p == '-' || *p == '+'))
1346 {
1347 negative = (*p == '-');
1348 ++p;
1349 }
1350 if (p == end)
1351 return 0;
1352
1353 /* Read negative numbers in a separate loop because the most
1354 negative integer cannot be represented as a positive number. */
1355
1356 if (!negative)
1357 for (; p < end && ISDIGIT (*p); p++)
1358 {
1359 int next = (10 * result) + (*p - '0');
1360 if (next < result)
1361 return 0; /* overflow */
1362 result = next;
1363 }
1364 else
1365 for (; p < end && ISDIGIT (*p); p++)
1366 {
1367 int next = (10 * result) - (*p - '0');
1368 if (next > result)
1369 return 0; /* underflow */
1370 result = next;
1371 }
1372
1373 if (p != end)
1374 return 0;
1375
1376 *dest = result;
1377 return 1;
1378}
1379
1380/* Trivial atof, with error reporting. Handles "<digits>[.<digits>]",
1381 doesn't handle exponential notation. Returns 1 on success, 0 on
1382 failure. In case of success, stores its result to *DEST. */
1383
1384static int
1385simple_atof (const char *beg, const char *end, double *dest)
1386{
1387 double result = 0;
1388
1389 int negative = 0;
1390 int seen_dot = 0;
1391 int seen_digit = 0;
1392 double divider = 1;
1393
1394 const char *p = beg;
1395
1396 while (p < end && ISSPACE (*p))
1397 ++p;
1398 if (p < end && (*p == '-' || *p == '+'))
1399 {
1400 negative = (*p == '-');
1401 ++p;
1402 }
1403
1404 for (; p < end; p++)
1405 {
1406 char ch = *p;
1407 if (ISDIGIT (ch))
1408 {
1409 if (!seen_dot)
1410 result = (10 * result) + (ch - '0');
1411 else
1412 result += (ch - '0') / (divider *= 10);
1413 seen_digit = 1;
1414 }
1415 else if (ch == '.')
1416 {
1417 if (!seen_dot)
1418 seen_dot = 1;
1419 else
1420 return 0;
1421 }
1422 else
1423 return 0;
1424 }
1425 if (!seen_digit)
1426 return 0;
1427 if (negative)
1428 result = -result;
1429
1430 *dest = result;
1431 return 1;
1432}
1433
1434/* Verify that the user-specified header in S is valid. It must
1435 contain a colon preceded by non-white-space characters and must not
1436 contain newlines. */
1437
1438static int
1439check_user_specified_header (const char *s)
1440{
1441 const char *p;
1442
1443 for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1444 /* The header MUST contain `:' preceded by at least one
1445 non-whitespace character. */
1446 if (*p != ':' || p == s)
1447 return 0;
1448 /* The header MUST NOT contain newlines. */
1449 if (strchr (s, '\n'))
1450 return 0;
1451 return 1;
1452}
1453
1454/* Decode VAL into a number, according to ITEMS. */
1455
1456static int
1457decode_string (const char *val, const struct decode_item *items, int itemcount,
1458 int *place)
1459{
1460 int i;
1461 for (i = 0; i < itemcount; i++)
1462 if (0 == strcasecmp (val, items[i].name))
1463 {
1464 *place = items[i].code;
1465 return 1;
1466 }
1467 return 0;
1468}
1469
1470
1471
1472void cleanup_html_url PARAMS ((void));
1473void http_cleanup PARAMS ((void));
1474
1475
1476/* Free the memory allocated by global variables. */
1477void
1478cleanup (void)
1479{
1480 /* Free external resources, close files, etc. */
1481
1482 {
1483 extern FILE *output_stream;
1484 if (output_stream)
1485 fclose (output_stream);
1486 /* No need to check for error because Wget flushes its output (and
1487 checks for errors) after any data arrives. */
1488 }
1489
1490 /* We're exiting anyway so there's no real need to call free()
1491 hundreds of times. Skipping the frees will make Wget exit
1492 faster.
1493
1494 However, when detecting leaks, it's crucial to free() everything
1495 because then you can find the real leaks, i.e. the allocated
1496 memory which grows with the size of the program. */
1497
1498#ifdef DEBUG_MALLOC
1499 convert_cleanup ();
1500 res_cleanup ();
1501 http_cleanup ();
1502 cleanup_html_url ();
1503 host_cleanup ();
1504 log_cleanup ();
1505
1506 {
1507 extern acc_t *netrc_list;
1508 free_netrc (netrc_list);
1509 }
1510 xfree_null (opt.lfilename);
1511 xfree_null (opt.dir_prefix);
1512 xfree_null (opt.input_filename);
1513 xfree_null (opt.output_document);
1514 free_vec (opt.accepts);
1515 free_vec (opt.rejects);
1516 free_vec (opt.excludes);
1517 free_vec (opt.includes);
1518 free_vec (opt.domains);
1519 free_vec (opt.follow_tags);
1520 free_vec (opt.ignore_tags);
1521 xfree_null (opt.progress_type);
1522 xfree_null (opt.ftp_user);
1523 xfree_null (opt.ftp_passwd);
1524 xfree_null (opt.ftp_proxy);
1525 xfree_null (opt.https_proxy);
1526 xfree_null (opt.http_proxy);
1527 free_vec (opt.no_proxy);
1528 xfree_null (opt.useragent);
1529 xfree_null (opt.referer);
1530 xfree_null (opt.http_user);
1531 xfree_null (opt.http_passwd);
1532 free_vec (opt.user_headers);
1533# ifdef HAVE_SSL
1534 xfree_null (opt.cert_file);
1535 xfree_null (opt.private_key);
1536 xfree_null (opt.ca_directory);
1537 xfree_null (opt.ca_cert);
1538 xfree_null (opt.random_file);
1539 xfree_null (opt.egd_file);
1540# endif
1541 xfree_null (opt.bind_address);
1542 xfree_null (opt.cookies_input);
1543 xfree_null (opt.cookies_output);
1544 xfree_null (opt.user);
1545 xfree_null (opt.passwd);
1546#endif /* DEBUG_MALLOC */
1547}
Note: See TracBrowser for help on using the repository browser.