misc.c revision 22d8e007
1d522f475Smrg/* $XTermId: misc.c,v 1.383 2008/04/14 00:05:43 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d522f475Smrg * 5d522f475Smrg * Copyright 1999-2007,2008 by Thomas E. Dickey 6d522f475Smrg * 7d522f475Smrg * All Rights Reserved 8d522f475Smrg * 9d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 10d522f475Smrg * copy of this software and associated documentation files (the 11d522f475Smrg * "Software"), to deal in the Software without restriction, including 12d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 13d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 14d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 15d522f475Smrg * the following conditions: 16d522f475Smrg * 17d522f475Smrg * The above copyright notice and this permission notice shall be included 18d522f475Smrg * in all copies or substantial portions of the Software. 19d522f475Smrg * 20d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 24d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27d522f475Smrg * 28d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 29d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 30d522f475Smrg * sale, use or other dealings in this Software without prior written 31d522f475Smrg * authorization. 32d522f475Smrg * 33d522f475Smrg * 34d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 35d522f475Smrg * 36d522f475Smrg * All Rights Reserved 37d522f475Smrg * 38d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 39d522f475Smrg * documentation for any purpose and without fee is hereby granted, 40d522f475Smrg * provided that the above copyright notice appear in all copies and that 41d522f475Smrg * both that copyright notice and this permission notice appear in 42d522f475Smrg * supporting documentation, and that the name of Digital Equipment 43d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 44d522f475Smrg * distribution of the software without specific, written prior permission. 45d522f475Smrg * 46d522f475Smrg * 47d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 48d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 49d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 50d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 51d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 52d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 53d522f475Smrg * SOFTWARE. 54d522f475Smrg */ 55d522f475Smrg 56d522f475Smrg#include <version.h> 57d522f475Smrg#include <xterm.h> 58d522f475Smrg 59d522f475Smrg#include <sys/stat.h> 60d522f475Smrg#include <stdio.h> 61d522f475Smrg#include <signal.h> 62d522f475Smrg#include <ctype.h> 63d522f475Smrg#include <pwd.h> 64d522f475Smrg#include <sys/wait.h> 65d522f475Smrg 66d522f475Smrg#include <X11/keysym.h> 67d522f475Smrg#include <X11/Xatom.h> 68d522f475Smrg#include <X11/cursorfont.h> 69d522f475Smrg#include <X11/Xlocale.h> 70d522f475Smrg 71d522f475Smrg#include <X11/Xmu/Error.h> 72d522f475Smrg#include <X11/Xmu/SysUtil.h> 73d522f475Smrg#include <X11/Xmu/WinUtil.h> 74d522f475Smrg#include <X11/Xmu/Xmu.h> 75d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 76d522f475Smrg#include <X11/Sunkeysym.h> 77d522f475Smrg#endif 78d522f475Smrg 79d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 80d522f475Smrg#include <langinfo.h> 81d522f475Smrg#endif 82d522f475Smrg 83d522f475Smrg#include <xutf8.h> 84d522f475Smrg 85d522f475Smrg#include <data.h> 86d522f475Smrg#include <error.h> 87d522f475Smrg#include <menu.h> 88d522f475Smrg#include <fontutils.h> 89d522f475Smrg#include <xcharmouse.h> 90d522f475Smrg#include <xstrings.h> 91d522f475Smrg#include <xtermcap.h> 92d522f475Smrg#include <VTparse.h> 93d522f475Smrg 94d522f475Smrg#include <assert.h> 95d522f475Smrg 96d522f475Smrg#if (XtSpecificationRelease < 6) 97d522f475Smrg#ifndef X_GETTIMEOFDAY 98d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 99d522f475Smrg#endif 100d522f475Smrg#endif 101d522f475Smrg 102d522f475Smrg#ifdef VMS 103d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 104d522f475Smrg#ifdef ALLOWLOGFILEEXEC 105d522f475Smrg#undef ALLOWLOGFILEEXEC 106d522f475Smrg#endif 107d522f475Smrg#endif /* VMS */ 108d522f475Smrg 109d522f475Smrg#if OPT_TEK4014 110d522f475Smrg#define OUR_EVENT(event,Type) \ 111d522f475Smrg (event.type == Type && \ 112d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 113d522f475Smrg (tekWidget && \ 114d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 115d522f475Smrg#else 116d522f475Smrg#define OUR_EVENT(event,Type) \ 117d522f475Smrg (event.type == Type && \ 118d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 119d522f475Smrg#endif 120d522f475Smrg 121d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 122d522f475Smrg 123d522f475Smrg#if OPT_EXEC_XTERM 124d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 125d522f475Smrg error; adapted from libc docs */ 126d522f475Smrgstatic char * 127d522f475SmrgReadlink(const char *filename) 128d522f475Smrg{ 129d522f475Smrg char *buf = NULL; 130d522f475Smrg unsigned size = 100; 131d522f475Smrg int n; 132d522f475Smrg 133d522f475Smrg for (;;) { 134d522f475Smrg buf = TypeRealloc(char, size, buf); 135d522f475Smrg memset(buf, 0, size); 136d522f475Smrg 137d522f475Smrg n = readlink(filename, buf, size); 138d522f475Smrg if (n < 0) { 139d522f475Smrg free(buf); 140d522f475Smrg return NULL; 141d522f475Smrg } 142d522f475Smrg 143d522f475Smrg if ((unsigned) n < size) { 144d522f475Smrg return buf; 145d522f475Smrg } 146d522f475Smrg 147d522f475Smrg size *= 2; 148d522f475Smrg } 149d522f475Smrg} 150d522f475Smrg#endif /* OPT_EXEC_XTERM */ 151d522f475Smrg 152d522f475Smrgstatic void 153d522f475SmrgSleep(int msec) 154d522f475Smrg{ 155d522f475Smrg static struct timeval select_timeout; 156d522f475Smrg 157d522f475Smrg select_timeout.tv_sec = 0; 158d522f475Smrg select_timeout.tv_usec = msec * 1000; 159d522f475Smrg select(0, 0, 0, 0, &select_timeout); 160d522f475Smrg} 161d522f475Smrg 162d522f475Smrgstatic void 163d522f475Smrgselectwindow(TScreen * screen, int flag) 164d522f475Smrg{ 165d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 166d522f475Smrg 167d522f475Smrg#if OPT_TEK4014 168d522f475Smrg if (TEK4014_ACTIVE(term)) { 169d522f475Smrg if (!Ttoggled) 170d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 171d522f475Smrg screen->select |= flag; 172d522f475Smrg if (!Ttoggled) 173d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 174d522f475Smrg } else 175d522f475Smrg#endif 176d522f475Smrg { 177d522f475Smrg if (screen->xic) 178d522f475Smrg XSetICFocus(screen->xic); 179d522f475Smrg 180d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 181d522f475Smrg HideCursor(); 182d522f475Smrg screen->select |= flag; 183d522f475Smrg if (screen->cursor_state) 184d522f475Smrg ShowCursor(); 185d522f475Smrg } 186d522f475Smrg} 187d522f475Smrg 188d522f475Smrgstatic void 189d522f475Smrgunselectwindow(TScreen * screen, int flag) 190d522f475Smrg{ 191d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 192d522f475Smrg 193d522f475Smrg if (screen->hide_pointer) { 194d522f475Smrg screen->hide_pointer = False; 195d522f475Smrg xtermDisplayCursor(term); 196d522f475Smrg } 197d522f475Smrg 198d522f475Smrg if (!screen->always_highlight) { 199d522f475Smrg#if OPT_TEK4014 200d522f475Smrg if (TEK4014_ACTIVE(term)) { 201d522f475Smrg if (!Ttoggled) 202d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 203d522f475Smrg screen->select &= ~flag; 204d522f475Smrg if (!Ttoggled) 205d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 206d522f475Smrg } else 207d522f475Smrg#endif 208d522f475Smrg { 209d522f475Smrg if (screen->xic) 210d522f475Smrg XUnsetICFocus(screen->xic); 211d522f475Smrg 212d522f475Smrg screen->select &= ~flag; 213d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 214d522f475Smrg HideCursor(); 215d522f475Smrg if (screen->cursor_state) 216d522f475Smrg ShowCursor(); 217d522f475Smrg } 218d522f475Smrg } 219d522f475Smrg} 220d522f475Smrg 221d522f475Smrgstatic void 222d522f475SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent * ev) 223d522f475Smrg{ 224d522f475Smrg TScreen *screen = TScreenOf(xw); 225d522f475Smrg 226d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 227d522f475Smrg#ifdef ACTIVEWINDOWINPUTONLY 228d522f475Smrg if (ev->window == XtWindow(XtParent(CURRENT_EMU()))) 229d522f475Smrg#endif 230d522f475Smrg if (((ev->detail) != NotifyInferior) && 231d522f475Smrg ev->focus && 232d522f475Smrg !(screen->select & FOCUS)) 233d522f475Smrg selectwindow(screen, INWINDOW); 234d522f475Smrg} 235d522f475Smrg 236d522f475Smrgstatic void 237d522f475SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent * ev) 238d522f475Smrg{ 239d522f475Smrg TScreen *screen = TScreenOf(xw); 240d522f475Smrg 241d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 242d522f475Smrg#ifdef ACTIVEWINDOWINPUTONLY 243d522f475Smrg if (ev->window == XtWindow(XtParent(CURRENT_EMU()))) 244d522f475Smrg#endif 245d522f475Smrg if (((ev->detail) != NotifyInferior) && 246d522f475Smrg ev->focus && 247d522f475Smrg !(screen->select & FOCUS)) 248d522f475Smrg unselectwindow(screen, INWINDOW); 249d522f475Smrg} 250d522f475Smrg 251d522f475Smrg#ifndef XUrgencyHint 252d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 253d522f475Smrg#endif 254d522f475Smrg 255d522f475Smrgstatic void 256d522f475SmrgsetXUrgency(TScreen * screen, Bool enable) 257d522f475Smrg{ 258d522f475Smrg if (screen->bellIsUrgent) { 259d522f475Smrg XWMHints *h = XGetWMHints(screen->display, VShellWindow); 260d522f475Smrg if (h != 0) { 261d522f475Smrg if (enable) { 262d522f475Smrg h->flags |= XUrgencyHint; 263d522f475Smrg } else { 264d522f475Smrg h->flags &= ~XUrgencyHint; 265d522f475Smrg } 266d522f475Smrg XSetWMHints(screen->display, VShellWindow, h); 267d522f475Smrg } 268d522f475Smrg } 269d522f475Smrg} 270d522f475Smrg 271d522f475Smrgvoid 272d522f475Smrgdo_xevents(void) 273d522f475Smrg{ 274d522f475Smrg TScreen *screen = TScreenOf(term); 275d522f475Smrg 276d522f475Smrg if (XtAppPending(app_con) 277d522f475Smrg || 278d522f475Smrg#if defined(VMS) || defined(__VMS) 279d522f475Smrg screen->display->qlen > 0 280d522f475Smrg#else 281d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 282d522f475Smrg#endif 283d522f475Smrg ) 284d522f475Smrg xevents(); 285d522f475Smrg} 286d522f475Smrg 287d522f475Smrgvoid 288d522f475SmrgxtermDisplayCursor(XtermWidget xw) 289d522f475Smrg{ 290d522f475Smrg TScreen *screen = TScreenOf(xw); 291d522f475Smrg 292d522f475Smrg if (screen->Vshow) { 293d522f475Smrg if (screen->hide_pointer) { 294d522f475Smrg TRACE(("Display hidden_cursor\n")); 295d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 296d522f475Smrg } else { 297d522f475Smrg TRACE(("Display pointer_cursor\n")); 298d522f475Smrg recolor_cursor(screen, 299d522f475Smrg screen->pointer_cursor, 300d522f475Smrg T_COLOR(screen, MOUSE_FG), 301d522f475Smrg T_COLOR(screen, MOUSE_BG)); 302d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 303d522f475Smrg } 304d522f475Smrg } 305d522f475Smrg} 306d522f475Smrg 307d522f475Smrgvoid 308d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 309d522f475Smrg{ 310d522f475Smrg static int tried = -1; 311d522f475Smrg TScreen *screen = TScreenOf(xw); 312d522f475Smrg 313d522f475Smrg#if OPT_TEK4014 314d522f475Smrg if (TEK4014_SHOWN(xw)) 315d522f475Smrg enable = True; 316d522f475Smrg#endif 317d522f475Smrg 318d522f475Smrg /* 319d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 320d522f475Smrg * the mouse-mode: 321d522f475Smrg */ 322d522f475Smrg if (!enable) { 323d522f475Smrg switch (screen->pointer_mode) { 324d522f475Smrg case pNever: 325d522f475Smrg enable = True; 326d522f475Smrg break; 327d522f475Smrg case pNoMouse: 328d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 329d522f475Smrg enable = True; 330d522f475Smrg break; 331d522f475Smrg case pAlways: 332d522f475Smrg break; 333d522f475Smrg } 334d522f475Smrg } 335d522f475Smrg 336d522f475Smrg if (enable) { 337d522f475Smrg if (screen->hide_pointer) { 338d522f475Smrg screen->hide_pointer = False; 339d522f475Smrg xtermDisplayCursor(xw); 340d522f475Smrg switch (screen->send_mouse_pos) { 341d522f475Smrg case ANY_EVENT_MOUSE: 342d522f475Smrg break; 343d522f475Smrg default: 344d522f475Smrg MotionOff(screen, xw); 345d522f475Smrg break; 346d522f475Smrg } 347d522f475Smrg } 348d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 349d522f475Smrg if (screen->hidden_cursor == 0) { 350d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 351d522f475Smrg } 352d522f475Smrg if (screen->hidden_cursor == 0) { 353d522f475Smrg tried = 1; 354d522f475Smrg } else { 355d522f475Smrg tried = 0; 356d522f475Smrg screen->hide_pointer = True; 357d522f475Smrg xtermDisplayCursor(xw); 358d522f475Smrg MotionOn(screen, xw); 359d522f475Smrg } 360d522f475Smrg } 361d522f475Smrg} 362d522f475Smrg 363d522f475Smrgvoid 364d522f475Smrgxevents(void) 365d522f475Smrg{ 366d522f475Smrg XtermWidget xw = term; 367d522f475Smrg TScreen *screen = TScreenOf(xw); 368d522f475Smrg XEvent event; 369d522f475Smrg XtInputMask input_mask; 370d522f475Smrg 371d522f475Smrg if (need_cleanup) 372d522f475Smrg Cleanup(0); 373d522f475Smrg 374d522f475Smrg if (screen->scroll_amt) 375d522f475Smrg FlushScroll(xw); 376d522f475Smrg /* 377d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 378d522f475Smrg * will process the timeout and return without blockng on the 379d522f475Smrg * XEvent queue. Other sources i.e. the pty are handled elsewhere 380d522f475Smrg * with select(). 381d522f475Smrg */ 382d522f475Smrg while ((input_mask = XtAppPending(app_con)) & XtIMTimer) 383d522f475Smrg XtAppProcessEvent(app_con, XtIMTimer); 384d522f475Smrg#if OPT_SESSION_MGT 385d522f475Smrg /* 386d522f475Smrg * Session management events are alternative input events. Deal with 387d522f475Smrg * them in the same way. 388d522f475Smrg */ 389d522f475Smrg while ((input_mask = XtAppPending(app_con)) & XtIMAlternateInput) 390d522f475Smrg XtAppProcessEvent(app_con, XtIMAlternateInput); 391d522f475Smrg#endif 392d522f475Smrg 393d522f475Smrg /* 394d522f475Smrg * If there's no XEvents, don't wait around... 395d522f475Smrg */ 396d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 397d522f475Smrg return; 398d522f475Smrg do { 399d522f475Smrg /* 400d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 401d522f475Smrg * We simply ignore all events except for those not passed down to 402d522f475Smrg * this function, e.g., those handled in in_put(). 403d522f475Smrg */ 404d522f475Smrg if (screen->waitingForTrackInfo) { 405d522f475Smrg Sleep(10); 406d522f475Smrg return; 407d522f475Smrg } 408d522f475Smrg XtAppNextEvent(app_con, &event); 409d522f475Smrg /* 410d522f475Smrg * Hack to get around problems with the toolkit throwing away 411d522f475Smrg * eventing during the exclusive grab of the menu popup. By 412d522f475Smrg * looking at the event ourselves we make sure that we can 413d522f475Smrg * do the right thing. 414d522f475Smrg */ 415d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 416d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 417d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 418d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 419d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 420d522f475Smrg#if OPT_DEC_LOCATOR 421d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 422d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 423d522f475Smrg ) 424d522f475Smrg && event.xany.type == MotionNotify 425d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 426d522f475Smrg SendMousePosition(xw, &event); 427d522f475Smrg continue; 428d522f475Smrg } 429d522f475Smrg 430d522f475Smrg if (!event.xany.send_event || 431d522f475Smrg screen->allowSendEvents || 432d522f475Smrg ((event.xany.type != KeyPress) && 433d522f475Smrg (event.xany.type != KeyRelease) && 434d522f475Smrg (event.xany.type != ButtonPress) && 435d522f475Smrg (event.xany.type != ButtonRelease))) { 436d522f475Smrg 437d522f475Smrg /* 438d522f475Smrg * If the event is interesting (and not a keyboard event), turn the 439d522f475Smrg * mouse pointer back on. 440d522f475Smrg */ 441d522f475Smrg if (screen->hide_pointer) { 442d522f475Smrg switch (event.xany.type) { 443d522f475Smrg case KeyPress: 444d522f475Smrg case KeyRelease: 445d522f475Smrg case ButtonPress: 446d522f475Smrg case ButtonRelease: 447d522f475Smrg /* also these... */ 448d522f475Smrg case Expose: 449d522f475Smrg case NoExpose: 450d522f475Smrg case PropertyNotify: 451d522f475Smrg break; 452d522f475Smrg default: 453d522f475Smrg xtermShowPointer(xw, True); 454d522f475Smrg break; 455d522f475Smrg } 456d522f475Smrg } 457d522f475Smrg 458d522f475Smrg XtDispatchEvent(&event); 459d522f475Smrg } 460d522f475Smrg } while ((input_mask = XtAppPending(app_con)) & XtIMXEvent); 461d522f475Smrg} 462d522f475Smrg 463d522f475Smrgstatic Cursor 464d522f475Smrgmake_hidden_cursor(XtermWidget xw) 465d522f475Smrg{ 466d522f475Smrg TScreen *screen = TScreenOf(xw); 467d522f475Smrg Cursor c; 468d522f475Smrg Display *dpy = screen->display; 469d522f475Smrg XFontStruct *fn; 470d522f475Smrg 471d522f475Smrg static XColor dummy; 472d522f475Smrg 473d522f475Smrg /* 474d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 475d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 476d522f475Smrg * server insists on drawing _somethng_. 477d522f475Smrg */ 478d522f475Smrg TRACE(("Ask for nil2 font\n")); 479d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 480d522f475Smrg TRACE(("...Ask for fixed font\n")); 481d522f475Smrg fn = XLoadQueryFont(dpy, "fixed"); 482d522f475Smrg } 483d522f475Smrg 484d522f475Smrg if (fn != 0) { 485d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 486d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 487d522f475Smrg XFreeFont(dpy, fn); 488d522f475Smrg } else { 489d522f475Smrg c = 0; 490d522f475Smrg } 491d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 492d522f475Smrg return (c); 493d522f475Smrg} 494d522f475Smrg 495d522f475SmrgCursor 496d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 497d522f475Smrg unsigned long fg, /* pixel value */ 498d522f475Smrg unsigned long bg) /* pixel value */ 499d522f475Smrg{ 500d522f475Smrg TScreen *screen = TScreenOf(term); 501d522f475Smrg Cursor c; 502d522f475Smrg Display *dpy = screen->display; 503d522f475Smrg 504d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 505d522f475Smrg if (c != None) { 506d522f475Smrg recolor_cursor(screen, c, fg, bg); 507d522f475Smrg } 508d522f475Smrg return (c); 509d522f475Smrg} 510d522f475Smrg 511d522f475Smrg/* ARGSUSED */ 512d522f475Smrgvoid 513d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 514d522f475Smrg XEvent * event, 515d522f475Smrg String * params GCC_UNUSED, 516d522f475Smrg Cardinal *nparams GCC_UNUSED) 517d522f475Smrg{ 518d522f475Smrg TRACE(("Handle 7bit-key\n")); 519d522f475Smrg#ifdef ACTIVEWINDOWINPUTONLY 520d522f475Smrg if (w == CURRENT_EMU()) 521d522f475Smrg#endif 522d522f475Smrg Input(term, &event->xkey, False); 523d522f475Smrg} 524d522f475Smrg 525d522f475Smrg/* ARGSUSED */ 526d522f475Smrgvoid 527d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 528d522f475Smrg XEvent * event, 529d522f475Smrg String * params GCC_UNUSED, 530d522f475Smrg Cardinal *nparams GCC_UNUSED) 531d522f475Smrg{ 532d522f475Smrg TRACE(("Handle 8bit-key\n")); 533d522f475Smrg#ifdef ACTIVEWINDOWINPUTONLY 534d522f475Smrg if (w == CURRENT_EMU()) 535d522f475Smrg#endif 536d522f475Smrg Input(term, &event->xkey, True); 537d522f475Smrg} 538d522f475Smrg 539d522f475Smrg/* ARGSUSED */ 540d522f475Smrgvoid 541d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 542d522f475Smrg XEvent * event GCC_UNUSED, 543d522f475Smrg String * params, 544d522f475Smrg Cardinal *nparams) 545d522f475Smrg{ 546d522f475Smrg#ifdef ACTIVEWINDOWINPUTONLY 547d522f475Smrg if (w != CURRENT_EMU()) 548d522f475Smrg return; 549d522f475Smrg#endif 550d522f475Smrg 551d522f475Smrg if (*nparams != 1) 552d522f475Smrg return; 553d522f475Smrg 554d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 555d522f475Smrg Char c, *p; 556d522f475Smrg Char hexval[2]; 557d522f475Smrg hexval[0] = hexval[1] = 0; 558d522f475Smrg for (p = (Char *) (*params + 2); (c = *p); p++) { 559d522f475Smrg hexval[0] *= 16; 560d522f475Smrg if (isupper(c)) 561d522f475Smrg c = tolower(c); 562d522f475Smrg if (c >= '0' && c <= '9') 563d522f475Smrg hexval[0] += c - '0'; 564d522f475Smrg else if (c >= 'a' && c <= 'f') 565d522f475Smrg hexval[0] += c - 'a' + 10; 566d522f475Smrg else 567d522f475Smrg break; 568d522f475Smrg } 569d522f475Smrg if (c == '\0') 570d522f475Smrg StringInput(term, hexval, 1); 571d522f475Smrg } else { 572d522f475Smrg StringInput(term, (Char *) * params, strlen(*params)); 573d522f475Smrg } 574d522f475Smrg} 575d522f475Smrg 576d522f475Smrg#if OPT_EXEC_XTERM 577d522f475Smrg 578d522f475Smrg#ifndef PROCFS_ROOT 579d522f475Smrg#define PROCFS_ROOT "/proc" 580d522f475Smrg#endif 581d522f475Smrg 582d522f475Smrg/* ARGSUSED */ 583d522f475Smrgvoid 584d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 585d522f475Smrg XEvent * event GCC_UNUSED, 586d522f475Smrg String * params, 587d522f475Smrg Cardinal *nparams) 588d522f475Smrg{ 589d522f475Smrg TScreen *screen = &term->screen; 590d522f475Smrg char *child_cwd = NULL; 591d522f475Smrg char *child_exe; 592d522f475Smrg pid_t pid; 593d522f475Smrg 594d522f475Smrg /* 595d522f475Smrg * Try to find the actual program which is running in the child process. 596d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 597d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 598d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 599d522f475Smrg */ 600d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 601d522f475Smrg if (!child_exe) { 602d522f475Smrg if (strncmp(ProgramName, "./", 2) 603d522f475Smrg && strncmp(ProgramName, "../", 3)) { 604d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 605d522f475Smrg } else { 606d522f475Smrg fprintf(stderr, "Cannot exec-xterm given %s\n", ProgramName); 607d522f475Smrg } 608d522f475Smrg if (child_exe == 0) 609d522f475Smrg return; 610d522f475Smrg } 611d522f475Smrg 612d522f475Smrg /* 613d522f475Smrg * Determine the current working directory of the child so that we can 614d522f475Smrg * spawn a new terminal in the same directory. 615d522f475Smrg * 616d522f475Smrg * If we cannot get the CWD of the child, just use our own. 617d522f475Smrg */ 618d522f475Smrg if (screen->pid) { 619d522f475Smrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 620d522f475Smrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) screen->pid); 621d522f475Smrg child_cwd = Readlink(child_cwd_link); 622d522f475Smrg } 623d522f475Smrg 624d522f475Smrg /* The reaper will take care of cleaning up the child */ 625d522f475Smrg pid = fork(); 626d522f475Smrg if (pid == -1) { 627d522f475Smrg fprintf(stderr, "Could not fork: %s\n", SysErrorMsg(errno)); 628d522f475Smrg } else if (!pid) { 629d522f475Smrg /* We are the child */ 630d522f475Smrg if (child_cwd) { 631d522f475Smrg chdir(child_cwd); /* We don't care if this fails */ 632d522f475Smrg } 633d522f475Smrg 634d522f475Smrg if (setuid(screen->uid) == -1 635d522f475Smrg || setgid(screen->gid) == -1) { 636d522f475Smrg fprintf(stderr, "Cannot reset uid/gid\n"); 637d522f475Smrg } else { 638d522f475Smrg int myargc = *nparams + 1; 639d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 640d522f475Smrg int n = 0; 641d522f475Smrg 642d522f475Smrg myargv[n++] = child_exe; 643d522f475Smrg 644d522f475Smrg while (n < myargc) { 645d522f475Smrg myargv[n++] = *params++; 646d522f475Smrg } 647d522f475Smrg 648d522f475Smrg myargv[n] = 0; 649d522f475Smrg execv(child_exe, myargv); 650d522f475Smrg 651d522f475Smrg /* If we get here, we've failed */ 652d522f475Smrg fprintf(stderr, "exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 653d522f475Smrg } 654d522f475Smrg _exit(0); 655d522f475Smrg } else { 656d522f475Smrg /* We are the parent; clean up */ 657d522f475Smrg if (child_cwd) 658d522f475Smrg free(child_cwd); 659d522f475Smrg if (child_exe) 660d522f475Smrg free(child_exe); 661d522f475Smrg } 662d522f475Smrg} 663d522f475Smrg#endif /* OPT_EXEC_XTERM */ 664d522f475Smrg 665d522f475Smrg/* 666d522f475Smrg * Rather than sending characters to the host, put them directly into our 667d522f475Smrg * input queue. That lets a user have access to any of the control sequences 668d522f475Smrg * for a key binding. This is the equivalent of local function key support. 669d522f475Smrg * 670d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 671d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 672d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 673d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 674d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 675d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 676d522f475Smrg */ 677d522f475Smrg/* ARGSUSED */ 678d522f475Smrgvoid 679d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 680d522f475Smrg XEvent * event GCC_UNUSED, 681d522f475Smrg String * params, 682d522f475Smrg Cardinal *param_count) 683d522f475Smrg{ 684d522f475Smrg if (*param_count == 1) { 685d522f475Smrg char *value = params[0]; 686d522f475Smrg int need = strlen(value); 687d522f475Smrg int used = VTbuffer->next - VTbuffer->buffer; 688d522f475Smrg int have = VTbuffer->last - VTbuffer->buffer; 689d522f475Smrg 690d522f475Smrg if (have - used + need < BUF_SIZE) { 691d522f475Smrg 692d522f475Smrg fillPtyData(TScreenOf(term), VTbuffer, value, (int) strlen(value)); 693d522f475Smrg 694d522f475Smrg TRACE(("Interpret %s\n", value)); 695d522f475Smrg VTbuffer->update++; 696d522f475Smrg } 697d522f475Smrg } 698d522f475Smrg} 699d522f475Smrg 700d522f475Smrg/*ARGSUSED*/ 701d522f475Smrgvoid 702d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 703d522f475Smrg XtPointer eventdata GCC_UNUSED, 704d522f475Smrg XEvent * event GCC_UNUSED, 705d522f475Smrg Boolean * cont GCC_UNUSED) 706d522f475Smrg{ 707d522f475Smrg /* NOP since we handled it above */ 708d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 709d522f475Smrg} 710d522f475Smrg 711d522f475Smrg/*ARGSUSED*/ 712d522f475Smrgvoid 713d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 714d522f475Smrg XtPointer eventdata GCC_UNUSED, 715d522f475Smrg XEvent * event GCC_UNUSED, 716d522f475Smrg Boolean * cont GCC_UNUSED) 717d522f475Smrg{ 718d522f475Smrg /* NOP since we handled it above */ 719d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 720d522f475Smrg} 721d522f475Smrg 722d522f475Smrg/*ARGSUSED*/ 723d522f475Smrgvoid 724d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 725d522f475Smrg XtPointer eventdata GCC_UNUSED, 726d522f475Smrg XEvent * ev, 727d522f475Smrg Boolean * cont GCC_UNUSED) 728d522f475Smrg{ 729d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 730d522f475Smrg XtermWidget xw = term; 731d522f475Smrg TScreen *screen = TScreenOf(xw); 732d522f475Smrg 733d522f475Smrg TRACE(("HandleFocusChange type=%s, mode=%d, detail=%d\n", 734d522f475Smrg visibleEventType(event->type), 735d522f475Smrg event->mode, 736d522f475Smrg event->detail)); 737d522f475Smrg 738d522f475Smrg if (screen->quiet_grab 739d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 740d522f475Smrg ; 741d522f475Smrg } else if (event->type == FocusIn) { 742d522f475Smrg setXUrgency(screen, False); 743d522f475Smrg 744d522f475Smrg /* 745d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 746d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 747d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 748d522f475Smrg * pointer was in the window. In particular, this can happen if the 749d522f475Smrg * user is resizing the obscuring window, causing some events to not be 750d522f475Smrg * delivered to the obscured window. 751d522f475Smrg */ 752d522f475Smrg if (event->detail == NotifyNonlinear 753d522f475Smrg && (screen->select & INWINDOW) != 0) { 754d522f475Smrg unselectwindow(screen, INWINDOW); 755d522f475Smrg } 756d522f475Smrg selectwindow(screen, 757d522f475Smrg ((event->detail == NotifyPointer) 758d522f475Smrg ? INWINDOW 759d522f475Smrg : FOCUS)); 760d522f475Smrg SendFocusButton(xw, event); 761d522f475Smrg } else { 762d522f475Smrg#if OPT_FOCUS_EVENT 763d522f475Smrg if (event->type == FocusOut) { 764d522f475Smrg SendFocusButton(xw, event); 765d522f475Smrg } 766d522f475Smrg#endif 767d522f475Smrg /* 768d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 769d522f475Smrg * ignore. 770d522f475Smrg */ 771d522f475Smrg if (event->mode != NotifyGrab) { 772d522f475Smrg unselectwindow(screen, 773d522f475Smrg ((event->detail == NotifyPointer) 774d522f475Smrg ? INWINDOW 775d522f475Smrg : FOCUS)); 776d522f475Smrg } 777d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 778d522f475Smrg Bell(XkbBI_Info, 100); 779d522f475Smrg ReverseVideo(xw); 780d522f475Smrg screen->grabbedKbd = False; 781d522f475Smrg update_securekbd(); 782d522f475Smrg } 783d522f475Smrg } 784d522f475Smrg} 785d522f475Smrg 786d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 787d522f475Smrg 788d522f475Smrgvoid 789d522f475SmrgBell(Atom which GCC_UNUSED, int percent) 790d522f475Smrg{ 791d522f475Smrg TScreen *screen = TScreenOf(term); 792d522f475Smrg struct timeval curtime; 793d522f475Smrg long now_msecs; 794d522f475Smrg 795d522f475Smrg TRACE(("BELL %ld %d%%\n", (long) which, percent)); 796d522f475Smrg if (!XtIsRealized((Widget) term)) { 797d522f475Smrg return; 798d522f475Smrg } 799d522f475Smrg 800d522f475Smrg setXUrgency(screen, True); 801d522f475Smrg 802d522f475Smrg /* has enough time gone by that we are allowed to ring 803d522f475Smrg the bell again? */ 804d522f475Smrg if (screen->bellSuppressTime) { 805d522f475Smrg if (screen->bellInProgress) { 806d522f475Smrg do_xevents(); 807d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 808d522f475Smrg return; 809d522f475Smrg } 810d522f475Smrg } 811d522f475Smrg X_GETTIMEOFDAY(&curtime); 812d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 813d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 814d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 815d522f475Smrg return; 816d522f475Smrg } 817d522f475Smrg lastBellTime = now_msecs; 818d522f475Smrg } 819d522f475Smrg 820d522f475Smrg if (screen->visualbell) { 821d522f475Smrg VisualBell(); 822d522f475Smrg } else { 823d522f475Smrg#if defined(HAVE_XKB_BELL_EXT) 824d522f475Smrg XkbBell(screen->display, VShellWindow, percent, which); 825d522f475Smrg#else 826d522f475Smrg XBell(screen->display, percent); 827d522f475Smrg#endif 828d522f475Smrg } 829d522f475Smrg 830d522f475Smrg if (screen->poponbell) 831d522f475Smrg XRaiseWindow(screen->display, VShellWindow); 832d522f475Smrg 833d522f475Smrg if (screen->bellSuppressTime) { 834d522f475Smrg /* now we change a property and wait for the notify event to come 835d522f475Smrg back. If the server is suspending operations while the bell 836d522f475Smrg is being emitted (problematic for audio bell), this lets us 837d522f475Smrg know when the previous bell has finished */ 838d522f475Smrg Widget w = CURRENT_EMU(); 839d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 840d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 841d522f475Smrg screen->bellInProgress = True; 842d522f475Smrg } 843d522f475Smrg} 844d522f475Smrg 845d522f475Smrg#define VB_DELAY screen->visualBellDelay 846d522f475Smrg 847d522f475Smrgstatic void 848d522f475SmrgflashWindow(TScreen * screen, Window window, GC visualGC, unsigned width, unsigned height) 849d522f475Smrg{ 850d522f475Smrg XFillRectangle(screen->display, window, visualGC, 0, 0, width, height); 851d522f475Smrg XFlush(screen->display); 852d522f475Smrg Sleep(VB_DELAY); 853d522f475Smrg XFillRectangle(screen->display, window, visualGC, 0, 0, width, height); 854d522f475Smrg} 855d522f475Smrg 856d522f475Smrgvoid 857d522f475SmrgVisualBell(void) 858d522f475Smrg{ 859d522f475Smrg TScreen *screen = TScreenOf(term); 860d522f475Smrg 861d522f475Smrg if (VB_DELAY > 0) { 862d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 863d522f475Smrg T_COLOR(screen, TEXT_BG)); 864d522f475Smrg XGCValues gcval; 865d522f475Smrg GC visualGC; 866d522f475Smrg 867d522f475Smrg gcval.function = GXxor; 868d522f475Smrg gcval.foreground = xorPixel; 869d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 870d522f475Smrg#if OPT_TEK4014 871d522f475Smrg if (TEK4014_ACTIVE(term)) { 872d522f475Smrg TekScreen *tekscr = &(tekWidget->screen); 873d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 874d522f475Smrg TFullWidth(tekscr), 875d522f475Smrg TFullHeight(tekscr)); 876d522f475Smrg } else 877d522f475Smrg#endif 878d522f475Smrg { 879d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 880d522f475Smrg FullWidth(screen), 881d522f475Smrg FullHeight(screen)); 882d522f475Smrg } 883d522f475Smrg XtReleaseGC((Widget) term, visualGC); 884d522f475Smrg } 885d522f475Smrg} 886d522f475Smrg 887d522f475Smrg/* ARGSUSED */ 888d522f475Smrgvoid 889d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 890d522f475Smrg XtPointer data GCC_UNUSED, 891d522f475Smrg XEvent * ev, 892d522f475Smrg Boolean * more GCC_UNUSED) 893d522f475Smrg{ 894d522f475Smrg TScreen *screen = TScreenOf(term); 895d522f475Smrg 896d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 897d522f475Smrg screen->bellInProgress = False; 898d522f475Smrg } 899d522f475Smrg} 900d522f475Smrg 901d522f475SmrgWindow 902d522f475SmrgWMFrameWindow(XtermWidget termw) 903d522f475Smrg{ 904d522f475Smrg Window win_root, win_current, *children; 905d522f475Smrg Window win_parent = 0; 906d522f475Smrg unsigned int nchildren; 907d522f475Smrg 908d522f475Smrg win_current = XtWindow(termw); 909d522f475Smrg 910d522f475Smrg /* find the parent which is child of root */ 911d522f475Smrg do { 912d522f475Smrg if (win_parent) 913d522f475Smrg win_current = win_parent; 914d522f475Smrg XQueryTree((&termw->screen)->display, 915d522f475Smrg win_current, 916d522f475Smrg &win_root, 917d522f475Smrg &win_parent, 918d522f475Smrg &children, 919d522f475Smrg &nchildren); 920d522f475Smrg XFree(children); 921d522f475Smrg } while (win_root != win_parent); 922d522f475Smrg 923d522f475Smrg return win_current; 924d522f475Smrg} 925d522f475Smrg 926d522f475Smrg#if OPT_DABBREV 927d522f475Smrg/* 928d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 929d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 930d522f475Smrg * to find expansions of a typed word. It compares consecutive 931d522f475Smrg * expansions and ignores one of them if they are identical. 932d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 933d522f475Smrg */ 934d522f475Smrg 935d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 936d522f475Smrg#define MAXWLEN 1024 /* maximum word length as in tcsh */ 937d522f475Smrg 938d522f475Smrgstatic int 939d522f475Smrgdabbrev_prev_char(int *xp, int *yp, TScreen * screen) 940d522f475Smrg{ 941d522f475Smrg Char *linep; 942d522f475Smrg 943d522f475Smrg while (*yp >= 0) { 944d522f475Smrg linep = BUF_CHARS(screen->allbuf, *yp); 945d522f475Smrg if (--*xp >= 0) 946d522f475Smrg return linep[*xp]; 947d522f475Smrg if (--*yp < 0) /* go to previous line */ 948d522f475Smrg break; 949d522f475Smrg *xp = MaxCols(screen); 950d522f475Smrg if (!((long) BUF_FLAGS(screen->allbuf, *yp) & LINEWRAPPED)) 951d522f475Smrg return ' '; /* treat lines as separate */ 952d522f475Smrg } 953d522f475Smrg return -1; 954d522f475Smrg} 955d522f475Smrg 956d522f475Smrgstatic char * 957d522f475Smrgdabbrev_prev_word(int *xp, int *yp, TScreen * screen) 958d522f475Smrg{ 959d522f475Smrg static char ab[MAXWLEN]; 960d522f475Smrg char *abword; 961d522f475Smrg int c; 962d522f475Smrg 963d522f475Smrg abword = ab + MAXWLEN - 1; 964d522f475Smrg *abword = '\0'; /* end of string marker */ 965d522f475Smrg 966d522f475Smrg while ((c = dabbrev_prev_char(xp, yp, screen)) >= 0 && 967d522f475Smrg IS_WORD_CONSTITUENT(c)) 968d522f475Smrg if (abword > ab) /* store only |MAXWLEN| last chars */ 969d522f475Smrg *(--abword) = c; 970d522f475Smrg if (c < 0) { 971d522f475Smrg if (abword < ab + MAXWLEN - 1) 972d522f475Smrg return abword; 973d522f475Smrg else 974d522f475Smrg return 0; 975d522f475Smrg } 976d522f475Smrg 977d522f475Smrg while ((c = dabbrev_prev_char(xp, yp, screen)) >= 0 && 978d522f475Smrg !IS_WORD_CONSTITUENT(c)) ; /* skip preceding spaces */ 979d522f475Smrg (*xp)++; /* can be | > screen->max_col| */ 980d522f475Smrg return abword; 981d522f475Smrg} 982d522f475Smrg 983d522f475Smrgstatic int 984d522f475Smrgdabbrev_expand(TScreen * screen) 985d522f475Smrg{ 986d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 987d522f475Smrg 988d522f475Smrg static int x, y; 989d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 990d522f475Smrg static unsigned int expansions; 991d522f475Smrg 992d522f475Smrg char *expansion; 993d522f475Smrg Char *copybuffer; 994d522f475Smrg size_t hint_len; 995d522f475Smrg unsigned del_cnt; 996d522f475Smrg unsigned buf_cnt; 997d522f475Smrg 998d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 999d522f475Smrg expansions = 0; 1000d522f475Smrg x = screen->cur_col; 1001d522f475Smrg y = screen->cur_row + screen->savelines; 1002d522f475Smrg 1003d522f475Smrg free(dabbrev_hint); /* free(NULL) is OK */ 1004d522f475Smrg dabbrev_hint = dabbrev_prev_word(&x, &y, screen); 1005d522f475Smrg if (!dabbrev_hint) 1006d522f475Smrg return 0; /* no preceding word? */ 1007d522f475Smrg free(lastexpansion); 1008d522f475Smrg if (!(lastexpansion = strdup(dabbrev_hint))) /* make own copy */ 1009d522f475Smrg return 0; 1010d522f475Smrg if (!(dabbrev_hint = strdup(dabbrev_hint))) { 1011d522f475Smrg free(lastexpansion); 1012d522f475Smrg return 0; 1013d522f475Smrg } 1014d522f475Smrg screen->dabbrev_working = 1; /* we are in the middle of dabbrev process */ 1015d522f475Smrg } 1016d522f475Smrg 1017d522f475Smrg hint_len = strlen(dabbrev_hint); 1018d522f475Smrg for (;;) { 1019d522f475Smrg if (!(expansion = dabbrev_prev_word(&x, &y, screen))) { 1020d522f475Smrg if (expansions >= 2) { 1021d522f475Smrg expansions = 0; 1022d522f475Smrg x = screen->cur_col; 1023d522f475Smrg y = screen->cur_row + screen->savelines; 1024d522f475Smrg continue; 1025d522f475Smrg } 1026d522f475Smrg break; 1027d522f475Smrg } 1028d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1029d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1030d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1031d522f475Smrg break; 1032d522f475Smrg } 1033d522f475Smrg if (!expansion) /* no expansion found */ 1034d522f475Smrg return 0; 1035d522f475Smrg 1036d522f475Smrg del_cnt = strlen(lastexpansion) - hint_len; 1037d522f475Smrg buf_cnt = del_cnt + strlen(expansion) - hint_len; 1038d522f475Smrg if (!(copybuffer = TypeMallocN(Char, buf_cnt))) 1039d522f475Smrg return 0; 1040d522f475Smrg memset(copybuffer, screen->dabbrev_erase_char, del_cnt); /* delete previous expansion */ 1041d522f475Smrg memmove(copybuffer + del_cnt, 1042d522f475Smrg expansion + hint_len, 1043d522f475Smrg strlen(expansion) - hint_len); 1044d522f475Smrg v_write(pty, copybuffer, buf_cnt); 1045d522f475Smrg screen->dabbrev_working = 1; /* v_write() just set it to 1 */ 1046d522f475Smrg free(copybuffer); 1047d522f475Smrg 1048d522f475Smrg free(lastexpansion); 1049d522f475Smrg lastexpansion = strdup(expansion); 1050d522f475Smrg if (!lastexpansion) 1051d522f475Smrg return 0; 1052d522f475Smrg expansions++; 1053d522f475Smrg return 1; 1054d522f475Smrg} 1055d522f475Smrg 1056d522f475Smrg/*ARGSUSED*/ 1057d522f475Smrgvoid 1058d522f475SmrgHandleDabbrevExpand(Widget gw, 1059d522f475Smrg XEvent * event GCC_UNUSED, 1060d522f475Smrg String * params GCC_UNUSED, 1061d522f475Smrg Cardinal *nparams GCC_UNUSED) 1062d522f475Smrg{ 1063d522f475Smrg if (IsXtermWidget(gw)) { 1064d522f475Smrg XtermWidget w = (XtermWidget) gw; 1065d522f475Smrg TScreen *screen = &w->screen; 1066d522f475Smrg if (!dabbrev_expand(screen)) 1067d522f475Smrg Bell(XkbBI_TerminalBell, 0); 1068d522f475Smrg } 1069d522f475Smrg} 1070d522f475Smrg#endif /* OPT_DABBREV */ 1071d522f475Smrg 1072d522f475Smrg#if OPT_MAXIMIZE 1073d522f475Smrg/*ARGSUSED*/ 1074d522f475Smrgvoid 1075d522f475SmrgHandleDeIconify(Widget gw, 1076d522f475Smrg XEvent * event GCC_UNUSED, 1077d522f475Smrg String * params GCC_UNUSED, 1078d522f475Smrg Cardinal *nparams GCC_UNUSED) 1079d522f475Smrg{ 1080d522f475Smrg if (IsXtermWidget(gw)) { 1081d522f475Smrg TScreen *screen = TScreenOf((XtermWidget) gw); 1082d522f475Smrg XMapWindow(screen->display, VShellWindow); 1083d522f475Smrg } 1084d522f475Smrg} 1085d522f475Smrg 1086d522f475Smrg/*ARGSUSED*/ 1087d522f475Smrgvoid 1088d522f475SmrgHandleIconify(Widget gw, 1089d522f475Smrg XEvent * event GCC_UNUSED, 1090d522f475Smrg String * params GCC_UNUSED, 1091d522f475Smrg Cardinal *nparams GCC_UNUSED) 1092d522f475Smrg{ 1093d522f475Smrg if (IsXtermWidget(gw)) { 1094d522f475Smrg TScreen *screen = TScreenOf((XtermWidget) gw); 1095d522f475Smrg XIconifyWindow(screen->display, 1096d522f475Smrg VShellWindow, 1097d522f475Smrg DefaultScreen(screen->display)); 1098d522f475Smrg } 1099d522f475Smrg} 1100d522f475Smrg 1101d522f475Smrgint 1102d522f475SmrgQueryMaximize(XtermWidget termw, unsigned *width, unsigned *height) 1103d522f475Smrg{ 1104d522f475Smrg TScreen *screen = &termw->screen; 1105d522f475Smrg XSizeHints hints; 1106d522f475Smrg long supp = 0; 1107d522f475Smrg Window root_win; 1108d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1109d522f475Smrg int root_y = -1; 1110d522f475Smrg unsigned root_border; 1111d522f475Smrg unsigned root_depth; 1112d522f475Smrg 1113d522f475Smrg if (XGetGeometry(screen->display, 1114d522f475Smrg RootWindowOfScreen(XtScreen(termw)), 1115d522f475Smrg &root_win, 1116d522f475Smrg &root_x, 1117d522f475Smrg &root_y, 1118d522f475Smrg width, 1119d522f475Smrg height, 1120d522f475Smrg &root_border, 1121d522f475Smrg &root_depth)) { 1122d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1123d522f475Smrg root_x, 1124d522f475Smrg root_y, 1125d522f475Smrg *width, 1126d522f475Smrg *height, 1127d522f475Smrg root_border)); 1128d522f475Smrg 1129d522f475Smrg *width -= (root_border * 2); 1130d522f475Smrg *height -= (root_border * 2); 1131d522f475Smrg 1132d522f475Smrg hints.flags = PMaxSize; 1133d522f475Smrg if (XGetWMNormalHints(screen->display, 1134d522f475Smrg VShellWindow, 1135d522f475Smrg &hints, 1136d522f475Smrg &supp) 1137d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1138d522f475Smrg 1139d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1140d522f475Smrg hints.max_width, 1141d522f475Smrg hints.max_height)); 1142d522f475Smrg 1143d522f475Smrg if ((unsigned) hints.max_width < *width) 1144d522f475Smrg *width = hints.max_width; 1145d522f475Smrg if ((unsigned) hints.max_height < *height) 1146d522f475Smrg *height = hints.max_height; 1147d522f475Smrg } 1148d522f475Smrg return 1; 1149d522f475Smrg } 1150d522f475Smrg return 0; 1151d522f475Smrg} 1152d522f475Smrg 1153d522f475Smrgvoid 1154d522f475SmrgRequestMaximize(XtermWidget termw, int maximize) 1155d522f475Smrg{ 1156d522f475Smrg TScreen *screen = &termw->screen; 1157d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1158d522f475Smrg unsigned root_width, root_height; 1159d522f475Smrg 1160d522f475Smrg if (maximize) { 1161d522f475Smrg 1162d522f475Smrg if (QueryMaximize(termw, &root_width, &root_height)) { 1163d522f475Smrg 1164d522f475Smrg if (XGetWindowAttributes(screen->display, 1165d522f475Smrg WMFrameWindow(termw), 1166d522f475Smrg &wm_attrs)) { 1167d522f475Smrg 1168d522f475Smrg if (XGetWindowAttributes(screen->display, 1169d522f475Smrg VShellWindow, 1170d522f475Smrg &vshell_attrs)) { 1171d522f475Smrg 1172d522f475Smrg if (screen->restore_data != True 1173d522f475Smrg || screen->restore_width != root_width 1174d522f475Smrg || screen->restore_height != root_height) { 1175d522f475Smrg screen->restore_data = True; 1176d522f475Smrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 1177d522f475Smrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 1178d522f475Smrg screen->restore_width = vshell_attrs.width; 1179d522f475Smrg screen->restore_height = vshell_attrs.height; 1180d522f475Smrg TRACE(("HandleMaximize: save window position %d,%d size %d,%d\n", 1181d522f475Smrg screen->restore_x, 1182d522f475Smrg screen->restore_y, 1183d522f475Smrg screen->restore_width, 1184d522f475Smrg screen->restore_height)); 1185d522f475Smrg } 1186d522f475Smrg 1187d522f475Smrg /* subtract wm decoration dimensions */ 1188d522f475Smrg root_width -= ((wm_attrs.width - vshell_attrs.width) 1189d522f475Smrg + (wm_attrs.border_width * 2)); 1190d522f475Smrg root_height -= ((wm_attrs.height - vshell_attrs.height) 1191d522f475Smrg + (wm_attrs.border_width * 2)); 1192d522f475Smrg 1193d522f475Smrg XMoveResizeWindow(screen->display, VShellWindow, 1194d522f475Smrg 0 + wm_attrs.border_width, /* x */ 1195d522f475Smrg 0 + wm_attrs.border_width, /* y */ 1196d522f475Smrg root_width, 1197d522f475Smrg root_height); 1198d522f475Smrg } 1199d522f475Smrg } 1200d522f475Smrg } 1201d522f475Smrg } else { 1202d522f475Smrg if (screen->restore_data) { 1203d522f475Smrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 1204d522f475Smrg screen->restore_x, 1205d522f475Smrg screen->restore_y, 1206d522f475Smrg screen->restore_width, 1207d522f475Smrg screen->restore_height)); 1208d522f475Smrg screen->restore_data = False; 1209d522f475Smrg 1210d522f475Smrg XMoveResizeWindow(screen->display, 1211d522f475Smrg VShellWindow, 1212d522f475Smrg screen->restore_x, 1213d522f475Smrg screen->restore_y, 1214d522f475Smrg screen->restore_width, 1215d522f475Smrg screen->restore_height); 1216d522f475Smrg } 1217d522f475Smrg } 1218d522f475Smrg} 1219d522f475Smrg 1220d522f475Smrg/*ARGSUSED*/ 1221d522f475Smrgvoid 1222d522f475SmrgHandleMaximize(Widget gw, 1223d522f475Smrg XEvent * event GCC_UNUSED, 1224d522f475Smrg String * params GCC_UNUSED, 1225d522f475Smrg Cardinal *nparams GCC_UNUSED) 1226d522f475Smrg{ 1227d522f475Smrg if (IsXtermWidget(gw)) { 1228d522f475Smrg RequestMaximize((XtermWidget) gw, 1); 1229d522f475Smrg } 1230d522f475Smrg} 1231d522f475Smrg 1232d522f475Smrg/*ARGSUSED*/ 1233d522f475Smrgvoid 1234d522f475SmrgHandleRestoreSize(Widget gw, 1235d522f475Smrg XEvent * event GCC_UNUSED, 1236d522f475Smrg String * params GCC_UNUSED, 1237d522f475Smrg Cardinal *nparams GCC_UNUSED) 1238d522f475Smrg{ 1239d522f475Smrg if (IsXtermWidget(gw)) { 1240d522f475Smrg RequestMaximize((XtermWidget) gw, 0); 1241d522f475Smrg } 1242d522f475Smrg} 1243d522f475Smrg#endif /* OPT_MAXIMIZE */ 1244d522f475Smrg 1245d522f475Smrgvoid 1246d522f475SmrgRedraw(void) 1247d522f475Smrg{ 1248d522f475Smrg TScreen *screen = TScreenOf(term); 1249d522f475Smrg XExposeEvent event; 1250d522f475Smrg 1251d522f475Smrg TRACE(("Redraw\n")); 1252d522f475Smrg 1253d522f475Smrg event.type = Expose; 1254d522f475Smrg event.display = screen->display; 1255d522f475Smrg event.x = 0; 1256d522f475Smrg event.y = 0; 1257d522f475Smrg event.count = 0; 1258d522f475Smrg 1259d522f475Smrg if (VWindow(screen)) { 1260d522f475Smrg event.window = VWindow(screen); 1261d522f475Smrg event.width = term->core.width; 1262d522f475Smrg event.height = term->core.height; 1263d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 1264d522f475Smrg (XEvent *) & event, 1265d522f475Smrg NULL); 1266d522f475Smrg if (ScrollbarWidth(screen)) { 1267d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 1268d522f475Smrg (screen->scrollWidget, (XEvent *) & event, NULL); 1269d522f475Smrg } 1270d522f475Smrg } 1271d522f475Smrg#if OPT_TEK4014 1272d522f475Smrg if (TEK4014_SHOWN(term)) { 1273d522f475Smrg TekScreen *tekscr = &(tekWidget->screen); 1274d522f475Smrg event.window = TWindow(tekscr); 1275d522f475Smrg event.width = tekWidget->core.width; 1276d522f475Smrg event.height = tekWidget->core.height; 1277d522f475Smrg TekExpose((Widget) tekWidget, (XEvent *) & event, NULL); 1278d522f475Smrg } 1279d522f475Smrg#endif 1280d522f475Smrg} 1281d522f475Smrg 1282d522f475Smrg#ifdef VMS 1283d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1284d522f475Smrg#else 1285d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1286d522f475Smrg#endif 1287d522f475Smrg 1288d522f475Smrgvoid 1289d522f475Smrgtimestamp_filename(char *dst, const char *src) 1290d522f475Smrg{ 1291d522f475Smrg time_t tstamp; 1292d522f475Smrg struct tm *tstruct; 1293d522f475Smrg 1294d522f475Smrg tstamp = time((time_t *) 0); 1295d522f475Smrg tstruct = localtime(&tstamp); 1296d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1297d522f475Smrg src, 1298d522f475Smrg tstruct->tm_year + 1900, 1299d522f475Smrg tstruct->tm_mon + 1, 1300d522f475Smrg tstruct->tm_mday, 1301d522f475Smrg tstruct->tm_hour, 1302d522f475Smrg tstruct->tm_min, 1303d522f475Smrg tstruct->tm_sec); 1304d522f475Smrg} 1305d522f475Smrg 1306d522f475Smrgint 1307d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1308d522f475Smrg{ 1309d522f475Smrg int fd; 1310d522f475Smrg struct stat sb; 1311d522f475Smrg 1312d522f475Smrg#ifdef VMS 1313d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1314d522f475Smrg int the_error = errno; 1315d522f475Smrg fprintf(stderr, "%s: cannot open %s: %d:%s\n", 1316d522f475Smrg xterm_name, 1317d522f475Smrg path, 1318d522f475Smrg the_error, 1319d522f475Smrg SysErrorMsg(the_error)); 1320d522f475Smrg return -1; 1321d522f475Smrg } 1322d522f475Smrg chown(path, uid, gid); 1323d522f475Smrg#else 1324d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1325d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1326d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1327d522f475Smrg int the_error = errno; 1328d522f475Smrg fprintf(stderr, "%s: cannot open %s: %d:%s\n", 1329d522f475Smrg xterm_name, 1330d522f475Smrg path, 1331d522f475Smrg the_error, 1332d522f475Smrg SysErrorMsg(the_error)); 1333d522f475Smrg return -1; 1334d522f475Smrg } 1335d522f475Smrg#endif 1336d522f475Smrg 1337d522f475Smrg /* 1338d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1339d522f475Smrg * we do any damage, and that it is not world-writable. 1340d522f475Smrg */ 1341d522f475Smrg if (fstat(fd, &sb) < 0 1342d522f475Smrg || sb.st_uid != uid 1343d522f475Smrg || (sb.st_mode & 022) != 0) { 1344d522f475Smrg fprintf(stderr, "%s: you do not own %s\n", xterm_name, path); 1345d522f475Smrg close(fd); 1346d522f475Smrg return -1; 1347d522f475Smrg } 1348d522f475Smrg return fd; 1349d522f475Smrg} 1350d522f475Smrg 1351d522f475Smrg#ifndef VMS 1352d522f475Smrg/* 1353d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1354d522f475Smrg * We could emulate this with careful use of access() and following 1355d522f475Smrg * symbolic links, but that is messy and has race conditions. 1356d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1357d522f475Smrg * being available. 1358d522f475Smrg * 1359d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1360d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1361d522f475Smrg * for the debug logs. 1362d522f475Smrg * 1363d522f475Smrg * Returns 1364d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1365d522f475Smrg * -1 on error, e.g., cannot fork 1366d522f475Smrg * 0 otherwise. 1367d522f475Smrg */ 1368d522f475Smrgint 1369d522f475Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, int mode) 1370d522f475Smrg{ 1371d522f475Smrg int fd; 1372d522f475Smrg pid_t pid; 1373d522f475Smrg int retval = 0; 1374d522f475Smrg int childstat = 0; 1375d522f475Smrg#ifndef HAVE_WAITPID 1376d522f475Smrg int waited; 1377d522f475Smrg SIGNAL_T(*chldfunc) (int); 1378d522f475Smrg 1379d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1380d522f475Smrg#endif /* HAVE_WAITPID */ 1381d522f475Smrg 1382d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1383d522f475Smrg (int) uid, (int) geteuid(), 1384d522f475Smrg (int) gid, (int) getegid(), 1385d522f475Smrg append, 1386d522f475Smrg pathname, 1387d522f475Smrg mode)); 1388d522f475Smrg 1389d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1390d522f475Smrg fd = open(pathname, 1391d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1392d522f475Smrg mode); 1393d522f475Smrg if (fd >= 0) 1394d522f475Smrg close(fd); 1395d522f475Smrg return (fd >= 0); 1396d522f475Smrg } 1397d522f475Smrg 1398d522f475Smrg pid = fork(); 1399d522f475Smrg switch (pid) { 1400d522f475Smrg case 0: /* child */ 1401d522f475Smrg if (setgid(gid) == -1 1402d522f475Smrg || setuid(uid) == -1) { 1403d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1404d522f475Smrg retval = 1; 1405d522f475Smrg } else { 1406d522f475Smrg fd = open(pathname, 1407d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1408d522f475Smrg mode); 1409d522f475Smrg if (fd >= 0) { 1410d522f475Smrg close(fd); 1411d522f475Smrg retval = 0; 1412d522f475Smrg } else { 1413d522f475Smrg retval = 1; 1414d522f475Smrg } 1415d522f475Smrg } 1416d522f475Smrg _exit(retval); 1417d522f475Smrg /* NOTREACHED */ 1418d522f475Smrg case -1: /* error */ 1419d522f475Smrg return retval; 1420d522f475Smrg default: /* parent */ 1421d522f475Smrg#ifdef HAVE_WAITPID 1422d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1423d522f475Smrg#ifdef EINTR 1424d522f475Smrg if (errno == EINTR) 1425d522f475Smrg continue; 1426d522f475Smrg#endif /* EINTR */ 1427d522f475Smrg#ifdef ERESTARTSYS 1428d522f475Smrg if (errno == ERESTARTSYS) 1429d522f475Smrg continue; 1430d522f475Smrg#endif /* ERESTARTSYS */ 1431d522f475Smrg break; 1432d522f475Smrg } 1433d522f475Smrg#else /* HAVE_WAITPID */ 1434d522f475Smrg waited = wait(&childstat); 1435d522f475Smrg signal(SIGCHLD, chldfunc); 1436d522f475Smrg /* 1437d522f475Smrg Since we had the signal handler uninstalled for a while, 1438d522f475Smrg we might have missed the termination of our screen child. 1439d522f475Smrg If we can check for this possibility without hanging, do so. 1440d522f475Smrg */ 1441d522f475Smrg do 1442d522f475Smrg if (waited == term->screen.pid) 1443d522f475Smrg Cleanup(0); 1444d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1445d522f475Smrg#endif /* HAVE_WAITPID */ 1446d522f475Smrg#ifndef WIFEXITED 1447d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1448d522f475Smrg#endif 1449d522f475Smrg if (WIFEXITED(childstat)) 1450d522f475Smrg retval = 1; 1451d522f475Smrg return retval; 1452d522f475Smrg } 1453d522f475Smrg} 1454d522f475Smrg#endif /* !VMS */ 1455d522f475Smrg 1456d522f475Smrgint 1457d522f475SmrgxtermResetIds(TScreen * screen) 1458d522f475Smrg{ 1459d522f475Smrg int result = 0; 1460d522f475Smrg if (setgid(screen->gid) == -1) { 1461d522f475Smrg fprintf(stderr, "%s: unable to reset group-id\n", ProgramName); 1462d522f475Smrg result = -1; 1463d522f475Smrg } 1464d522f475Smrg if (setuid(screen->uid) == -1) { 1465d522f475Smrg fprintf(stderr, "%s: unable to reset user-id\n", ProgramName); 1466d522f475Smrg result = -1; 1467d522f475Smrg } 1468d522f475Smrg return result; 1469d522f475Smrg} 1470d522f475Smrg 1471d522f475Smrg#ifdef ALLOWLOGGING 1472d522f475Smrg 1473d522f475Smrg/* 1474d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1475d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1476d522f475Smrg */ 1477d522f475Smrg 1478d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1479d522f475Smrgstatic SIGNAL_T 1480d522f475Smrglogpipe(int sig GCC_UNUSED) 1481d522f475Smrg{ 1482d522f475Smrg TScreen *screen = TScreenOf(term); 1483d522f475Smrg 1484d522f475Smrg#ifdef SYSV 1485d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1486d522f475Smrg#endif /* SYSV */ 1487d522f475Smrg if (screen->logging) 1488d522f475Smrg CloseLog(screen); 1489d522f475Smrg} 1490d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1491d522f475Smrg 1492d522f475Smrgvoid 1493d522f475SmrgStartLog(TScreen * screen) 1494d522f475Smrg{ 1495d522f475Smrg static char *log_default; 1496d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1497d522f475Smrg char *cp; 1498d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1499d522f475Smrg 1500d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1501d522f475Smrg return; 1502d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1503d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1504d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1505d522f475Smrg 0640); 1506d522f475Smrg if (screen->logfd < 0) 1507d522f475Smrg return; /* open failed */ 1508d522f475Smrg#else /*VMS */ 1509d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1510d522f475Smrg if (screen->logfile) 1511d522f475Smrg free(screen->logfile); 1512d522f475Smrg if (log_default == NULL) { 1513d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1514d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1515d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1516d522f475Smrg ``To simplify implementations, the 1517d522f475Smrg total length of a domain name (i.e., 1518d522f475Smrg label octets and label length 1519d522f475Smrg octets) is restricted to 255 octets 1520d522f475Smrg or less.'' */ 1521d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1522d522f475Smrg time_t now; 1523d522f475Smrg struct tm *ltm; 1524d522f475Smrg 1525d522f475Smrg now = time((time_t *) 0); 1526d522f475Smrg ltm = (struct tm *) localtime(&now); 1527d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 1528d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 1529d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 1530d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 1531d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 1532d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 1533d522f475Smrg } 1534d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1535d522f475Smrg return; 1536d522f475Smrg#else 1537d522f475Smrg const char *log_def_name = "XtermLog.XXXXXX"; 1538d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1539d522f475Smrg return; 1540d522f475Smrg 1541d522f475Smrg mktemp(log_default); 1542d522f475Smrg#endif 1543d522f475Smrg } 1544d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 1545d522f475Smrg return; 1546d522f475Smrg } 1547d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 1548d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1549d522f475Smrg /* 1550d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 1551d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 1552d522f475Smrg * done through escape sequences.... You have been warned. 1553d522f475Smrg */ 1554d522f475Smrg int pid; 1555d522f475Smrg int p[2]; 1556d522f475Smrg static char *shell; 1557d522f475Smrg struct passwd *pw; 1558d522f475Smrg 1559d522f475Smrg if (pipe(p) < 0 || (pid = fork()) < 0) 1560d522f475Smrg return; 1561d522f475Smrg if (pid == 0) { /* child */ 1562d522f475Smrg /* 1563d522f475Smrg * Close our output (we won't be talking back to the 1564d522f475Smrg * parent), and redirect our child's output to the 1565d522f475Smrg * original stderr. 1566d522f475Smrg */ 1567d522f475Smrg close(p[1]); 1568d522f475Smrg dup2(p[0], 0); 1569d522f475Smrg close(p[0]); 1570d522f475Smrg dup2(fileno(stderr), 1); 1571d522f475Smrg dup2(fileno(stderr), 2); 1572d522f475Smrg 1573d522f475Smrg close(fileno(stderr)); 1574d522f475Smrg close(ConnectionNumber(screen->display)); 1575d522f475Smrg close(screen->respond); 1576d522f475Smrg 1577d522f475Smrg if ((((cp = x_getenv("SHELL")) == NULL) 1578d522f475Smrg && ((pw = getpwuid(screen->uid)) == NULL 1579d522f475Smrg || *(cp = pw->pw_shell) == 0)) 1580d522f475Smrg || (shell = CastMallocN(char, strlen(cp))) == 0) { 1581d522f475Smrg shell = "/bin/sh"; 1582d522f475Smrg } else { 1583d522f475Smrg strcpy(shell, cp); 1584d522f475Smrg } 1585d522f475Smrg 1586d522f475Smrg signal(SIGHUP, SIG_DFL); 1587d522f475Smrg signal(SIGCHLD, SIG_DFL); 1588d522f475Smrg 1589d522f475Smrg /* (this is redundant) */ 1590d522f475Smrg if (xtermResetIds(screen) < 0) 1591d522f475Smrg exit(ERROR_SETUID); 1592d522f475Smrg 1593d522f475Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 1594d522f475Smrg 1595d522f475Smrg fprintf(stderr, "%s: Can't exec `%s'\n", xterm_name, 1596d522f475Smrg &screen->logfile[1]); 1597d522f475Smrg exit(ERROR_LOGEXEC); 1598d522f475Smrg } 1599d522f475Smrg close(p[0]); 1600d522f475Smrg screen->logfd = p[1]; 1601d522f475Smrg signal(SIGPIPE, logpipe); 1602d522f475Smrg#else 1603d522f475Smrg Bell(XkbBI_Info, 0); 1604d522f475Smrg Bell(XkbBI_Info, 0); 1605d522f475Smrg return; 1606d522f475Smrg#endif 1607d522f475Smrg } else { 1608d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 1609d522f475Smrg screen->gid, 1610d522f475Smrg screen->logfile, 1611d522f475Smrg (log_default != 0))) < 0) 1612d522f475Smrg return; 1613d522f475Smrg } 1614d522f475Smrg#endif /*VMS */ 1615d522f475Smrg screen->logstart = VTbuffer->next; 1616d522f475Smrg screen->logging = True; 1617d522f475Smrg update_logging(); 1618d522f475Smrg} 1619d522f475Smrg 1620d522f475Smrgvoid 1621d522f475SmrgCloseLog(TScreen * screen) 1622d522f475Smrg{ 1623d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 1624d522f475Smrg return; 1625d522f475Smrg FlushLog(screen); 1626d522f475Smrg close(screen->logfd); 1627d522f475Smrg screen->logging = False; 1628d522f475Smrg update_logging(); 1629d522f475Smrg} 1630d522f475Smrg 1631d522f475Smrgvoid 1632d522f475SmrgFlushLog(TScreen * screen) 1633d522f475Smrg{ 1634d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 1635d522f475Smrg Char *cp; 1636d522f475Smrg int i; 1637d522f475Smrg 1638d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 1639d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 1640d522f475Smrg if (!tt_new_output) 1641d522f475Smrg return; 1642d522f475Smrg tt_new_output = False; 1643d522f475Smrg#endif /* VMS */ 1644d522f475Smrg cp = VTbuffer->next; 1645d522f475Smrg if (screen->logstart != 0 1646d522f475Smrg && (i = cp - screen->logstart) > 0) { 1647d522f475Smrg write(screen->logfd, (char *) screen->logstart, (unsigned) i); 1648d522f475Smrg } 1649d522f475Smrg screen->logstart = VTbuffer->next; 1650d522f475Smrg } 1651d522f475Smrg} 1652d522f475Smrg 1653d522f475Smrg#endif /* ALLOWLOGGING */ 1654d522f475Smrg 1655d522f475Smrg/***====================================================================***/ 1656d522f475Smrg 1657d522f475Smrg#if OPT_ISO_COLORS 1658d522f475Smrgstatic void 1659d522f475SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 1660d522f475Smrg{ 1661d522f475Smrg XColor color; 1662d522f475Smrg Colormap cmap = xw->core.colormap; 1663d522f475Smrg char buffer[80]; 1664d522f475Smrg 1665d522f475Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 1666d522f475Smrg color.pixel = GET_COLOR_RES(xw->screen.Acolors[colornum]); 1667d522f475Smrg XQueryColor(xw->screen.display, cmap, &color); 1668d522f475Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 1669d522f475Smrg colornum, 1670d522f475Smrg color.red, 1671d522f475Smrg color.green, 1672d522f475Smrg color.blue); 1673d522f475Smrg unparseputc1(xw, ANSI_OSC); 1674d522f475Smrg unparseputs(xw, buffer); 1675d522f475Smrg unparseputc1(xw, final); 1676d522f475Smrg unparse_end(xw); 1677d522f475Smrg} 1678d522f475Smrg 1679d522f475Smrgstatic int 1680d522f475SmrggetColormapSize(Display * display) 1681d522f475Smrg{ 1682d522f475Smrg int result; 1683d522f475Smrg int numFound; 1684d522f475Smrg XVisualInfo myTemplate, *visInfoPtr; 1685d522f475Smrg 1686d522f475Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(display, 1687d522f475Smrg XDefaultScreen(display))); 1688d522f475Smrg visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask, 1689d522f475Smrg &myTemplate, &numFound); 1690d522f475Smrg result = (numFound >= 1) ? visInfoPtr->colormap_size : 0; 1691d522f475Smrg 1692d522f475Smrg XFree((char *) visInfoPtr); 1693d522f475Smrg return result; 1694d522f475Smrg} 1695d522f475Smrg 1696d522f475Smrg/* 1697d522f475Smrg * Find closest color for "def" in "cmap". 1698d522f475Smrg * Set "def" to the resulting color. 1699d522f475Smrg * 1700d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 1701d522f475Smrg * modified with ideas from David Tong's "noflash" library. 1702d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 1703d522f475Smrg * 1704d522f475Smrg * These provide some introduction: 1705d522f475Smrg * http://en.wikipedia.org/wiki/YIQ 1706d522f475Smrg * for an introduction to YIQ weights. 1707d522f475Smrg * http://en.wikipedia.org/wiki/Luminance_(video) 1708d522f475Smrg * for a discussion of luma. 1709d522f475Smrg * http://en.wikipedia.org/wiki/YUV 1710d522f475Smrg * 1711d522f475Smrg * Return False if not able to find or allocate a color. 1712d522f475Smrg */ 1713d522f475Smrgstatic Boolean 1714d522f475Smrgfind_closest_color(Display * dpy, Colormap cmap, XColor * def) 1715d522f475Smrg{ 1716d522f475Smrg Boolean result = False; 1717d522f475Smrg XColor *colortable; 1718d522f475Smrg char *tried; 1719d522f475Smrg double diff, thisRGB, bestRGB; 1720d522f475Smrg unsigned attempts; 1721d522f475Smrg unsigned bestInx; 1722d522f475Smrg unsigned cmap_size; 1723d522f475Smrg unsigned i; 1724d522f475Smrg 1725d522f475Smrg cmap_size = getColormapSize(dpy); 1726d522f475Smrg if (cmap_size != 0) { 1727d522f475Smrg 1728d522f475Smrg colortable = TypeMallocN(XColor, cmap_size); 1729d522f475Smrg if (colortable != 0) { 1730d522f475Smrg 1731d522f475Smrg tried = TypeCallocN(char, cmap_size); 1732d522f475Smrg if (tried != 0) { 1733d522f475Smrg 1734d522f475Smrg for (i = 0; i < cmap_size; i++) { 1735d522f475Smrg colortable[i].pixel = (unsigned long) i; 1736d522f475Smrg } 1737d522f475Smrg XQueryColors(dpy, cmap, colortable, (int) cmap_size); 1738d522f475Smrg 1739d522f475Smrg /* 1740d522f475Smrg * Try (possibly each entry in the color map) to find the best 1741d522f475Smrg * approximation to the requested color. 1742d522f475Smrg */ 1743d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 1744d522f475Smrg Boolean first = True; 1745d522f475Smrg 1746d522f475Smrg bestRGB = 0.0; 1747d522f475Smrg bestInx = 0; 1748d522f475Smrg for (i = 0; i < cmap_size; i++) { 1749d522f475Smrg if (!tried[bestInx]) { 1750d522f475Smrg /* 1751d522f475Smrg * Look for the best match based on luminance. 1752d522f475Smrg * Measure this by the least-squares difference of 1753d522f475Smrg * the weighted R/G/B components from the color map 1754d522f475Smrg * versus the requested color. Use the Y (luma) 1755d522f475Smrg * component of the YIQ color space model for 1756d522f475Smrg * weights that correspond to the luminance. 1757d522f475Smrg */ 1758d522f475Smrg#define AddColorWeight(weight, color) \ 1759d522f475Smrg diff = weight * (int) ((def->color) - colortable[i].color); \ 1760d522f475Smrg thisRGB = diff * diff 1761d522f475Smrg 1762d522f475Smrg AddColorWeight(0.30, red); 1763d522f475Smrg AddColorWeight(0.61, green); 1764d522f475Smrg AddColorWeight(0.11, blue); 1765d522f475Smrg 1766d522f475Smrg if (first || (thisRGB < bestRGB)) { 1767d522f475Smrg first = False; 1768d522f475Smrg bestInx = i; 1769d522f475Smrg bestRGB = thisRGB; 1770d522f475Smrg } 1771d522f475Smrg } 1772d522f475Smrg } 1773d522f475Smrg if (XAllocColor(dpy, cmap, &colortable[bestInx]) != 0) { 1774d522f475Smrg *def = colortable[bestInx]; 1775d522f475Smrg result = True; 1776d522f475Smrg break; 1777d522f475Smrg } 1778d522f475Smrg /* 1779d522f475Smrg * It failed - either the color map entry was readonly, or 1780d522f475Smrg * another client has allocated the entry. Mark the entry 1781d522f475Smrg * so we will ignore it 1782d522f475Smrg */ 1783d522f475Smrg tried[bestInx] = True; 1784d522f475Smrg } 1785d522f475Smrg free(tried); 1786d522f475Smrg } 1787d522f475Smrg free(colortable); 1788d522f475Smrg } 1789d522f475Smrg } 1790d522f475Smrg return result; 1791d522f475Smrg} 1792d522f475Smrg 1793d522f475Smrg/* 1794d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 1795d522f475Smrg * to 256. 1796d522f475Smrg * 1797d522f475Smrg * Returns 1798d522f475Smrg * -1 on error 1799d522f475Smrg * 0 on no change 1800d522f475Smrg * 1 if a new color was allocated. 1801d522f475Smrg */ 1802d522f475Smrgstatic int 1803d522f475SmrgAllocateAnsiColor(XtermWidget xw, 1804d522f475Smrg ColorRes * res, 1805d522f475Smrg char *spec) 1806d522f475Smrg{ 1807d522f475Smrg int result; 1808d522f475Smrg XColor def; 1809d522f475Smrg TScreen *screen = &xw->screen; 1810d522f475Smrg Colormap cmap = xw->core.colormap; 1811d522f475Smrg 1812d522f475Smrg if (XParseColor(screen->display, cmap, spec, &def) 1813d522f475Smrg && (XAllocColor(screen->display, cmap, &def) 1814d522f475Smrg || find_closest_color(screen->display, cmap, &def))) { 1815d522f475Smrg if ( 1816d522f475Smrg#if OPT_COLOR_RES 1817d522f475Smrg res->mode == True && 1818d522f475Smrg#endif 1819d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 1820d522f475Smrg result = 0; 1821d522f475Smrg } else { 1822d522f475Smrg result = 1; 1823d522f475Smrg SET_COLOR_RES(res, def.pixel); 1824d522f475Smrg TRACE(("AllocateAnsiColor[%d] %s (pixel %#lx)\n", 1825d522f475Smrg (res - screen->Acolors), spec, def.pixel)); 1826d522f475Smrg#if OPT_COLOR_RES 1827d522f475Smrg if (!res->mode) 1828d522f475Smrg result = 0; 1829d522f475Smrg res->mode = True; 1830d522f475Smrg#endif 1831d522f475Smrg } 1832d522f475Smrg } else { 1833d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 1834d522f475Smrg result = -1; 1835d522f475Smrg } 1836d522f475Smrg return (result); 1837d522f475Smrg} 1838d522f475Smrg 1839d522f475Smrg#if OPT_COLOR_RES 1840d522f475SmrgPixel 1841d522f475SmrgxtermGetColorRes(ColorRes * res) 1842d522f475Smrg{ 1843d522f475Smrg Pixel result = 0; 1844d522f475Smrg 1845d522f475Smrg if (res->mode) { 1846d522f475Smrg result = res->value; 1847d522f475Smrg } else { 1848d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 1849d522f475Smrg res - term->screen.Acolors)); 1850d522f475Smrg 1851d522f475Smrg if (res >= term->screen.Acolors) { 1852d522f475Smrg assert(res - term->screen.Acolors < MAXCOLORS); 1853d522f475Smrg 1854d522f475Smrg if (AllocateAnsiColor(term, res, res->resource) < 0) { 1855d522f475Smrg res->value = term->screen.Tcolors[TEXT_FG].value; 1856d522f475Smrg res->mode = -True; 1857d522f475Smrg fprintf(stderr, 1858d522f475Smrg "%s: Cannot allocate color %s\n", 1859d522f475Smrg xterm_name, 1860d522f475Smrg NonNull(res->resource)); 1861d522f475Smrg } 1862d522f475Smrg result = res->value; 1863d522f475Smrg } else { 1864d522f475Smrg result = 0; 1865d522f475Smrg } 1866d522f475Smrg } 1867d522f475Smrg return result; 1868d522f475Smrg} 1869d522f475Smrg#endif 1870d522f475Smrg 1871d522f475Smrgstatic Bool 1872d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 1873d522f475Smrg char *buf, 1874d522f475Smrg int final) 1875d522f475Smrg{ 1876d522f475Smrg char *name; 1877d522f475Smrg int color; 1878d522f475Smrg int repaint = False; 1879d522f475Smrg int code; 1880d522f475Smrg 1881d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 1882d522f475Smrg 1883d522f475Smrg while (buf && *buf) { 1884d522f475Smrg name = strchr(buf, ';'); 1885d522f475Smrg if (name == NULL) 1886d522f475Smrg break; 1887d522f475Smrg *name = '\0'; 1888d522f475Smrg name++; 1889d522f475Smrg color = atoi(buf); 1890d522f475Smrg if (color < 0 || color >= NUM_ANSI_COLORS) 1891d522f475Smrg break; 1892d522f475Smrg buf = strchr(name, ';'); 1893d522f475Smrg if (buf) { 1894d522f475Smrg *buf = '\0'; 1895d522f475Smrg buf++; 1896d522f475Smrg } 1897d522f475Smrg if (!strcmp(name, "?")) 1898d522f475Smrg ReportAnsiColorRequest(xw, color, final); 1899d522f475Smrg else { 1900d522f475Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 1901d522f475Smrg code = AllocateAnsiColor(xw, &(xw->screen.Acolors[color]), name); 1902d522f475Smrg if (code < 0) { 1903d522f475Smrg /* stop on any error */ 1904d522f475Smrg break; 1905d522f475Smrg } else if (code > 0) { 1906d522f475Smrg repaint = True; 1907d522f475Smrg } 1908d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 1909d522f475Smrg * change style (dynamic colors). 1910d522f475Smrg */ 1911d522f475Smrg } 1912d522f475Smrg } 1913d522f475Smrg if (repaint) 1914d522f475Smrg xtermRepaint(xw); 1915d522f475Smrg 1916d522f475Smrg return (repaint); 1917d522f475Smrg} 1918d522f475Smrg#else 1919d522f475Smrg#define find_closest_color(display, cmap, def) 0 1920d522f475Smrg#endif /* OPT_ISO_COLORS */ 1921d522f475Smrg 1922d522f475Smrg#if OPT_PASTE64 1923d522f475Smrgstatic void 1924d522f475SmrgManipulateSelectionData(XtermWidget xw, TScreen * screen, char *buf, int final) 1925d522f475Smrg{ 1926d522f475Smrg#define PDATA(a,b) { a, #b } 1927d522f475Smrg static struct { 1928d522f475Smrg char given; 1929d522f475Smrg char *result; 1930d522f475Smrg } table[] = { 1931d522f475Smrg PDATA('s', SELECT), 1932d522f475Smrg PDATA('p', PRIMARY), 1933d522f475Smrg PDATA('c', CLIPBOARD), 1934d522f475Smrg PDATA('0', CUT_BUFFER0), 1935d522f475Smrg PDATA('1', CUT_BUFFER1), 1936d522f475Smrg PDATA('2', CUT_BUFFER2), 1937d522f475Smrg PDATA('3', CUT_BUFFER3), 1938d522f475Smrg PDATA('4', CUT_BUFFER4), 1939d522f475Smrg PDATA('5', CUT_BUFFER5), 1940d522f475Smrg PDATA('6', CUT_BUFFER6), 1941d522f475Smrg PDATA('7', CUT_BUFFER7), 1942d522f475Smrg }; 1943d522f475Smrg 1944d522f475Smrg char *base = buf; 1945d522f475Smrg char *used = x_strdup(base); 1946d522f475Smrg Cardinal j, n = 0; 1947d522f475Smrg char **select_args = 0; 1948d522f475Smrg 1949d522f475Smrg TRACE(("Manipulate selection data\n")); 1950d522f475Smrg 1951d522f475Smrg while (*buf != ';' && *buf != '\0') { 1952d522f475Smrg ++buf; 1953d522f475Smrg } 1954d522f475Smrg 1955d522f475Smrg if (*buf == ';') { 1956d522f475Smrg *buf++ = '\0'; 1957d522f475Smrg 1958d522f475Smrg if (*base == '\0') 1959d522f475Smrg base = "s0"; 1960d522f475Smrg if ((select_args = TypeCallocN(String, 1 + strlen(base))) == 0) 1961d522f475Smrg return; 1962d522f475Smrg while (*base != '\0') { 1963d522f475Smrg for (j = 0; j < XtNumber(table); ++j) { 1964d522f475Smrg if (*base == table[j].given) { 1965d522f475Smrg used[n] = *base; 1966d522f475Smrg select_args[n++] = table[j].result; 1967d522f475Smrg TRACE(("atom[%d] %s\n", n, table[j].result)); 1968d522f475Smrg break; 1969d522f475Smrg } 1970d522f475Smrg } 1971d522f475Smrg ++base; 1972d522f475Smrg } 1973d522f475Smrg used[n] = 0; 1974d522f475Smrg 1975d522f475Smrg if (!strcmp(buf, "?")) { 1976d522f475Smrg TRACE(("Getting selection\n")); 1977d522f475Smrg unparseputc1(xw, ANSI_OSC); 1978d522f475Smrg unparseputs(xw, "52"); 1979d522f475Smrg unparseputc(xw, ';'); 1980d522f475Smrg 1981d522f475Smrg unparseputs(xw, used); 1982d522f475Smrg unparseputc(xw, ';'); 1983d522f475Smrg 1984d522f475Smrg /* Tell xtermGetSelection data is base64 encoded */ 1985d522f475Smrg screen->base64_paste = n; 1986d522f475Smrg screen->base64_final = final; 1987d522f475Smrg 1988d522f475Smrg /* terminator will be written in this call */ 1989d522f475Smrg xtermGetSelection((Widget) xw, 0, select_args, n, NULL); 1990d522f475Smrg } else { 1991d522f475Smrg TRACE(("Setting selection with %s\n", buf)); 1992d522f475Smrg ClearSelectionBuffer(screen); 1993d522f475Smrg while (*buf != '\0') 1994d522f475Smrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 1995d522f475Smrg CompleteSelection(xw, select_args, n); 1996d522f475Smrg } 1997d522f475Smrg } 1998d522f475Smrg} 1999d522f475Smrg#endif /* OPT_PASTE64 */ 2000d522f475Smrg 2001d522f475Smrg/***====================================================================***/ 2002d522f475Smrg 2003d522f475Smrgstatic Bool 2004d522f475SmrgxtermIsPrintable(TScreen * screen, Char ** bufp, Char * last) 2005d522f475Smrg{ 2006d522f475Smrg Bool result = False; 2007d522f475Smrg Char *cp = *bufp; 2008d522f475Smrg Char *next = cp; 2009d522f475Smrg 2010d522f475Smrg (void) screen; 2011d522f475Smrg (void) last; 2012d522f475Smrg 2013d522f475Smrg#if OPT_WIDE_CHARS 2014d522f475Smrg if (xtermEnvUTF8() && screen->utf8_title) { 2015d522f475Smrg PtyData data; 2016d522f475Smrg 2017d522f475Smrg if (decodeUtf8(fakePtyData(&data, cp, last))) { 2018d522f475Smrg if (data.utf_data != UCS_REPL 2019d522f475Smrg && (data.utf_data >= 128 || 2020d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2021d522f475Smrg next += (data.utf_size - 1); 2022d522f475Smrg result = True; 2023d522f475Smrg } else { 2024d522f475Smrg result = False; 2025d522f475Smrg } 2026d522f475Smrg } else { 2027d522f475Smrg result = False; 2028d522f475Smrg } 2029d522f475Smrg } else 2030d522f475Smrg#endif 2031d522f475Smrg#if OPT_C1_PRINT 2032d522f475Smrg if (screen->c1_printable 2033d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2034d522f475Smrg result = True; 2035d522f475Smrg } else 2036d522f475Smrg#endif 2037d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2038d522f475Smrg result = True; 2039d522f475Smrg } 2040d522f475Smrg *bufp = next; 2041d522f475Smrg return result; 2042d522f475Smrg} 2043d522f475Smrg 2044d522f475Smrg/***====================================================================***/ 2045d522f475Smrg 2046d522f475Smrg/* 2047d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2048d522f475Smrg * array indices. 2049d522f475Smrg */ 2050d522f475Smrgtypedef enum { 2051d522f475Smrg OSC_TEXT_FG = 10 2052d522f475Smrg ,OSC_TEXT_BG 2053d522f475Smrg ,OSC_TEXT_CURSOR 2054d522f475Smrg ,OSC_MOUSE_FG 2055d522f475Smrg ,OSC_MOUSE_BG 2056d522f475Smrg#if OPT_TEK4014 2057d522f475Smrg ,OSC_TEK_FG = 15 2058d522f475Smrg ,OSC_TEK_BG 2059d522f475Smrg#endif 2060d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2061d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 2062d522f475Smrg#endif 2063d522f475Smrg#if OPT_TEK4014 2064d522f475Smrg ,OSC_TEK_CURSOR = 18 2065d522f475Smrg#endif 2066d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2067d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 2068d522f475Smrg#endif 2069d522f475Smrg ,OSC_NCOLORS 2070d522f475Smrg} OscTextColors; 2071d522f475Smrg 2072d522f475Smrgstatic ScrnColors *pOldColors = NULL; 2073d522f475Smrg 2074d522f475Smrgstatic Bool 2075d522f475SmrgGetOldColors(XtermWidget xw) 2076d522f475Smrg{ 2077d522f475Smrg int i; 2078d522f475Smrg if (pOldColors == NULL) { 2079d522f475Smrg pOldColors = (ScrnColors *) XtMalloc(sizeof(ScrnColors)); 2080d522f475Smrg if (pOldColors == NULL) { 2081d522f475Smrg fprintf(stderr, "allocation failure in GetOldColors\n"); 2082d522f475Smrg return (False); 2083d522f475Smrg } 2084d522f475Smrg pOldColors->which = 0; 2085d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2086d522f475Smrg pOldColors->colors[i] = 0; 2087d522f475Smrg pOldColors->names[i] = NULL; 2088d522f475Smrg } 2089d522f475Smrg GetColors(xw, pOldColors); 2090d522f475Smrg } 2091d522f475Smrg return (True); 2092d522f475Smrg} 2093d522f475Smrg 2094d522f475Smrgstatic int 2095d522f475SmrgoppositeColor(int n) 2096d522f475Smrg{ 2097d522f475Smrg switch (n) { 2098d522f475Smrg case TEXT_FG: 2099d522f475Smrg n = TEXT_BG; 2100d522f475Smrg break; 2101d522f475Smrg case TEXT_BG: 2102d522f475Smrg n = TEXT_FG; 2103d522f475Smrg break; 2104d522f475Smrg case MOUSE_FG: 2105d522f475Smrg n = MOUSE_BG; 2106d522f475Smrg break; 2107d522f475Smrg case MOUSE_BG: 2108d522f475Smrg n = MOUSE_FG; 2109d522f475Smrg break; 2110d522f475Smrg#if OPT_TEK4014 2111d522f475Smrg case TEK_FG: 2112d522f475Smrg n = TEK_BG; 2113d522f475Smrg break; 2114d522f475Smrg case TEK_BG: 2115d522f475Smrg n = TEK_FG; 2116d522f475Smrg break; 2117d522f475Smrg#endif 2118d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2119d522f475Smrg case HIGHLIGHT_FG: 2120d522f475Smrg n = HIGHLIGHT_BG; 2121d522f475Smrg break; 2122d522f475Smrg case HIGHLIGHT_BG: 2123d522f475Smrg n = HIGHLIGHT_FG; 2124d522f475Smrg break; 2125d522f475Smrg#endif 2126d522f475Smrg default: 2127d522f475Smrg break; 2128d522f475Smrg } 2129d522f475Smrg return n; 2130d522f475Smrg} 2131d522f475Smrg 2132d522f475Smrgstatic void 2133d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 2134d522f475Smrg{ 2135d522f475Smrg XColor color; 2136d522f475Smrg Colormap cmap = xw->core.colormap; 2137d522f475Smrg char buffer[80]; 2138d522f475Smrg 2139d522f475Smrg /* 2140d522f475Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 2141d522f475Smrg * reverse-video is set. Report this as the original color index, but 2142d522f475Smrg * reporting the opposite color which would be used. 2143d522f475Smrg */ 2144d522f475Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 2145d522f475Smrg 2146d522f475Smrg GetOldColors(xw); 2147d522f475Smrg color.pixel = pOldColors->colors[ndx]; 2148d522f475Smrg XQueryColor(xw->screen.display, cmap, &color); 2149d522f475Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 2150d522f475Smrg color.red, 2151d522f475Smrg color.green, 2152d522f475Smrg color.blue); 2153d522f475Smrg TRACE(("ReportColors %d: %#lx as %s\n", ndx, pOldColors->colors[ndx], buffer)); 2154d522f475Smrg unparseputc1(xw, ANSI_OSC); 2155d522f475Smrg unparseputs(xw, buffer); 2156d522f475Smrg unparseputc1(xw, final); 2157d522f475Smrg unparse_end(xw); 2158d522f475Smrg} 2159d522f475Smrg 2160d522f475Smrgstatic Bool 2161d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 2162d522f475Smrg{ 2163d522f475Smrg int i; 2164d522f475Smrg 2165d522f475Smrg /* if we were going to free old colors, this would be the place to 2166d522f475Smrg * do it. I've decided not to (for now), because it seems likely 2167d522f475Smrg * that we'd have a small set of colors we use over and over, and that 2168d522f475Smrg * we could save some overhead this way. The only case in which this 2169d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 2170d522f475Smrg * which case they can restart xterm 2171d522f475Smrg */ 2172d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2173d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 2174d522f475Smrg if (pOldColors->names[i] != NULL) { 2175d522f475Smrg XtFree(pOldColors->names[i]); 2176d522f475Smrg pOldColors->names[i] = NULL; 2177d522f475Smrg } 2178d522f475Smrg if (pNew->names[i]) { 2179d522f475Smrg pOldColors->names[i] = pNew->names[i]; 2180d522f475Smrg } 2181d522f475Smrg pOldColors->colors[i] = pNew->colors[i]; 2182d522f475Smrg } 2183d522f475Smrg } 2184d522f475Smrg return (True); 2185d522f475Smrg} 2186d522f475Smrg 2187d522f475Smrg/* 2188d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 2189d522f475Smrg * xterm is compiled. 2190d522f475Smrg */ 2191d522f475Smrgstatic int 2192d522f475SmrgOscToColorIndex(OscTextColors mode) 2193d522f475Smrg{ 2194d522f475Smrg int result = 0; 2195d522f475Smrg 2196d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 2197d522f475Smrg switch (mode) { 2198d522f475Smrg CASE(TEXT_FG); 2199d522f475Smrg CASE(TEXT_BG); 2200d522f475Smrg CASE(TEXT_CURSOR); 2201d522f475Smrg CASE(MOUSE_FG); 2202d522f475Smrg CASE(MOUSE_BG); 2203d522f475Smrg#if OPT_TEK4014 2204d522f475Smrg CASE(TEK_FG); 2205d522f475Smrg CASE(TEK_BG); 2206d522f475Smrg#endif 2207d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2208d522f475Smrg CASE(HIGHLIGHT_BG); 2209d522f475Smrg CASE(HIGHLIGHT_FG); 2210d522f475Smrg#endif 2211d522f475Smrg#if OPT_TEK4014 2212d522f475Smrg CASE(TEK_CURSOR); 2213d522f475Smrg#endif 2214d522f475Smrg case OSC_NCOLORS: 2215d522f475Smrg break; 2216d522f475Smrg } 2217d522f475Smrg return result; 2218d522f475Smrg} 2219d522f475Smrg 2220d522f475Smrgstatic Bool 2221d522f475SmrgChangeColorsRequest(XtermWidget xw, 2222d522f475Smrg int start, 2223d522f475Smrg char *names, 2224d522f475Smrg int final) 2225d522f475Smrg{ 2226d522f475Smrg Bool result = False; 2227d522f475Smrg char *thisName; 2228d522f475Smrg ScrnColors newColors; 2229d522f475Smrg int i, ndx; 2230d522f475Smrg 2231d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 2232d522f475Smrg 2233d522f475Smrg if (GetOldColors(xw)) { 2234d522f475Smrg newColors.which = 0; 2235d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2236d522f475Smrg newColors.names[i] = NULL; 2237d522f475Smrg } 2238d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 2239d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 2240d522f475Smrg if (xw->misc.re_verse) 2241d522f475Smrg ndx = oppositeColor(ndx); 2242d522f475Smrg 2243d522f475Smrg if ((names == NULL) || (names[0] == '\0')) { 2244d522f475Smrg newColors.names[ndx] = NULL; 2245d522f475Smrg } else { 2246d522f475Smrg if (names[0] == ';') 2247d522f475Smrg thisName = NULL; 2248d522f475Smrg else 2249d522f475Smrg thisName = names; 2250d522f475Smrg names = strchr(names, ';'); 2251d522f475Smrg if (names != NULL) { 2252d522f475Smrg *names++ = '\0'; 2253d522f475Smrg } 2254d522f475Smrg if (thisName != 0 && !strcmp(thisName, "?")) { 2255d522f475Smrg ReportColorRequest(xw, ndx, final); 2256d522f475Smrg } else if (!pOldColors->names[ndx] 2257d522f475Smrg || (thisName 2258d522f475Smrg && strcmp(thisName, pOldColors->names[ndx]))) { 2259d522f475Smrg AllocateTermColor(xw, &newColors, ndx, thisName); 2260d522f475Smrg } 2261d522f475Smrg } 2262d522f475Smrg } 2263d522f475Smrg 2264d522f475Smrg if (newColors.which != 0) { 2265d522f475Smrg ChangeColors(xw, &newColors); 2266d522f475Smrg UpdateOldColors(xw, &newColors); 2267d522f475Smrg } 2268d522f475Smrg result = True; 2269d522f475Smrg } 2270d522f475Smrg return result; 2271d522f475Smrg} 2272d522f475Smrg 2273d522f475Smrg/***====================================================================***/ 2274d522f475Smrg 2275d522f475Smrgvoid 2276d522f475Smrgdo_osc(XtermWidget xw, Char * oscbuf, unsigned len GCC_UNUSED, int final) 2277d522f475Smrg{ 2278d522f475Smrg TScreen *screen = &(xw->screen); 2279d522f475Smrg int mode; 2280d522f475Smrg Char *cp; 2281d522f475Smrg int state = 0; 2282d522f475Smrg char *buf = 0; 2283d522f475Smrg 2284d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 2285d522f475Smrg 2286d522f475Smrg /* 2287d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 2288d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 2289d522f475Smrg * with the same final character as the application sends to make this 2290d522f475Smrg * work better with shell scripts, which may have trouble reading an 2291d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 2292d522f475Smrg */ 2293d522f475Smrg mode = 0; 2294d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 2295d522f475Smrg switch (state) { 2296d522f475Smrg case 0: 2297d522f475Smrg if (isdigit(*cp)) { 2298d522f475Smrg mode = 10 * mode + (*cp - '0'); 2299d522f475Smrg if (mode > 65535) { 2300d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 2301d522f475Smrg return; 2302d522f475Smrg } 2303d522f475Smrg break; 2304d522f475Smrg } 2305d522f475Smrg /* FALLTHRU */ 2306d522f475Smrg case 1: 2307d522f475Smrg if (*cp != ';') { 2308d522f475Smrg TRACE(("do_osc did not find semicolon offset %d\n", cp - oscbuf)); 2309d522f475Smrg return; 2310d522f475Smrg } 2311d522f475Smrg state = 2; 2312d522f475Smrg break; 2313d522f475Smrg case 2: 2314d522f475Smrg buf = (char *) cp; 2315d522f475Smrg state = 3; 2316d522f475Smrg /* FALLTHRU */ 2317d522f475Smrg default: 2318d522f475Smrg if (!xtermIsPrintable(screen, &cp, oscbuf + len)) { 2319d522f475Smrg switch (mode) { 2320d522f475Smrg case 0: 2321d522f475Smrg case 1: 2322d522f475Smrg case 2: 2323d522f475Smrg break; 2324d522f475Smrg default: 2325d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 2326d522f475Smrg CharOf(*cp), 2327d522f475Smrg cp - oscbuf)); 2328d522f475Smrg return; 2329d522f475Smrg } 2330d522f475Smrg } 2331d522f475Smrg } 2332d522f475Smrg } 2333d522f475Smrg if (buf == 0) 2334d522f475Smrg return; 2335d522f475Smrg 2336d522f475Smrg switch (mode) { 2337d522f475Smrg case 0: /* new icon name and title */ 2338d522f475Smrg ChangeIconName(buf); 2339d522f475Smrg ChangeTitle(buf); 2340d522f475Smrg break; 2341d522f475Smrg 2342d522f475Smrg case 1: /* new icon name only */ 2343d522f475Smrg ChangeIconName(buf); 2344d522f475Smrg break; 2345d522f475Smrg 2346d522f475Smrg case 2: /* new title only */ 2347d522f475Smrg ChangeTitle(buf); 2348d522f475Smrg break; 2349d522f475Smrg 235022d8e007Schristos#ifdef notdef 2351d522f475Smrg case 3: /* change X property */ 2352d522f475Smrg ChangeXprop(buf); 2353d522f475Smrg break; 235422d8e007Schristos#endif 2355d522f475Smrg#if OPT_ISO_COLORS 2356d522f475Smrg case 4: 2357d522f475Smrg ChangeAnsiColorRequest(xw, buf, final); 2358d522f475Smrg break; 2359d522f475Smrg#endif 2360d522f475Smrg case OSC_TEXT_FG: 2361d522f475Smrg case OSC_TEXT_BG: 2362d522f475Smrg case OSC_TEXT_CURSOR: 2363d522f475Smrg case OSC_MOUSE_FG: 2364d522f475Smrg case OSC_MOUSE_BG: 2365d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2366d522f475Smrg case OSC_HIGHLIGHT_BG: 2367d522f475Smrg#endif 2368d522f475Smrg#if OPT_TEK4014 2369d522f475Smrg case OSC_TEK_FG: 2370d522f475Smrg case OSC_TEK_BG: 2371d522f475Smrg case OSC_TEK_CURSOR: 2372d522f475Smrg#endif 2373d522f475Smrg if (xw->misc.dynamicColors) 2374d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 2375d522f475Smrg break; 2376d522f475Smrg 2377d522f475Smrg case 30: 2378d522f475Smrg case 31: 2379d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 2380d522f475Smrg break; 2381d522f475Smrg 2382d522f475Smrg#ifdef ALLOWLOGGING 2383d522f475Smrg case 46: /* new log file */ 2384d522f475Smrg#ifdef ALLOWLOGFILECHANGES 2385d522f475Smrg /* 2386d522f475Smrg * Warning, enabling this feature allows people to overwrite 2387d522f475Smrg * arbitrary files accessible to the person running xterm. 2388d522f475Smrg */ 2389d522f475Smrg if (buf != 0 2390d522f475Smrg && strcmp(buf, "?") 2391d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 2392d522f475Smrg strcpy(cp, buf); 2393d522f475Smrg if (screen->logfile) 2394d522f475Smrg free(screen->logfile); 2395d522f475Smrg screen->logfile = cp; 2396d522f475Smrg break; 2397d522f475Smrg } 2398d522f475Smrg#endif 2399d522f475Smrg Bell(XkbBI_Info, 0); 2400d522f475Smrg Bell(XkbBI_Info, 0); 2401d522f475Smrg break; 2402d522f475Smrg#endif /* ALLOWLOGGING */ 2403d522f475Smrg 2404d522f475Smrg case 50: 2405d522f475Smrg#if OPT_SHIFT_FONTS 2406d522f475Smrg if (buf != 0 && !strcmp(buf, "?")) { 2407d522f475Smrg int num = screen->menu_font_number; 2408d522f475Smrg 2409d522f475Smrg unparseputc1(xw, ANSI_OSC); 2410d522f475Smrg unparseputs(xw, "50"); 2411d522f475Smrg 2412d522f475Smrg if ((buf = screen->MenuFontName(num)) != 0) { 2413d522f475Smrg unparseputc(xw, ';'); 2414d522f475Smrg unparseputs(xw, buf); 2415d522f475Smrg } 2416d522f475Smrg unparseputc1(xw, final); 2417d522f475Smrg unparse_end(xw); 2418d522f475Smrg } else if (buf != 0) { 2419d522f475Smrg int num = screen->menu_font_number; 2420d522f475Smrg VTFontNames fonts; 2421d522f475Smrg 2422d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 2423d522f475Smrg 2424d522f475Smrg /* 2425d522f475Smrg * If the font specification is a "#", followed by an 2426d522f475Smrg * optional sign and optional number, lookup the 2427d522f475Smrg * corresponding menu font entry. 2428d522f475Smrg */ 2429d522f475Smrg if (*buf == '#') { 2430d522f475Smrg int rel = 0; 2431d522f475Smrg 2432d522f475Smrg if (*++buf == '+') { 2433d522f475Smrg rel = 1; 2434d522f475Smrg buf++; 2435d522f475Smrg } else if (*buf == '-') { 2436d522f475Smrg rel = -1; 2437d522f475Smrg buf++; 2438d522f475Smrg } 2439d522f475Smrg 2440d522f475Smrg if (isdigit(CharOf(*buf))) { 2441d522f475Smrg int val = atoi(buf); 2442d522f475Smrg if (rel > 0) 2443d522f475Smrg rel = val; 2444d522f475Smrg else if (rel < 0) 2445d522f475Smrg rel = -val; 2446d522f475Smrg else 2447d522f475Smrg num = val; 2448d522f475Smrg } else if (rel == 0) { 2449d522f475Smrg num = 0; 2450d522f475Smrg } 2451d522f475Smrg 2452d522f475Smrg if (rel != 0) { 2453d522f475Smrg num = lookupRelativeFontSize(xw, 2454d522f475Smrg screen->menu_font_number, rel); 2455d522f475Smrg 2456d522f475Smrg } 2457d522f475Smrg if (num < 0 2458d522f475Smrg || num > fontMenu_lastBuiltin 2459d522f475Smrg || (buf = screen->MenuFontName(num)) == 0) { 2460d522f475Smrg Bell(XkbBI_MinorError, 0); 2461d522f475Smrg break; 2462d522f475Smrg } 2463d522f475Smrg } else { 2464d522f475Smrg num = fontMenu_fontescape; 2465d522f475Smrg } 2466d522f475Smrg fonts.f_n = buf; 2467d522f475Smrg SetVTFont(xw, num, True, &fonts); 2468d522f475Smrg } 2469d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 2470d522f475Smrg break; 2471d522f475Smrg case 51: 2472d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 2473d522f475Smrg break; 2474d522f475Smrg 2475d522f475Smrg#if OPT_PASTE64 2476d522f475Smrg case 52: 2477d522f475Smrg if (screen->allowWindowOps && (buf != 0)) 2478d522f475Smrg ManipulateSelectionData(xw, screen, buf, final); 2479d522f475Smrg break; 2480d522f475Smrg#endif 2481d522f475Smrg /* 2482d522f475Smrg * One could write code to send back the display and host names, 2483d522f475Smrg * but that could potentially open a fairly nasty security hole. 2484d522f475Smrg */ 2485d522f475Smrg } 2486d522f475Smrg unparse_end(xw); 2487d522f475Smrg} 2488d522f475Smrg 2489d522f475Smrg#ifdef SunXK_F36 2490d522f475Smrg#define MAX_UDK 37 2491d522f475Smrg#else 2492d522f475Smrg#define MAX_UDK 35 2493d522f475Smrg#endif 2494d522f475Smrgstatic struct { 2495d522f475Smrg char *str; 2496d522f475Smrg int len; 2497d522f475Smrg} user_keys[MAX_UDK]; 2498d522f475Smrg 2499d522f475Smrg/* 2500d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 2501d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 2502d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 2503d522f475Smrg * "real" terminals accept commas in the string definitions). 2504d522f475Smrg */ 2505d522f475Smrgstatic int 2506d522f475Smrgudk_value(char **cp) 2507d522f475Smrg{ 2508d522f475Smrg int c; 2509d522f475Smrg 2510d522f475Smrg for (;;) { 2511d522f475Smrg if ((c = **cp) != '\0') 2512d522f475Smrg *cp = *cp + 1; 2513d522f475Smrg if (c == ';' || c == '\0') 2514d522f475Smrg return -1; 2515d522f475Smrg if (c >= '0' && c <= '9') 2516d522f475Smrg return c - '0'; 2517d522f475Smrg if (c >= 'A' && c <= 'F') 2518d522f475Smrg return c - 'A' + 10; 2519d522f475Smrg if (c >= 'a' && c <= 'f') 2520d522f475Smrg return c - 'a' + 10; 2521d522f475Smrg } 2522d522f475Smrg} 2523d522f475Smrg 2524d522f475Smrgvoid 2525d522f475Smrgreset_decudk(void) 2526d522f475Smrg{ 2527d522f475Smrg int n; 2528d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 2529d522f475Smrg if (user_keys[n].str != 0) { 2530d522f475Smrg free(user_keys[n].str); 2531d522f475Smrg user_keys[n].str = 0; 2532d522f475Smrg user_keys[n].len = 0; 2533d522f475Smrg } 2534d522f475Smrg } 2535d522f475Smrg} 2536d522f475Smrg 2537d522f475Smrg/* 2538d522f475Smrg * Parse the data for DECUDK (user-defined keys). 2539d522f475Smrg */ 2540d522f475Smrgstatic void 2541d522f475Smrgparse_decudk(char *cp) 2542d522f475Smrg{ 2543d522f475Smrg while (*cp) { 2544d522f475Smrg char *base = cp; 2545d522f475Smrg char *str = CastMallocN(char, strlen(cp) + 1); 2546d522f475Smrg unsigned key = 0; 2547d522f475Smrg int lo, hi; 2548d522f475Smrg int len = 0; 2549d522f475Smrg 2550d522f475Smrg while (isdigit(CharOf(*cp))) 2551d522f475Smrg key = (key * 10) + (*cp++ - '0'); 2552d522f475Smrg if (*cp == '/') { 2553d522f475Smrg cp++; 2554d522f475Smrg while ((hi = udk_value(&cp)) >= 0 2555d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 2556d522f475Smrg str[len++] = (hi << 4) | lo; 2557d522f475Smrg } 2558d522f475Smrg } 2559d522f475Smrg if (len > 0 && key < MAX_UDK) { 2560d522f475Smrg if (user_keys[key].str != 0) 2561d522f475Smrg free(user_keys[key].str); 2562d522f475Smrg user_keys[key].str = str; 2563d522f475Smrg user_keys[key].len = len; 2564d522f475Smrg } else { 2565d522f475Smrg free(str); 2566d522f475Smrg } 2567d522f475Smrg if (*cp == ';') 2568d522f475Smrg cp++; 2569d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 2570d522f475Smrg break; 2571d522f475Smrg } 2572d522f475Smrg} 2573d522f475Smrg 2574d522f475Smrg#if OPT_TRACE 2575d522f475Smrg#define SOFT_WIDE 10 2576d522f475Smrg#define SOFT_HIGH 20 2577d522f475Smrg 2578d522f475Smrgstatic void 2579d522f475Smrgparse_decdld(ANSI * params, char *string) 2580d522f475Smrg{ 2581d522f475Smrg char DscsName[8]; 2582d522f475Smrg int len; 2583d522f475Smrg int Pfn = params->a_param[0]; 2584d522f475Smrg int Pcn = params->a_param[1]; 2585d522f475Smrg int Pe = params->a_param[2]; 2586d522f475Smrg int Pcmw = params->a_param[3]; 2587d522f475Smrg int Pw = params->a_param[4]; 2588d522f475Smrg int Pt = params->a_param[5]; 2589d522f475Smrg int Pcmh = params->a_param[6]; 2590d522f475Smrg int Pcss = params->a_param[7]; 2591d522f475Smrg 2592d522f475Smrg int start_char = Pcn + 0x20; 2593d522f475Smrg int char_wide = ((Pcmw == 0) 2594d522f475Smrg ? (Pcss ? 6 : 10) 2595d522f475Smrg : (Pcmw > 4 2596d522f475Smrg ? Pcmw 2597d522f475Smrg : (Pcmw + 3))); 2598d522f475Smrg int char_high = ((Pcmh == 0) 2599d522f475Smrg ? ((Pcmw >= 2 || Pcmw <= 4) 2600d522f475Smrg ? 10 2601d522f475Smrg : 20) 2602d522f475Smrg : Pcmh); 2603d522f475Smrg Char ch; 2604d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 2605d522f475Smrg Bool first = True; 2606d522f475Smrg Bool prior = False; 2607d522f475Smrg int row = 0, col = 0; 2608d522f475Smrg 2609d522f475Smrg TRACE(("Parsing DECDLD\n")); 2610d522f475Smrg TRACE((" font number %d\n", Pfn)); 2611d522f475Smrg TRACE((" starting char %d\n", Pcn)); 2612d522f475Smrg TRACE((" erase control %d\n", Pe)); 2613d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 2614d522f475Smrg TRACE((" font-width %d\n", Pw)); 2615d522f475Smrg TRACE((" text/full %d\n", Pt)); 2616d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 2617d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 2618d522f475Smrg 2619d522f475Smrg if (Pfn > 1 2620d522f475Smrg || Pcn > 95 2621d522f475Smrg || Pe > 2 2622d522f475Smrg || Pcmw > 10 2623d522f475Smrg || Pcmw == 1 2624d522f475Smrg || Pt > 2 2625d522f475Smrg || Pcmh > 20 2626d522f475Smrg || Pcss > 1 2627d522f475Smrg || char_wide > SOFT_WIDE 2628d522f475Smrg || char_high > SOFT_HIGH) { 2629d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 2630d522f475Smrg return; 2631d522f475Smrg } 2632d522f475Smrg 2633d522f475Smrg len = 0; 2634d522f475Smrg while (*string != '\0') { 2635d522f475Smrg ch = CharOf(*string++); 2636d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 2637d522f475Smrg if (len < 2) 2638d522f475Smrg DscsName[len++] = ch; 2639d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 2640d522f475Smrg DscsName[len++] = ch; 2641d522f475Smrg break; 2642d522f475Smrg } 2643d522f475Smrg } 2644d522f475Smrg DscsName[len] = 0; 2645d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 2646d522f475Smrg 2647d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 2648d522f475Smrg while (*string != '\0') { 2649d522f475Smrg if (first) { 2650d522f475Smrg TRACE(("Char %d:\n", start_char)); 2651d522f475Smrg if (prior) { 2652d522f475Smrg for (row = 0; row < char_high; ++row) { 2653d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 2654d522f475Smrg } 2655d522f475Smrg } 2656d522f475Smrg prior = False; 2657d522f475Smrg first = False; 2658d522f475Smrg for (row = 0; row < char_high; ++row) { 2659d522f475Smrg for (col = 0; col < char_wide; ++col) { 2660d522f475Smrg bits[row][col] = '.'; 2661d522f475Smrg } 2662d522f475Smrg } 2663d522f475Smrg row = col = 0; 2664d522f475Smrg } 2665d522f475Smrg ch = CharOf(*string++); 2666d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 2667d522f475Smrg int n; 2668d522f475Smrg 2669d522f475Smrg ch -= 0x3f; 2670d522f475Smrg for (n = 0; n < 6; ++n) { 2671d522f475Smrg bits[row + n][col] = (ch & (1 << n)) ? '*' : '.'; 2672d522f475Smrg } 2673d522f475Smrg col += 1; 2674d522f475Smrg prior = True; 2675d522f475Smrg } else if (ch == '/') { 2676d522f475Smrg row += 6; 2677d522f475Smrg col = 0; 2678d522f475Smrg } else if (ch == ';') { 2679d522f475Smrg first = True; 2680d522f475Smrg ++start_char; 2681d522f475Smrg } 2682d522f475Smrg } 2683d522f475Smrg} 2684d522f475Smrg#else 2685d522f475Smrg#define parse_decdld(p,q) /* nothing */ 2686d522f475Smrg#endif 2687d522f475Smrg 2688d522f475Smrg/* 2689d522f475Smrg * Parse numeric parameters. Normally we use a state machine to simplify 2690d522f475Smrg * interspersing with control characters, but have the string already. 2691d522f475Smrg */ 2692d522f475Smrgstatic void 2693d522f475Smrgparse_ansi_params(ANSI * params, char **string) 2694d522f475Smrg{ 2695d522f475Smrg char *cp = *string; 2696d522f475Smrg short nparam = 0; 2697d522f475Smrg 2698d522f475Smrg memset(params, 0, sizeof(*params)); 2699d522f475Smrg while (*cp != '\0') { 2700d522f475Smrg Char ch = CharOf(*cp++); 2701d522f475Smrg 2702d522f475Smrg if (isdigit(ch)) { 2703d522f475Smrg if (nparam < NPARAM) { 2704d522f475Smrg params->a_param[nparam] *= 10; 2705d522f475Smrg params->a_param[nparam] += (ch - '0'); 2706d522f475Smrg } 2707d522f475Smrg } else if (ch == ';') { 2708d522f475Smrg if (++nparam < NPARAM) 2709d522f475Smrg params->a_nparam = nparam; 2710d522f475Smrg } else if (ch < 32) { 2711d522f475Smrg ; 2712d522f475Smrg } else { 2713d522f475Smrg /* should be 0x30 to 0x7e */ 2714d522f475Smrg params->a_final = ch; 2715d522f475Smrg break; 2716d522f475Smrg } 2717d522f475Smrg } 2718d522f475Smrg *string = cp; 2719d522f475Smrg} 2720d522f475Smrg 2721d522f475Smrgvoid 2722d522f475Smrgdo_dcs(XtermWidget xw, Char * dcsbuf, size_t dcslen) 2723d522f475Smrg{ 2724d522f475Smrg TScreen *screen = &xw->screen; 2725d522f475Smrg char reply[BUFSIZ]; 2726d522f475Smrg char *cp = (char *) dcsbuf; 2727d522f475Smrg Bool okay; 2728d522f475Smrg ANSI params; 2729d522f475Smrg 2730d522f475Smrg TRACE(("do_dcs(%s:%d)\n", (char *) dcsbuf, dcslen)); 2731d522f475Smrg 2732d522f475Smrg if (dcslen != strlen(cp)) 2733d522f475Smrg /* shouldn't have nulls in the string */ 2734d522f475Smrg return; 2735d522f475Smrg 2736d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 2737d522f475Smrg case '$': /* DECRQSS */ 2738d522f475Smrg okay = True; 2739d522f475Smrg 2740d522f475Smrg cp++; 2741d522f475Smrg if (*cp++ == 'q') { 2742d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 2743d522f475Smrg sprintf(reply, "%d%s", 2744d522f475Smrg (screen->protected_mode == DEC_PROTECT) 2745d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 2746d522f475Smrg cp); 2747d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 2748d522f475Smrg sprintf(reply, "%d%s%s", 2749d522f475Smrg (screen->vtXX_level ? 2750d522f475Smrg screen->vtXX_level : 1) + 60, 2751d522f475Smrg (screen->vtXX_level >= 2) 2752d522f475Smrg ? (screen->control_eight_bits 2753d522f475Smrg ? ";0" : ";1") 2754d522f475Smrg : "", 2755d522f475Smrg cp); 2756d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 2757d522f475Smrg sprintf(reply, "%d;%dr", 2758d522f475Smrg screen->top_marg + 1, 2759d522f475Smrg screen->bot_marg + 1); 2760d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 2761d522f475Smrg strcpy(reply, "0"); 2762d522f475Smrg if (xw->flags & BOLD) 2763d522f475Smrg strcat(reply, ";1"); 2764d522f475Smrg if (xw->flags & UNDERLINE) 2765d522f475Smrg strcat(reply, ";4"); 2766d522f475Smrg if (xw->flags & BLINK) 2767d522f475Smrg strcat(reply, ";5"); 2768d522f475Smrg if (xw->flags & INVERSE) 2769d522f475Smrg strcat(reply, ";7"); 2770d522f475Smrg if (xw->flags & INVISIBLE) 2771d522f475Smrg strcat(reply, ";8"); 2772d522f475Smrg if_OPT_EXT_COLORS(screen, { 2773d522f475Smrg if (xw->flags & FG_COLOR) { 2774d522f475Smrg if (xw->cur_foreground >= 16) 2775d522f475Smrg sprintf(reply + strlen(reply), 2776d522f475Smrg ";38;5;%d", xw->cur_foreground); 2777d522f475Smrg else 2778d522f475Smrg sprintf(reply + strlen(reply), 2779d522f475Smrg ";%d%d", 2780d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 2781d522f475Smrg xw->cur_foreground >= 8 ? 2782d522f475Smrg xw->cur_foreground - 8 : 2783d522f475Smrg xw->cur_foreground); 2784d522f475Smrg } 2785d522f475Smrg if (xw->flags & BG_COLOR) { 2786d522f475Smrg if (xw->cur_background >= 16) 2787d522f475Smrg sprintf(reply + strlen(reply), 2788d522f475Smrg ";48;5;%d", xw->cur_foreground); 2789d522f475Smrg else 2790d522f475Smrg sprintf(reply + strlen(reply), 2791d522f475Smrg ";%d%d", 2792d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 2793d522f475Smrg xw->cur_background >= 8 ? 2794d522f475Smrg xw->cur_background - 8 : 2795d522f475Smrg xw->cur_background); 2796d522f475Smrg } 2797d522f475Smrg }); 2798d522f475Smrg if_OPT_ISO_TRADITIONAL_COLORS(screen, { 2799d522f475Smrg if (xw->flags & FG_COLOR) 2800d522f475Smrg sprintf(reply + strlen(reply), 2801d522f475Smrg ";%d%d", 2802d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 2803d522f475Smrg xw->cur_foreground >= 8 ? 2804d522f475Smrg xw->cur_foreground - 8 : 2805d522f475Smrg xw->cur_foreground); 2806d522f475Smrg if (xw->flags & BG_COLOR) 2807d522f475Smrg sprintf(reply + strlen(reply), 2808d522f475Smrg ";%d%d", 2809d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 2810d522f475Smrg xw->cur_background >= 8 ? 2811d522f475Smrg xw->cur_background - 8 : 2812d522f475Smrg xw->cur_background); 2813d522f475Smrg }); 2814d522f475Smrg strcat(reply, "m"); 2815d522f475Smrg } else 2816d522f475Smrg okay = False; 2817d522f475Smrg 2818d522f475Smrg unparseputc1(xw, ANSI_DCS); 2819d522f475Smrg unparseputc(xw, okay ? '1' : '0'); 2820d522f475Smrg unparseputc(xw, '$'); 2821d522f475Smrg unparseputc(xw, 'r'); 282222d8e007Schristos if (okay) { 2823d522f475Smrg cp = reply; 282422d8e007Schristos unparseputs(xw, cp); 282522d8e007Schristos } 2826d522f475Smrg unparseputc1(xw, ANSI_ST); 2827d522f475Smrg } else { 2828d522f475Smrg unparseputc(xw, ANSI_CAN); 2829d522f475Smrg } 2830d522f475Smrg break; 2831d522f475Smrg#if OPT_TCAP_QUERY 2832d522f475Smrg case '+': 2833d522f475Smrg cp++; 2834d522f475Smrg if (*cp == 'q') { 2835d522f475Smrg Bool fkey; 2836d522f475Smrg unsigned state; 2837d522f475Smrg int code; 2838d522f475Smrg char *tmp; 2839d522f475Smrg char *parsed = ++cp; 2840d522f475Smrg 2841d522f475Smrg unparseputc1(xw, ANSI_DCS); 2842d522f475Smrg 2843d522f475Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 2844d522f475Smrg 2845d522f475Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 2846d522f475Smrg 2847d522f475Smrg unparseputc(xw, '+'); 2848d522f475Smrg unparseputc(xw, 'r'); 2849d522f475Smrg 2850d522f475Smrg while (*cp != 0) { 2851d522f475Smrg if (cp == parsed) 2852d522f475Smrg break; /* no data found, error */ 2853d522f475Smrg 2854d522f475Smrg for (tmp = cp; tmp != parsed; ++tmp) 2855d522f475Smrg unparseputc(xw, *tmp); 2856d522f475Smrg 2857d522f475Smrg if (code >= 0) { 2858d522f475Smrg unparseputc(xw, '='); 2859d522f475Smrg screen->tc_query_code = code; 2860d522f475Smrg screen->tc_query_fkey = fkey; 2861d522f475Smrg#if OPT_ISO_COLORS 2862d522f475Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 2863d522f475Smrg * number of colors) */ 2864d522f475Smrg if (code == XK_COLORS) { 2865d522f475Smrg unparseputn(xw, NUM_ANSI_COLORS); 2866d522f475Smrg } else 2867d522f475Smrg#endif 2868d522f475Smrg#if OPT_TCAP_FKEYS 2869d522f475Smrg /* 2870d522f475Smrg * First ensure that we handle the extended cursor- and 2871d522f475Smrg * editing-keypad keys. 2872d522f475Smrg */ 2873d522f475Smrg if ((code <= XK_Fn(MAX_FKEY)) 2874d522f475Smrg || xtermcapString(xw, CodeToXkey(code), 0) == 0) 2875d522f475Smrg#endif 2876d522f475Smrg { 2877d522f475Smrg XKeyEvent event; 2878d522f475Smrg event.state = state; 2879d522f475Smrg Input(xw, &event, False); 2880d522f475Smrg } 2881d522f475Smrg screen->tc_query_code = -1; 2882d522f475Smrg } else { 2883d522f475Smrg break; /* no match found, error */ 2884d522f475Smrg } 2885d522f475Smrg 2886d522f475Smrg cp = parsed; 2887d522f475Smrg if (*parsed == ';') { 2888d522f475Smrg unparseputc(xw, *parsed++); 2889d522f475Smrg cp = parsed; 2890d522f475Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 2891d522f475Smrg } 2892d522f475Smrg } 2893d522f475Smrg unparseputc1(xw, ANSI_ST); 2894d522f475Smrg } 2895d522f475Smrg break; 2896d522f475Smrg#endif 2897d522f475Smrg default: 2898d522f475Smrg parse_ansi_params(¶ms, &cp); 2899d522f475Smrg switch (params.a_final) { 2900d522f475Smrg case '|': /* DECUDK */ 2901d522f475Smrg if (params.a_param[0] == 0) 2902d522f475Smrg reset_decudk(); 290322d8e007Schristos#ifdef notdef 2904d522f475Smrg parse_decudk(cp); 290522d8e007Schristos#endif 2906d522f475Smrg break; 2907d522f475Smrg case '{': /* DECDLD (no '}' case though) */ 2908d522f475Smrg parse_decdld(¶ms, cp); 2909d522f475Smrg break; 2910d522f475Smrg } 2911d522f475Smrg break; 2912d522f475Smrg } 2913d522f475Smrg unparse_end(xw); 2914d522f475Smrg} 2915d522f475Smrg 2916d522f475Smrgchar * 2917d522f475Smrgudk_lookup(int keycode, int *len) 2918d522f475Smrg{ 2919d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 2920d522f475Smrg *len = user_keys[keycode].len; 2921d522f475Smrg return user_keys[keycode].str; 2922d522f475Smrg } 2923d522f475Smrg return 0; 2924d522f475Smrg} 2925d522f475Smrg 2926d522f475Smrgstatic void 2927d522f475SmrgChangeGroup(String attribute, char *value) 2928d522f475Smrg{ 2929d522f475Smrg#if OPT_WIDE_CHARS 2930d522f475Smrg static Char *converted; /* NO_LEAKS */ 2931d522f475Smrg#endif 2932d522f475Smrg static char empty[1]; 2933d522f475Smrg 2934d522f475Smrg Arg args[1]; 2935d522f475Smrg char *original = (value != 0) ? value : empty; 2936d522f475Smrg char *name = original; 2937d522f475Smrg TScreen *screen = TScreenOf(term); 2938d522f475Smrg Widget w = CURRENT_EMU(); 2939d522f475Smrg Widget top = SHELL_OF(w); 2940d522f475Smrg unsigned limit = strlen(name); 2941d522f475Smrg Char *c1 = (Char *) original; 2942d522f475Smrg Char *cp; 2943d522f475Smrg 2944d522f475Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", attribute, name)); 2945d522f475Smrg 2946d522f475Smrg if (!screen->allowTitleOps) 2947d522f475Smrg return; 2948d522f475Smrg 2949d522f475Smrg /* 2950d522f475Smrg * Ignore titles that are too long to be plausible requests. 2951d522f475Smrg */ 2952d522f475Smrg if (limit >= 1024) 2953d522f475Smrg return; 2954d522f475Smrg 2955d522f475Smrg for (cp = c1; *cp != 0; ++cp) { 2956d522f475Smrg Char *c2 = cp; 2957d522f475Smrg if (!xtermIsPrintable(screen, &cp, c1 + limit)) { 2958d522f475Smrg memset(c2, '?', (unsigned) (cp + 1 - c2)); 2959d522f475Smrg } 2960d522f475Smrg } 2961d522f475Smrg 2962d522f475Smrg#if OPT_WIDE_CHARS 2963d522f475Smrg /* 2964d522f475Smrg * Title strings are limited to ISO-8859-1, which is consistent with the 2965d522f475Smrg * printable data in sos_table. However, if we're running in UTF-8 mode, 2966d522f475Smrg * it is likely that non-ASCII text in the string will be rejected because 2967d522f475Smrg * it is not printable in the current locale. So we convert it to UTF-8, 2968d522f475Smrg * allowing the X library to convert it back. 2969d522f475Smrg */ 2970d522f475Smrg if (xtermEnvUTF8() && !screen->utf8_title) { 2971d522f475Smrg int n; 2972d522f475Smrg 2973d522f475Smrg for (n = 0; name[n] != '\0'; ++n) { 2974d522f475Smrg if (CharOf(name[n]) > 127) { 2975d522f475Smrg if (converted != 0) 2976d522f475Smrg free(converted); 2977d522f475Smrg if ((converted = TypeMallocN(Char, 1 + (5 * limit))) != 0) { 2978d522f475Smrg Char *temp = converted; 2979d522f475Smrg while (*name != 0) { 2980d522f475Smrg temp = convertToUTF8(temp, CharOf(*name)); 2981d522f475Smrg ++name; 2982d522f475Smrg } 2983d522f475Smrg *temp = 0; 2984d522f475Smrg name = (char *) converted; 2985d522f475Smrg TRACE(("...converted{%s}\n", name)); 2986d522f475Smrg } 2987d522f475Smrg break; 2988d522f475Smrg } 2989d522f475Smrg } 2990d522f475Smrg } 2991d522f475Smrg#endif 2992d522f475Smrg 2993d522f475Smrg#if OPT_SAME_NAME 2994d522f475Smrg /* If the attribute isn't going to change, then don't bother... */ 2995d522f475Smrg 2996d522f475Smrg if (resource.sameName) { 2997d522f475Smrg char *buf; 2998d522f475Smrg XtSetArg(args[0], attribute, &buf); 2999d522f475Smrg XtGetValues(top, args, 1); 3000d522f475Smrg TRACE(("...comparing{%s}\n", buf)); 3001d522f475Smrg if (strcmp(name, buf) == 0) 3002d522f475Smrg return; 3003d522f475Smrg } 3004d522f475Smrg#endif /* OPT_SAME_NAME */ 3005d522f475Smrg 3006d522f475Smrg TRACE(("...updating %s\n", attribute)); 3007d522f475Smrg TRACE(("...value is %s\n", name)); 3008d522f475Smrg XtSetArg(args[0], attribute, name); 3009d522f475Smrg XtSetValues(top, args, 1); 3010d522f475Smrg 3011d522f475Smrg#if OPT_WIDE_CHARS 3012d522f475Smrg if (xtermEnvUTF8()) { 3013d522f475Smrg Display *dpy = XtDisplay(term); 3014d522f475Smrg Atom my_atom; 3015d522f475Smrg 3016d522f475Smrg const char *propname = (!strcmp(attribute, XtNtitle) 3017d522f475Smrg ? "_NET_WM_NAME" 3018d522f475Smrg : "_NET_WM_ICON_NAME"); 3019d522f475Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 3020d522f475Smrg if (screen->utf8_title) { /* FIXME - redundant? */ 3021d522f475Smrg TRACE(("...updating %s\n", propname)); 3022d522f475Smrg TRACE(("...value is %s\n", original)); 3023d522f475Smrg XChangeProperty(dpy, VShellWindow, 3024d522f475Smrg my_atom, XA_UTF8_STRING(dpy), 8, 3025d522f475Smrg PropModeReplace, 3026d522f475Smrg (Char *) original, (int) strlen(original)); 3027d522f475Smrg } else { 3028d522f475Smrg TRACE(("...deleting %s\n", propname)); 3029d522f475Smrg XDeleteProperty(dpy, VShellWindow, my_atom); 3030d522f475Smrg } 3031d522f475Smrg } 3032d522f475Smrg } 3033d522f475Smrg#endif 3034d522f475Smrg} 3035d522f475Smrg 3036d522f475Smrgvoid 3037d522f475SmrgChangeIconName(char *name) 3038d522f475Smrg{ 3039d522f475Smrg if (name == 0) 3040d522f475Smrg name = ""; 3041d522f475Smrg#if OPT_ZICONBEEP /* If warning should be given then give it */ 3042d522f475Smrg if (resource.zIconBeep && term->screen.zIconBeep_flagged) { 3043d522f475Smrg char *newname = CastMallocN(char, strlen(name) + 4); 3044d522f475Smrg if (!newname) { 3045d522f475Smrg fprintf(stderr, "malloc failed in ChangeIconName\n"); 3046d522f475Smrg return; 3047d522f475Smrg } 3048d522f475Smrg strcpy(newname, "*** "); 3049d522f475Smrg strcat(newname, name); 3050d522f475Smrg ChangeGroup(XtNiconName, newname); 3051d522f475Smrg free(newname); 3052d522f475Smrg } else 3053d522f475Smrg#endif /* OPT_ZICONBEEP */ 3054d522f475Smrg ChangeGroup(XtNiconName, name); 3055d522f475Smrg} 3056d522f475Smrg 3057d522f475Smrgvoid 3058d522f475SmrgChangeTitle(char *name) 3059d522f475Smrg{ 3060d522f475Smrg ChangeGroup(XtNtitle, name); 3061d522f475Smrg} 3062d522f475Smrg 3063d522f475Smrg#define Strlen(s) strlen((char *)(s)) 3064d522f475Smrg 3065d522f475Smrgvoid 3066d522f475SmrgChangeXprop(char *buf) 3067d522f475Smrg{ 3068d522f475Smrg Display *dpy = XtDisplay(toplevel); 3069d522f475Smrg Window w = XtWindow(toplevel); 3070d522f475Smrg XTextProperty text_prop; 3071d522f475Smrg Atom aprop; 3072d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 3073d522f475Smrg 3074d522f475Smrg if (pchEndPropName) 3075d522f475Smrg *pchEndPropName = '\0'; 3076d522f475Smrg aprop = XInternAtom(dpy, buf, False); 3077d522f475Smrg if (pchEndPropName == NULL) { 3078d522f475Smrg /* no "=value" given, so delete the property */ 3079d522f475Smrg XDeleteProperty(dpy, w, aprop); 3080d522f475Smrg } else { 3081d522f475Smrg text_prop.value = pchEndPropName + 1; 3082d522f475Smrg text_prop.encoding = XA_STRING; 3083d522f475Smrg text_prop.format = 8; 3084d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 3085d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 3086d522f475Smrg } 3087d522f475Smrg} 3088d522f475Smrg 3089d522f475Smrg/***====================================================================***/ 3090d522f475Smrg 3091d522f475Smrg/* 3092d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 3093d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 3094d522f475Smrg */ 3095d522f475Smrgvoid 3096d522f475SmrgReverseOldColors(void) 3097d522f475Smrg{ 3098d522f475Smrg ScrnColors *pOld = pOldColors; 3099d522f475Smrg Pixel tmpPix; 3100d522f475Smrg char *tmpName; 3101d522f475Smrg 3102d522f475Smrg if (pOld) { 3103d522f475Smrg /* change text cursor, if necesary */ 3104d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 3105d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 3106d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 3107d522f475Smrg XtFree(pOldColors->names[TEXT_CURSOR]); 3108d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 3109d522f475Smrg } 3110d522f475Smrg if (pOld->names[TEXT_BG]) { 3111d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 3112d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 3113d522f475Smrg } 3114d522f475Smrg } 3115d522f475Smrg } 3116d522f475Smrg 3117d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 3118d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 3119d522f475Smrg 3120d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 3121d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 3122d522f475Smrg 3123d522f475Smrg#if OPT_TEK4014 3124d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 3125d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 3126d522f475Smrg#endif 3127d522f475Smrg } 3128d522f475Smrg return; 3129d522f475Smrg} 3130d522f475Smrg 3131d522f475SmrgBool 3132d522f475SmrgAllocateTermColor(XtermWidget xw, 3133d522f475Smrg ScrnColors * pNew, 3134d522f475Smrg int ndx, 3135d522f475Smrg const char *name) 3136d522f475Smrg{ 3137d522f475Smrg XColor def; 3138d522f475Smrg TScreen *screen = &xw->screen; 3139d522f475Smrg Colormap cmap = xw->core.colormap; 3140d522f475Smrg char *newName; 3141d522f475Smrg 3142d522f475Smrg if (XParseColor(screen->display, cmap, name, &def) 3143d522f475Smrg && (XAllocColor(screen->display, cmap, &def) 3144d522f475Smrg || find_closest_color(screen->display, cmap, &def)) 3145d522f475Smrg && (newName = x_strdup(name)) != 0) { 3146d522f475Smrg if (COLOR_DEFINED(pNew, ndx)) 3147d522f475Smrg free(pNew->names[ndx]); 3148d522f475Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 3149d522f475Smrg SET_COLOR_NAME(pNew, ndx, newName); 3150d522f475Smrg TRACE(("AllocateTermColor #%d: %s (pixel %#lx)\n", ndx, newName, def.pixel)); 3151d522f475Smrg return (True); 3152d522f475Smrg } 3153d522f475Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 3154d522f475Smrg return (False); 3155d522f475Smrg} 3156d522f475Smrg/***====================================================================***/ 3157d522f475Smrg 3158d522f475Smrg/* ARGSUSED */ 3159d522f475Smrgvoid 3160d522f475SmrgPanic(char *s GCC_UNUSED, int a GCC_UNUSED) 3161d522f475Smrg{ 3162d522f475Smrg#ifdef DEBUG 3163d522f475Smrg if (debug) { 3164d522f475Smrg fprintf(stderr, "%s: PANIC!\t", xterm_name); 3165d522f475Smrg fprintf(stderr, s, a); 3166d522f475Smrg fputs("\r\n", stderr); 3167d522f475Smrg fflush(stderr); 3168d522f475Smrg } 3169d522f475Smrg#endif /* DEBUG */ 3170d522f475Smrg} 3171d522f475Smrg 3172d522f475Smrgconst char * 3173d522f475SmrgSysErrorMsg(int code) 3174d522f475Smrg{ 3175d522f475Smrg static char unknown[] = "unknown error"; 3176d522f475Smrg char *s = strerror(code); 3177d522f475Smrg return s ? s : unknown; 3178d522f475Smrg} 3179d522f475Smrg 3180d522f475Smrgconst char * 3181d522f475SmrgSysReasonMsg(int code) 3182d522f475Smrg{ 3183d522f475Smrg /* *INDENT-OFF* */ 3184d522f475Smrg static const struct { 3185d522f475Smrg int code; 3186d522f475Smrg const char *name; 3187d522f475Smrg } table[] = { 3188d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 3189d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 3190d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 3191d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 3192d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 3193d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 3194d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 3195d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 3196d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 3197d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 3198d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 3199d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 3200d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 3201d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 3202d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 3203d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 3204d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 3205d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 3206d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 3207d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 3208d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 3209d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 3210d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 3211d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 3212d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 3213d522f475Smrg { ERROR_SPREALLOC, "spawn: realloc of ttydev failed" }, 3214d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 3215d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 3216d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 3217d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 3218d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 3219d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 3220d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 3221d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 3222d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 3223d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 3224d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 3225d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 3226d522f475Smrg { ERROR_SREALLOC, "ScreenResize: realloc() failed on alt base" }, 3227d522f475Smrg { ERROR_RESIZE, "ScreenResize: malloc() or realloc() failed" }, 3228d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 3229d522f475Smrg { ERROR_SBRALLOC, "ScrollBarOn: realloc() failed on base" }, 3230d522f475Smrg { ERROR_SBRALLOC2, "ScrollBarOn: realloc() failed on rows" }, 3231d522f475Smrg { ERROR_MMALLOC, "my_memmove: malloc/realloc failed" }, 3232d522f475Smrg }; 3233d522f475Smrg /* *INDENT-ON* */ 3234d522f475Smrg 3235d522f475Smrg Cardinal n; 3236d522f475Smrg const char *result = "?"; 3237d522f475Smrg 3238d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 3239d522f475Smrg if (code == table[n].code) { 3240d522f475Smrg result = table[n].name; 3241d522f475Smrg break; 3242d522f475Smrg } 3243d522f475Smrg } 3244d522f475Smrg return result; 3245d522f475Smrg} 3246d522f475Smrg 3247d522f475Smrgvoid 3248d522f475SmrgSysError(int code) 3249d522f475Smrg{ 3250d522f475Smrg int oerrno = errno; 3251d522f475Smrg 3252d522f475Smrg fprintf(stderr, "%s: Error %d, errno %d: ", xterm_name, code, oerrno); 3253d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 3254d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 3255d522f475Smrg 3256d522f475Smrg Cleanup(code); 3257d522f475Smrg} 3258d522f475Smrg 3259d522f475Smrg/* 3260d522f475Smrg * cleanup by sending SIGHUP to client processes 3261d522f475Smrg */ 3262d522f475Smrgvoid 3263d522f475SmrgCleanup(int code) 3264d522f475Smrg{ 3265d522f475Smrg static Bool cleaning; 3266d522f475Smrg TScreen *screen = TScreenOf(term); 3267d522f475Smrg 3268d522f475Smrg /* 3269d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 3270d522f475Smrg */ 3271d522f475Smrg if (code == 0) { 3272d522f475Smrg if (cleaning) { 3273d522f475Smrg hold_screen = 0; 3274d522f475Smrg return; 3275d522f475Smrg } 3276d522f475Smrg 3277d522f475Smrg cleaning = True; 3278d522f475Smrg need_cleanup = False; 3279d522f475Smrg 3280d522f475Smrg TRACE(("Cleanup %d\n", code)); 3281d522f475Smrg 3282d522f475Smrg if (hold_screen) { 3283d522f475Smrg hold_screen = 2; 3284d522f475Smrg while (hold_screen) { 3285d522f475Smrg xevents(); 3286d522f475Smrg Sleep(10); 3287d522f475Smrg } 3288d522f475Smrg } 3289d522f475Smrg#if OPT_SESSION_MGT 3290d522f475Smrg if (resource.sessionMgt) { 3291d522f475Smrg XtVaSetValues(toplevel, 3292d522f475Smrg XtNjoinSession, False, 3293d522f475Smrg (XtPointer *) 0); 3294d522f475Smrg } 3295d522f475Smrg#endif 3296d522f475Smrg } 3297d522f475Smrg 3298d522f475Smrg if (screen->pid > 1) { 3299d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 3300d522f475Smrg } 3301d522f475Smrg Exit(code); 3302d522f475Smrg} 3303d522f475Smrg 3304d522f475Smrg#ifndef VMS 3305d522f475Smrgchar * 3306d522f475SmrgxtermFindShell(char *leaf, Bool warning) 3307d522f475Smrg{ 3308d522f475Smrg char *s; 3309d522f475Smrg char *d; 3310d522f475Smrg char *tmp; 3311d522f475Smrg char *result = leaf; 3312d522f475Smrg 3313d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 3314d522f475Smrg if (*result != '\0' && strchr("+/-", *result) == 0) { 3315d522f475Smrg /* find it in $PATH */ 3316d522f475Smrg if ((s = x_getenv("PATH")) != 0) { 3317d522f475Smrg if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 1)) != 0) { 3318d522f475Smrg Bool found = False; 3319d522f475Smrg while (*s != '\0') { 3320d522f475Smrg strcpy(tmp, s); 3321d522f475Smrg for (d = tmp;; ++d) { 3322d522f475Smrg if (*d == ':' || *d == '\0') { 3323d522f475Smrg int skip = (*d != '\0'); 3324d522f475Smrg *d = '/'; 3325d522f475Smrg strcpy(d + 1, leaf); 3326d522f475Smrg if (skip) 3327d522f475Smrg ++d; 3328d522f475Smrg s += (d - tmp); 3329d522f475Smrg if (*tmp == '/' 3330d522f475Smrg && strstr(tmp, "..") == 0 3331d522f475Smrg && access(tmp, X_OK) == 0) { 3332d522f475Smrg result = x_strdup(tmp); 3333d522f475Smrg found = True; 3334d522f475Smrg } 3335d522f475Smrg break; 3336d522f475Smrg } 3337d522f475Smrg if (found) 3338d522f475Smrg break; 3339d522f475Smrg } 3340d522f475Smrg if (found) 3341d522f475Smrg break; 3342d522f475Smrg } 3343d522f475Smrg free(tmp); 3344d522f475Smrg } 3345d522f475Smrg } 3346d522f475Smrg } 3347d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 3348d522f475Smrg if (*result != '/' 3349d522f475Smrg || strstr(result, "..") != 0 3350d522f475Smrg || access(result, X_OK) != 0) { 3351d522f475Smrg if (warning) 3352d522f475Smrg fprintf(stderr, "No absolute path found for shell: %s\n", result); 3353d522f475Smrg result = 0; 3354d522f475Smrg } 3355d522f475Smrg return result; 3356d522f475Smrg} 3357d522f475Smrg#endif /* VMS */ 3358d522f475Smrg 3359d522f475Smrg#define ENV_HUNK(n) ((((n) + 1) | 31) + 1) 3360d522f475Smrg 3361d522f475Smrg/* 3362d522f475Smrg * copy the environment before Setenv'ing. 3363d522f475Smrg */ 3364d522f475Smrgvoid 3365d522f475SmrgxtermCopyEnv(char **oldenv) 3366d522f475Smrg{ 3367d522f475Smrg unsigned size; 3368d522f475Smrg char **newenv; 3369d522f475Smrg 3370d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 3371d522f475Smrg ; 3372d522f475Smrg } 3373d522f475Smrg 3374d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 3375d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 3376d522f475Smrg environ = newenv; 3377d522f475Smrg} 3378d522f475Smrg 3379d522f475Smrg/* 3380d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 3381d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 3382d522f475Smrg * This procedure assumes the memory for the first level of environ 3383d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 3384d522f475Smrg * to have to do a realloc(). 3385d522f475Smrg */ 3386d522f475Smrgvoid 3387d522f475SmrgxtermSetenv(char *var, char *value) 3388d522f475Smrg{ 3389d522f475Smrg if (value != 0) { 3390d522f475Smrg char *test; 3391d522f475Smrg int envindex = 0; 3392d522f475Smrg size_t len = strlen(var); 3393d522f475Smrg int found = -1; 3394d522f475Smrg 3395d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 3396d522f475Smrg 3397d522f475Smrg while ((test = environ[envindex]) != NULL) { 3398d522f475Smrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 3399d522f475Smrg found = envindex; 3400d522f475Smrg break; 3401d522f475Smrg } 3402d522f475Smrg envindex++; 3403d522f475Smrg } 3404d522f475Smrg 3405d522f475Smrg if (found < 0) { 3406d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 3407d522f475Smrg unsigned have = ENV_HUNK(envindex); 3408d522f475Smrg 3409d522f475Smrg if (need > have) { 3410d522f475Smrg char **newenv; 3411d522f475Smrg newenv = TypeMallocN(char *, need); 3412d522f475Smrg if (newenv == 0) { 3413d522f475Smrg fprintf(stderr, "Cannot increase environment\n"); 3414d522f475Smrg return; 3415d522f475Smrg } 3416d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 3417d522f475Smrg free(environ); 3418d522f475Smrg environ = newenv; 3419d522f475Smrg } 3420d522f475Smrg 3421d522f475Smrg found = envindex; 3422d522f475Smrg environ[found + 1] = NULL; 3423d522f475Smrg environ = environ; 3424d522f475Smrg } 3425d522f475Smrg 3426d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 3427d522f475Smrg if (environ[found] == 0) { 3428d522f475Smrg fprintf(stderr, "Cannot allocate environment %s\n", var); 3429d522f475Smrg return; 3430d522f475Smrg } 3431d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 3432d522f475Smrg } 3433d522f475Smrg} 3434d522f475Smrg 3435d522f475Smrg/*ARGSUSED*/ 3436d522f475Smrgint 3437d522f475Smrgxerror(Display * d, XErrorEvent * ev) 3438d522f475Smrg{ 3439d522f475Smrg fprintf(stderr, "%s: warning, error event received:\n", xterm_name); 3440d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 3441d522f475Smrg Exit(ERROR_XERROR); 3442d522f475Smrg return 0; /* appease the compiler */ 3443d522f475Smrg} 3444d522f475Smrg 3445d522f475Smrg/*ARGSUSED*/ 3446d522f475Smrgint 3447d522f475Smrgxioerror(Display * dpy) 3448d522f475Smrg{ 3449d522f475Smrg int the_error = errno; 3450d522f475Smrg 3451d522f475Smrg (void) fprintf(stderr, 3452d522f475Smrg "%s: fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 3453d522f475Smrg xterm_name, the_error, SysErrorMsg(the_error), 3454d522f475Smrg DisplayString(dpy)); 3455d522f475Smrg 3456d522f475Smrg Exit(ERROR_XIOERROR); 3457d522f475Smrg return 0; /* appease the compiler */ 3458d522f475Smrg} 3459d522f475Smrg 3460d522f475Smrgvoid 3461d522f475Smrgxt_error(String message) 3462d522f475Smrg{ 3463d522f475Smrg (void) fprintf(stderr, "%s Xt error: %s\n", ProgramName, message); 3464d522f475Smrg 3465d522f475Smrg /* 3466d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 3467d522f475Smrg */ 3468d522f475Smrg if (x_getenv("DISPLAY") == 0) { 3469d522f475Smrg fprintf(stderr, "%s: DISPLAY is not set\n", ProgramName); 3470d522f475Smrg } 3471d522f475Smrg exit(1); 3472d522f475Smrg} 3473d522f475Smrg 3474d522f475Smrgint 3475d522f475SmrgXStrCmp(char *s1, char *s2) 3476d522f475Smrg{ 3477d522f475Smrg if (s1 && s2) 3478d522f475Smrg return (strcmp(s1, s2)); 3479d522f475Smrg if (s1 && *s1) 3480d522f475Smrg return (1); 3481d522f475Smrg if (s2 && *s2) 3482d522f475Smrg return (-1); 3483d522f475Smrg return (0); 3484d522f475Smrg} 3485d522f475Smrg 3486d522f475Smrg#if OPT_TEK4014 3487d522f475Smrgstatic void 3488d522f475Smrgwithdraw_window(Display * dpy, Window w, int scr) 3489d522f475Smrg{ 3490d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 3491d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 3492d522f475Smrg XWithdrawWindow(dpy, w, scr); 3493d522f475Smrg return; 3494d522f475Smrg} 3495d522f475Smrg#endif 3496d522f475Smrg 3497d522f475Smrgvoid 3498d522f475Smrgset_vt_visibility(Bool on) 3499d522f475Smrg{ 3500d522f475Smrg TScreen *screen = TScreenOf(term); 3501d522f475Smrg 3502d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 3503d522f475Smrg if (on) { 3504d522f475Smrg if (!screen->Vshow && term) { 3505d522f475Smrg VTInit(); 3506d522f475Smrg XtMapWidget(XtParent(term)); 3507d522f475Smrg#if OPT_TOOLBAR 3508d522f475Smrg /* we need both of these during initialization */ 3509d522f475Smrg XtMapWidget(SHELL_OF(term)); 3510d522f475Smrg ShowToolbar(resource.toolBar); 3511d522f475Smrg#endif 3512d522f475Smrg screen->Vshow = True; 3513d522f475Smrg } 3514d522f475Smrg } 3515d522f475Smrg#if OPT_TEK4014 3516d522f475Smrg else { 3517d522f475Smrg if (screen->Vshow && term) { 3518d522f475Smrg withdraw_window(XtDisplay(term), 3519d522f475Smrg VShellWindow, 3520d522f475Smrg XScreenNumberOfScreen(XtScreen(term))); 3521d522f475Smrg screen->Vshow = False; 3522d522f475Smrg } 3523d522f475Smrg } 3524d522f475Smrg set_vthide_sensitivity(); 3525d522f475Smrg set_tekhide_sensitivity(); 3526d522f475Smrg update_vttekmode(); 3527d522f475Smrg update_tekshow(); 3528d522f475Smrg update_vtshow(); 3529d522f475Smrg#endif 3530d522f475Smrg return; 3531d522f475Smrg} 3532d522f475Smrg 3533d522f475Smrg#if OPT_TEK4014 3534d522f475Smrgvoid 3535d522f475Smrgset_tek_visibility(Bool on) 3536d522f475Smrg{ 3537d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 3538d522f475Smrg 3539d522f475Smrg if (on) { 3540d522f475Smrg if (!TEK4014_SHOWN(term) && (tekWidget || TekInit())) { 3541d522f475Smrg Widget tekParent = SHELL_OF(tekWidget); 3542d522f475Smrg XtRealizeWidget(tekParent); 3543d522f475Smrg XtMapWidget(XtParent(tekWidget)); 3544d522f475Smrg#if OPT_TOOLBAR 3545d522f475Smrg /* we need both of these during initialization */ 3546d522f475Smrg XtMapWidget(tekParent); 3547d522f475Smrg XtMapWidget(tekWidget); 3548d522f475Smrg#endif 3549d522f475Smrg XtOverrideTranslations(tekParent, 3550d522f475Smrg XtParseTranslationTable 3551d522f475Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 3552d522f475Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 3553d522f475Smrg XtWindow(tekParent), 3554d522f475Smrg &wm_delete_window, 1); 3555d522f475Smrg TEK4014_SHOWN(term) = True; 3556d522f475Smrg } 3557d522f475Smrg } else { 3558d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 3559d522f475Smrg withdraw_window(XtDisplay(tekWidget), 3560d522f475Smrg TShellWindow, 3561d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 3562d522f475Smrg TEK4014_SHOWN(term) = False; 3563d522f475Smrg } 3564d522f475Smrg } 3565d522f475Smrg set_tekhide_sensitivity(); 3566d522f475Smrg set_vthide_sensitivity(); 3567d522f475Smrg update_vtshow(); 3568d522f475Smrg update_tekshow(); 3569d522f475Smrg update_vttekmode(); 3570d522f475Smrg return; 3571d522f475Smrg} 3572d522f475Smrg 3573d522f475Smrgvoid 3574d522f475Smrgend_tek_mode(void) 3575d522f475Smrg{ 3576d522f475Smrg if (TEK4014_ACTIVE(term)) { 3577d522f475Smrg FlushLog(&(term->screen)); 3578d522f475Smrg longjmp(Tekend, 1); 3579d522f475Smrg } 3580d522f475Smrg return; 3581d522f475Smrg} 3582d522f475Smrg 3583d522f475Smrgvoid 3584d522f475Smrgend_vt_mode(void) 3585d522f475Smrg{ 3586d522f475Smrg if (!TEK4014_ACTIVE(term)) { 3587d522f475Smrg FlushLog(&(term->screen)); 3588d522f475Smrg TEK4014_ACTIVE(term) = True; 3589d522f475Smrg longjmp(VTend, 1); 3590d522f475Smrg } 3591d522f475Smrg return; 3592d522f475Smrg} 3593d522f475Smrg 3594d522f475Smrgvoid 3595d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 3596d522f475Smrg{ 3597d522f475Smrg if (tovt) { 3598d522f475Smrg if (tekRefreshList) 3599d522f475Smrg TekRefresh(tekWidget); 3600d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 3601d522f475Smrg } else { 3602d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 3603d522f475Smrg } 3604d522f475Smrg} 3605d522f475Smrg 3606d522f475Smrgvoid 3607d522f475Smrghide_vt_window(void) 3608d522f475Smrg{ 3609d522f475Smrg set_vt_visibility(False); 3610d522f475Smrg if (!TEK4014_ACTIVE(term)) 3611d522f475Smrg switch_modes(False); /* switch to tek mode */ 3612d522f475Smrg} 3613d522f475Smrg 3614d522f475Smrgvoid 3615d522f475Smrghide_tek_window(void) 3616d522f475Smrg{ 3617d522f475Smrg set_tek_visibility(False); 3618d522f475Smrg tekRefreshList = (TekLink *) 0; 3619d522f475Smrg if (TEK4014_ACTIVE(term)) 3620d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 3621d522f475Smrg} 3622d522f475Smrg#endif /* OPT_TEK4014 */ 3623d522f475Smrg 3624d522f475Smrgstatic const char * 3625d522f475Smrgskip_punct(const char *s) 3626d522f475Smrg{ 3627d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 3628d522f475Smrg ++s; 3629d522f475Smrg } 3630d522f475Smrg return s; 3631d522f475Smrg} 3632d522f475Smrg 3633d522f475Smrgstatic int 3634d522f475Smrgcmp_options(const void *a, const void *b) 3635d522f475Smrg{ 3636d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 3637d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 3638d522f475Smrg return strcmp(s1, s2); 3639d522f475Smrg} 3640d522f475Smrg 3641d522f475Smrgstatic int 3642d522f475Smrgcmp_resources(const void *a, const void *b) 3643d522f475Smrg{ 3644d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 3645d522f475Smrg ((const XrmOptionDescRec *) b)->option); 3646d522f475Smrg} 3647d522f475Smrg 3648d522f475SmrgXrmOptionDescRec * 3649d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 3650d522f475Smrg{ 3651d522f475Smrg static XrmOptionDescRec *res_array = 0; 3652d522f475Smrg 3653d522f475Smrg#ifdef NO_LEAKS 3654d522f475Smrg if (descs == 0 && res_array != 0) { 3655d522f475Smrg free(res_array); 3656d522f475Smrg res_array = 0; 3657d522f475Smrg } else 3658d522f475Smrg#endif 3659d522f475Smrg if (res_array == 0) { 3660d522f475Smrg Cardinal j; 3661d522f475Smrg 3662d522f475Smrg /* make a sorted index to 'resources' */ 3663d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 3664d522f475Smrg for (j = 0; j < res_count; j++) 3665d522f475Smrg res_array[j] = descs[j]; 3666d522f475Smrg qsort(res_array, res_count, sizeof(*res_array), cmp_resources); 3667d522f475Smrg } 3668d522f475Smrg return res_array; 3669d522f475Smrg} 3670d522f475Smrg 3671d522f475Smrg/* 3672d522f475Smrg * The first time this is called, construct sorted index to the main program's 3673d522f475Smrg * list of options, taking into account the on/off options which will be 3674d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 3675d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 3676d522f475Smrg */ 3677d522f475SmrgOptionHelp * 3678d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 3679d522f475Smrg{ 3680d522f475Smrg static OptionHelp *opt_array = 0; 3681d522f475Smrg 3682d522f475Smrg#ifdef NO_LEAKS 3683d522f475Smrg if (descs == 0 && opt_array != 0) { 3684d522f475Smrg sortedOptDescs(descs, numDescs); 3685d522f475Smrg free(opt_array); 3686d522f475Smrg opt_array = 0; 3687d522f475Smrg return 0; 3688d522f475Smrg } else if (options == 0 || descs == 0) { 3689d522f475Smrg return 0; 3690d522f475Smrg } 3691d522f475Smrg#endif 3692d522f475Smrg 3693d522f475Smrg if (opt_array == 0) { 3694d522f475Smrg Cardinal opt_count, j; 3695d522f475Smrg#if OPT_TRACE 3696d522f475Smrg Cardinal k; 3697d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 3698d522f475Smrg int code; 3699d522f475Smrg char *mesg; 3700d522f475Smrg#else 3701d522f475Smrg (void) descs; 3702d522f475Smrg (void) numDescs; 3703d522f475Smrg#endif 3704d522f475Smrg 3705d522f475Smrg /* count 'options' and make a sorted index to it */ 3706d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 3707d522f475Smrg ; 3708d522f475Smrg } 3709d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 3710d522f475Smrg for (j = 0; j < opt_count; j++) 3711d522f475Smrg opt_array[j] = options[j]; 3712d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 3713d522f475Smrg 3714d522f475Smrg /* supply the "turn on/off" strings if needed */ 3715d522f475Smrg#if OPT_TRACE 3716d522f475Smrg for (j = 0; j < opt_count; j++) { 3717d522f475Smrg if (!strncmp(opt_array[j].opt, "-/+", 3)) { 3718d522f475Smrg char *name = opt_array[j].opt + 3; 3719d522f475Smrg for (k = 0; k < numDescs; ++k) { 3720d522f475Smrg char *value = res_array[k].value; 3721d522f475Smrg if (res_array[k].option[0] == '-') { 3722d522f475Smrg code = -1; 3723d522f475Smrg } else if (res_array[k].option[0] == '+') { 3724d522f475Smrg code = 1; 3725d522f475Smrg } else { 3726d522f475Smrg code = 0; 3727d522f475Smrg } 3728d522f475Smrg if (x_strindex(opt_array[j].desc, "inhibit") != 0) 3729d522f475Smrg code = -code; 3730d522f475Smrg if (code != 0 3731d522f475Smrg && res_array[k].value != 0 3732d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 3733d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 3734d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 3735d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 3736d522f475Smrg mesg = "turn on/off"; 3737d522f475Smrg } else { 3738d522f475Smrg mesg = "turn off/on"; 3739d522f475Smrg } 3740d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 3741d522f475Smrg if (strncmp(opt_array[j].desc, "turn ", 5)) { 3742d522f475Smrg char *s = CastMallocN(char, 3743d522f475Smrg strlen(mesg) 3744d522f475Smrg + 1 3745d522f475Smrg + strlen(opt_array[j].desc)); 3746d522f475Smrg if (s != 0) { 3747d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 3748d522f475Smrg opt_array[j].desc = s; 3749d522f475Smrg } 3750d522f475Smrg } else { 3751d522f475Smrg TRACE(("OOPS ")); 3752d522f475Smrg } 3753d522f475Smrg } 3754d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 3755d522f475Smrg mesg, 3756d522f475Smrg res_array[k].option, 3757d522f475Smrg res_array[k].value, 3758d522f475Smrg opt_array[j].opt, 3759d522f475Smrg opt_array[j].desc)); 3760d522f475Smrg break; 3761d522f475Smrg } 3762d522f475Smrg } 3763d522f475Smrg } 3764d522f475Smrg } 3765d522f475Smrg#endif 3766d522f475Smrg } 3767d522f475Smrg return opt_array; 3768d522f475Smrg} 3769d522f475Smrg 3770d522f475Smrg/* 3771d522f475Smrg * Report the character-type locale that xterm was started in. 3772d522f475Smrg */ 3773d522f475Smrgchar * 3774d522f475SmrgxtermEnvLocale(void) 3775d522f475Smrg{ 3776d522f475Smrg static char *result; 3777d522f475Smrg 3778d522f475Smrg if (result == 0) { 3779d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 3780d522f475Smrg result = "C"; 3781d522f475Smrg } 3782d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 3783d522f475Smrg } 3784d522f475Smrg return result; 3785d522f475Smrg} 3786d522f475Smrg 3787d522f475Smrgchar * 3788d522f475SmrgxtermEnvEncoding(void) 3789d522f475Smrg{ 3790d522f475Smrg static char *result; 3791d522f475Smrg 3792d522f475Smrg if (result == 0) { 3793d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 3794d522f475Smrg result = nl_langinfo(CODESET); 3795d522f475Smrg#else 3796d522f475Smrg char *locale = xtermEnvLocale(); 3797d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 3798d522f475Smrg result = "ASCII"; 3799d522f475Smrg } else { 3800d522f475Smrg result = "ISO-8859-1"; 3801d522f475Smrg } 3802d522f475Smrg#endif 3803d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 3804d522f475Smrg } 3805d522f475Smrg return result; 3806d522f475Smrg} 3807d522f475Smrg 3808d522f475Smrg#if OPT_WIDE_CHARS 3809d522f475Smrg/* 3810d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 3811d522f475Smrg * characters. That environment is inherited by subprocesses and used in 3812d522f475Smrg * various library calls. 3813d522f475Smrg */ 3814d522f475SmrgBool 3815d522f475SmrgxtermEnvUTF8(void) 3816d522f475Smrg{ 3817d522f475Smrg static Bool init = False; 3818d522f475Smrg static Bool result = False; 3819d522f475Smrg 3820d522f475Smrg if (!init) { 3821d522f475Smrg init = True; 3822d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 3823d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 3824d522f475Smrg#else 3825d522f475Smrg result = (strstr(xtermEnvLocale(), "UTF-8") != NULL); 3826d522f475Smrg#endif 3827d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 3828d522f475Smrg } 3829d522f475Smrg return result; 3830d522f475Smrg} 3831d522f475Smrg#endif /* OPT_WIDE_CHARS */ 3832d522f475Smrg 3833d522f475Smrg/* 3834d522f475Smrg * Returns the version-string used in the "-v' message as well as a few other 3835d522f475Smrg * places. It is derived (when possible) from the __vendorversion__ symbol 3836d522f475Smrg * that some newer imake configurations define. 3837d522f475Smrg */ 3838d522f475Smrgchar * 3839d522f475SmrgxtermVersion(void) 3840d522f475Smrg{ 3841d522f475Smrg static char *result; 3842d522f475Smrg if (result == 0) { 3843d522f475Smrg char *vendor = __vendorversion__; 3844d522f475Smrg char first[BUFSIZ]; 3845d522f475Smrg char second[BUFSIZ]; 3846d522f475Smrg 3847d522f475Smrg result = CastMallocN(char, strlen(vendor) + 9); 3848d522f475Smrg if (result == 0) 3849d522f475Smrg result = vendor; 3850d522f475Smrg else { 3851d522f475Smrg /* some vendors leave trash in this string */ 3852d522f475Smrg for (;;) { 3853d522f475Smrg if (!strncmp(vendor, "Version ", 8)) 3854d522f475Smrg vendor += 8; 3855d522f475Smrg else if (isspace(CharOf(*vendor))) 3856d522f475Smrg ++vendor; 3857d522f475Smrg else 3858d522f475Smrg break; 3859d522f475Smrg } 3860d522f475Smrg if (strlen(vendor) < BUFSIZ && 3861d522f475Smrg sscanf(vendor, "%[0-9.] %[A-Za-z_0-9.]", first, second) == 2) 3862d522f475Smrg sprintf(result, "%s %s(%d)", second, first, XTERM_PATCH); 3863d522f475Smrg else 3864d522f475Smrg sprintf(result, "%s(%d)", vendor, XTERM_PATCH); 3865d522f475Smrg } 3866d522f475Smrg } 3867d522f475Smrg return result; 3868d522f475Smrg} 3869