1 /* dotfile.c --- management of the ~/.xscreensaver file.
2 * xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #include <sys/types.h>
21 #include <X11/Xresource.h>
30 /* This file doesn't need the Xt headers, so stub these types out... */
32 #define XtAppContext void*
33 #define XtIntervalId void*
34 #define XtPointer void*
37 #include "xscreensaver.h"
38 #include "resources.h"
40 /* Just in case there's something pathological about stat.h... */
42 # define S_IRUSR 00400
45 # define S_IWUSR 00200
48 # define S_IXUSR 00100
51 # define S_IXGRP 00010
54 # define S_IXOTH 00001
61 static char *file = 0;
65 struct passwd *p = getpwuid (getuid ());
67 if (!p || !p->pw_name || !*p->pw_name)
69 fprintf (stderr, "%s: couldn't get user info of uid %d\n",
73 else if (!p->pw_dir || !*p->pw_dir)
75 fprintf (stderr, "%s: couldn't get home directory of %s\n",
76 blurb(), (p->pw_name ? p->pw_name : "???"));
81 const char *home = p->pw_dir;
82 const char *name = ".xscreensaver";
83 file = (char *) malloc(strlen(home) + strlen(name) + 2);
85 if (!*home || home[strlen(home)-1] != '/')
99 init_file_tmp_name (void)
101 static char *file = 0;
104 const char *name = init_file_name();
105 const char *suffix = ".tmp";
110 file = (char *) malloc(strlen(name) + strlen(suffix) + 2);
112 strcat(file, suffix);
123 static const char * const prefs[] = {
134 "splash", /* not saved -- same as "splashDuration: 0" */
144 "captureStdout", /* not saved -- obsolete */
150 "windowCreationTimeout",
156 "overlayTextBackground", /* not saved -- X resources only */
157 "overlayTextForeground", /* not saved -- X resources only */
158 "bourneShell", /* not saved -- X resources only */
162 static char *strip(char *s)
165 while (*s == '\t' || *s == ' ' || *s == '\r' || *s == '\n')
167 for (s2 = s; *s2; s2++)
169 for (s2--; s2 >= s; s2--)
170 if (*s2 == '\t' || *s2 == ' ' || *s2 == '\r' || *s2 =='\n')
182 handle_entry (saver_info *si, const char *key, const char *value,
183 const char *filename, int line)
186 for (i = 0; prefs[i]; i++)
187 if (*prefs[i] && !strcasecmp(key, prefs[i]))
189 char *val = strdup(value);
190 char *spec = (char *) malloc(strlen(progclass) + strlen(prefs[i]) +10);
191 strcpy(spec, progclass);
193 strcat(spec, prefs[i]);
195 XrmPutStringResource (&si->db, spec, val);
202 fprintf(stderr, "%s: %s:%d: unknown option \"%s\"\n",
203 blurb(), filename, line, key);
208 read_init_file (saver_info *si)
210 time_t write_date = 0;
211 const char *name = init_file_name();
220 if (stat(name, &st) != 0)
222 si->init_file_date = 0;
226 in = fopen(name, "r");
229 char *buf = (char *) malloc(1024 + strlen(name));
230 sprintf(buf, "%s: error reading %s", blurb(), name);
236 if (fstat (fileno(in), &st) == 0)
238 write_date = st.st_mtime;
242 char *buf = (char *) malloc(1024 + strlen(name));
243 sprintf(buf, "%s: couldn't re-stat %s", blurb(), name);
249 buf = (char *) malloc(buf_size);
251 while (fgets (buf, buf_size-1, in))
258 (buf[L-1] != '\n' || /* whole line didn't fit in buffer */
259 buf[L-2] == '\\')) /* or line ended with backslash */
261 if (buf[L-2] == '\\') /* backslash-newline gets swallowed */
267 buf = (char *) realloc(buf, buf_size);
271 if (!fgets (buf + L, buf_size-L-1, in))
276 /* Now handle other backslash escapes. */
279 for (i = 0; buf[i]; i++)
284 case 'n': buf[i] = '\n'; break;
285 case 'r': buf[i] = '\r'; break;
286 case 't': buf[i] = '\t'; break;
287 default: buf[i] = buf[i+1]; break;
289 for (j = i+2; buf[j]; j++)
297 if (*key == '#' || *key == '!' || *key == ';' ||
298 *key == '\n' || *key == 0)
301 value = strchr (key, ':');
304 fprintf(stderr, "%s: %s:%d: unparsable line: %s\n", blurb(),
311 value = strip(value);
314 handle_entry (si, key, value, name, line);
318 si->init_file_date = write_date;
324 maybe_reload_init_file (saver_info *si)
326 saver_preferences *p = &si->prefs;
327 const char *name = init_file_name();
333 if (stat(name, &st) != 0)
336 if (si->init_file_date == st.st_mtime)
340 fprintf (stderr, "%s: file %s has changed, reloading.\n", blurb(), name);
342 status = read_init_file (si);
353 tab_to (FILE *out, int from, int to)
356 int to_mod = (to / tab_width) * tab_width;
357 while (from < to_mod)
360 from = (((from / tab_width) + 1) * tab_width);
371 write_entry (FILE *out, const char *key, const char *value)
373 char *v = strdup(value ? value : "");
377 Bool do_visual_kludge = (!strcmp(key, "programs"));
378 Bool do_wrap = do_visual_kludge;
379 int tab = (do_visual_kludge ? 16 : 23);
383 fprintf(out, "%s:", key);
384 col = strlen(key) + 1;
393 col = tab_to(out, col, 75);
394 fprintf(out, " \\n\\\n");
399 nl = strchr(v2, '\n');
403 s = (do_visual_kludge ? strpbrk(v2, " \t\n:") : 0);
405 col = tab_to (out, col, tab2);
407 col = tab_to (out, col, tab);
410 strlen(v2) + col > 75)
417 while (v2[end] == ' ' || v2[end] == '\t')
419 while (v2[end] != ' ' && v2[end] != '\t' &&
420 v2[end] != '\n' && v2[end] != 0)
422 if (col + (end - start) >= 74)
424 col = tab_to (out, col, 75);
425 fprintf(out, " \\\n");
426 col = tab_to (out, 0, tab + 2);
427 while (v2[start] == ' ' || v2[start] == '\t')
433 fputc(v2[start++], out);
440 fprintf (out, "%s", v2);
455 write_init_file (saver_info *si)
457 const char *name = init_file_name();
458 const char *tmp_name = init_file_tmp_name();
460 saver_preferences *p = &si->prefs;
463 /* Kludge, since these aren't in the saver_preferences struct as strings...
467 Bool capture_stderr_p;
468 Bool overlay_stderr_p;
474 if (si->dangerous_uid_p)
478 fprintf (stderr, "%s: not writing \"%s\":\n", blurb(), name);
479 describe_uids (si, stderr);
485 fprintf (stderr, "%s: writing \"%s\".\n", blurb(), name);
488 out = fopen(tmp_name, "w");
491 char *buf = (char *) malloc(1024 + strlen(name));
492 sprintf(buf, "%s: error writing %s", blurb(), name);
498 /* Give the new .xscreensaver file the same permissions as the old one;
499 except ensure that it is readable and writable by owner, and not
502 if (stat(name, &st) == 0)
504 mode_t mode = st.st_mode;
505 mode |= S_IRUSR | S_IWUSR;
506 mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
507 if (fchmod (fileno(out), mode) != 0)
509 char *buf = (char *) malloc(1024 + strlen(name));
510 sprintf (buf, "%s: error fchmodding %s to 0%o", blurb(),
511 tmp_name, (unsigned int) mode);
518 /* Kludge, since these aren't in the saver_preferences struct... */
519 visual_name = get_string_resource ("visualID", "VisualID");
521 capture_stderr_p = get_boolean_resource ("captureStderr", "Boolean");
522 overlay_stderr_p = get_boolean_resource ("overlayStderr", "Boolean");
523 stderr_font = get_string_resource ("font", "Font");
526 for (j = 0; j < p->screenhacks_count; j++)
527 i += strlen(p->screenhacks[j]) + 2;
529 char *ss = programs = (char *) malloc(i + 10);
531 for (j = 0; j < p->screenhacks_count; j++)
533 strcat(ss, p->screenhacks[j]);
541 struct passwd *p = getpwuid (getuid ());
542 char *whoami = (p && p->pw_name && *p->pw_name
543 ? p->pw_name : "<unknown>");
545 "# %s Preferences File\n"
546 "# Written by %s %s for %s on %s.\n"
547 "# http://www.jwz.org/xscreensaver/\n"
549 progclass, progname, si->version,
550 (whoami ? whoami : "<unknown>"),
554 for (j = 0; prefs[j]; j++)
557 const char *pr = prefs[j];
558 enum pref_type { pref_str, pref_int, pref_bool, pref_time
572 # define CHECK(X) else if (!strcmp(pr, X))
574 CHECK("timeout") type = pref_time, t = p->timeout;
575 CHECK("cycle") type = pref_time, t = p->cycle;
576 CHECK("lock") type = pref_bool, b = p->lock_p;
577 # if 0 /* #### not ready yet */
578 CHECK("lockVTs") type = pref_bool, b = p->lock_vt_p;
580 CHECK("lockVTs") continue; /* don't save */
582 CHECK("lockTimeout") type = pref_time, t = p->lock_timeout;
583 CHECK("passwdTimeout") type = pref_time, t = p->passwd_timeout;
584 CHECK("visualID") type = pref_str, s = visual_name;
585 CHECK("installColormap") type = pref_bool, b = p->install_cmap_p;
586 CHECK("verbose") type = pref_bool, b = p->verbose_p;
587 CHECK("timestamp") type = pref_bool, b = p->timestamp_p;
588 CHECK("splash") continue; /* don't save */
589 CHECK("splashDuration") type = pref_time, t = p->splash_duration;
590 CHECK("helpURL") type = pref_str, s = p->help_url;
591 CHECK("loadURL") type = pref_str, s = p->load_url_command;
592 CHECK("nice") type = pref_int, i = p->nice_inferior;
593 CHECK("fade") type = pref_bool, b = p->fade_p;
594 CHECK("unfade") type = pref_bool, b = p->unfade_p;
595 CHECK("fadeSeconds") type = pref_time, t = p->fade_seconds;
596 CHECK("fadeTicks") type = pref_int, i = p->fade_ticks;
597 CHECK("captureStderr") type = pref_bool, b = capture_stderr_p;
598 CHECK("captureStdout") continue; /* don't save */
599 CHECK("font") type = pref_str, s = stderr_font;
600 CHECK("programs") type = pref_str, s = programs;
601 CHECK("pointerPollTime") type = pref_time, t = p->pointer_timeout;
602 CHECK("windowCreationTimeout")type=pref_time,t= p->notice_events_timeout;
603 CHECK("initialDelay") type = pref_time, t = p->initial_delay;
604 CHECK("sgiSaverExtension")type = pref_bool, b=p->use_sgi_saver_extension;
605 CHECK("mitSaverExtension")type = pref_bool, b=p->use_mit_saver_extension;
606 CHECK("xidleExtension") type = pref_bool, b = p->use_xidle_extension;
607 CHECK("overlayStderr") type = pref_bool, b = overlay_stderr_p;
608 CHECK("overlayTextBackground") continue; /* don't save */
609 CHECK("overlayTextForeground") continue; /* don't save */
610 CHECK("bourneShell") continue;
619 sprintf(buf, "%d", i);
623 s = b ? "True" : "False";
627 unsigned int hour = 0, min = 0, sec = (unsigned int) (t/1000);
638 sprintf (buf, "%u:%02u:%02u", hour, min, sec);
646 write_entry (out, pr, s);
651 if (visual_name) free(visual_name);
652 if (stderr_font) free(stderr_font);
653 if (programs) free(programs);
655 if (fclose(out) == 0)
657 time_t write_date = 0;
659 if (stat(tmp_name, &st) == 0)
661 write_date = st.st_mtime;
665 char *buf = (char *) malloc(1024 + strlen(tmp_name) + strlen(name));
666 sprintf(buf, "%s: couldn't stat %s", blurb(), tmp_name);
673 if (rename (tmp_name, name) != 0)
675 char *buf = (char *) malloc(1024 + strlen(tmp_name) + strlen(name));
676 sprintf(buf, "%s: error renaming %s to %s", blurb(), tmp_name, name);
684 si->init_file_date = write_date;
689 char *buf = (char *) malloc(1024 + strlen(name));
690 sprintf(buf, "%s: error closing %s", blurb(), name);