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