summaryrefslogtreecommitdiffstats
path: root/driver/stderr.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/stderr.c')
-rw-r--r--driver/stderr.c560
1 files changed, 0 insertions, 560 deletions
diff --git a/driver/stderr.c b/driver/stderr.c
deleted file mode 100644
index 84fa697..0000000
--- a/driver/stderr.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/* stderr.c --- capturing stdout/stderr output onto the screensaver window.
- * xscreensaver, Copyright (c) 1991-2016 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- */
-
-/* stderr hackery - Why Unix Sucks, reason number 32767.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-
-#include <stdio.h>
-#include <time.h>
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL
-# include <fcntl.h>
-#endif
-
-#include <X11/Intrinsic.h>
-
-#include "xscreensaver.h"
-#include "resources.h"
-#include "visual.h"
-
-FILE *real_stderr = 0;
-FILE *real_stdout = 0;
-
-
-/* It's ok for these to be global, since they refer to the one and only
- stderr stream, not to a particular screen or window or visual.
- */
-static char stderr_buffer [4096];
-static char *stderr_tail = 0;
-static time_t stderr_last_read = 0;
-
-static int stderr_stdout_read_fd = -1;
-
-static void make_stderr_overlay_window (saver_screen_info *);
-
-
-/* Recreates the stderr window or GCs: do this when the xscreensaver window
- on a screen has been re-created.
- */
-void
-reset_stderr (saver_screen_info *ssi)
-{
- saver_info *si = ssi->global;
-
- if (si->prefs.debug_p)
- fprintf ((real_stderr ? real_stderr : stderr),
- "%s: resetting stderr\n", blurb());
-
- ssi->stderr_text_x = 0;
- ssi->stderr_text_y = 0;
-
- if (ssi->stderr_gc)
- XFreeGC (si->dpy, ssi->stderr_gc);
- ssi->stderr_gc = 0;
-
- if (ssi->stderr_overlay_window)
- XDestroyWindow(si->dpy, ssi->stderr_overlay_window);
- ssi->stderr_overlay_window = 0;
-
- if (ssi->stderr_cmap)
- XFreeColormap(si->dpy, ssi->stderr_cmap);
- ssi->stderr_cmap = 0;
-}
-
-/* Erases any stderr text overlaying the screen (if possible) and resets
- the stderr output cursor to the upper left. Do this when the xscreensaver
- window is cleared.
- */
-void
-clear_stderr (saver_screen_info *ssi)
-{
- saver_info *si = ssi->global;
- ssi->stderr_text_x = 0;
- ssi->stderr_text_y = 0;
- if (ssi->stderr_overlay_window)
- XClearWindow (si->dpy, ssi->stderr_overlay_window);
-}
-
-
-/* Draws the string on the screen's window.
- */
-static void
-print_stderr_1 (saver_screen_info *ssi, char *string)
-{
- saver_info *si = ssi->global;
- Display *dpy = si->dpy;
- Screen *screen = ssi->screen;
- Window window = (ssi->stderr_overlay_window ?
- ssi->stderr_overlay_window :
- ssi->screensaver_window);
- int h_border = 20;
- int v_border = 20;
- char *head = string;
- char *tail;
-
- if (! ssi->stderr_font)
- {
- char *font_name = get_string_resource (dpy, "font", "Font");
- if (!font_name) font_name = strdup ("fixed");
- ssi->stderr_font = XLoadQueryFont (dpy, font_name);
- if (! ssi->stderr_font) ssi->stderr_font = XLoadQueryFont (dpy, "fixed");
- ssi->stderr_line_height = (ssi->stderr_font->ascent +
- ssi->stderr_font->descent);
- free (font_name);
- }
-
- if (! ssi->stderr_gc)
- {
- XGCValues gcv;
- Pixel fg, bg;
- Colormap cmap = ssi->cmap;
-
- if (!ssi->stderr_overlay_window &&
- get_boolean_resource(dpy, "overlayStderr", "Boolean"))
- {
- make_stderr_overlay_window (ssi);
- if (ssi->stderr_overlay_window)
- window = ssi->stderr_overlay_window;
- if (ssi->stderr_cmap)
- cmap = ssi->stderr_cmap;
- }
-
- fg = get_pixel_resource (dpy,cmap,"overlayTextForeground","Foreground");
- bg = get_pixel_resource (dpy,cmap,"overlayTextBackground","Background");
- gcv.font = ssi->stderr_font->fid;
- gcv.foreground = fg;
- gcv.background = bg;
- ssi->stderr_gc = XCreateGC (dpy, window,
- (GCFont | GCForeground | GCBackground),
- &gcv);
- }
-
-
- if (ssi->stderr_cmap)
- XInstallColormap(si->dpy, ssi->stderr_cmap);
-
- for (tail = string; *tail; tail++)
- {
- if (*tail == '\n' || *tail == '\r')
- {
- int maxy = HeightOfScreen (screen) - v_border - v_border;
- if (tail != head)
- XDrawImageString (dpy, window, ssi->stderr_gc,
- ssi->stderr_text_x + h_border,
- ssi->stderr_text_y + v_border +
- ssi->stderr_font->ascent,
- head, tail - head);
- ssi->stderr_text_x = 0;
- ssi->stderr_text_y += ssi->stderr_line_height;
- head = tail + 1;
- if (*tail == '\r' && *head == '\n')
- head++, tail++;
-
- if (ssi->stderr_text_y > maxy - ssi->stderr_line_height)
- {
-#if 0
- ssi->stderr_text_y = 0;
-#else
- int offset = ssi->stderr_line_height * 5;
- XWindowAttributes xgwa;
- XGetWindowAttributes (dpy, window, &xgwa);
-
- XCopyArea (dpy, window, window, ssi->stderr_gc,
- 0, v_border + offset,
- xgwa.width,
- (xgwa.height - v_border - v_border - offset),
- 0, v_border);
- XClearArea (dpy, window,
- 0, xgwa.height - v_border - offset,
- xgwa.width, offset, False);
- ssi->stderr_text_y -= offset;
-#endif
- }
- }
- }
- if (tail != head)
- {
- int direction, ascent, descent;
- XCharStruct overall;
- XDrawImageString (dpy, window, ssi->stderr_gc,
- ssi->stderr_text_x + h_border,
- ssi->stderr_text_y + v_border
- + ssi->stderr_font->ascent,
- head, tail - head);
- XTextExtents (ssi->stderr_font, tail, tail - head,
- &direction, &ascent, &descent, &overall);
- ssi->stderr_text_x += overall.width;
- }
-}
-
-static void
-make_stderr_overlay_window (saver_screen_info *ssi)
-{
- saver_info *si = ssi->global;
- unsigned long transparent_pixel = 0;
- Visual *visual = get_overlay_visual (ssi->screen, &transparent_pixel);
- if (visual)
- {
- int depth = visual_depth (ssi->screen, visual);
- XSetWindowAttributes attrs;
- XWindowAttributes xgwa;
- unsigned long attrmask;
- XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
-
- if (si->prefs.debug_p)
- fprintf(real_stderr,
- "%s: using overlay visual 0x%0x for stderr text layer.\n",
- blurb(), (int) XVisualIDFromVisual (visual));
-
- ssi->stderr_cmap = XCreateColormap(si->dpy,
- RootWindowOfScreen(ssi->screen),
- visual, AllocNone);
-
- attrmask = (CWColormap | CWBackPixel | CWBackingPixel | CWBorderPixel |
- CWBackingStore | CWSaveUnder);
- attrs.colormap = ssi->stderr_cmap;
- attrs.background_pixel = transparent_pixel;
- attrs.backing_pixel = transparent_pixel;
- attrs.border_pixel = transparent_pixel;
- attrs.backing_store = NotUseful;
- attrs.save_under = False;
-
- ssi->stderr_overlay_window =
- XCreateWindow(si->dpy, ssi->screensaver_window, 0, 0,
- xgwa.width, xgwa.height,
- 0, depth, InputOutput, visual, attrmask, &attrs);
- XMapRaised(si->dpy, ssi->stderr_overlay_window);
- }
-}
-
-
-/* Draws the string on each screen's window as error text.
- */
-static void
-print_stderr (saver_info *si, char *string)
-{
- saver_preferences *p = &si->prefs;
- int i;
-
- /* In verbose mode, copy it to stderr as well. */
- if (p->verbose_p)
- fprintf (real_stderr, "%s", string);
-
- for (i = 0; i < si->nscreens; i++)
- print_stderr_1 (&si->screens[i], string);
-}
-
-
-/* Polls the stderr buffer every few seconds and if it finds any text,
- writes it on all screens.
- */
-static void
-stderr_popup_timer_fn (XtPointer closure, XtIntervalId *id)
-{
- saver_info *si = (saver_info *) closure;
- char *s = stderr_buffer;
- if (*s)
- {
- /* If too much data was printed, then something has gone haywire,
- so truncate it. */
- char *trailer = "\n\n<< stderr diagnostics have been truncated >>\n\n";
- int max = sizeof (stderr_buffer) - strlen (trailer) - 5;
- if (strlen (s) > max)
- strcpy (s + max, trailer);
- /* Now show the user. */
- print_stderr (si, s);
- }
-
- stderr_tail = stderr_buffer;
- si->stderr_popup_timer = 0;
-}
-
-
-/* Called when data becomes available on the stderr pipe. Copies it into
- stderr_buffer where stderr_popup_timer_fn() can find it later.
- */
-static void
-stderr_callback (XtPointer closure, int *fd, XtIntervalId *id)
-{
- saver_info *si = (saver_info *) closure;
- char *s;
- int left;
- int size;
- int read_this_time = 0;
-
- if (!fd || *fd < 0 || *fd != stderr_stdout_read_fd)
- abort();
-
- if (stderr_tail == 0)
- stderr_tail = stderr_buffer;
-
- left = ((sizeof (stderr_buffer) - 2) - (stderr_tail - stderr_buffer));
-
- s = stderr_tail;
- *s = 0;
-
- /* Read as much data from the fd as we can, up to our buffer size. */
- if (left > 0)
- {
- while ((size = read (*fd, (void *) s, left)) > 0)
- {
- left -= size;
- s += size;
- read_this_time += size;
- }
- *s = 0;
- }
- else
- {
- char buf2 [1024];
- /* The buffer is full; flush the rest of it. */
- while (read (*fd, (void *) buf2, sizeof (buf2)) > 0)
- ;
- }
-
- stderr_tail = s;
- stderr_last_read = time ((time_t *) 0);
-
- /* Now we have read some data that we would like to put up in a dialog
- box. But more data may still be coming in - so don't pop up the
- dialog right now, but instead, start a timer that will pop it up
- a second from now. Should more data come in in the meantime, we
- will be called again, and will reset that timer again. So the
- dialog will only pop up when a second has elapsed with no new data
- being written to stderr.
-
- However, if the buffer is full (meaning lots of data has been written)
- then we don't reset the timer.
- */
- if (read_this_time > 0)
- {
- if (si->stderr_popup_timer)
- XtRemoveTimeOut (si->stderr_popup_timer);
-
- si->stderr_popup_timer =
- XtAppAddTimeOut (si->app, 1 * 1000, stderr_popup_timer_fn,
- (XtPointer) si);
- }
-}
-
-/* If stderr capturing is desired, this replaces `stdout' and `stderr'
- with a pipe, so that any output written to them will show up on the
- screen as well as on the original value of those streams.
- */
-void
-initialize_stderr (saver_info *si)
-{
- static Boolean done = False;
- int fds [2];
- int in, out;
- int new_stdout, new_stderr;
- int stdout_fd = 1;
- int stderr_fd = 2;
- int flags = 0;
- Boolean stderr_dialog_p;
-
- if (done) return;
- done = True;
-
- real_stderr = stderr;
- real_stdout = stdout;
-
- stderr_dialog_p = get_boolean_resource (si->dpy, "captureStderr", "Boolean");
-
- if (!stderr_dialog_p)
- return;
-
- if (pipe (fds))
- {
- perror ("error creating pipe:");
- return;
- }
-
- in = fds [0];
- out = fds [1];
-
-# ifdef HAVE_FCNTL
-
-# if defined(O_NONBLOCK)
- flags = O_NONBLOCK;
-# elif defined(O_NDELAY)
- flags = O_NDELAY;
-# else
- ERROR!! neither O_NONBLOCK nor O_NDELAY are defined.
-# endif
-
- /* Set both sides of the pipe to nonblocking - this is so that
- our reads (in stderr_callback) will terminate, and so that
- out writes (in the client programs) will silently fail when
- the pipe is full, instead of hosing the program. */
- if (fcntl (in, F_SETFL, flags) != 0)
- {
- perror ("fcntl:");
- return;
- }
- if (fcntl (out, F_SETFL, flags) != 0)
- {
- perror ("fcntl:");
- return;
- }
-
-# endif /* !HAVE_FCNTL */
-
- if (stderr_dialog_p)
- {
- FILE *new_stderr_file;
- FILE *new_stdout_file;
-
- new_stderr = dup (stderr_fd);
- if (new_stderr < 0)
- {
- perror ("could not dup() a stderr:");
- return;
- }
- if (! (new_stderr_file = fdopen (new_stderr, "w")))
- {
- perror ("could not fdopen() the new stderr:");
- return;
- }
- real_stderr = new_stderr_file;
-
- close (stderr_fd);
- if (dup2 (out, stderr_fd) < 0)
- {
- perror ("could not dup() a new stderr:");
- return;
- }
-
-
- new_stdout = dup (stdout_fd);
- if (new_stdout < 0)
- {
- perror ("could not dup() a stdout:");
- return;
- }
- if (! (new_stdout_file = fdopen (new_stdout, "w")))
- {
- perror ("could not fdopen() the new stdout:");
- return;
- }
- real_stdout = new_stdout_file;
-
- close (stdout_fd);
- if (dup2 (out, stdout_fd) < 0)
- {
- perror ("could not dup() a new stdout:");
- return;
- }
- close (out);
- }
-
- stderr_stdout_read_fd = in;
- XtAppAddInput (si->app, in, (XtPointer) XtInputReadMask, stderr_callback,
- (XtPointer) si);
-}
-
-
-/* If the "-log file" command-line option has been specified,
- open the file for append, and redirect stdout/stderr there.
- This is called very early, before initialize_stderr().
- */
-void
-stderr_log_file (saver_info *si)
-{
- int stdout_fd = 1;
- int stderr_fd = 2;
- const char *filename = get_string_resource (si->dpy, "logFile", "LogFile");
- int fd;
-
- if (!filename || !*filename) return;
-
- fd = open (filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
-
- if (fd < 0)
- {
- char buf[255];
- FAIL:
- sprintf (buf, "%.100s: %.100s", blurb(), filename);
- perror (buf);
- fflush (stderr);
- fflush (stdout);
- exit (1);
- }
-
- fprintf (stderr, "%s: logging to file %s\n", blurb(), filename);
-
- if (dup2 (fd, stdout_fd) < 0) goto FAIL;
- if (dup2 (fd, stderr_fd) < 0) goto FAIL;
-
- fprintf (stderr, "\n\n"
- "##########################################################################\n"
- "%s: logging to \"%s\" at %s\n"
- "##########################################################################\n"
- "\n",
- blurb(), filename, timestring(0));
-}
-
-
-/* If there is anything in the stderr buffer, flush it to the real stderr.
- This does no X operations. Call this when exiting to make sure any
- last words actually show up.
- */
-void
-shutdown_stderr (saver_info *si)
-{
- fflush (stdout);
- fflush (stderr);
-
- if (!real_stderr || stderr_stdout_read_fd < 0)
- return;
-
- stderr_callback ((XtPointer) si, &stderr_stdout_read_fd, 0);
-
- if (stderr_tail &&
- stderr_buffer < stderr_tail)
- {
- *stderr_tail = 0;
- fprintf (real_stderr, "%s", stderr_buffer);
- stderr_tail = stderr_buffer;
- }
-
- if (real_stdout) fflush (real_stdout);
- if (real_stderr) fflush (real_stderr);
-
- if (stdout != real_stdout)
- {
- dup2 (fileno(real_stdout), fileno(stdout));
- fclose (real_stdout);
- real_stdout = stdout;
- }
- if (stderr != real_stderr)
- {
- dup2 (fileno(real_stderr), fileno(stderr));
- fclose (real_stderr);
- real_stderr = stderr;
- }
- if (stderr_stdout_read_fd != -1)
- {
- close (stderr_stdout_read_fd);
- stderr_stdout_read_fd = -1;
- }
-}