1 | /* Reading/parsing the initialization file.
|
---|
2 | Copyright (C) 2005 Free Software Foundation, Inc.
|
---|
3 |
|
---|
4 | This file is part of GNU Wget.
|
---|
5 |
|
---|
6 | GNU Wget is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2 of the License, or
|
---|
9 | (at your option) any later version.
|
---|
10 |
|
---|
11 | GNU Wget is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with Wget; if not, write to the Free Software
|
---|
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
19 |
|
---|
20 | In addition, as a special exception, the Free Software Foundation
|
---|
21 | gives permission to link the code of its release of Wget with the
|
---|
22 | OpenSSL project's "OpenSSL" library (or with modified versions of it
|
---|
23 | that use the same license as the "OpenSSL" library), and distribute
|
---|
24 | the linked executables. You must obey the GNU General Public License
|
---|
25 | in all respects for all of the code used other than "OpenSSL". If you
|
---|
26 | modify this file, you may extend this exception to your version of the
|
---|
27 | file, but you are not obligated to do so. If you do not wish to do
|
---|
28 | so, 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
|
---|
61 | extern 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 |
|
---|
68 | static int enable_tilde_expansion;
|
---|
69 |
|
---|
70 |
|
---|
71 | #define CMD_DECLARE(func) static int func \
|
---|
72 | PARAMS ((const char *, const char *, void *))
|
---|
73 |
|
---|
74 | CMD_DECLARE (cmd_boolean);
|
---|
75 | CMD_DECLARE (cmd_bytes);
|
---|
76 | CMD_DECLARE (cmd_bytes_sum);
|
---|
77 | #ifdef HAVE_SSL
|
---|
78 | CMD_DECLARE (cmd_cert_type);
|
---|
79 | #endif
|
---|
80 | CMD_DECLARE (cmd_directory_vector);
|
---|
81 | CMD_DECLARE (cmd_lockable_boolean);
|
---|
82 | CMD_DECLARE (cmd_number);
|
---|
83 | CMD_DECLARE (cmd_number_inf);
|
---|
84 | CMD_DECLARE (cmd_string);
|
---|
85 | CMD_DECLARE (cmd_file);
|
---|
86 | CMD_DECLARE (cmd_directory);
|
---|
87 | CMD_DECLARE (cmd_time);
|
---|
88 | CMD_DECLARE (cmd_vector);
|
---|
89 |
|
---|
90 | CMD_DECLARE (cmd_spec_dirstruct);
|
---|
91 | CMD_DECLARE (cmd_spec_header);
|
---|
92 | CMD_DECLARE (cmd_spec_htmlify);
|
---|
93 | CMD_DECLARE (cmd_spec_mirror);
|
---|
94 | CMD_DECLARE (cmd_spec_prefer_family);
|
---|
95 | CMD_DECLARE (cmd_spec_progress);
|
---|
96 | CMD_DECLARE (cmd_spec_recursive);
|
---|
97 | CMD_DECLARE (cmd_spec_restrict_file_names);
|
---|
98 | #ifdef HAVE_SSL
|
---|
99 | CMD_DECLARE (cmd_spec_secure_protocol);
|
---|
100 | #endif
|
---|
101 | CMD_DECLARE (cmd_spec_timeout);
|
---|
102 | CMD_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 |
|
---|
111 | static 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 |
|
---|
251 | static int
|
---|
252 | command_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. */
|
---|
274 | static void
|
---|
275 | defaults (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. */
|
---|
329 | char *
|
---|
330 | home_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(). */
|
---|
358 | static char *
|
---|
359 | wgetrc_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. */
|
---|
409 | enum parse_line {
|
---|
410 | line_ok,
|
---|
411 | line_empty,
|
---|
412 | line_syntax_error,
|
---|
413 | line_unknown_command
|
---|
414 | };
|
---|
415 |
|
---|
416 | static enum parse_line parse_line PARAMS ((const char *, char **,
|
---|
417 | char **, int *));
|
---|
418 | static 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 |
|
---|
423 | static int
|
---|
424 | run_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. */
|
---|
485 | void
|
---|
486 | initialize (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 |
|
---|
528 | static void
|
---|
529 | dehyphen (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 |
|
---|
553 | static enum parse_line
|
---|
554 | parse_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 |
|
---|
613 | static int
|
---|
614 | setval_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 |
|
---|
631 | void
|
---|
632 | setoptval (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 |
|
---|
649 | void
|
---|
650 | run_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: */
|
---|
673 | struct decode_item {
|
---|
674 | const char *name;
|
---|
675 | int code;
|
---|
676 | };
|
---|
677 | static int decode_string PARAMS ((const char *, const struct decode_item *,
|
---|
678 | int, int *));
|
---|
679 | static int simple_atoi PARAMS ((const char *, const char *, int *));
|
---|
680 | static 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. */
|
---|
696 | static int
|
---|
697 | cmd_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 |
|
---|
737 | static int
|
---|
738 | cmd_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\
|
---|
763 | use 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. */
|
---|
774 | static int
|
---|
775 | cmd_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. */
|
---|
788 | static int
|
---|
789 | cmd_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. */
|
---|
801 | static int
|
---|
802 | cmd_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. */
|
---|
820 | static int
|
---|
821 | cmd_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. */
|
---|
865 | static int
|
---|
866 | cmd_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 |
|
---|
888 | static int
|
---|
889 | cmd_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 |
|
---|
903 | static int
|
---|
904 | cmd_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 |
|
---|
937 | static int
|
---|
938 | parse_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 |
|
---|
1005 | static int
|
---|
1006 | cmd_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 |
|
---|
1024 | static int
|
---|
1025 | cmd_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 |
|
---|
1042 | static int
|
---|
1043 | cmd_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
|
---|
1099 | static int
|
---|
1100 | cmd_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 |
|
---|
1118 | static int check_user_specified_header PARAMS ((const char *));
|
---|
1119 |
|
---|
1120 | static int
|
---|
1121 | cmd_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 |
|
---|
1134 | static int
|
---|
1135 | cmd_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 |
|
---|
1155 | static int
|
---|
1156 | cmd_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 |
|
---|
1167 | static int
|
---|
1168 | cmd_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 |
|
---|
1189 | static int
|
---|
1190 | cmd_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 |
|
---|
1207 | static int
|
---|
1208 | cmd_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 |
|
---|
1228 | static int
|
---|
1229 | cmd_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 |
|
---|
1241 | static int
|
---|
1242 | cmd_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
|
---|
1284 | static int
|
---|
1285 | cmd_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 |
|
---|
1302 | static int
|
---|
1303 | cmd_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 |
|
---|
1314 | static int
|
---|
1315 | cmd_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 |
|
---|
1336 | static int
|
---|
1337 | simple_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 |
|
---|
1384 | static int
|
---|
1385 | simple_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 |
|
---|
1438 | static int
|
---|
1439 | check_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 |
|
---|
1456 | static int
|
---|
1457 | decode_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 |
|
---|
1472 | void cleanup_html_url PARAMS ((void));
|
---|
1473 | void http_cleanup PARAMS ((void));
|
---|
1474 |
|
---|
1475 |
|
---|
1476 | /* Free the memory allocated by global variables. */
|
---|
1477 | void
|
---|
1478 | cleanup (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 | }
|
---|