+/* Parsing the programs resource.
+ */
+
+static char *
+reformat_hack (const char *hack)
+{
+ int i;
+ const char *in = hack;
+ int indent = 13;
+ char *h2 = (char *) malloc(strlen(in) + indent + 2);
+ char *out = h2;
+
+ while (isspace(*in)) in++; /* skip whitespace */
+ while (*in && !isspace(*in) && *in != ':')
+ *out++ = *in++; /* snarf first token */
+ while (isspace(*in)) in++; /* skip whitespace */
+
+ if (*in == ':')
+ *out++ = *in++; /* copy colon */
+ else
+ {
+ in = hack;
+ out = h2; /* reset to beginning */
+ }
+
+ *out = 0;
+
+ while (isspace(*in)) in++; /* skip whitespace */
+ for (i = strlen(h2); i < indent; i++) /* indent */
+ *out++ = ' ';
+
+ /* copy the rest of the line. */
+ while (*in)
+ {
+ /* shrink all whitespace to one space, for the benefit of the "demo"
+ mode display. We only do this when we can easily tell that the
+ whitespace is not significant (no shell metachars).
+ */
+ switch (*in)
+ {
+ case '\'': case '"': case '`': case '\\':
+ {
+ /* Metachars are scary. Copy the rest of the line unchanged. */
+ while (*in)
+ *out++ = *in++;
+ }
+ break;
+ case ' ': case '\t':
+ {
+ while (*in == ' ' || *in == '\t')
+ in++;
+ *out++ = ' ';
+ }
+ break;
+ default:
+ *out++ = *in++;
+ break;
+ }
+ }
+ *out = 0;
+
+ /* strip trailing whitespace. */
+ out = out-1;
+ while (out > h2 && (*out == ' ' || *out == '\t' || *out == '\n'))
+ *out-- = 0;
+
+ return h2;
+}
+
+
+static void
+get_screenhacks (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ int i = 0;
+ int start = 0;
+ int end = 0;
+ int size;
+ char *d;
+
+ d = get_string_resource ("monoPrograms", "MonoPrograms");
+ if (d && !*d) { free(d); d = 0; }
+ if (!d)
+ d = get_string_resource ("colorPrograms", "ColorPrograms");
+ if (d && !*d) { free(d); d = 0; }
+
+ if (d)
+ {
+ fprintf (stderr,
+ "%s: the `monoPrograms' and `colorPrograms' resources are obsolete;\n\
+ see the manual for details.\n", blurb());
+ free(d);
+ }
+
+ d = get_string_resource ("programs", "Programs");
+
+ if (p->screenhacks)
+ {
+ for (i = 0; i < p->screenhacks_count; i++)
+ if (p->screenhacks[i])
+ free (p->screenhacks[i]);
+ free(p->screenhacks);
+ p->screenhacks = 0;
+ }
+
+ if (!d || !*d)
+ {
+ p->screenhacks_count = 0;
+ p->screenhacks = 0;
+ return;
+ }
+
+ size = strlen (d);
+
+
+ /* Count up the number of newlines (which will be equal to or larger than
+ the number of hacks.)
+ */
+ i = 0;
+ for (i = 0; d[i]; i++)
+ if (d[i] == '\n')
+ i++;
+ i++;
+
+ p->screenhacks = (char **) calloc (sizeof (char *), i+1);
+
+ /* Iterate over the lines in `d' (the string with newlines)
+ and make new strings to stuff into the `screenhacks' array.
+ */
+ p->screenhacks_count = 0;
+ while (start < size)
+ {
+ /* skip forward over whitespace. */
+ while (d[start] == ' ' || d[start] == '\t' || d[start] == '\n')
+ start++;
+
+ /* skip forward to newline or end of string. */
+ end = start;
+ while (d[end] != 0 && d[end] != '\n')
+ end++;
+
+ /* null terminate. */
+ d[end] = 0;
+
+ p->screenhacks[p->screenhacks_count++] = reformat_hack (d + start);
+ if (p->screenhacks_count >= i)
+ abort();
+
+ start = end+1;
+ }
+
+ if (p->screenhacks_count == 0)
+ {
+ free (p->screenhacks);
+ p->screenhacks = 0;
+ }
+}
+
+
+\f
+/* Processing ClientMessage events.
+ */
+
+static void
+clientmessage_response (saver_info *si, Window w, Bool error,
+ const char *stderr_msg,
+ const char *protocol_msg)
+{
+ char *proto;
+ int L;
+ saver_preferences *p = &si->prefs;
+ if (error || p->verbose_p)
+ fprintf (stderr, "%s: %s\n", blurb(), stderr_msg);
+
+ L = strlen(protocol_msg);
+ proto = (char *) malloc (L + 2);
+ proto[0] = (error ? '-' : '+');
+ strcpy (proto+1, protocol_msg);
+ L++;
+
+ XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8,
+ PropModeReplace, proto, L);
+ XSync (si->dpy, False);
+ free (proto);
+}