wmclockmon: handle fgets NULL returns and zero-length lines
[dockapps.git] / wmget / configure.c
blob73b44a3f08d5fb1bba6c09439458daf953dee078
1 /*
2 wmget - A background download manager as a Window Maker dock app
3 Copyright (c) 2001-2003 Aaron Trickey <aaron@amtrickey.net>
5 Permission is hereby granted, free of charge, to any person
6 obtaining a copy of this software and associated documentation files
7 (the "Software"), to deal in the Software without restriction,
8 including without limitation the rights to use, copy, modify, merge,
9 publish, distribute, sublicense, and/or sell copies of the Software,
10 and to permit persons to whom the Software is furnished to do so,
11 subject to the following conditions:
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ********************************************************************
25 config.c - Implementation of command-line and RC-file configuration
27 The code in this file parses RC files and command lines and provides
28 defaults for what you don't specify. Used to configure both
29 requests and servers.
32 #include <string.h>
33 #include <malloc.h>
34 #include <ctype.h>
35 #include <getopt.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
40 #include "wmget.h"
46 /* Option characters.
48 #define O(s,l,a,t) optchar_##l = s,
49 enum {
50 #include "config.def"
52 #undef O
56 /***********************************************************************
57 * clear_request(): Initialize an empty Request object.
59 void clear_request (Request *req)
61 req->source_url = 0;
62 req->display = 0;
63 req->save_to = 0;
64 req->overwrite = -1;
65 req->continue_from = -1;
66 req->proxy = 0;
67 req->follow = -1;
68 req->user_agent = 0;
70 req->use_ascii = -1;
71 req->referer = 0;
72 req->include = -1;
73 req->interface = 0;
74 req->proxy_auth = 0;
75 req->auth = 0;
79 static void set_silent ()
81 set_output_level (OL_SILENT);
85 static void set_verbose ()
87 set_output_level (OL_DEBUG);
91 static void set_output (Request *r, ServerConfig *c, const char *value)
93 if (r) r->save_to = value;
94 if (c) {
95 struct stat st;
97 /* For server configuration, we must set the default to an
98 * absolute path.
100 if (value[0] == '/') {
101 if (strlen (value) + 1 > sizeof c->job_defaults.save_to) {
102 error (
103 "Download directory name too long! Defaulting to home directory");
104 strcpy (c->job_defaults.save_to, home_directory ());
105 } else {
106 strcpy (c->job_defaults.save_to, value);
108 } else {
109 if (strlen (value) + strlen (home_directory ()) + 2
110 > sizeof c->job_defaults.save_to) {
111 error (
112 "Download directory name too long! Defaulting to home directory");
113 strcpy (c->job_defaults.save_to, home_directory ());
114 } else {
115 strcpy (c->job_defaults.save_to, home_directory ());
116 strcat (c->job_defaults.save_to, "/");
117 strcat (c->job_defaults.save_to, value);
121 /* And we need to make sure it's really a directory.
123 if ( stat (c->job_defaults.save_to, &st)
124 || !S_ISDIR (st.st_mode)) {
125 error (
126 "``output'' option is not a valid directory! Defaulting to home");
127 strcpy (c->job_defaults.save_to, home_directory ());
133 static void set_display (Request *r, ServerConfig *c, const char *value)
135 if (r) r->display = value;
136 if (c) info ("Cannot set ``display'' option on dockapp");
140 static void set_overwrite (Request *r, ServerConfig *c)
142 if (r) r->overwrite = 1;
143 if (c) c->job_defaults.overwrite = 1;
147 static void set_continue (Request *r, ServerConfig *c)
149 if (r) r->continue_from = 1;
150 if (c) c->job_defaults.continue_from = 1;
154 static void set_proxy (Request *r, ServerConfig *c, const char *value)
156 if (r) r->proxy = value;
157 if (c) STRCPY_TO_ARRAY (c->job_defaults.proxy, value);
161 static void set_follow (Request *r, ServerConfig *c, const char *value)
163 if (r) r->follow = atoi (value);
164 if (c) c->job_defaults.follow = atoi (value);
168 static void set_user_agent (Request *r, ServerConfig *c, const char *v)
170 if (r) r->user_agent = v;
171 if (c) STRCPY_TO_ARRAY (c->job_defaults.user_agent, v);
175 static void set_ascii (Request *r, ServerConfig *c)
177 if (r) r->use_ascii = 1;
178 if (c) c->job_defaults.use_ascii = 1;
182 static void set_referer (Request *r, ServerConfig *c, const char *v)
184 if (r) r->referer = v;
185 if (c) STRCPY_TO_ARRAY (c->job_defaults.referer, v);
189 static void set_headers (Request *r, ServerConfig *c)
191 if (r) r->include = 1;
192 if (c) c->job_defaults.include = 1;
196 static void set_interface (Request *r, ServerConfig *c, const char *v)
198 if (r) r->interface = v;
199 if (c) STRCPY_TO_ARRAY (c->job_defaults.interface, v);
203 static void set_proxy_auth (Request *r, ServerConfig *c, const char *v)
205 if (r) r->proxy_auth = v;
206 if (c) STRCPY_TO_ARRAY (c->job_defaults.proxy_auth, v);
210 static void set_auth (Request *r, ServerConfig *c, const char *v)
212 if (r) r->auth = v;
213 if (c) STRCPY_TO_ARRAY (c->job_defaults.auth, v);
217 /***********************************************************************
218 * load_cmdline(): Parse options from the command line.
220 static int load_cmdline (int argc, char **argv,
221 Request *req, ServerConfig *cfg)
223 int o;
224 static const char shortopts[] = {
225 #define no
226 #define yes , ':'
227 #define O(s,l,a,t) s a,
228 #include "config.def"
229 #undef O
230 #undef no
231 #undef yes
235 static const struct option longopts[] = {
236 #define no no_argument
237 #define yes required_argument
238 #define O(s,l,a,t) { #l, a, 0, s },
239 #include "config.def"
240 #undef O
241 #undef yes
242 #undef no
243 { 0, 0, 0, 0 }
246 while ((o = getopt_long (argc, argv, shortopts, longopts, 0))
247 != EOF) {
248 switch (o) {
249 default:
250 return 1;
252 #define yes , optarg
253 #define no
254 #define O(s,l,a,t) \
255 case optchar_##l: \
256 set_##l (req, cfg a); \
257 break;
258 #include "config.def"
259 #undef O
260 #undef no
261 #undef yes
265 if (optind < argc) {
266 if (req) {
267 if (strlen (argv[optind]) > MAXURL) {
268 error ("URL too long!");
269 } else {
270 req->source_url = argv[optind];
272 ++optind;
275 if (cfg) {
276 if (strcasecmp (argv[optind], "dock") == 0) {
277 /* That's part of the syntax... ignore. */
278 ++optind;
283 if (optind < argc) {
284 error ("Extra argument: '%s'", argv[optind]);
287 return 0;
291 static void read_rcfile (FILE *rcfp, ServerConfig *cfg)
293 char line[MAXRCLINELEN];
295 while (fgets (line, sizeof line, rcfp)) {
296 char *name = 0;
297 char *value = 0;
298 char *value_end = 0;
299 char *tictactoe = strchr (line, '#');
301 if (tictactoe) {
302 *tictactoe = '\0';
305 name = line; /* locate name: */
306 while (*name && isspace (*name)) /* skip leading ws */
307 ++name;
308 if (!*name) { /* no name? skip line */
309 continue;
311 value = name; /* locate value: */
312 while (*value && !isspace (*value)) /* skip name */
313 ++value;
314 if (*value) { /* not eol: look for val */
315 *value++ = '\0'; /* terminate name */
316 while (*value && isspace (*value)) /* skip dividing ws */
317 ++value;
318 value_end = value + strlen (value); /* right-trim */
319 --value_end;
320 while (value_end > value && isspace (*value_end)) {
321 *value_end-- = 0;
326 # define ARG_yes(NAM) \
327 if (!*value) { \
328 error ("Keyword '" #NAM "' in config file is missing " \
329 "its required argument"); \
330 } else { \
331 debug ("set " #NAM " (%s)", value); \
332 set_##NAM (0, cfg, value); \
335 # define ARG_no(NAM) \
336 if (*value) { \
337 error ("Keyword '" #NAM "' in config file has an "\
338 "extra argument: '%s'", value); \
339 } else { \
340 debug ("set " #NAM " <no value>"); \
341 set_##NAM (0, cfg); \
344 # define O(s,l,a,t) \
345 if (strcasecmp (name, #l) == 0) { \
346 ARG_##a (l) \
347 } else
349 # include "config.def"
351 # undef O
352 # undef ARG_yes
353 # undef ARG_no
355 error ("Unknown keyword in config file: %s", name);
360 static void load_rcfile (ServerConfig *cfg)
362 char rcfile[MAXPATHLEN + 1];
363 static const char *rcfile_base = "/.wmgetrc";
364 FILE *rcfp = 0;
366 strcpy (rcfile, home_directory ());
367 if (strlen (rcfile) + strlen (rcfile_base) >= sizeof rcfile) {
368 error ("Your home directory name is too long!");
369 return;
372 strcat (rcfile, rcfile_base);
374 if ((rcfp = fopen (rcfile, "rt"))) {
375 read_rcfile (rcfp, cfg);
376 fclose (rcfp);
377 } else {
378 /* rcfiles are fully optional... */
379 debug_sys ("Could not open rcfile '%s'", rcfile);
384 void config_server (int argc, char **argv, ServerConfig *cfg)
386 /* Default job options: These take effect unless overridden by
387 * server configuration or per-job configuration.
389 cfg->job_defaults.display[0] = 0;
390 STRCPY_TO_ARRAY (cfg->job_defaults.save_to, home_directory ());
391 cfg->job_defaults.overwrite = 0;
392 cfg->job_defaults.continue_from = 0;
393 cfg->job_defaults.proxy[0] = 0;
394 cfg->job_defaults.follow = 5;
395 STRCPY_TO_ARRAY (cfg->job_defaults.user_agent, DEFAULT_USER_AGENT);
397 cfg->job_defaults.use_ascii = 0;
398 cfg->job_defaults.referer[0] = 0;
399 cfg->job_defaults.include = 0;
400 cfg->job_defaults.interface[0] = 0;
401 cfg->job_defaults.proxy_auth[0] = 0;
402 cfg->job_defaults.auth[0] = 0;
404 load_rcfile (cfg);
405 load_cmdline (argc, argv, 0, cfg);
409 void config_request (int argc, char **argv, Request *req)
411 clear_request (req);
413 load_cmdline (argc, argv, req, 0);