1 /*****************************************************************************
2 *
3 * Authors: Michel Eyckmans (MCE) + Stefan De Troch (SDT)
4 *
5 * Content: This file is part of version 2.x of xautolock. It implements
6 * all option and X resource processing support.
7 *
8 * Please send bug reports etc. to mce@scarlet.be.
9 *
10 * --------------------------------------------------------------------------
11 *
12 * Copyright 1990, 1992-1999, 2001-2002, 2004, 2007 by Stefan De Troch and
13 * Michel Eyckmans.
14 *
15 * Versions 2.0 and above of xautolock are available under version 2 of the
16 * GNU GPL. Earlier versions are available under other conditions. For more
17 * information, see the License file.
18 *
19 *****************************************************************************/
20
21 #include "options.h"
22 #include "state.h"
23 #include "miscutil.h"
24 #include "version.h"
25
26 /*
27 * Global option settings. Do not modify outside this file.
28 */
29 const char* locker = LOCKER; /* as it says */
30 const char* nowLocker = LOCKER; /* as it says */
31 const char* notifier = NOTIFIER; /* as it says */
32 const char* killer = KILLER; /* as it says */
33 time_t lockTime = LOCK_MINS; /* as it says */
34 time_t killTime = KILL_MINS; /* as it says */
35 time_t notifyMargin; /* as it says */
36 Bool secure = SECURE; /* as it says */
37 int bellPercent = BELL_PERCENT; /* as it says */
38 unsigned cornerSize = CORNER_SIZE; /* as it says */
39 time_t cornerDelay = CORNER_DELAY; /* as it says */
40 time_t cornerRedelay; /* as it says */
41 Bool notifyLock = False; /* whether to notify the user
42 before locking */
43 Bool useRedelay = False; /* as it says */
44 cornerAction corners[4] = { ca_ignore, ca_ignore, ca_ignore, ca_ignore };
45 /* default cornerActions */
46 Bool resetSaver = False; /* whether to reset the X
47 screensaver */
48 Bool noCloseOut = False; /* whether keep stdout open */
49 Bool noCloseErr = False; /* whether keep stderr open */
50 message messageToSend = msg_none; /* message to send to an
51 already running xautolock */
52 Bool detectSleep = False; /* whether to reset the timers
53 after a (laptop) sleep,
54 i.e. after a big time jump */
55
56 #ifdef VMS
57 struct dsc$descriptor lockerDescr; /* used to fire up the locker */
58 struct dsc$descriptor nowLockerDescr; /* used to fire up the locker */
59 int vmsStatus = 1; /* locker completion status */
60 #endif /* VMS */
61
62 Bool notifierSpecified = False;
63 Bool killerSpecified = False;
64
65 /*
66 * Guess what, these are private.
67 */
68 static Bool killTimeSpecified = False;
69 static Bool redelaySpecified = False;
70 static Bool bellSpecified = False;
71 static Bool dummySpecified;
72
73 static void usage (int exitCode);
74
75 /*
76 * Argument scanning support.
77 */
78 static Bool
getInteger(const char * arg,int * in)79 getInteger (const char* arg, int* in)
80 {
81 char c; /* dummy */
82 return (sscanf (arg, "%d%c", in, &c) == 1);
83 }
84
85 static Bool
getPositive(const char * arg,int * pos)86 getPositive (const char* arg, int* pos)
87 {
88 return getInteger (arg, pos) && *pos >= 0;
89 }
90
91 /*
92 * Option action functions
93 */
94 static Bool
helpAction(Display * d,const char * arg)95 helpAction (Display* d, const char* arg)
96 {
97 usage (EXIT_SUCCESS);
98 return True; /* keep gcc happy */
99 }
100
101 static Bool
versionAction(Display * d,const char * arg)102 versionAction (Display* d, const char* arg)
103 {
104 error2 ("%s : version %s\n", progName, VERSION);
105 exit (EXIT_SUCCESS);
106 return True; /* keep gcc happy */
107 }
108
109 static Bool
lockerAction(Display * d,const char * arg)110 lockerAction (Display* d, const char* arg)
111 {
112 nowLocker = locker = arg;
113 return True;
114 }
115
116 static Bool
nowLockerAction(Display * d,const char * arg)117 nowLockerAction (Display* d, const char* arg)
118 {
119 nowLocker = arg;
120 return True;
121 }
122
123 static Bool
killerAction(Display * d,const char * arg)124 killerAction (Display* d, const char* arg)
125 {
126 killerSpecified = True;
127 killer = arg;
128 return True;
129 }
130
131 static Bool
notifierAction(Display * d,const char * arg)132 notifierAction (Display* d, const char* arg)
133 {
134 notifierSpecified = True;
135 notifier = arg;
136 return True;
137 }
138
139 static Bool
bellAction(Display * d,const char * arg)140 bellAction (Display* d, const char* arg)
141 {
142 bellSpecified = True;
143 return getInteger (arg, &bellPercent);
144 }
145
146 static Bool
cornerSizeAction(Display * d,const char * arg)147 cornerSizeAction (Display* d, const char* arg)
148 {
149 Bool retVal;
150 int tmp;
151
152 if ((retVal = getPositive (arg, &tmp))) /* = intended */
153 {
154 cornerSize = tmp;
155 }
156
157 return retVal;
158 }
159
160 static Bool
cornersAction(Display * d,const char * arg)161 cornersAction (Display* d, const char* arg)
162 {
163 int c;
164
165 if (strlen (arg) != 4) return False;
166
167 for (c = -1; ++c < 4; )
168 {
169 switch (arg[c])
170 {
171 case '0': corners[c] = ca_ignore; continue;
172 case '-': corners[c] = ca_dontLock; continue;
173 case '+': corners[c] = ca_forceLock; continue;
174 default: return False;
175 }
176 }
177
178 return True;
179 }
180
181 #define TIME_ACTION(name,nameSpecified) \
182 static Bool \
183 name##Action (Display* d, const char* arg) \
184 { \
185 Bool retVal; \
186 int tmp = 0; \
187 \
188 if ((retVal = getPositive (arg, &tmp))) /* = intended */ \
189 { \
190 name = (time_t) tmp; \
191 } \
192 \
193 nameSpecified = True; \
194 return retVal; \
195 } \
196
TIME_ACTION(lockTime,dummySpecified)197 TIME_ACTION (lockTime , dummySpecified )
198 TIME_ACTION (killTime , killTimeSpecified)
199 TIME_ACTION (cornerDelay , dummySpecified )
200 TIME_ACTION (cornerRedelay, redelaySpecified )
201 TIME_ACTION (notifyMargin , notifyLock )
202
203 #define notifyAction notifyMarginAction
204
205 #define MESSAGE_ACTION(name) \
206 static Bool \
207 name##Action (Display* d, const char* arg) \
208 { \
209 if (messageToSend) return False; \
210 messageToSend = msg_##name; \
211 return True; \
212 }
213
214 MESSAGE_ACTION (disable )
215 MESSAGE_ACTION (enable )
216 MESSAGE_ACTION (toggle )
217 MESSAGE_ACTION (exit )
218 MESSAGE_ACTION (lockNow )
219 MESSAGE_ACTION (unlockNow)
220 MESSAGE_ACTION (restart )
221
222 #define BOOL_ACTION(name) \
223 static Bool \
224 name##Action (Display* d, const char* arg) \
225 { \
226 return name = True; \
227 }
228
229 BOOL_ACTION (secure )
230 BOOL_ACTION (resetSaver)
231 BOOL_ACTION (noCloseOut)
232 BOOL_ACTION (noCloseErr)
233 BOOL_ACTION (detectSleep)
234
235 static Bool
236 noCloseAction (Display* d, const char* arg)
237 {
238 (void) noCloseOutAction (d, arg);
239 (void) noCloseErrAction (d, arg);
240 return True;
241 }
242
243 /*
244 * Option checking logistics.
245 */
246 #ifndef VMS
247 static void
addExecToCommand(const char ** command)248 addExecToCommand (const char** command)
249 {
250 /*
251 * On UNIX systems, we dont want to have an extra shell process
252 * hanging about all the time while the locker is running, so we
253 * want to insert an `exec' in front of the command. But since
254 * this obviuosly would fail to work correctly if the command
255 * actually consists of multiple ones, we need to look for `;'
256 * characters first. We can only err on the safe side here...
257 */
258 if (!strchr (*command, ';'))
259 {
260 char* tmp;
261 (void) sprintf (tmp = newArray (char, strlen (*command) + 6),
262 "exec %s", *command);
263 *command = tmp;
264 }
265 }
266 #endif /* !VMS */
267
268 static void
lockTimeChecker(Display * d)269 lockTimeChecker (Display* d)
270 {
271 if (lockTime < MIN_LOCK_MINS)
272 {
273 error1 ("Setting lock time to minimum value of %ld minute(s).\n",
274 (long) (lockTime = MIN_LOCK_MINS));
275 }
276 else if (lockTime > MAX_LOCK_MINS)
277 {
278 error1 ("Setting lock time to maximum value of %ld minute(s).\n",
279 (long) (lockTime = MAX_LOCK_MINS));
280 }
281
282 lockTime *= 60; /* convert to seconds */
283 }
284
285 static void
killTimeChecker(Display * d)286 killTimeChecker (Display* d)
287 {
288 if (killTimeSpecified && !killerSpecified)
289 {
290 error0 ("Using -killtime without -killer makes no sense.\n");
291 return;
292 }
293
294 if (killTime < MIN_KILL_MINS)
295 {
296 error1 ("Setting kill time to minimum value of %ld minute(s).\n",
297 (long) (killTime = MIN_KILL_MINS));
298 }
299 else if (killTime > MAX_KILL_MINS)
300 {
301 error1 ("Setting kill time to maximum value of %ld minute(s).\n",
302 (long) (killTime = MAX_KILL_MINS));
303 }
304
305 killTime *= 60; /* convert to seconds */
306 }
307
308 static void
lockerChecker(Display * d)309 lockerChecker (Display* d)
310 {
311 #ifndef VMS
312 addExecToCommand (&locker);
313 #else /* VMS */
314 /*
315 * Translate things to something that VMS knows how to handle.
316 */
317 lockerDescr.dsc$w_length = (unsigned short) strlen (locker);
318 lockerDescr.dsc$b_class = DSC$K_CLASS_S;
319 lockerDescr.dsc$b_dtype = DSC$K_DTYPE_T;
320 lockerDescr.dsc$a_pointer = (char*) locker;
321 #endif /* VMS */
322 }
323
324 static void
nowLockerChecker(Display * d)325 nowLockerChecker (Display* d)
326 {
327 #ifndef VMS
328 addExecToCommand (&nowLocker);
329 #else /* VMS */
330 /*
331 * Translate things to something that VMS knows how to handle.
332 */
333 nowLockerDescr.dsc$w_length = (unsigned short) strlen (now_locker);
334 nowLockerDescr.dsc$b_class = DSC$K_CLASS_S;
335 nowLockerDescr.dsc$b_dtype = DSC$K_DTYPE_T;
336 nowLockerDescr.dsc$a_pointer = (char*) nowLocker;
337 #endif /* VMS */
338 }
339
340 static void
notifierChecker(Display * d)341 notifierChecker (Display* d)
342 {
343 if (strcmp (notifier, ""))
344 {
345 if (!notifyLock)
346 {
347 error0 ("Using -notifier without -notify makes no sense.\n");
348 }
349 #ifndef VMS
350 else
351 {
352 /*
353 * Add an `&' to the notifier command, so that it always gets
354 * run as a background process and things will work out properly
355 * later. The rationale behind this hack is explained elsewhere.
356 */
357 char* tmp;
358 (void) sprintf (tmp = newArray (char, strlen (notifier) + 3),
359 "%s &", notifier);
360 notifier = tmp;
361 }
362 #endif /* !VMS */
363 }
364 }
365
366 static void
killerChecker(Display * d)367 killerChecker (Display* d)
368 {
369 #ifndef VMS
370 if (strcmp (killer, ""))
371 {
372 /*
373 * Add an `&' to the killer command, so that it always gets
374 * run as a background process and things will work out properly
375 * later. The rationale behind this hack is explained elsewhere.
376 */
377 char* tmp;
378 (void) sprintf (tmp = newArray (char, strlen (killer) + 3),
379 "%s &", killer);
380 killer = tmp;
381 }
382 #endif /* !VMS */
383 }
384
385 static void
notifyChecker(Display * d)386 notifyChecker (Display* d)
387 {
388 if ( notifyLock
389 && ( corners[0] == ca_forceLock
390 || corners[1] == ca_forceLock
391 || corners[2] == ca_forceLock
392 || corners[3] == ca_forceLock))
393 {
394 time_t minDelay = MIN (cornerDelay, cornerRedelay);
395
396 if (notifyMargin > minDelay)
397 {
398 error1 ("Notification time reset to %ld second(s).\n",
399 (long) (notifyMargin = minDelay));
400 }
401
402 if (notifyMargin > lockTime / 2)
403 {
404 error1 ("Notification time reset to %ld seconds.\n",
405 (long) (notifyMargin = lockTime / 2));
406 }
407 }
408 }
409
410 static void
bellChecker(Display * d)411 bellChecker (Display* d)
412 {
413 if (bellSpecified)
414 {
415 if (!notifyLock)
416 {
417 error0 ("Using -bell without -notify makes no sense.\n");
418 bellPercent = 0;
419 }
420 else if (notifierSpecified)
421 {
422 error0 ("Using both -bell and -notifier makes no sense.\n");
423 bellPercent = 0;
424 }
425 }
426
427 if ( bellPercent < -100
428 || bellPercent > 100)
429 {
430 error1 ("Bell percentage reset to %d%%.\n",
431 bellPercent = BELL_PERCENT);
432 }
433 }
434
435 static void
cornerSizeChecker(Display * d)436 cornerSizeChecker (Display* d)
437 {
438 int s;
439 Screen* scr;
440 int maxCornerSize;
441
442 for (maxCornerSize = 32000, s = -1; ++s < ScreenCount (d); )
443 {
444 scr = ScreenOfDisplay (d, s);
445
446 if ( maxCornerSize > WidthOfScreen (scr) / 4
447 || maxCornerSize > HeightOfScreen (scr) / 4)
448 {
449 maxCornerSize = MIN (WidthOfScreen (scr), HeightOfScreen (scr)) / 4;
450 }
451 }
452
453 if (cornerSize > maxCornerSize)
454 {
455 error1 ("Corner size reset to %d pixels.\n",
456 cornerSize = maxCornerSize);
457 }
458 }
459
460 static void
cornerReDelayChecker(Display * d)461 cornerReDelayChecker (Display* d)
462 {
463 if (!redelaySpecified)
464 {
465 cornerRedelay = cornerDelay;
466 }
467 }
468
469 /*
470 * The central option table.
471 */
472 typedef Bool (*optAction) (Display*, const char*);
473 typedef void (*optChecker) (Display*);
474
475 static struct
476 {
477 const char* name; /* as it says */
478 XrmOptionKind kind; /* as it says */
479 caddr_t value; /* only for XrmOptionNoArg */
480 optAction action; /* as it says */
481 optChecker checker; /* as it says */
482 } options[] =
483 {
484 {"help" , XrmoptionNoArg , (caddr_t) "",
485 helpAction , (optChecker) 0 },
486 {"version" , XrmoptionNoArg , (caddr_t) "",
487 versionAction , (optChecker) 0 },
488 {"locker" , XrmoptionSepArg, (caddr_t) 0 ,
489 lockerAction , lockerChecker },
490 {"nowlocker" , XrmoptionSepArg, (caddr_t) 0 ,
491 nowLockerAction , nowLockerChecker },
492 {"killer" , XrmoptionSepArg, (caddr_t) 0 ,
493 killerAction , killerChecker },
494 {"notifier" , XrmoptionSepArg, (caddr_t) 0 ,
495 notifierAction , notifierChecker },
496 {"corners" , XrmoptionSepArg, (caddr_t) 0 ,
497 cornersAction , (optChecker) 0 },
498 {"cornersize" , XrmoptionSepArg, (caddr_t) 0 ,
499 cornerSizeAction , cornerSizeChecker },
500 {"cornerdelay" , XrmoptionSepArg, (caddr_t) 0 ,
501 cornerDelayAction , (optChecker) 0 },
502 {"cornerredelay" , XrmoptionSepArg, (caddr_t) 0 ,
503 cornerRedelayAction, cornerReDelayChecker },
504 {"killtime" , XrmoptionSepArg, (caddr_t) 0 ,
505 killTimeAction , killTimeChecker },
506 {"time" , XrmoptionSepArg, (caddr_t) 0 ,
507 lockTimeAction , lockTimeChecker },
508 {"notify" , XrmoptionSepArg, (caddr_t) 0 ,
509 notifyAction , notifyChecker },
510 {"bell" , XrmoptionSepArg, (caddr_t) 0 ,
511 bellAction , bellChecker },
512 {"secure" , XrmoptionNoArg , (caddr_t) "",
513 secureAction , (optChecker) 0 },
514 {"enable" , XrmoptionNoArg , (caddr_t) "",
515 enableAction , (optChecker) 0 },
516 {"disable" , XrmoptionNoArg , (caddr_t) "",
517 disableAction , (optChecker) 0 },
518 {"toggle" , XrmoptionNoArg , (caddr_t) "",
519 toggleAction , (optChecker) 0 },
520 {"exit" , XrmoptionNoArg , (caddr_t) "",
521 exitAction , (optChecker) 0 },
522 {"locknow" , XrmoptionNoArg , (caddr_t) "",
523 lockNowAction , (optChecker) 0 },
524 {"unlocknow" , XrmoptionNoArg , (caddr_t) "",
525 unlockNowAction , (optChecker) 0 },
526 {"restart" , XrmoptionNoArg , (caddr_t) "",
527 restartAction , (optChecker) 0 },
528 {"resetsaver" , XrmoptionNoArg , (caddr_t) "",
529 resetSaverAction , (optChecker) 0 },
530 {"noclose" , XrmoptionNoArg , (caddr_t) "",
531 noCloseAction , (optChecker) 0 },
532 {"nocloseout" , XrmoptionNoArg , (caddr_t) "",
533 noCloseOutAction , (optChecker) 0 },
534 {"nocloseerr" , XrmoptionNoArg , (caddr_t) "",
535 noCloseErrAction , (optChecker) 0 },
536 {"detectsleep" , XrmoptionNoArg , (caddr_t) "",
537 detectSleepAction , (optChecker) 0 },
538 }; /* as it says, the order is important! */
539
540 /*
541 * Have a guess...
542 */
543 static void
usage(int exitCode)544 usage (int exitCode)
545 {
546 /*
547 * The relative overhead is enormous here, but who cares.
548 * I'm a perfectionist and usage() doesn't return anyway.
549 */
550 char* blanks; /* string full of blanks */
551 size_t len; /* number of blanks */
552 len = strlen ("Usage : ") + strlen (progName);
553 (void) memset (blanks = newArray (char, len + 1), ' ', len);
554 blanks[len] = '\0';
555
556 /*
557 * This is where the actual work gets done...
558 */
559 error0 ("\n");
560 error1 ("Usage : %s ", progName);
561 error0 ("[-help][-version][-time mins][-locker locker]\n");
562 error1 ("%s[-killtime mins][-killer killer]\n", blanks);
563 error1 ("%s[-notify margin][-notifier notifier][-bell percent]\n", blanks);
564 error1 ("%s[-corners xxxx][-cornerdelay secs]\n", blanks);
565 error1 ("%s[-cornerredelay secs][-cornersize pixels]\n", blanks);
566 error1 ("%s[-nocloseout][-nocloseerr][-noclose]\n", blanks);
567 error1 ("%s[-enable][-disable][-toggle][-exit][-secure]\n", blanks);
568 error1 ("%s[-locknow][-unlocknow][-nowlocker locker]\n", blanks);
569 error1 ("%s[-restart][-resetsaver][-detectsleep]\n", blanks);
570
571 error0 ("\n");
572 error0 (" -help : print this message and exit.\n");
573 error0 (" -version : print version number and exit.\n");
574 error0 (" -time mins : time before locking the screen");
575 error2 (" [%d <= mins <= %d].\n", MIN_LOCK_MINS, MAX_LOCK_MINS);
576 error0 (" -locker locker : program used to lock.\n");
577 error0 (" -nowlocker locker : program used to lock immediately.\n");
578 error0 (" -killtime killmins : time after locking at which to run\n");
579 error2 (" the killer [%d <= killmins <= %d].\n",
580 MIN_KILL_MINS, MAX_KILL_MINS);
581 error0 (" -killer killer : program used to kill.\n");
582 error0 (" -notify margin : notify this many seconds before locking.\n");
583 error0 (" -notifier notifier : program used to notify.\n");
584 error0 (" -bell percent : loudness of notification beeps.\n");
585 error0 (" -corners xxxx : corner actions (0, +, -) in this order:\n");
586 error0 (" topleft topright bottomleft bottomright\n");
587 error0 (" -cornerdelay secs : time to lock screen in a `+' corner.\n");
588 error0 (" -cornerredelay secs : time to relock screen in a `+' corner.\n");
589 error0 (" -cornersize pixels : size of corner areas.\n");
590 error0 (" -nocloseout : do not close stdout.\n");
591 error0 (" -nocloseerr : do not close stderr.\n");
592 error0 (" -noclose : close neither stdout nor stderr.\n");
593 error0 (" -enable : enable a running xautolock.\n");
594 error0 (" -disable : disable a running xautolock.\n");
595 error0 (" -toggle : toggle a running xautolock.\n");
596 error0 (" -locknow : tell a running xautolock to lock.\n");
597 error0 (" -unlocknow : tell a running xautolock to unlock.\n");
598 error0 (" -restart : tell a running xautolock to restart.\n");
599 error0 (" -exit : kill a running xautolock.\n");
600 error0 (" -secure : ignore enable, disable, toggle, locknow\n");
601 error0 (" unlocknow, and restart messages.\n");
602 error0 (" -resetsaver : reset the screensaver when starting "
603 "the locker.\n");
604 error0 (" -detectsleep : reset timers when awaking from sleep.\n");
605
606 error0 ("\n");
607 error0 ("Defaults :\n");
608
609 error0 ("\n");
610 error1 (" time : %d minutes\n" , LOCK_MINS );
611 error1 (" locker : %s\n" , LOCKER );
612 error1 (" nowlocker : %s\n" , LOCKER );
613 error1 (" killtime : %d minutes\n" , KILL_MINS );
614 error0 (" killer : none\n" );
615 error0 (" notify : don't notify\n" );
616 error0 (" notifier : none\n" );
617 error1 (" bell : %d%%\n" , BELL_PERCENT);
618 error0 (" corners : 0000\n" );
619 error1 (" cornerdelay : %d seconds\n" , CORNER_DELAY);
620 error1 (" cornerredelay : %d seconds\n" , CORNER_DELAY);
621 error1 (" cornersize : %d pixels\n" , CORNER_SIZE );
622
623 error0 ("\n");
624 error1 ("Version : %s\n", VERSION);
625
626 error0 ("\n");
627
628 exit (exitCode);
629 }
630
631 /*
632 * Public interface to the above lot.
633 */
634 void
processOpts(Display * d,int argc,char * argv[])635 processOpts (Display* d, int argc, char* argv[])
636 {
637 int nofOptions = sizeof (options) / sizeof (options[0]);
638 /* number of supported options */
639 int j; /* loop counter */
640 unsigned l; /* temporary storage */
641 unsigned maxLen; /* temporary storage */
642 char* dummy; /* as it says */
643 char* fullname; /* full resource name */
644 char* str; /* temporary storage */
645 XrmValue value; /* resource value container */
646 XrmOptionDescList xoptions; /* optionslist in Xlib format */
647 XrmDatabase rescDb = (XrmDatabase) 0;
648 /* resource file database */
649 XrmDatabase cmdlDb = (XrmDatabase) 0;
650 /* command line options database */
651
652 /*
653 * Collect defaults from various places except the command line into one
654 * resource database, then parse the command line options into an other.
655 * Both databases are not merged, because we want to know where exactly
656 * each resource value came from.
657 *
658 * One day I might extend this stuff to fully cover *all* possible
659 * resource value sources, but... One of the problems is that various
660 * pieces of documentation make conflicting claims with respect to the
661 * proper order in which resource value sources should be accessed.
662 */
663 XrmInitialize ();
664
665 if (XResourceManagerString (d))
666 {
667 XrmMergeDatabases (XrmGetStringDatabase (XResourceManagerString (d)),
668 &rescDb);
669 }
670 else if ((str = getenv ("XENVIRONMENT"))) /* = intended */
671 {
672 XrmMergeDatabases (XrmGetFileDatabase (str), &rescDb);
673 }
674 #if defined (ReadXdefaultsFile) && !defined (VMS)
675 else
676 {
677 /*
678 * In general, the following is a not a good idea. Who is to say that
679 * the user's .Xdefaults file matches the screen being used? And who
680 * says we shouldn't run the file through cpp first? Using which
681 * options, by the way?
682 *
683 * Fortunately, chances are pretty small that anyone will actually run
684 * xautolock remotely. And even if someone does, the same .Xdefaults
685 * file will most likely be involved on both sides of the link. Also,
686 * we only do this of we failed to get our resources from the standard
687 * places. People who have .Xdefaults files that need to be fed to cpp,
688 * will run the appropriate xrdb command on login anyway, such that we
689 * never get here.
690 *
691 * Having said that, I'm only keeping this stuff around because of the
692 * desire to be backward compatible for those who originally convinced
693 * me to include it, or who since became to depend on it. If I could
694 * live my life over again, this wouldn't get added in the first place.
695 */
696 XrmDatabase Xdefaults;
697 struct passwd *passwd;
698 const char* home;
699 char* path;
700
701 passwd = getpwuid (getuid ());
702
703 if (passwd)
704 {
705 home = passwd->pw_dir;
706 }
707 else
708 {
709 home = getenv ("HOME");
710 if (!home) home = ".";
711 }
712
713 path = newArray (char, strlen (home) + strlen ("/.Xdefaults") + 1);
714 (void) sprintf (path, "%s/.Xdefaults", home);
715 Xdefaults = XrmGetFileDatabase (path);
716 if (Xdefaults) XrmMergeDatabases (Xdefaults, &rescDb);
717
718 free (path);
719 }
720 #endif /* ReadXdefaultsFile && !VMS */
721
722 xoptions = newArray (XrmOptionDescRec, nofOptions);
723
724 for (j = -1, maxLen = 0; ++j < nofOptions; )
725 {
726 l = strlen (options[j].name) + 1;
727 maxLen = MAX (maxLen, l);
728
729 (void) sprintf (xoptions[j].option = newArray (char, l + 1),
730 "-%s", options[j].name);
731 (void) sprintf (xoptions[j].specifier = newArray (char, l + 1),
732 ".%s", options[j].name);
733 xoptions[j].argKind = options[j].kind;
734 xoptions[j].value = options[j].value;
735 }
736
737 XrmParseCommand (&cmdlDb, xoptions, nofOptions, progName, &argc, argv);
738
739 if (--argc) usage (EXIT_FAILURE);
740
741 /*
742 * Let's be perfect...
743 */
744 {
745 unsigned classLen = strlen (APPLIC_CLASS);
746 unsigned progLen = strlen (progName);
747
748 fullname = newArray (char, MAX (progLen, classLen) + maxLen + 1);
749 }
750
751 /*
752 * Call the action functions.
753 */
754 for (j = -1; ++j < nofOptions; )
755 {
756 (void) sprintf (fullname, "%s%s", progName, xoptions[j].specifier);
757
758 if ( XrmGetResource (cmdlDb, fullname, DUMMY_RES_CLASS,
759 &dummy, &value)
760 == True)
761 {
762 if (!(*(options[j].action)) (d, value.addr))
763 {
764 usage (EXIT_FAILURE);
765 }
766 }
767 else if ( XrmGetResource (rescDb, fullname, DUMMY_RES_CLASS,
768 &dummy, &value)
769 == True)
770 {
771 if (!(*(options[j].action)) (d, value.addr))
772 {
773 error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
774 value.addr, fullname);
775 }
776 }
777 else
778 {
779 (void) sprintf (fullname, "%s%s", APPLIC_CLASS, xoptions[j].specifier);
780
781 if ( ( XrmGetResource (rescDb, fullname, DUMMY_RES_CLASS,
782 &dummy, &value)
783 == True)
784 && !(*(options[j].action)) (d, value.addr))
785 {
786 error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
787 value.addr, fullname);
788 }
789 }
790 }
791
792 /*
793 * Call the consistency checkers.
794 */
795 for (j = -1; ++j < nofOptions; )
796 {
797 if (options[j].checker != (optChecker) NULL)
798 {
799 (*(options[j].checker)) (d);
800 }
801 }
802
803 /*
804 * General clean up.
805 */
806 XrmDestroyDatabase (cmdlDb);
807 XrmDestroyDatabase (rescDb);
808
809 for (j = -1; ++j < nofOptions; )
810 {
811 free (xoptions[j].option);
812 free (xoptions[j].specifier);
813 }
814
815 free (xoptions);
816 free (fullname);
817 }
818