X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utils%2Ftextclient.c;h=fe409287db6fbc0d015087505e9150b1937fa312;hb=d6b0217f2417bd19187f0ebc389d6c5c2233b11c;hp=794441f9c71d33913320d4566876b300cfe691b5;hpb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;p=xscreensaver diff --git a/utils/textclient.c b/utils/textclient.c index 794441f9..fe409287 100644 --- a/utils/textclient.c +++ b/utils/textclient.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 2012-2014 Jamie Zawinski +/* xscreensaver, Copyright (c) 2012-2016 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -16,11 +16,13 @@ * usePty: bool Whether to run the command interactively. * metaSendsESC: bool Whether to send Alt-x as ESC x in pty-mode. * swapBSDEL: bool Swap Backspace and Delete in pty-mode. + * + * On iOS and Android, textclient-mobile.c is used instead. */ #include "utils.h" -#ifndef USE_IPHONE /* whole file -- see OSX/iostextclient.m */ +#if !defined(USE_IPHONE) && !defined(HAVE_ANDROID) /* whole file */ #include "textclient.h" #include "resources.h" @@ -50,6 +52,9 @@ # ifdef HAVE_UTIL_H # include # endif +# ifdef HAVE_SYS_TERMIOS_H +# include +# endif #endif /* HAVE_FORKPTY */ #undef DEBUG @@ -93,16 +98,53 @@ subproc_cb (XtPointer closure, int *source, XtInputId *id) } +# define BACKSLASH(c) \ + (! ((c >= 'a' && c <= 'z') || \ + (c >= 'A' && c <= 'Z') || \ + (c >= '0' && c <= '9') || \ + c == '.' || c == '_' || c == '-' || c == '+' || c == '/')) + +#ifdef HAVE_COCOA +static char * +escape_str (char *s, const char *src) +{ + while (*src) { + char c = *src++; + if (BACKSLASH(c)) *s++ = '\\'; + *s++ = c; + } + return s; +} +#endif + static void launch_text_generator (text_data *d) { XtAppContext app = XtDisplayToApplicationContext (d->dpy); char buf[255]; const char *oprogram = d->program; - char *program = (char *) malloc (strlen (oprogram) + 50); + char *s; + + size_t oprogram_size = strlen(oprogram); + size_t len; + +# ifdef HAVE_COCOA + /* /bin/sh on OS X 10.10 wipes out the PATH. */ + const char *path = getenv("PATH"); + size_t cmd_capacity = (oprogram_size + strlen(path)) * 2 + 100; + char *cmd = s = malloc (cmd_capacity); + strcpy (s, "export PATH="); + s += strlen (s); + s = escape_str (s, path); + strcpy (s, "; "); + s += strlen (s); +# else + char *cmd = s = malloc ((strlen(oprogram)) * 2 + 100); +# endif - strcpy (program, "( "); - strcat (program, oprogram); + strcpy (s, "( "); + strcat (s, oprogram); + s += strlen (s); /* Kludge! Special-case "xscreensaver-text" to tell it how wide the screen is. We used to do this by just always feeding @@ -110,19 +152,82 @@ launch_text_generator (text_data *d) "xscreensaver-text --cols %d", but that makes things blow up if someone ever uses a --program that includes a % anywhere. */ - if (!strcmp (oprogram, "xscreensaver-text")) + len = 17; /* strlen("xscreensaver-text") */ + if (oprogram_size >= len && + !memcmp (oprogram, "xscreensaver-text", len) && + (oprogram[len] == ' ' || !oprogram[len])) { - if (d->char_w) - sprintf (program + strlen(program), " --cols %d", d->char_w); - if (d->max_lines) - sprintf (program + strlen(program), " --lines %d", d->max_lines); + /* strstr is sloppy here. Technically, we should be parsing the command + line to identify flags and their arguments. This will blow up if one + of those pesky end users could set .textLiteral to "--cols". + */ + if (d->char_w && !strstr (oprogram, "--cols ")) + sprintf (s, " --cols %d", d->char_w); + if (d->max_lines && !strstr (oprogram, "--lines ")) + sprintf (s, " --lines %d", d->max_lines); + s += strlen(s); + +# ifdef HAVE_COCOA + /* Also special-case "xscreensaver-text" to specify the text content on + the command line. defaults(1) on macOS doesn't know about the default + screenhack resources that don't make it into the + ~/Library/Preferences/ByHost/org.jwz.xscreensaver.*.plist. + */ + + char *text_mode_flag = " --date"; + char *value_res = NULL; + char *text_mode = get_string_resource (d->dpy, "textMode", "String"); + + if (text_mode) + { + if (!strcmp (text_mode, "1") || !strcmp (text_mode, "literal")) + { + text_mode_flag = " --text"; + value_res = "textLiteral"; + } + else if (!strcmp (text_mode, "2") || !strcmp (text_mode, "file")) + { + text_mode_flag = " --file"; + value_res = "textFile"; + } + else if (!strcmp (text_mode, "3") || !strcmp (text_mode, "url")) + { + text_mode_flag = " --url"; + value_res = "textURL"; + } + else if (!strcmp (text_mode, "4") || !strcmp (text_mode, "program")) + { + text_mode_flag = " --program"; + value_res = "textProgram"; + } + + free (text_mode); + } + + strcpy (s, text_mode_flag); + s += strlen (s); + + if (value_res) + { + size_t old_s = s - cmd; + char *value = get_string_resource (d->dpy, value_res, ""); + if (!value) + value = strdup(""); + cmd = realloc(cmd, cmd_capacity + strlen(value) * 2); + s = cmd + old_s; + *s = ' '; + ++s; + s = escape_str(s, value); + free(value); + } +# endif /* HAVE_COCOA */ } - strcat (program, " ) 2>&1"); + strcpy (s, " ) 2>&1"); # ifdef DEBUG fprintf (stderr, "%s: textclient: launch %s: %s\n", progname, - (d->pty_p ? "pty" : "pipe"), program); + (d->pty_p ? "pty" : "pipe"), cmd); # endif #ifdef HAVE_FORKPTY @@ -137,6 +242,15 @@ launch_text_generator (text_data *d) ws.ws_ypixel = d->pix_h; d->pipe = 0; + +# ifdef HAVE_COCOA + if (getenv ("MallocScribble")) + /* This is here to stop me from wasting my time trying to answer + this question the next time I forget about it. */ + fprintf (stderr, "%s: WARNING: forkpty hates 'Enable Guard Malloc'\n", + progname); +# endif + if ((d->pid = forkpty(&fd, NULL, NULL, &ws)) < 0) { /* Unable to fork */ @@ -152,8 +266,17 @@ launch_text_generator (text_data *d) abort(); av[i++] = "/bin/sh"; av[i++] = "-c"; - av[i++] = program; + av[i++] = cmd; av[i] = 0; +# ifdef DEBUG + { + int j; + fprintf (stderr, "%s: textclient: execvp:", progname); + for (j = 0; j < i; j++) + fprintf (stderr, " %s", av[j]); + fprintf (stderr, "\n"); + } +# endif execvp (av[0], av); sprintf (buf, "%.100s: %.100s", progname, oprogram); perror (buf); @@ -186,7 +309,7 @@ launch_text_generator (text_data *d) } if (d->pipe) abort(); - if ((d->pipe = popen (program, "r"))) + if ((d->pipe = popen (cmd, "r"))) { if (d->pipe_id) abort(); d->pipe_id = @@ -199,12 +322,12 @@ launch_text_generator (text_data *d) } else { - sprintf (buf, "%.100s: %.100s", progname, program); + sprintf (buf, "%.100s: %.100s", progname, cmd); perror (buf); } } - free (program); + free (cmd); } @@ -297,6 +420,9 @@ textclient_reshape (text_data *d, ws.ws_ypixel = pix_h; ioctl (fileno (d->pipe), TIOCSWINSZ, &ws); kill (d->pid, SIGWINCH); +# ifdef DEBUG + fprintf (stderr, "%s: textclient: SIGWINCH\n", progname); +# endif } # endif /* HAVE_FORKPTY && TIOCSWINSZ */ @@ -307,6 +433,9 @@ textclient_reshape (text_data *d, */ if (!strcmp (d->program, "xscreensaver-text")) { +# ifdef DEBUG + fprintf (stderr, "%s: textclient: reshape relaunch\n", progname); +# endif close_pipe (d); d->input_available_p = False; start_timer (d); @@ -357,6 +486,10 @@ textclient_open (Display *dpy) { d->pty_p = 1; d->program = strdup (getenv ("SHELL")); +# ifdef DEBUG + fprintf (stderr, "%s: textclient: standalone: %s\n", + progname, d->program); +# endif } } # endif