1c7484f1fSmrg/* 2c7484f1fSmrg * 3c7484f1fSmrgCopyright 1990, 1998 The Open Group 4c7484f1fSmrg 5c7484f1fSmrgPermission to use, copy, modify, distribute, and sell this software and its 6c7484f1fSmrgdocumentation for any purpose is hereby granted without fee, provided that 7c7484f1fSmrgthe above copyright notice appear in all copies and that both that 8c7484f1fSmrgcopyright notice and this permission notice appear in supporting 9c7484f1fSmrgdocumentation. 10c7484f1fSmrg 11c7484f1fSmrgThe above copyright notice and this permission notice shall be included in 12c7484f1fSmrgall copies or substantial portions of the Software. 13c7484f1fSmrg 14c7484f1fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15c7484f1fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16c7484f1fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17c7484f1fSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18c7484f1fSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19c7484f1fSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20c7484f1fSmrg 21c7484f1fSmrgExcept as contained in this notice, the name of The Open Group shall not be 22c7484f1fSmrgused in advertising or otherwise to promote the sale, use or other dealings 23c7484f1fSmrgin this Software without prior written authorization from The Open Group. 24c7484f1fSmrg * 25c7484f1fSmrg * Author: Keith Packard, MIT X Consortium 26c7484f1fSmrg */ 27c7484f1fSmrg 28c7484f1fSmrg 29c7484f1fSmrg#ifdef HAVE_CONFIG_H 30c7484f1fSmrg#include "config.h" 31c7484f1fSmrg#endif 32c7484f1fSmrg 33eaad2c89Smrg#include <X11/Xfuncproto.h> 34eaad2c89Smrg 35c7484f1fSmrg#include <X11/Intrinsic.h> 36c7484f1fSmrg#include <X11/StringDefs.h> 37c7484f1fSmrg#include <X11/Xatom.h> 38c7484f1fSmrg 39c7484f1fSmrg#include <X11/Xmu/Atoms.h> 40c7484f1fSmrg#include <X11/Xmu/StdSel.h> 41c7484f1fSmrg#include <X11/Xmu/SysUtil.h> 42c7484f1fSmrg 43c7484f1fSmrg#include <X11/Xaw/Form.h> 44c7484f1fSmrg#include <X11/Xaw/Label.h> 45c7484f1fSmrg#include <X11/Xaw/Command.h> 46c7484f1fSmrg#include <X11/Xaw/AsciiText.h> 47c7484f1fSmrg#include <X11/Xaw/Dialog.h> 48c7484f1fSmrg#include <X11/Xaw/Cardinals.h> 49c7484f1fSmrg#include <X11/Xaw/Paned.h> 50c7484f1fSmrg#include <X11/Xaw/Box.h> 51c7484f1fSmrg 52c7484f1fSmrgextern char *_XawTextGetSTRING(TextWidget ctx, XawTextPosition left, 53c7484f1fSmrg XawTextPosition right); 54c7484f1fSmrg 55c7484f1fSmrg#include <X11/Xos.h> 56c7484f1fSmrg#include <X11/Xfuncs.h> 57c7484f1fSmrg#include <sys/stat.h> 58c7484f1fSmrg#ifndef _POSIX_SOURCE 59c7484f1fSmrg#define _POSIX_SOURCE 60c7484f1fSmrg#include <stdio.h> 61c7484f1fSmrg#undef _POSIX_SOURCE 62c7484f1fSmrg#else 63c7484f1fSmrg#include <stdio.h> 64c7484f1fSmrg#endif 65c7484f1fSmrg#include <X11/Shell.h> 66c7484f1fSmrg#include <ctype.h> 67c7484f1fSmrg#include <stdlib.h> 68c7484f1fSmrg#ifdef HAS_OPENPTY 69f91b368dSmrg# ifdef HAVE_UTIL_H 70c7484f1fSmrg# include <util.h> 71c7484f1fSmrg# endif 72eaad2c89Smrg# ifdef HAVE_LIBUTIL_H 73eaad2c89Smrg# include <libutil.h> 74eaad2c89Smrg# endif 75f91b368dSmrg# ifdef HAVE_PTY_H 76c7484f1fSmrg# include <pty.h> 77c7484f1fSmrg# endif 78c7484f1fSmrg#endif 79c7484f1fSmrg 80c7484f1fSmrgstatic void inputReady(XtPointer w, int *source, XtInputId *id); 81c7484f1fSmrgstatic long TextLength(Widget w); 82c7484f1fSmrgstatic void TextReplace(Widget w, int start, int end, XawTextBlock *block); 83c7484f1fSmrgstatic void TextAppend(Widget w, char *s, int len); 84c7484f1fSmrgstatic void TextInsert(Widget w, char *s, int len); 85c7484f1fSmrgstatic Bool ExceededMaxLines(Widget w); 86c7484f1fSmrgstatic void ScrollLine(Widget w); 87c7484f1fSmrg 88c7484f1fSmrgstatic Widget top, text; 89c7484f1fSmrg 90c7484f1fSmrgstatic XtInputId input_id; 91c7484f1fSmrg 92c7484f1fSmrgstatic FILE *input; 93c7484f1fSmrgstatic Boolean regularFile = FALSE; 94c7484f1fSmrg 95c7484f1fSmrgstatic Boolean notified; 96c7484f1fSmrgstatic Boolean iconified; 97c7484f1fSmrg 98c7484f1fSmrgstatic Atom wm_delete_window; 99c7484f1fSmrgstatic Atom mit_console; 100c7484f1fSmrg 101c7484f1fSmrg#define MIT_CONSOLE_LEN 12 102c7484f1fSmrg#define MIT_CONSOLE "MIT_CONSOLE_" 103c7484f1fSmrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE; 104c7484f1fSmrg 105c7484f1fSmrgstatic struct _app_resources { 106c7484f1fSmrg char *file; 107c7484f1fSmrg Boolean stripNonprint; 108c7484f1fSmrg Boolean notify; 109c7484f1fSmrg Boolean daemon; 110c7484f1fSmrg Boolean verbose; 111c7484f1fSmrg Boolean exitOnFail; 112c7484f1fSmrg int saveLines; 113c7484f1fSmrg} app_resources; 114c7484f1fSmrg 115c7484f1fSmrg#define Offset(field) XtOffsetOf(struct _app_resources, field) 116c7484f1fSmrg 117c7484f1fSmrgstatic XtResource resources[] = { 118c7484f1fSmrg {"file", "File", XtRString, sizeof (char *), 119c7484f1fSmrg Offset (file), XtRString, "console" }, 120c7484f1fSmrg {"notify", "Notify", XtRBoolean, sizeof (Boolean), 121c7484f1fSmrg Offset (notify), XtRImmediate, (XtPointer)True }, 122c7484f1fSmrg {"stripNonprint", "StripNonprint", XtRBoolean, sizeof (Boolean), 123c7484f1fSmrg Offset (stripNonprint), XtRImmediate, (XtPointer)True }, 124c7484f1fSmrg {"daemon", "Daemon", XtRBoolean, sizeof (Boolean), 125c7484f1fSmrg Offset (daemon), XtRImmediate, (XtPointer)False}, 126c7484f1fSmrg {"verbose", "Verbose", XtRBoolean, sizeof (Boolean), 127c7484f1fSmrg Offset (verbose),XtRImmediate, (XtPointer)False}, 128c7484f1fSmrg {"exitOnFail", "ExitOnFail", XtRBoolean, sizeof (Boolean), 129c7484f1fSmrg Offset (exitOnFail),XtRImmediate, (XtPointer)False}, 130c7484f1fSmrg {"saveLines", "SaveLines", XtRInt, sizeof (int), 131c7484f1fSmrg Offset (saveLines), XtRImmediate, (XtPointer) 0 }, 132c7484f1fSmrg}; 133c7484f1fSmrg 134c7484f1fSmrg#undef Offset 135c7484f1fSmrg 136c7484f1fSmrgstatic XrmOptionDescRec options[] = { 137c7484f1fSmrg {"-file", "*file", XrmoptionSepArg, NULL}, 138c7484f1fSmrg {"-notify", "*notify", XrmoptionNoArg, "TRUE"}, 139c7484f1fSmrg {"-nonotify", "*notify", XrmoptionNoArg, "FALSE"}, 140c7484f1fSmrg {"-daemon", "*daemon", XrmoptionNoArg, "TRUE"}, 141c7484f1fSmrg {"-verbose", "*verbose", XrmoptionNoArg, "TRUE"}, 142c7484f1fSmrg {"-exitOnFail", "*exitOnFail", XrmoptionNoArg, "TRUE"}, 143c7484f1fSmrg {"-saveLines", "*saveLines", XrmoptionSepArg, NULL}, 144c7484f1fSmrg}; 145c7484f1fSmrg 146c7484f1fSmrg 147c7484f1fSmrg#ifdef linux 148c7484f1fSmrg#define USE_FILE 149c7484f1fSmrg#define FILE_NAME "/dev/xconsole" 150c7484f1fSmrg# if defined (__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) 151c7484f1fSmrg/* 152c7484f1fSmrg * Linux distribution based on glibc 2.1 and higher should use 153c7484f1fSmrg * devpts. This is the fallback if open file FILE_NAME fails. 154c7484f1fSmrg * <werner@suse.de> 155c7484f1fSmrg */ 156eaad2c89Smrg# define USE_PTS 157c7484f1fSmrg# endif 158c7484f1fSmrg#endif 159c7484f1fSmrg 160c7484f1fSmrg#if !defined (USE_FILE) || defined (linux) 161c7484f1fSmrg# include <sys/ioctl.h> 162c7484f1fSmrg# if defined (SVR4) || defined (USE_PTS) 163c7484f1fSmrg# include <termios.h> 164f91b368dSmrg# ifndef HAS_OPENPTY 165c7484f1fSmrg# include <sys/stropts.h> /* for I_PUSH */ 166f91b368dSmrg# endif 167c7484f1fSmrg# ifdef sun 168c7484f1fSmrg# include <sys/strredir.h> 169c7484f1fSmrg# endif 170c7484f1fSmrg# endif 171eaad2c89Smrg# if defined(TIOCCONS) || defined(SRIOCSREDIR) 172c7484f1fSmrg# define USE_PTY 173c7484f1fSmrgstatic int tty_fd, pty_fd; 174c7484f1fSmrg# endif 175c7484f1fSmrg#endif 176c7484f1fSmrg 177c7484f1fSmrg#ifdef USE_PTY 178bfce1ac2Smrgstatic int get_pty(int *pty, int *tty); 179c7484f1fSmrg#endif 180c7484f1fSmrg 181c7484f1fSmrg/* Copied from xterm/ptyx.h */ 182c7484f1fSmrg#ifndef PTYCHAR1 183c7484f1fSmrg#define PTYCHAR1 "pqrstuvwxyzPQRSTUVWXYZ" 184c7484f1fSmrg#endif /* !PTYCHAR1 */ 185c7484f1fSmrg 186c7484f1fSmrg#ifndef PTYCHAR2 187c7484f1fSmrg#ifdef __FreeBSD__ 188c7484f1fSmrg#define PTYCHAR2 "0123456789abcdefghijklmnopqrstuv" 189c7484f1fSmrg#else /* !__FreeBSD__ */ 190c7484f1fSmrg#define PTYCHAR2 "0123456789abcdef" 191c7484f1fSmrg#endif /* !__FreeBSD__ */ 192c7484f1fSmrg#endif /* !PTYCHAR2 */ 193c7484f1fSmrg 194c7484f1fSmrgstatic void 195c7484f1fSmrgOpenConsole(void) 196c7484f1fSmrg{ 197c7484f1fSmrg input = 0; 198c7484f1fSmrg if (app_resources.file) 199c7484f1fSmrg { 200c7484f1fSmrg if (!strcmp (app_resources.file, "console")) 201c7484f1fSmrg { 202c7484f1fSmrg /* must be owner and have read/write permission */ 203eaad2c89Smrg#if !defined(__NetBSD__) && !defined(__OpenBSD__) 204c7484f1fSmrg struct stat sbuf; 205c7484f1fSmrg# if !defined (linux) 206c7484f1fSmrg if (!stat("/dev/console", &sbuf) && 207c7484f1fSmrg (sbuf.st_uid == getuid()) && 208c7484f1fSmrg !access("/dev/console", R_OK|W_OK)) 209c7484f1fSmrg# endif 210c7484f1fSmrg#endif 211c7484f1fSmrg { 212c7484f1fSmrg#ifdef USE_FILE 213c7484f1fSmrg# ifdef linux 214c7484f1fSmrg if (!stat(FILE_NAME, &sbuf)) 215c7484f1fSmrg# endif 216eaad2c89Smrg input = fopen (FILE_NAME, "r"); 217c7484f1fSmrg#endif 218eaad2c89Smrg 219c7484f1fSmrg#ifdef USE_PTY 220bfce1ac2Smrg if (!input && get_pty (&pty_fd, &tty_fd) == 0) 221c7484f1fSmrg { 222c7484f1fSmrg# ifdef TIOCCONS 223c7484f1fSmrg int on = 1; 224c7484f1fSmrg if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1) 225c7484f1fSmrg input = fdopen (pty_fd, "r"); 226c7484f1fSmrg# else 227c7484f1fSmrg int consfd = open("/dev/console", O_RDONLY); 228c7484f1fSmrg if (consfd >= 0) 229c7484f1fSmrg { 230c7484f1fSmrg if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1) 231c7484f1fSmrg input = fdopen (pty_fd, "r"); 232c7484f1fSmrg close(consfd); 233c7484f1fSmrg } 234c7484f1fSmrg# endif 235c7484f1fSmrg } 236c7484f1fSmrg#endif /* USE_PTY */ 237c7484f1fSmrg } 238c7484f1fSmrg if (input && app_resources.verbose) 239c7484f1fSmrg { 240c7484f1fSmrg char *hostname; 241c7484f1fSmrg TextAppend (text, "Console log for ", 16); 242c7484f1fSmrg hostname = mit_console_name + MIT_CONSOLE_LEN; 243c7484f1fSmrg TextAppend (text, hostname, strlen (hostname)); 244c7484f1fSmrg TextAppend (text, "\n", 1); 245c7484f1fSmrg } 246c7484f1fSmrg } 247c7484f1fSmrg else 248c7484f1fSmrg { 249c7484f1fSmrg regularFile = FALSE; 250c7484f1fSmrg if (access(app_resources.file, R_OK) == 0) 251c7484f1fSmrg { 252eaad2c89Smrg int fd = open (app_resources.file, 253eaad2c89Smrg O_RDONLY | O_NONBLOCK | O_NOCTTY); 254eaad2c89Smrg if (fd != -1) { 255eaad2c89Smrg input = fdopen (fd, "r"); 256eaad2c89Smrg 257eaad2c89Smrg if (input) { 258eaad2c89Smrg struct stat sbuf; 259eaad2c89Smrg 260eaad2c89Smrg if ((fstat(fd, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) 261eaad2c89Smrg regularFile = TRUE; 262eaad2c89Smrg } 263eaad2c89Smrg else 264eaad2c89Smrg close(fd); 265eaad2c89Smrg } 266c7484f1fSmrg } 267c7484f1fSmrg } 268c7484f1fSmrg if (!input) 269c7484f1fSmrg { 270c7484f1fSmrg if (app_resources.exitOnFail) 271c7484f1fSmrg exit(0); 272c7484f1fSmrg TextAppend (text, "Couldn't open ", 14); 273c7484f1fSmrg TextAppend (text, app_resources.file, strlen (app_resources.file)); 274c7484f1fSmrg TextAppend (text, "\n", 1); 275c7484f1fSmrg } 276c7484f1fSmrg } 277c7484f1fSmrg else 278c7484f1fSmrg input = stdin; 279c7484f1fSmrg 280c7484f1fSmrg if (input) 281c7484f1fSmrg { 282c7484f1fSmrg input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask, 283c7484f1fSmrg inputReady, (XtPointer) text); 284c7484f1fSmrg } 285c7484f1fSmrg} 286c7484f1fSmrg 287c7484f1fSmrgstatic void 288c7484f1fSmrgCloseConsole (void) 289c7484f1fSmrg{ 290c7484f1fSmrg if (input) 291c7484f1fSmrg { 292c7484f1fSmrg XtRemoveInput (input_id); 293c7484f1fSmrg fclose (input); 294c7484f1fSmrg } 295c7484f1fSmrg#ifdef USE_PTY 296c7484f1fSmrg close (tty_fd); 297c7484f1fSmrg#endif 298c7484f1fSmrg} 299c7484f1fSmrg 300c7484f1fSmrg/*ARGSUSED*/ 301eaad2c89Smrgstatic void _X_NORETURN 302c7484f1fSmrgQuit(Widget widget, XEvent *event, String *params, Cardinal *num_params) 303c7484f1fSmrg{ 304c7484f1fSmrg exit (0); 305c7484f1fSmrg} 306c7484f1fSmrg 307c7484f1fSmrgstatic void 308c7484f1fSmrgNotify(void) 309c7484f1fSmrg{ 310c7484f1fSmrg Arg arglist[1]; 311c7484f1fSmrg char *oldName; 312c7484f1fSmrg char *newName; 313c7484f1fSmrg 314c7484f1fSmrg if (!iconified || !app_resources.notify || notified) 315c7484f1fSmrg return; 316c7484f1fSmrg XtSetArg (arglist[0], XtNiconName, &oldName); 317c7484f1fSmrg XtGetValues (top, arglist, 1); 318c7484f1fSmrg newName = malloc (strlen (oldName) + 3); 319c7484f1fSmrg if (!newName) 320c7484f1fSmrg return; 321c7484f1fSmrg sprintf (newName, "%s *", oldName); 322c7484f1fSmrg XtSetArg (arglist[0], XtNiconName, newName); 323c7484f1fSmrg XtSetValues (top, arglist, 1); 324c7484f1fSmrg free (newName); 325c7484f1fSmrg notified = True; 326c7484f1fSmrg} 327c7484f1fSmrg 328c7484f1fSmrg/*ARGSUSED*/ 329c7484f1fSmrgstatic void 330c7484f1fSmrgDeiconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 331c7484f1fSmrg{ 332c7484f1fSmrg Arg arglist[1]; 333c7484f1fSmrg char *oldName; 334c7484f1fSmrg char *newName; 335eaad2c89Smrg size_t oldlen; 336c7484f1fSmrg 337c7484f1fSmrg iconified = False; 338c7484f1fSmrg if (!app_resources.notify || !notified) 339c7484f1fSmrg return; 340c7484f1fSmrg XtSetArg (arglist[0], XtNiconName, &oldName); 341c7484f1fSmrg XtGetValues (top, arglist, 1); 342c7484f1fSmrg oldlen = strlen (oldName); 343c7484f1fSmrg if (oldlen >= 2) 344c7484f1fSmrg { 345c7484f1fSmrg newName = malloc (oldlen - 1); 346c7484f1fSmrg if (!newName) 347c7484f1fSmrg return; 348c7484f1fSmrg strncpy (newName, oldName, oldlen - 2); 349c7484f1fSmrg newName[oldlen - 2] = '\0'; 350c7484f1fSmrg XtSetArg (arglist[0], XtNiconName, newName); 351c7484f1fSmrg XtSetValues (top, arglist, 1); 352c7484f1fSmrg free (newName); 353c7484f1fSmrg } 354c7484f1fSmrg notified = False; 355c7484f1fSmrg} 356c7484f1fSmrg 357c7484f1fSmrg/*ARGSUSED*/ 358c7484f1fSmrgstatic void 359c7484f1fSmrgIconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 360c7484f1fSmrg{ 361c7484f1fSmrg iconified = True; 362c7484f1fSmrg} 363c7484f1fSmrg 364c7484f1fSmrg/*ARGSUSED*/ 365c7484f1fSmrgstatic void 366c7484f1fSmrgClear(Widget widget, XEvent *event, String *params, Cardinal *num_params) 367c7484f1fSmrg{ 368c7484f1fSmrg long last; 369c7484f1fSmrg XawTextBlock block; 370c7484f1fSmrg 371c7484f1fSmrg last = TextLength (text); 372c7484f1fSmrg block.ptr = ""; 373c7484f1fSmrg block.firstPos = 0; 374c7484f1fSmrg block.length = 0; 375c7484f1fSmrg block.format = FMT8BIT; 376c7484f1fSmrg TextReplace (text, 0, last, &block); 377c7484f1fSmrg} 378c7484f1fSmrg 379c7484f1fSmrgstatic XtActionsRec actions[] = { 380c7484f1fSmrg { "Quit", Quit }, 381c7484f1fSmrg { "Iconified", Iconified }, 382c7484f1fSmrg { "Deiconified", Deiconified }, 383c7484f1fSmrg { "Clear", Clear }, 384c7484f1fSmrg}; 385c7484f1fSmrg 386c7484f1fSmrgstatic void 387c7484f1fSmrgstripNonprint(char *b) 388c7484f1fSmrg{ 389c7484f1fSmrg char *c; 390c7484f1fSmrg 391c7484f1fSmrg c = b; 392c7484f1fSmrg while (*b) 393c7484f1fSmrg { 394c7484f1fSmrg if (isprint (*b) || (isspace (*b) && *b != '\r')) 395c7484f1fSmrg { 396c7484f1fSmrg if (c != b) 397c7484f1fSmrg *c = *b; 398c7484f1fSmrg ++c; 399c7484f1fSmrg } 400c7484f1fSmrg ++b; 401c7484f1fSmrg } 402c7484f1fSmrg *c = '\0'; 403c7484f1fSmrg} 404c7484f1fSmrg 405c7484f1fSmrgstatic void 406c7484f1fSmrginputReady(XtPointer w, int *source, XtInputId *id) 407c7484f1fSmrg{ 408c7484f1fSmrg char buffer[1025]; 409c7484f1fSmrg int n; 410c7484f1fSmrg 411c7484f1fSmrg n = read (*source, buffer, sizeof (buffer) - 1); 412c7484f1fSmrg if (n <= 0) 413c7484f1fSmrg { 414c7484f1fSmrg if (app_resources.file && regularFile && n == 0) 415c7484f1fSmrg { 416c7484f1fSmrg if (XPending(XtDisplay(w))) 417c7484f1fSmrg return; 418c7484f1fSmrg 419c7484f1fSmrg sleep(1); 420c7484f1fSmrg return; 421c7484f1fSmrg } 422c7484f1fSmrg 423c7484f1fSmrg fclose (input); 424c7484f1fSmrg XtRemoveInput (*id); 425c7484f1fSmrg 426c7484f1fSmrg /* try to reopen if pipe; this can be caused by syslog restart */ 427c7484f1fSmrg if (app_resources.file && !regularFile && n == 0) 428c7484f1fSmrg { 429c7484f1fSmrg OpenConsole(); 430c7484f1fSmrg } 431c7484f1fSmrg } else { 432c7484f1fSmrg Notify(); 433c7484f1fSmrg buffer[n] = '\0'; 434c7484f1fSmrg if (app_resources.stripNonprint) 435c7484f1fSmrg { 436c7484f1fSmrg stripNonprint (buffer); 437c7484f1fSmrg n = strlen (buffer); 438c7484f1fSmrg } 439eaad2c89Smrg 440c7484f1fSmrg TextAppend ((Widget) text, buffer, n); 441c7484f1fSmrg } 442c7484f1fSmrg} 443c7484f1fSmrg 444c7484f1fSmrgstatic Boolean 445c7484f1fSmrgConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 446c7484f1fSmrg XtPointer *value, unsigned long *length, int *format) 447c7484f1fSmrg{ 448c7484f1fSmrg Display* d = XtDisplay(w); 449c7484f1fSmrg XSelectionRequestEvent* req = 450c7484f1fSmrg XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); 451c7484f1fSmrg 452c7484f1fSmrg if (*target == XA_TARGETS(d)) 453c7484f1fSmrg { 454c7484f1fSmrg Atom* targetP; 455c7484f1fSmrg Atom* std_targets; 456c7484f1fSmrg unsigned long std_length; 457c7484f1fSmrg XmuConvertStandardSelection(w, req->time, selection, target, type, 458c7484f1fSmrg (XPointer *)&std_targets, &std_length, 459c7484f1fSmrg format); 460c7484f1fSmrg *value = (XtPointer)XtMalloc(sizeof(Atom)*(std_length + 5)); 461c7484f1fSmrg targetP = *(Atom**)value; 462c7484f1fSmrg *targetP++ = XA_STRING; 463c7484f1fSmrg *targetP++ = XA_TEXT(d); 464c7484f1fSmrg *targetP++ = XA_LENGTH(d); 465c7484f1fSmrg *targetP++ = XA_LIST_LENGTH(d); 466c7484f1fSmrg *targetP++ = XA_CHARACTER_POSITION(d); 467c7484f1fSmrg *length = std_length + (targetP - (*(Atom **) value)); 468c7484f1fSmrg memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 469c7484f1fSmrg XtFree((char*)std_targets); 470c7484f1fSmrg *type = XA_ATOM; 471c7484f1fSmrg *format = 32; 472c7484f1fSmrg return True; 473c7484f1fSmrg } 474c7484f1fSmrg 475c7484f1fSmrg if (*target == XA_LIST_LENGTH(d) || 476c7484f1fSmrg *target == XA_LENGTH(d)) 477c7484f1fSmrg { 478c7484f1fSmrg long * temp; 479c7484f1fSmrg 480c7484f1fSmrg temp = (long *) XtMalloc(sizeof(long)); 481c7484f1fSmrg if (*target == XA_LIST_LENGTH(d)) 482c7484f1fSmrg *temp = 1L; 483c7484f1fSmrg else /* *target == XA_LENGTH(d) */ 484c7484f1fSmrg *temp = (long) TextLength (text); 485c7484f1fSmrg 486c7484f1fSmrg *value = (XtPointer) temp; 487c7484f1fSmrg *type = XA_INTEGER; 488c7484f1fSmrg *length = 1L; 489c7484f1fSmrg *format = 32; 490c7484f1fSmrg return True; 491c7484f1fSmrg } 492c7484f1fSmrg 493c7484f1fSmrg if (*target == XA_CHARACTER_POSITION(d)) 494c7484f1fSmrg { 495c7484f1fSmrg long * temp; 496c7484f1fSmrg 497c7484f1fSmrg temp = (long *) XtMalloc(2 * sizeof(long)); 498c7484f1fSmrg temp[0] = (long) 0; 499c7484f1fSmrg temp[1] = TextLength (text); 500c7484f1fSmrg *value = (XtPointer) temp; 501c7484f1fSmrg *type = XA_SPAN(d); 502c7484f1fSmrg *length = 2L; 503c7484f1fSmrg *format = 32; 504c7484f1fSmrg return True; 505c7484f1fSmrg } 506c7484f1fSmrg 507c7484f1fSmrg if (*target == XA_STRING || 508c7484f1fSmrg *target == XA_TEXT(d) || 509c7484f1fSmrg *target == XA_COMPOUND_TEXT(d)) 510c7484f1fSmrg { 511c7484f1fSmrg if (*target == XA_COMPOUND_TEXT(d)) 512c7484f1fSmrg *type = *target; 513c7484f1fSmrg else 514c7484f1fSmrg *type = XA_STRING; 515c7484f1fSmrg *length = TextLength (text); 516c7484f1fSmrg *value = (XtPointer)_XawTextGetSTRING((TextWidget) text, 0, *length); 517c7484f1fSmrg *format = 8; 518c7484f1fSmrg /* 519c7484f1fSmrg * Drop our connection to the file; the new console program 520c7484f1fSmrg * will open as soon as it receives the selection contents; there 521c7484f1fSmrg * is a small window where console output will not be redirected, 522c7484f1fSmrg * but I see no way of avoiding that without having two programs 523c7484f1fSmrg * attempt to redirect console output at the same time, which seems 524c7484f1fSmrg * worse 525c7484f1fSmrg */ 526c7484f1fSmrg CloseConsole (); 527c7484f1fSmrg return True; 528c7484f1fSmrg } 529c7484f1fSmrg 530c7484f1fSmrg if (XmuConvertStandardSelection(w, req->time, selection, target, type, 531c7484f1fSmrg (XPointer *)value, length, format)) 532c7484f1fSmrg return True; 533c7484f1fSmrg 534c7484f1fSmrg return False; 535c7484f1fSmrg} 536c7484f1fSmrg 537eaad2c89Smrgstatic void _X_NORETURN 538c7484f1fSmrgLoseSelection(Widget w, Atom *selection) 539c7484f1fSmrg{ 540c7484f1fSmrg Quit (w, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 541c7484f1fSmrg} 542c7484f1fSmrg 543c7484f1fSmrg/*ARGSUSED*/ 544c7484f1fSmrgstatic void 545c7484f1fSmrgInsertSelection(Widget w, XtPointer client_data, Atom *selection, Atom *type, 546c7484f1fSmrg XtPointer value, unsigned long *length, int *format) 547c7484f1fSmrg{ 548c7484f1fSmrg if (*type != XT_CONVERT_FAIL) 549c7484f1fSmrg TextInsert (text, (char *) value, *length); 550c7484f1fSmrg XtOwnSelection(top, mit_console, CurrentTime, 551c7484f1fSmrg ConvertSelection, LoseSelection, NULL); 552c7484f1fSmrg OpenConsole (); 553c7484f1fSmrg} 554c7484f1fSmrg 5556448b35cSmrgstatic void _X_NORETURN 5566448b35cSmrgusage(int exitval) 5576448b35cSmrg{ 5586448b35cSmrg const char *usage_message = 5596448b35cSmrg "usage: xconsole [-toolkitoption ...] [-file file-name] [-notify|-nonotify]\n" 5606448b35cSmrg " [-stripNonprint] [-daemon] [-verbose] [-exitOnFail]\n" 5616448b35cSmrg " [-saveLines count]\n" 5626448b35cSmrg " xconsole -help\n" 5636448b35cSmrg " xconsole -version\n"; 5646448b35cSmrg 5656448b35cSmrg fputs(usage_message, stderr); 5666448b35cSmrg exit(exitval); 5676448b35cSmrg} 5686448b35cSmrg 569c7484f1fSmrgint 570c7484f1fSmrgmain(int argc, char *argv[]) 571c7484f1fSmrg{ 572c7484f1fSmrg Arg arglist[10]; 573c7484f1fSmrg Cardinal num_args; 574c7484f1fSmrg 575c7484f1fSmrg XtSetLanguageProc(NULL,NULL,NULL); 5766448b35cSmrg 5776448b35cSmrg /* Handle args that don't require opening a display */ 5786448b35cSmrg for (int n = 1; n < argc; n++) { 5796448b35cSmrg const char *argn = argv[n]; 5806448b35cSmrg /* accept single or double dash for -help & -version */ 5816448b35cSmrg if (argn[0] == '-' && argn[1] == '-') { 5826448b35cSmrg argn++; 5836448b35cSmrg } 5846448b35cSmrg if (strcmp(argn, "-help") == 0) { 5856448b35cSmrg usage(0); 5866448b35cSmrg } 5876448b35cSmrg if (strcmp(argn, "-version") == 0) { 5886448b35cSmrg puts(PACKAGE_STRING); 5896448b35cSmrg exit(0); 5906448b35cSmrg } 5916448b35cSmrg } 5926448b35cSmrg 593c7484f1fSmrg top = XtInitialize ("xconsole", "XConsole", options, XtNumber (options), 594c7484f1fSmrg &argc, argv); 5956448b35cSmrg if (argc != 1) { 5966448b35cSmrg fputs("Unknown argument(s):", stderr); 5976448b35cSmrg for (int n = 1; n < argc; n++) { 5986448b35cSmrg fprintf(stderr, " %s", argv[n]); 5996448b35cSmrg } 6006448b35cSmrg fputs("\n\n", stderr); 6016448b35cSmrg usage(1); 6026448b35cSmrg } 6036448b35cSmrg 604c7484f1fSmrg XtGetApplicationResources (top, (XtPointer)&app_resources, resources, 605c7484f1fSmrg XtNumber (resources), NULL, 0); 606c7484f1fSmrg 607c7484f1fSmrg if (app_resources.daemon) 608c7484f1fSmrg if (fork ()) exit (0); 609c7484f1fSmrg XtAddActions (actions, XtNumber (actions)); 610c7484f1fSmrg 611c7484f1fSmrg text = XtCreateManagedWidget ("text", asciiTextWidgetClass, 612c7484f1fSmrg top, NULL, 0); 613c7484f1fSmrg 614c7484f1fSmrg XtRealizeWidget (top); 615c7484f1fSmrg num_args = 0; 616c7484f1fSmrg XtSetArg(arglist[num_args], XtNiconic, &iconified); num_args++; 617c7484f1fSmrg XtGetValues(top, arglist, num_args); 618c7484f1fSmrg if (iconified) 619c7484f1fSmrg Iconified((Widget)NULL, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 620c7484f1fSmrg else 621c7484f1fSmrg Deiconified((Widget)NULL,(XEvent*)NULL,(String*)NULL,(Cardinal*)NULL); 622c7484f1fSmrg wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", 623c7484f1fSmrg False); 624c7484f1fSmrg (void) XSetWMProtocols (XtDisplay(top), XtWindow(top), 625c7484f1fSmrg &wm_delete_window, 1); 626c7484f1fSmrg 627c7484f1fSmrg XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255); 628c7484f1fSmrg 629c7484f1fSmrg mit_console = XInternAtom(XtDisplay(top), mit_console_name, False); 630c7484f1fSmrg 631c7484f1fSmrg if (XGetSelectionOwner (XtDisplay (top), mit_console)) 632c7484f1fSmrg { 633c7484f1fSmrg XtGetSelectionValue(top, mit_console, XA_STRING, InsertSelection, 634c7484f1fSmrg NULL, CurrentTime); 635c7484f1fSmrg } 636c7484f1fSmrg else 637c7484f1fSmrg { 638c7484f1fSmrg XtOwnSelection(top, mit_console, CurrentTime, 639c7484f1fSmrg ConvertSelection, LoseSelection, NULL); 640c7484f1fSmrg OpenConsole (); 641c7484f1fSmrg } 642c7484f1fSmrg XtMainLoop (); 643c7484f1fSmrg return 0; 644c7484f1fSmrg} 645c7484f1fSmrg 646c7484f1fSmrgstatic long 647c7484f1fSmrgTextLength(Widget w) 648c7484f1fSmrg{ 649c7484f1fSmrg return XawTextSourceScan (XawTextGetSource (w), 650c7484f1fSmrg (XawTextPosition) 0, 651c7484f1fSmrg XawstAll, XawsdRight, 1, TRUE); 652c7484f1fSmrg} 653c7484f1fSmrg 654c7484f1fSmrgstatic void 655c7484f1fSmrgTextReplace(Widget w, int start, int end, XawTextBlock *block) 656c7484f1fSmrg{ 657c7484f1fSmrg Arg arg; 658c7484f1fSmrg Widget source; 659c7484f1fSmrg XawTextEditType edit_mode; 660c7484f1fSmrg 661c7484f1fSmrg source = XawTextGetSource (w); 662c7484f1fSmrg XtSetArg (arg, XtNeditType, &edit_mode); 663c7484f1fSmrg XtGetValues (source, &arg, ONE); 664c7484f1fSmrg XtSetArg (arg, XtNeditType, XawtextEdit); 665c7484f1fSmrg XtSetValues (source, &arg, ONE); 666c7484f1fSmrg XawTextReplace (w, start, end, block); 667c7484f1fSmrg XtSetArg (arg, XtNeditType, edit_mode); 668c7484f1fSmrg XtSetValues (source, &arg, ONE); 669c7484f1fSmrg} 670c7484f1fSmrg 671c7484f1fSmrgstatic void 672c7484f1fSmrgTextAppend(Widget w, char *s, int len) 673c7484f1fSmrg{ 674c7484f1fSmrg long last, current; 675c7484f1fSmrg XawTextBlock block; 676c7484f1fSmrg 677c7484f1fSmrg current = XawTextGetInsertionPoint (w); 678c7484f1fSmrg last = TextLength (w); 679c7484f1fSmrg block.ptr = s; 680c7484f1fSmrg block.firstPos = 0; 681c7484f1fSmrg block.length = len; 682c7484f1fSmrg block.format = FMT8BIT; 683c7484f1fSmrg /* 684c7484f1fSmrg * If saveLines is 1, just replace the entire contents of the widget 685c7484f1fSmrg * each time, so the test in ExceededMaxLines() isn't fooled. 686c7484f1fSmrg */ 687c7484f1fSmrg if (app_resources.saveLines == 1) 688c7484f1fSmrg TextReplace (w, 0, last, &block); 689c7484f1fSmrg else 690c7484f1fSmrg TextReplace (w, last, last, &block); 691c7484f1fSmrg if (current == last) 692c7484f1fSmrg XawTextSetInsertionPoint (w, last + block.length); 693c7484f1fSmrg if (ExceededMaxLines(w)) 694c7484f1fSmrg ScrollLine(w); 695c7484f1fSmrg} 696c7484f1fSmrg 697c7484f1fSmrgstatic void 698c7484f1fSmrgTextInsert(Widget w, char *s, int len) 699c7484f1fSmrg{ 700c7484f1fSmrg XawTextBlock block; 701c7484f1fSmrg long current; 702c7484f1fSmrg 703c7484f1fSmrg current = XawTextGetInsertionPoint (w); 704c7484f1fSmrg block.ptr = s; 705c7484f1fSmrg block.firstPos = 0; 706c7484f1fSmrg block.length = len; 707c7484f1fSmrg block.format = FMT8BIT; 708c7484f1fSmrg TextReplace (w, 0, 0, &block); 709c7484f1fSmrg if (current == 0) 710c7484f1fSmrg XawTextSetInsertionPoint (w, len); 711c7484f1fSmrg if (ExceededMaxLines(w)) 712c7484f1fSmrg ScrollLine(w); 713c7484f1fSmrg} 714c7484f1fSmrg 715c7484f1fSmrgstatic Bool 716c7484f1fSmrgExceededMaxLines(Widget w) 717c7484f1fSmrg{ 718c7484f1fSmrg XawTextPosition end_of_last_line; 719c7484f1fSmrg Bool retval = False; 720c7484f1fSmrg 721c7484f1fSmrg if (app_resources.saveLines > 0) 722c7484f1fSmrg { 723c7484f1fSmrg /* 724c7484f1fSmrg * XawTextSourceScan() will return the end of the widget if it cannot 725c7484f1fSmrg * find what it is searching for. 726c7484f1fSmrg */ 727c7484f1fSmrg end_of_last_line = XawTextSourceScan (XawTextGetSource (w), 728c7484f1fSmrg (XawTextPosition) 0, 729c7484f1fSmrg XawstEOL, XawsdRight, 730c7484f1fSmrg app_resources.saveLines, TRUE); 731c7484f1fSmrg if (TextLength(w) > end_of_last_line) 732c7484f1fSmrg retval = True; 733c7484f1fSmrg else 734c7484f1fSmrg retval = False; 735c7484f1fSmrg } 736c7484f1fSmrg else 737c7484f1fSmrg retval = False; 738c7484f1fSmrg return retval; 739c7484f1fSmrg} 740c7484f1fSmrg 741c7484f1fSmrgstatic void 742c7484f1fSmrgScrollLine(Widget w) 743c7484f1fSmrg{ 744c7484f1fSmrg XawTextPosition firstnewline; 745c7484f1fSmrg XawTextBlock block; 746c7484f1fSmrg 747c7484f1fSmrg /* 748c7484f1fSmrg * This is pretty inefficient but should work well enough unless the 749c7484f1fSmrg * console device is getting totally spammed. Generally, new lines 750c7484f1fSmrg * only come in one at a time anyway. 751c7484f1fSmrg */ 752c7484f1fSmrg firstnewline = XawTextSourceScan (XawTextGetSource (w), 753c7484f1fSmrg (XawTextPosition) 0, 754c7484f1fSmrg XawstEOL, XawsdRight, 1, TRUE); 755c7484f1fSmrg block.ptr = ""; 756c7484f1fSmrg block.firstPos = 0; 757c7484f1fSmrg block.length = 0; 758c7484f1fSmrg block.format = FMT8BIT; 759c7484f1fSmrg TextReplace (w, 0, firstnewline, &block); 760c7484f1fSmrg} 761c7484f1fSmrg 762c7484f1fSmrg#ifdef USE_PTY 763c7484f1fSmrg/* 764c7484f1fSmrg * This function opens up a pty master and stuffs its value into pty. 765c7484f1fSmrg * If it finds one, it returns a value of 0. If it does not find one, 766c7484f1fSmrg * it returns a value of !0. This routine is designed to be re-entrant, 767c7484f1fSmrg * so that if a pty master is found and later, we find that the slave 768c7484f1fSmrg * has problems, we can re-enter this function and get another one. 769c7484f1fSmrg */ 770c7484f1fSmrg 771c7484f1fSmrgstatic int 772bfce1ac2Smrgget_pty(int *pty, int *tty) 773c7484f1fSmrg{ 774c7484f1fSmrg#ifdef HAS_OPENPTY 775c7484f1fSmrg if (openpty(pty, tty, NULL, NULL, NULL) == -1) { 776c7484f1fSmrg return 1; 777c7484f1fSmrg } 778c7484f1fSmrg return 0; 779bfce1ac2Smrg#else 780bfce1ac2Smrg static char ttydev[64], ptydev[64]; 781bfce1ac2Smrg 782bfce1ac2Smrg#if defined (SVR4) || defined (USE_PTS) 783c7484f1fSmrg if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) 784c7484f1fSmrg return 1; 785c7484f1fSmrg grantpt(*pty); 786c7484f1fSmrg unlockpt(*pty); 787c7484f1fSmrg strcpy(ttydev, (char *)ptsname(*pty)); 788c7484f1fSmrg if ((*tty = open(ttydev, O_RDWR)) >= 0) 789c7484f1fSmrg { 790c7484f1fSmrg (void)ioctl(*tty, I_PUSH, "ttcompat"); 791c7484f1fSmrg return 0; 792c7484f1fSmrg } 793c7484f1fSmrg if (*pty >= 0) 794c7484f1fSmrg close (*pty); 795c7484f1fSmrg#else /* !SVR4, need lots of code */ 796c7484f1fSmrg#ifdef USE_GET_PSEUDOTTY 797c7484f1fSmrg if ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 && 798c7484f1fSmrg (*tty = open (ttydev, O_RDWR)) >= 0) 799c7484f1fSmrg return 0; 800c7484f1fSmrg if (*pty >= 0) 801c7484f1fSmrg close (*pty); 802c7484f1fSmrg#else 803c7484f1fSmrg static int devindex, letter = 0; 804c7484f1fSmrg 805c7484f1fSmrg strcpy (ttydev, "/dev/ttyxx"); 806c7484f1fSmrg strcpy (ptydev, "/dev/ptyxx"); 807c7484f1fSmrg while (PTYCHAR1[letter]) { 808c7484f1fSmrg ttydev [strlen(ttydev) - 2] = ptydev [strlen(ptydev) - 2] = 809c7484f1fSmrg PTYCHAR1 [letter]; 810c7484f1fSmrg 811c7484f1fSmrg while (PTYCHAR2[devindex]) { 812c7484f1fSmrg ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] = 813c7484f1fSmrg PTYCHAR2 [devindex]; 814c7484f1fSmrg if ((*pty = open (ptydev, O_RDWR)) >= 0 && 815c7484f1fSmrg (*tty = open (ttydev, O_RDWR)) >= 0) 816c7484f1fSmrg { 817c7484f1fSmrg /* 818c7484f1fSmrg * We need to set things up for our next entry 819c7484f1fSmrg * into this function! 820c7484f1fSmrg */ 821c7484f1fSmrg (void) devindex++; 822c7484f1fSmrg return(0); 823c7484f1fSmrg } 824c7484f1fSmrg if (*pty >= 0) 825c7484f1fSmrg close (*pty); 826c7484f1fSmrg devindex++; 827c7484f1fSmrg } 828c7484f1fSmrg devindex = 0; 829c7484f1fSmrg (void) letter++; 830c7484f1fSmrg } 831c7484f1fSmrg#endif /* USE_GET_PSEUDOTTY */ 832c7484f1fSmrg#endif /* SVR4 */ 833c7484f1fSmrg /* 834c7484f1fSmrg * We were unable to allocate a pty master! Return an error 835c7484f1fSmrg * condition and let our caller terminate cleanly. 836c7484f1fSmrg */ 837c7484f1fSmrg return(1); 838bfce1ac2Smrg#endif /* HAS_OPENPTY */ 839c7484f1fSmrg} 840c7484f1fSmrg#endif 841