#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>
#include <X11/Xmu/Atoms.h>
#include <X11/Xmu/StdSel.h>
#include <X11/Xmu/SysUtil.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Box.h>
extern char *_XawTextGetSTRING(TextWidget ctx, XawTextPosition left,
XawTextPosition right);
#include <X11/Xos.h>
#include <X11/Xfuncs.h>
#include <sys/stat.h>
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#include <stdio.h>
#undef _POSIX_SOURCE
#else
#include <stdio.h>
#endif
#include <X11/Shell.h>
#include <ctype.h>
#include <stdlib.h>
#if defined(ISC) && __STDC__ && !defined(ISC30)
extern FILE *fdopen(int, char const *);
#endif
static void inputReady(XtPointer w, int *source, XtInputId *id);
static long TextLength(Widget w);
static void TextReplace(Widget w, int start, int end, XawTextBlock *block);
static void TextAppend(Widget w, char *s, int len);
static void TextInsert(Widget w, char *s, int len);
static Bool ExceededMaxLines(Widget w);
static void ScrollLine(Widget w);
static Widget top, text;
static XtInputId input_id;
static FILE *input;
static Boolean regularFile = FALSE;
static Boolean notified;
static Boolean iconified;
static Atom wm_delete_window;
static Atom mit_console;
#define MIT_CONSOLE_LEN 12
#define MIT_CONSOLE "MIT_CONSOLE_"
static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
static struct _app_resources {
char *file;
Boolean stripNonprint;
Boolean notify;
Boolean daemon;
Boolean verbose;
Boolean exitOnFail;
int saveLines;
} app_resources;
#define Offset(field) XtOffsetOf(struct _app_resources, field)
static XtResource resources[] = {
{"file", "File", XtRString, sizeof (char *),
Offset (file), XtRString, "console" },
{"notify", "Notify", XtRBoolean, sizeof (Boolean),
Offset (notify), XtRImmediate, (XtPointer)True },
{"stripNonprint", "StripNonprint", XtRBoolean, sizeof (Boolean),
Offset (stripNonprint), XtRImmediate, (XtPointer)True },
{"daemon", "Daemon", XtRBoolean, sizeof (Boolean),
Offset (daemon), XtRImmediate, (XtPointer)False},
{"verbose", "Verbose", XtRBoolean, sizeof (Boolean),
Offset (verbose),XtRImmediate, (XtPointer)False},
{"exitOnFail", "ExitOnFail", XtRBoolean, sizeof (Boolean),
Offset (exitOnFail),XtRImmediate, (XtPointer)False},
{"saveLines", "SaveLines", XtRInt, sizeof (int),
Offset (saveLines), XtRImmediate, (XtPointer) 0 },
};
#undef Offset
static XrmOptionDescRec options[] = {
{"-file", "*file", XrmoptionSepArg, NULL},
{"-notify", "*notify", XrmoptionNoArg, "TRUE"},
{"-nonotify", "*notify", XrmoptionNoArg, "FALSE"},
{"-daemon", "*daemon", XrmoptionNoArg, "TRUE"},
{"-verbose", "*verbose", XrmoptionNoArg, "TRUE"},
{"-exitOnFail", "*exitOnFail", XrmoptionNoArg, "TRUE"},
{"-saveLines", "*saveLines", XrmoptionSepArg, NULL},
};
#ifdef ultrix
#define USE_FILE
#define FILE_NAME "/dev/xcons"
#endif
#ifdef __UNIXOS2__
#define USE_FILE
#define FILE_NAME "/dev/console$"
#define INCL_DOSFILEMGR
#define INCL_DOSDEVIOCTL
#include <os2.h>
#endif
#ifndef USE_FILE
#include <sys/ioctl.h>
#ifdef hpux
#include <termios.h>
#endif
#ifdef SVR4
#include <termios.h>
#include <sys/stropts.h>
#ifdef sun
#include <sys/strredir.h>
#endif
#endif
#if defined(TIOCCONS) || defined(SRIOCSREDIR) || defined(Lynx)
#define USE_PTY
static int tty_fd, pty_fd;
static char ttydev[64], ptydev[64];
#endif
#endif
#if (defined(SVR4) && !defined(sun)) || (defined(SYSV) && defined(i386))
#define USE_OSM
#include <signal.h>
#endif
#ifdef USE_PTY
static int get_pty(int *pty, int *tty, char *ttydev, char *ptydev);
#endif
#ifdef USE_OSM
static FILE *osm_pipe(void);
static int child_pid;
#endif
#ifdef Lynx
static void
RestoreConsole(void)
{
int fd;
if ((fd = open("/dev/con", O_RDONLY)) >= 0)
newconsole(fd);
}
#endif
static void
OpenConsole(void)
{
input = 0;
if (app_resources.file)
{
if (!strcmp (app_resources.file, "console"))
{
#if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(Lynx) && !defined(__UNIXOS2__)
struct stat sbuf;
if (!stat("/dev/console", &sbuf) &&
(sbuf.st_uid == getuid()) &&
!access("/dev/console", R_OK|W_OK))
#endif
{
#ifdef USE_FILE
input = fopen (FILE_NAME, "r");
#ifdef __UNIXOS2__
if (input)
{
ULONG arg = 1,arglen;
APIRET rc;
if ((rc=DosDevIOCtl(fileno(input), 0x76,0x4d,
&arg, sizeof(arg), &arglen,
NULL, 0, NULL)) != 0)
{
fclose(input);
input = 0;
}
}
#endif
#endif
#ifdef USE_PTY
if (get_pty (&pty_fd, &tty_fd, ttydev, ptydev) == 0)
{
#ifdef TIOCCONS
int on = 1;
if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1)
input = fdopen (pty_fd, "r");
#else
#ifndef Lynx
int consfd = open("/dev/console", O_RDONLY);
if (consfd >= 0)
{
if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1)
input = fdopen (pty_fd, "r");
close(consfd);
}
#else
if (newconsole(tty_fd) < 0)
perror("newconsole");
else
{
input = fdopen (pty_fd, "r");
atexit(RestoreConsole);
}
#endif
#endif
}
#endif
}
#ifdef USE_OSM
if (!input)
input = osm_pipe();
#endif
if (input && app_resources.verbose)
{
char *hostname;
TextAppend (text, "Console log for ", 16);
hostname = mit_console_name + MIT_CONSOLE_LEN;
TextAppend (text, hostname, strlen (hostname));
TextAppend (text, "\n", 1);
}
}
else
{
struct stat sbuf;
regularFile = FALSE;
if (access(app_resources.file, R_OK) == 0)
{
input = fopen (app_resources.file, "r");
if (input)
if (!stat(app_resources.file, &sbuf) &&
S_ISREG( sbuf.st_mode ) )
regularFile = TRUE;
}
}
if (!input)
{
if (app_resources.exitOnFail)
exit(0);
TextAppend (text, "Couldn't open ", 14);
TextAppend (text, app_resources.file, strlen (app_resources.file));
TextAppend (text, "\n", 1);
}
}
else
input = stdin;
if (input)
{
input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask,
inputReady, (XtPointer) text);
}
}
static void
CloseConsole (void)
{
if (input)
{
XtRemoveInput (input_id);
fclose (input);
}
#ifdef USE_PTY
close (tty_fd);
#endif
}
#ifdef USE_OSM
static void
KillChild(int sig)
{
if (child_pid > 0)
kill(child_pid, SIGTERM);
_exit(0);
}
#endif
static void
Quit(Widget widget, XEvent *event, String *params, Cardinal *num_params)
{
#ifdef USE_OSM
if (child_pid > 0)
kill(child_pid, SIGTERM);
#endif
exit (0);
}
#ifdef USE_OSM
static int (*ioerror)(Display *);
static int
IOError(Display *dpy)
{
if (child_pid > 0)
kill(child_pid, SIGTERM);
return (*ioerror)(dpy);
}
#endif
static void
Notify(void)
{
Arg arglist[1];
char *oldName;
char *newName;
if (!iconified || !app_resources.notify || notified)
return;
XtSetArg (arglist[0], XtNiconName, &oldName);
XtGetValues (top, arglist, 1);
newName = malloc (strlen (oldName) + 3);
if (!newName)
return;
sprintf (newName, "%s *", oldName);
XtSetArg (arglist[0], XtNiconName, newName);
XtSetValues (top, arglist, 1);
free (newName);
notified = True;
}
static void
Deiconified(Widget widget, XEvent *event, String *params, Cardinal *num_params)
{
Arg arglist[1];
char *oldName;
char *newName;
int oldlen;
iconified = False;
if (!app_resources.notify || !notified)
return;
XtSetArg (arglist[0], XtNiconName, &oldName);
XtGetValues (top, arglist, 1);
oldlen = strlen (oldName);
if (oldlen >= 2)
{
newName = malloc (oldlen - 1);
if (!newName)
return;
strncpy (newName, oldName, oldlen - 2);
newName[oldlen - 2] = '\0';
XtSetArg (arglist[0], XtNiconName, newName);
XtSetValues (top, arglist, 1);
free (newName);
}
notified = False;
}
static void
Iconified(Widget widget, XEvent *event, String *params, Cardinal *num_params)
{
iconified = True;
}
static void
Clear(Widget widget, XEvent *event, String *params, Cardinal *num_params)
{
long last;
XawTextBlock block;
last = TextLength (text);
block.ptr = "";
block.firstPos = 0;
block.length = 0;
block.format = FMT8BIT;
TextReplace (text, 0, last, &block);
}
static XtActionsRec actions[] = {
{ "Quit", Quit },
{ "Iconified", Iconified },
{ "Deiconified", Deiconified },
{ "Clear", Clear },
};
static void
stripNonprint(char *b)
{
char *c;
c = b;
while (*b)
{
if (isprint (*b) || (isspace (*b) && *b != '\r'))
{
if (c != b)
*c = *b;
++c;
}
++b;
}
*c = '\0';
}
static void
inputReady(XtPointer w, int *source, XtInputId *id)
{
char buffer[1025];
int n;
n = read (*source, buffer, sizeof (buffer) - 1);
if (n <= 0)
{
if (app_resources.file && regularFile && n == 0)
{
if (XPending(XtDisplay(w)))
return;
sleep(1);
return;
}
fclose (input);
XtRemoveInput (*id);
if (app_resources.file && !regularFile && n == 0)
{
OpenConsole();
}
}
Notify ();
buffer[n] = '\0';
if (app_resources.stripNonprint)
{
stripNonprint (buffer);
n = strlen (buffer);
}
TextAppend ((Widget) text, buffer, n);
}
static Boolean
ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
XtPointer *value, unsigned long *length, int *format)
{
Display* d = XtDisplay(w);
XSelectionRequestEvent* req =
XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
if (*target == XA_TARGETS(d))
{
Atom* targetP;
Atom* std_targets;
unsigned long std_length;
XmuConvertStandardSelection(w, req->time, selection, target, type,
(XPointer *)&std_targets, &std_length,
format);
*value = (XtPointer)XtMalloc(sizeof(Atom)*(std_length + 5));
targetP = *(Atom**)value;
*targetP++ = XA_STRING;
*targetP++ = XA_TEXT(d);
*targetP++ = XA_LENGTH(d);
*targetP++ = XA_LIST_LENGTH(d);
*targetP++ = XA_CHARACTER_POSITION(d);
*length = std_length + (targetP - (*(Atom **) value));
memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
XtFree((char*)std_targets);
*type = XA_ATOM;
*format = 32;
return True;
}
if (*target == XA_LIST_LENGTH(d) ||
*target == XA_LENGTH(d))
{
long * temp;
temp = (long *) XtMalloc(sizeof(long));
if (*target == XA_LIST_LENGTH(d))
*temp = 1L;
else
*temp = (long) TextLength (text);
*value = (XtPointer) temp;
*type = XA_INTEGER;
*length = 1L;
*format = 32;
return True;
}
if (*target == XA_CHARACTER_POSITION(d))
{
long * temp;
temp = (long *) XtMalloc(2 * sizeof(long));
temp[0] = (long) 0;
temp[1] = TextLength (text);
*value = (XtPointer) temp;
*type = XA_SPAN(d);
*length = 2L;
*format = 32;
return True;
}
if (*target == XA_STRING ||
*target == XA_TEXT(d) ||
*target == XA_COMPOUND_TEXT(d))
{
if (*target == XA_COMPOUND_TEXT(d))
*type = *target;
else
*type = XA_STRING;
*length = TextLength (text);
*value = (XtPointer)_XawTextGetSTRING((TextWidget) text, 0, *length);
*format = 8;
CloseConsole ();
return True;
}
if (XmuConvertStandardSelection(w, req->time, selection, target, type,
(XPointer *)value, length, format))
return True;
return False;
}
static void
LoseSelection(Widget w, Atom *selection)
{
Quit (w, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL);
}
static void
InsertSelection(Widget w, XtPointer client_data, Atom *selection, Atom *type,
XtPointer value, unsigned long *length, int *format)
{
if (*type != XT_CONVERT_FAIL)
TextInsert (text, (char *) value, *length);
XtOwnSelection(top, mit_console, CurrentTime,
ConvertSelection, LoseSelection, NULL);
OpenConsole ();
}
int
main(int argc, char *argv[])
{
Arg arglist[10];
Cardinal num_args;
top = XtInitialize ("xconsole", "XConsole", options, XtNumber (options),
&argc, argv);
XtGetApplicationResources (top, (XtPointer)&app_resources, resources,
XtNumber (resources), NULL, 0);
if (app_resources.daemon)
if (fork ()) exit (0);
XtAddActions (actions, XtNumber (actions));
text = XtCreateManagedWidget ("text", asciiTextWidgetClass,
top, NULL, 0);
XtRealizeWidget (top);
num_args = 0;
XtSetArg(arglist[num_args], XtNiconic, &iconified); num_args++;
XtGetValues(top, arglist, num_args);
if (iconified)
Iconified((Widget)NULL, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL);
else
Deiconified((Widget)NULL,(XEvent*)NULL,(String*)NULL,(Cardinal*)NULL);
wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW",
False);
(void) XSetWMProtocols (XtDisplay(top), XtWindow(top),
&wm_delete_window, 1);
XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255);
mit_console = XInternAtom(XtDisplay(top), mit_console_name, False);
if (XGetSelectionOwner (XtDisplay (top), mit_console))
{
XtGetSelectionValue(top, mit_console, XA_STRING, InsertSelection,
NULL, CurrentTime);
}
else
{
XtOwnSelection(top, mit_console, CurrentTime,
ConvertSelection, LoseSelection, NULL);
OpenConsole ();
}
#ifdef USE_OSM
ioerror = XSetIOErrorHandler(IOError);
#endif
XtMainLoop ();
return 0;
}
static long
TextLength(Widget w)
{
return XawTextSourceScan (XawTextGetSource (w),
(XawTextPosition) 0,
XawstAll, XawsdRight, 1, TRUE);
}
static void
TextReplace(Widget w, int start, int end, XawTextBlock *block)
{
Arg arg;
Widget source;
XawTextEditType edit_mode;
source = XawTextGetSource (w);
XtSetArg (arg, XtNeditType, &edit_mode);
XtGetValues (source, &arg, ONE);
XtSetArg (arg, XtNeditType, XawtextEdit);
XtSetValues (source, &arg, ONE);
XawTextReplace (w, start, end, block);
XtSetArg (arg, XtNeditType, edit_mode);
XtSetValues (source, &arg, ONE);
}
static void
TextAppend(Widget w, char *s, int len)
{
long last, current;
XawTextBlock block;
current = XawTextGetInsertionPoint (w);
last = TextLength (w);
block.ptr = s;
block.firstPos = 0;
block.length = len;
block.format = FMT8BIT;
if (app_resources.saveLines == 1)
TextReplace (w, 0, last, &block);
else
TextReplace (w, last, last, &block);
if (current == last)
XawTextSetInsertionPoint (w, last + block.length);
if (ExceededMaxLines(w))
ScrollLine(w);
}
static void
TextInsert(Widget w, char *s, int len)
{
XawTextBlock block;
long current;
current = XawTextGetInsertionPoint (w);
block.ptr = s;
block.firstPos = 0;
block.length = len;
block.format = FMT8BIT;
TextReplace (w, 0, 0, &block);
if (current == 0)
XawTextSetInsertionPoint (w, len);
if (ExceededMaxLines(w))
ScrollLine(w);
}
static Bool
ExceededMaxLines(Widget w)
{
XawTextPosition end_of_last_line;
Bool retval = False;
if (app_resources.saveLines > 0)
{
end_of_last_line = XawTextSourceScan (XawTextGetSource (w),
(XawTextPosition) 0,
XawstEOL, XawsdRight,
app_resources.saveLines, TRUE);
if (TextLength(w) > end_of_last_line)
retval = True;
else
retval = False;
}
else
retval = False;
return retval;
}
static void
ScrollLine(Widget w)
{
XawTextPosition firstnewline;
XawTextBlock block;
firstnewline = XawTextSourceScan (XawTextGetSource (w),
(XawTextPosition) 0,
XawstEOL, XawsdRight, 1, TRUE);
block.ptr = "";
block.firstPos = 0;
block.length = 0;
block.format = FMT8BIT;
TextReplace (w, 0, firstnewline, &block);
}
#ifdef USE_PTY
#include "../xterm/ptyx.h"
static int
get_pty(int *pty, int *tty, char *ttydev, char *ptydev)
{
#ifdef SVR4
if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0)
return 1;
grantpt(*pty);
unlockpt(*pty);
strcpy(ttydev, (char *)ptsname(*pty));
if ((*tty = open(ttydev, O_RDWR)) >= 0)
{
(void)ioctl(*tty, I_PUSH, "ttcompat");
return 0;
}
if (*pty >= 0)
close (*pty);
#else
#ifdef USE_GET_PSEUDOTTY
if ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 &&
(*tty = open (ttydev, O_RDWR)) >= 0)
return 0;
if (*pty >= 0)
close (*pty);
#else
static int devindex, letter = 0;
#if defined(umips) && defined (SYSTYPE_SYSV)
struct stat fstat_buf;
*pty = open ("/dev/ptc", O_RDWR);
if (*pty < 0 || (fstat (*pty, &fstat_buf)) < 0)
{
return(1);
}
sprintf (ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
sprintf (ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev));
if ((*tty = open (ttydev, O_RDWR)) >= 0)
{
return(0);
}
close (*pty);
#else
#ifdef CRAY
for (; devindex < 256; devindex++) {
sprintf (ttydev, "/dev/ttyp%03d", devindex);
sprintf (ptydev, "/dev/pty/%03d", devindex);
if ((*pty = open (ptydev, O_RDWR)) >= 0 &&
(*tty = open (ttydev, O_RDWR)) >= 0)
{
(void) devindex++;
return(0);
}
if (*pty >= 0)
close (*pty);
}
#else
#ifdef sgi
{
char *slave;
slave = _getpty (pty, O_RDWR, 0622, 0);
if ((*tty = open (slave, O_RDWR)) != -1)
return 0;
}
#else
strcpy (ttydev, "/dev/ttyxx");
strcpy (ptydev, "/dev/ptyxx");
while (PTYCHAR1[letter]) {
ttydev [strlen(ttydev) - 2] = ptydev [strlen(ptydev) - 2] =
PTYCHAR1 [letter];
while (PTYCHAR2[devindex]) {
ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] =
PTYCHAR2 [devindex];
if ((*pty = open (ptydev, O_RDWR)) >= 0 &&
(*tty = open (ttydev, O_RDWR)) >= 0)
{
(void) devindex++;
return(0);
}
if (*pty >= 0)
close (*pty);
devindex++;
}
devindex = 0;
(void) letter++;
}
#endif
#endif
#endif
#endif
#endif
return(1);
}
#endif
#ifdef USE_OSM
#ifdef SCO
#define OSM_DEVICE "/dev/error"
#else
#ifdef USL
#define OSM_DEVICE "/dev/osm2"
#define NO_READAHEAD
#else
#define OSM_DEVICE "/dev/osm"
#endif
#endif
#ifdef ISC
#define NO_READAHEAD
#endif
static FILE *
osm_pipe(void)
{
int tty;
char ttydev[64];
if (access(OSM_DEVICE, R_OK) < 0)
return NULL;
if ((tty = open("/dev/ptmx", O_RDWR)) < 0)
return NULL;
grantpt(tty);
unlockpt(tty);
strcpy(ttydev, (char *)ptsname(tty));
if ((child_pid = fork()) == 0)
{
int pty, osm, nbytes, skip;
char cbuf[128];
skip = 0;
#ifndef NO_READAHEAD
osm = open(OSM_DEVICE, O_RDONLY);
if (osm >= 0)
{
while ((nbytes = read(osm, cbuf, sizeof(cbuf))) > 0)
skip += nbytes;
close(osm);
}
#endif
pty = open(ttydev, O_RDWR);
if (pty < 0)
exit(1);
osm = open(OSM_DEVICE, O_RDONLY);
if (osm < 0)
exit(1);
for (nbytes = 0; skip > 0 && nbytes >= 0; skip -= nbytes)
{
nbytes = skip;
if (nbytes > sizeof(cbuf))
nbytes = sizeof(cbuf);
nbytes = read(osm, cbuf, nbytes);
}
while ((nbytes = read(osm, cbuf, sizeof(cbuf))) >= 0)
write(pty, cbuf, nbytes);
exit(0);
}
signal(SIGHUP, KillChild);
signal(SIGINT, KillChild);
signal(SIGTERM, KillChild);
return fdopen(tty, "r");
}
#endif