#include <xterm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <pwd.h>
#include <sys/wait.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <X11/Xmu/Error.h>
#include <X11/Xmu/SysUtil.h>
#include <X11/Xmu/WinUtil.h>
#if HAVE_X11_SUNKEYSYM_H
#include <X11/Sunkeysym.h>
#endif
#include <data.h>
#include <error.h>
#include <menu.h>
#include <fontutils.h>
#include <xcharmouse.h>
#include <xstrings.h>
#include <VTparse.h>
#if (XtSpecificationRelease < 6)
#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0)
#endif
#endif
#ifdef __UNIXOS2__
#define environ gblenvp
#endif
#ifdef VMS
#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT"
#ifdef ALLOWLOGFILEEXEC
#undef ALLOWLOGFILEEXEC
#endif
#endif
extern char **environ;
#if OPT_TEK4014
#define OUR_EVENT(event,Type) \
(event.type == Type && \
(event.xcrossing.window == XtWindow(XtParent(term)) || \
(tekWidget && \
event.xcrossing.window == XtWindow(XtParent(tekWidget)))))
#else
#define OUR_EVENT(event,Type) \
(event.type == Type && \
(event.xcrossing.window == XtWindow(XtParent(term))))
#endif
static Boolean ChangeColorsRequest(XtermWidget pTerm, int start, char
*names, int final);
static void DoSpecialEnterNotify(XEnterWindowEvent * ev);
static void DoSpecialLeaveNotify(XEnterWindowEvent * ev);
static void selectwindow(TScreen * screen, int flag);
static void unselectwindow(TScreen * screen, int flag);
static void Sleep(int msec);
void
do_xevents(void)
{
register TScreen *screen = &term->screen;
if (XtAppPending(app_con)
||
#if defined(VMS) || defined(__VMS)
screen->display->qlen > 0
#else
GetBytesAvailable(ConnectionNumber(screen->display)) > 0
#endif
)
xevents();
}
void
xevents(void)
{
XEvent event;
XtInputMask input_mask;
register TScreen *screen = &term->screen;
if (screen->scroll_amt)
FlushScroll(screen);
while ((input_mask = XtAppPending(app_con)) & XtIMTimer)
XtAppProcessEvent(app_con, XtIMTimer);
if ((input_mask & XtIMXEvent) != XtIMXEvent)
return;
do {
if (waitingForTrackInfo) {
Sleep(10);
return;
}
XtAppNextEvent(app_con, &event);
if (OUR_EVENT(event, EnterNotify))
DoSpecialEnterNotify(&event.xcrossing);
else if (OUR_EVENT(event, LeaveNotify))
DoSpecialLeaveNotify(&event.xcrossing);
else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE
#if OPT_DEC_LOCATOR
|| screen->send_mouse_pos == DEC_LOCATOR
#endif
)
&& event.xany.type == MotionNotify
&& event.xcrossing.window == XtWindow(term)) {
SendMousePosition((Widget) term, &event);
continue;
}
if (!event.xany.send_event ||
screen->allowSendEvents ||
((event.xany.type != KeyPress) &&
(event.xany.type != KeyRelease) &&
(event.xany.type != ButtonPress) &&
(event.xany.type != ButtonRelease)))
XtDispatchEvent(&event);
} while ((input_mask = XtAppPending(app_con)) & XtIMXEvent);
}
Cursor
make_colored_cursor(
unsigned cursorindex,
unsigned long fg,
unsigned long bg)
{
register TScreen *screen = &term->screen;
Cursor c;
register Display *dpy = screen->display;
c = XCreateFontCursor(dpy, cursorindex);
if (c == (Cursor) 0)
return (c);
recolor_cursor(c, fg, bg);
return (c);
}
void
HandleKeyPressed(
Widget w GCC_UNUSED,
XEvent * event,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
register TScreen *screen = &term->screen;
#ifdef ACTIVEWINDOWINPUTONLY
if (w == CURRENT_EMU(screen))
#endif
Input(&term->keyboard, screen, &event->xkey, False);
}
void
HandleEightBitKeyPressed(
Widget w GCC_UNUSED,
XEvent * event,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
register TScreen *screen = &term->screen;
#ifdef ACTIVEWINDOWINPUTONLY
if (w == CURRENT_EMU(screen))
#endif
Input(&term->keyboard, screen, &event->xkey, True);
}
void
HandleStringEvent(
Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params,
Cardinal * nparams)
{
register TScreen *screen = &term->screen;
#ifdef ACTIVEWINDOWINPUTONLY
if (w != CURRENT_EMU(screen))
return;
#endif
if (*nparams != 1)
return;
if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') {
Char c, *p;
Char hexval[2];
hexval[0] = hexval[1] = 0;
for (p = (Char *) (*params + 2); (c = *p); p++) {
hexval[0] *= 16;
if (isupper(c))
c = tolower(c);
if (c >= '0' && c <= '9')
hexval[0] += c - '0';
else if (c >= 'a' && c <= 'f')
hexval[0] += c - 'a' + 10;
else
break;
}
if (c == '\0')
StringInput(screen, hexval, 1);
} else {
StringInput(screen, (Char *) * params, strlen(*params));
}
}
void
HandleInterpret(
Widget w GCC_UNUSED,
XEvent * event GCC_UNUSED,
String * params,
Cardinal * param_count)
{
if (*param_count == 1) {
char *value = params[0];
int need = strlen(value);
int used = usedPtyData(&VTbuffer);
int have = (VTbuffer.cnt >= 0) ? VTbuffer.cnt : 0;
int n;
if (have - used + need < BUF_SIZE) {
FlushLog(&term->screen);
if (have != 0
&& used < have) {
memmove(VTbuffer.ptr + (need - used),
VTbuffer.ptr,
VTbuffer.cnt * sizeof(*VTbuffer.ptr));
} else {
initPtyData(&VTbuffer);
used = 0;
}
VTbuffer.cnt += (need - used);
VTbuffer.ptr -= used;
for (n = 0; n < need; n++)
VTbuffer.ptr[n] = CharOf(value[n]);
}
}
}
static void
DoSpecialEnterNotify(register XEnterWindowEvent * ev)
{
register TScreen *screen = &term->screen;
#ifdef ACTIVEWINDOWINPUTONLY
if (ev->window == XtWindow(XtParent(CURRENT_EMU(screen))))
#endif
if (((ev->detail) != NotifyInferior) &&
ev->focus &&
!(screen->select & FOCUS))
selectwindow(screen, INWINDOW);
}
void
HandleEnterWindow(
Widget w GCC_UNUSED,
XtPointer eventdata GCC_UNUSED,
XEvent * event GCC_UNUSED,
Boolean * cont GCC_UNUSED)
{
}
static void
DoSpecialLeaveNotify(register XEnterWindowEvent * ev)
{
register TScreen *screen = &term->screen;
#ifdef ACTIVEWINDOWINPUTONLY
if (ev->window == XtWindow(XtParent(CURRENT_EMU(screen))))
#endif
if (((ev->detail) != NotifyInferior) &&
ev->focus &&
!(screen->select & FOCUS))
unselectwindow(screen, INWINDOW);
}
void
HandleLeaveWindow(
Widget w GCC_UNUSED,
XtPointer eventdata GCC_UNUSED,
XEvent * event GCC_UNUSED,
Boolean * cont GCC_UNUSED)
{
}
void
HandleFocusChange(
Widget w GCC_UNUSED,
XtPointer eventdata GCC_UNUSED,
XEvent * ev,
Boolean * cont GCC_UNUSED)
{
register XFocusChangeEvent *event = (XFocusChangeEvent *) ev;
register TScreen *screen = &term->screen;
if (event->type == FocusIn)
selectwindow(screen,
(event->detail == NotifyPointer) ? INWINDOW :
FOCUS);
else {
unselectwindow(screen,
(event->detail == NotifyPointer) ? INWINDOW :
FOCUS);
if (screen->grabbedKbd && (event->mode == NotifyUngrab)) {
Bell(XkbBI_Info, 100);
ReverseVideo(term);
screen->grabbedKbd = FALSE;
update_securekbd();
}
}
}
static void
selectwindow(register TScreen * screen, register int flag)
{
#if OPT_TEK4014
if (screen->TekEmu) {
if (!Ttoggled)
TCursorToggle(TOGGLE);
screen->select |= flag;
if (!Ttoggled)
TCursorToggle(TOGGLE);
return;
} else
#endif
{
if (screen->xic)
XSetICFocus(screen->xic);
if (screen->cursor_state &&
(screen->cursor_col != screen->cur_col ||
screen->cursor_row != screen->cur_row))
HideCursor();
screen->select |= flag;
if (screen->cursor_state)
ShowCursor();
return;
}
}
static void
unselectwindow(register TScreen * screen, register int flag)
{
if (screen->always_highlight)
return;
#if OPT_TEK4014
if (screen->TekEmu) {
if (!Ttoggled)
TCursorToggle(TOGGLE);
screen->select &= ~flag;
if (!Ttoggled)
TCursorToggle(TOGGLE);
} else
#endif
{
if (screen->xic)
XUnsetICFocus(screen->xic);
screen->select &= ~flag;
if (screen->cursor_state &&
(screen->cursor_col != screen->cur_col ||
screen->cursor_row != screen->cur_row))
HideCursor();
if (screen->cursor_state)
ShowCursor();
}
}
static long lastBellTime;
void
Bell(int which GCC_UNUSED, int percent)
{
register TScreen *screen = &term->screen;
struct timeval curtime;
long now_msecs;
TRACE(("BELL %d\n", percent));
if (screen->bellSuppressTime) {
if (screen->bellInProgress) {
do_xevents();
if (screen->bellInProgress) {
return;
}
}
X_GETTIMEOFDAY(&curtime);
now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000;
if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 &&
now_msecs - lastBellTime < screen->bellSuppressTime) {
return;
}
lastBellTime = now_msecs;
}
if (screen->visualbell)
VisualBell();
else
#ifdef XKB
XkbStdBell(screen->display, TWindow(screen), percent, which);
#else
XBell(screen->display, percent);
#endif
if (screen->poponbell)
XRaiseWindow(screen->display, VShellWindow);
if (screen->bellSuppressTime) {
Widget w = CURRENT_EMU(screen);
XChangeProperty(XtDisplay(w), XtWindow(w),
XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0);
screen->bellInProgress = TRUE;
}
}
void
VisualBell(void)
{
register TScreen *screen = &term->screen;
register Pixel xorPixel = screen->foreground ^ term->core.background_pixel;
XGCValues gcval;
GC visualGC;
gcval.function = GXxor;
gcval.foreground = xorPixel;
visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval);
#if OPT_TEK4014
if (screen->TekEmu) {
XFillRectangle(
screen->display,
TWindow(screen),
visualGC,
0, 0,
(unsigned) TFullWidth(screen),
(unsigned) TFullHeight(screen));
XFlush(screen->display);
XFillRectangle(
screen->display,
TWindow(screen),
visualGC,
0, 0,
(unsigned) TFullWidth(screen),
(unsigned) TFullHeight(screen));
} else
#endif
{
XFillRectangle(
screen->display,
VWindow(screen),
visualGC,
0, 0,
(unsigned) FullWidth(screen),
(unsigned) FullHeight(screen));
XFlush(screen->display);
XFillRectangle(
screen->display,
VWindow(screen),
visualGC,
0, 0,
(unsigned) FullWidth(screen),
(unsigned) FullHeight(screen));
}
}
void
HandleBellPropertyChange(
Widget w GCC_UNUSED,
XtPointer data GCC_UNUSED,
XEvent * ev,
Boolean * more GCC_UNUSED)
{
register TScreen *screen = &term->screen;
if (ev->xproperty.atom == XA_NOTICE) {
screen->bellInProgress = FALSE;
}
}
Window
WMFrameWindow(XtermWidget termw)
{
Window win_root, win_current, *children;
Window win_parent = 0;
unsigned int nchildren;
win_current = XtWindow(termw);
do {
if (win_parent)
win_current = win_parent;
XQueryTree((&termw->screen)->display,
win_current,
&win_root,
&win_parent,
&children,
&nchildren);
XFree(children);
} while (win_root != win_parent);
return win_current;
}
#if OPT_MAXIMIZE
void
HandleDeIconify(
Widget gw,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
if (IsXtermWidget(gw)) {
register TScreen *screen = &((XtermWidget) gw)->screen;
XMapWindow(screen->display, VShellWindow);
}
}
void
HandleIconify(
Widget gw,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
if (IsXtermWidget(gw)) {
register TScreen *screen = &((XtermWidget) gw)->screen;
XIconifyWindow(screen->display,
VShellWindow,
DefaultScreen(screen->display));
}
}
int
QueryMaximize(TScreen * screen, unsigned *width, unsigned *height)
{
XSizeHints hints;
long supp = 0;
Window root_win;
int root_x = -1;
int root_y = -1;
unsigned root_border;
unsigned root_depth;
if (XGetGeometry(screen->display,
XDefaultRootWindow(screen->display),
&root_win,
&root_x,
&root_y,
width,
height,
&root_border,
&root_depth)) {
TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n",
root_x,
root_y,
*width,
*height,
root_border));
*width -= (screen->border * 2),
*height -= (screen->border * 2);
hints.flags = PMaxSize;
if (XGetWMNormalHints(screen->display,
VShellWindow,
&hints,
&supp)
&& (hints.flags & PMaxSize) != 0) {
TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n",
hints.max_width,
hints.max_height));
if ((unsigned) hints.max_width < *width)
*width = hints.max_width;
if ((unsigned) hints.max_height < *height)
*height = hints.max_height;
}
return 1;
}
return 0;
}
void
RequestMaximize(XtermWidget termw, int maximize)
{
register TScreen *screen = &termw->screen;
XWindowAttributes win_attrs;
unsigned root_width, root_height;
if (maximize) {
if (QueryMaximize(screen, &root_width, &root_height)) {
if (XGetWindowAttributes(screen->display,
WMFrameWindow(termw),
&win_attrs)) {
if (screen->restore_data != True
|| screen->restore_width != root_width
|| screen->restore_height != root_height) {
screen->restore_data = True;
screen->restore_x = win_attrs.x;
screen->restore_y = win_attrs.y;
screen->restore_width = win_attrs.width;
screen->restore_height = win_attrs.height;
TRACE(("HandleMaximize: save window position %d,%d size %d,%d\n",
screen->restore_x,
screen->restore_y,
screen->restore_width,
screen->restore_height));
}
XMoveResizeWindow(screen->display,
VShellWindow,
0,
0,
root_width,
root_height);
}
}
} else {
if (screen->restore_data) {
TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n",
screen->restore_x,
screen->restore_y,
screen->restore_width,
screen->restore_height));
screen->restore_data = False;
XMoveResizeWindow(screen->display,
VShellWindow,
screen->restore_x,
screen->restore_y,
screen->restore_width,
screen->restore_height);
}
}
}
void
HandleMaximize(
Widget gw,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
if (IsXtermWidget(gw)) {
RequestMaximize((XtermWidget) gw, 1);
}
}
void
HandleRestoreSize(
Widget gw,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal * nparams GCC_UNUSED)
{
if (IsXtermWidget(gw)) {
RequestMaximize((XtermWidget) gw, 0);
}
}
#endif
void
Redraw(void)
{
register TScreen *screen = &term->screen;
XExposeEvent event;
event.type = Expose;
event.display = screen->display;
event.x = 0;
event.y = 0;
event.count = 0;
if (VWindow(screen)) {
event.window = VWindow(screen);
event.width = term->core.width;
event.height = term->core.height;
(*term->core.widget_class->core_class.expose) ((Widget) term,
(XEvent *) & event,
NULL);
if (ScrollbarWidth(screen)) {
(screen->scrollWidget->core.widget_class->core_class.expose)
(screen->scrollWidget, (XEvent *) & event, NULL);
}
}
#if OPT_TEK4014
if (TWindow(screen) && screen->Tshow) {
event.window = TWindow(screen);
event.width = tekWidget->core.width;
event.height = tekWidget->core.height;
TekExpose((Widget) tekWidget, (XEvent *) & event, NULL);
}
#endif
}
#ifdef VMS
#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d"
#else
#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d"
#endif
void
timestamp_filename(char *dst, const char *src)
{
time_t tstamp;
struct tm *tstruct;
time(&tstamp);
tstruct = localtime(&tstamp);
sprintf(dst, TIMESTAMP_FMT,
src,
tstruct->tm_year + 1900,
tstruct->tm_mon + 1,
tstruct->tm_mday,
tstruct->tm_hour,
tstruct->tm_min,
tstruct->tm_sec);
}
int
open_userfile(int uid, int gid, char *path, Boolean append)
{
int fd;
struct stat sb;
#ifdef VMS
if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
fprintf(stderr, "%s: cannot open %s: %d:%s\n",
xterm_name,
path,
errno,
SysErrorMsg(errno));
return -1;
}
chown(path, uid, gid);
#else
if ((access(path, F_OK) != 0 && (errno != ENOENT))
|| (!(creat_as(uid, gid, append, path, 0644)))
|| ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) {
fprintf(stderr, "%s: cannot open %s: %d:%s\n",
xterm_name,
path,
errno,
SysErrorMsg(errno));
return -1;
}
#endif
if (fstat(fd, &sb) < 0
|| (int) sb.st_uid != uid
|| (sb.st_mode & 022) != 0) {
fprintf(stderr, "%s: you do not own %s\n", xterm_name, path);
close(fd);
return -1;
}
return fd;
}
#ifndef VMS
int
creat_as(int uid, int gid, Boolean append, char *pathname, int mode)
{
int fd;
int pid;
int retval = 0;
int childstat = 0;
#ifndef HAVE_WAITPID
int waited;
SIGNAL_T(*chldfunc) (int);
chldfunc = signal(SIGCHLD, SIG_DFL);
#endif
pid = fork();
switch (pid) {
case 0:
setgid(gid);
setuid(uid);
fd = open(pathname,
O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL),
mode);
if (fd >= 0) {
close(fd);
_exit(0);
} else
_exit(1);
case -1:
return retval;
default:
#ifdef HAVE_WAITPID
while (waitpid(pid, &childstat, 0) < 0) {
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
#ifdef ERESTARTSYS
if (errno == ERESTARTSYS)
continue;
#endif
break;
}
#else
waited = wait(&childstat);
signal(SIGCHLD, chldfunc);
do
if (waited == term->screen.pid)
Cleanup(0);
while ((waited = nonblocking_wait()) > 0) ;
#endif
#ifndef WIFEXITED
#define WIFEXITED(status) ((status & 0xff) != 0)
#endif
if (WIFEXITED(childstat))
retval = 1;
return retval;
}
}
#endif
#ifdef ALLOWLOGGING
#ifdef ALLOWLOGFILEEXEC
static SIGNAL_T
logpipe(int sig GCC_UNUSED)
{
register TScreen *screen = &term->screen;
#ifdef SYSV
(void) signal(SIGPIPE, SIG_IGN);
#endif
if (screen->logging)
CloseLog(screen);
}
#endif
void
StartLog(register TScreen * screen)
{
static char *log_default;
#ifdef ALLOWLOGFILEEXEC
register char *cp;
register int i = 0;
#endif
if (screen->logging || (screen->inhibit & I_LOG))
return;
#ifdef VMS
screen->logfd = open(XTERM_VMS_LOGFILE,
O_CREAT | O_TRUNC | O_APPEND | O_RDWR,
0640);
if (screen->logfd < 0)
return;
#else
if (screen->logfile == NULL || *screen->logfile == 0) {
if (screen->logfile)
free(screen->logfile);
if (log_default == NULL) {
#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME)
char log_def_name[512];
char hostname[255 + 1];
char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1];
time_t now;
struct tm *ltm;
(void) time(&now);
ltm = (struct tm *) localtime(&now);
if ((gethostname(hostname, sizeof(hostname)) == 0) &&
(strftime(yyyy_mm_dd_hh_mm_ss,
sizeof(yyyy_mm_dd_hh_mm_ss),
"%Y.%m.%d.%H.%M.%S", ltm) > 0)) {
(void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.XXXXXX",
hostname, yyyy_mm_dd_hh_mm_ss);
}
#else
const char *log_def_name = "XtermLog.XXXXXX";
#endif
if ((log_default = x_strdup(log_def_name)) == NULL)
return;
mktemp(log_default);
}
if ((screen->logfile = x_strdup(log_default)) == 0)
return;
}
if (*screen->logfile == '|') {
#ifdef ALLOWLOGFILEEXEC
int p[2];
static char *shell;
register struct passwd *pw;
if (pipe(p) < 0 || (i = fork()) < 0)
return;
if (i == 0) {
close(p[1]);
dup2(p[0], 0);
close(p[0]);
dup2(fileno(stderr), 1);
dup2(fileno(stderr), 2);
close(fileno(stderr));
close(ConnectionNumber(screen->display));
close(screen->respond);
if ((((cp = getenv("SHELL")) == NULL || *cp == 0)
&& ((pw = getpwuid(screen->uid)) == NULL
|| *(cp = pw->pw_shell) == 0))
|| (shell = (char *) malloc(strlen(cp) + 1)) == 0)
shell = "/bin/sh";
else
strcpy(shell, cp);
signal(SIGHUP, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
setgid(screen->gid);
setuid(screen->uid);
execl(shell, shell, "-c", &screen->logfile[1], (void *) 0);
fprintf(stderr, "%s: Can't exec `%s'\n", xterm_name,
&screen->logfile[1]);
exit(ERROR_LOGEXEC);
}
close(p[0]);
screen->logfd = p[1];
signal(SIGPIPE, logpipe);
#else
Bell(XkbBI_Info, 0);
Bell(XkbBI_Info, 0);
return;
#endif
} else {
if ((screen->logfd = open_userfile(screen->uid,
screen->gid,
screen->logfile,
(log_default != 0))) < 0)
return;
}
#endif
screen->logstart = CURRENT_EMU_VAL(screen, Tbuffer->ptr, VTbuffer.ptr);
screen->logging = TRUE;
update_logging();
}
void
CloseLog(register TScreen * screen)
{
if (!screen->logging || (screen->inhibit & I_LOG))
return;
FlushLog(screen);
close(screen->logfd);
screen->logging = FALSE;
update_logging();
}
void
FlushLog(register TScreen * screen)
{
register IChar *cp;
register int i;
#ifdef VMS
if (!tt_new_output)
return;
tt_new_output = FALSE;
#endif
cp = CURRENT_EMU_VAL(screen, Tbuffer->ptr, VTbuffer.ptr);
if (screen->logstart != 0
&& (i = cp - screen->logstart) > 0) {
#if OPT_WIDE_CHARS
Char temp[80];
IChar code;
unsigned n;
while (i-- > 0) {
code = *(screen->logstart)++;
if (screen->utf8_mode) {
n = convertFromUTF8(code & 0xffff, temp);
} else {
temp[0] = code;
n = 1;
while (i > 0 && n < sizeof(temp)) {
i--;
temp[n++] = *(screen->logstart)++;
}
}
write(screen->logfd, temp, n);
}
#else
write(screen->logfd, (char *) screen->logstart, i);
#endif
}
screen->logstart = DecodedData(CURRENT_EMU_VAL(screen, Tbuffer, &VTbuffer));
}
#endif
#if OPT_ISO_COLORS
static void
ReportAnsiColorRequest(XtermWidget pTerm, int colornum, int final)
{
XColor color;
Colormap cmap = pTerm->core.colormap;
char buffer[80];
TRACE(("ReportAnsiColorRequest %d\n", colornum));
color.pixel = GET_COLOR_RES(pTerm->screen.Acolors[colornum]);
XQueryColor(term->screen.display, cmap, &color);
sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x",
colornum,
color.red,
color.green,
color.blue);
unparseputc1(OSC, pTerm->screen.respond);
unparseputs(buffer, pTerm->screen.respond);
unparseputc1(final, pTerm->screen.respond);
}
static int
find_closest_color(Display * display, Colormap cmap, XColor * def)
{
double tmp, distance, closestDistance;
int i, closest, numFound, cmap_size;
XColor *colortable;
XVisualInfo template, *visInfoPtr;
char *found;
int attempts;
template.visualid = XVisualIDFromVisual(DefaultVisual(display,
XDefaultScreen(display)));
visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask,
&template, &numFound);
if (numFound < 1) {
return FALSE;
}
cmap_size = visInfoPtr->colormap_size;
XFree((char *) visInfoPtr);
colortable = (XColor *) malloc(cmap_size * sizeof(XColor));
if (!colortable) {
return FALSE;
}
found = (char *) calloc(cmap_size, sizeof(char));
if (!found) {
free(colortable);
return FALSE;
}
for (i = 0; i < cmap_size; i++) {
colortable[i].pixel = (unsigned long) i;
}
XQueryColors(display, cmap, colortable, cmap_size);
for (attempts = 0; attempts < cmap_size; attempts++) {
closestDistance = 1e30;
closest = 0;
for (i = 0; i < cmap_size; i++) {
if (!found[closest]) {
tmp = .30 * (((int) def->red) - (int) colortable[i].red);
distance = tmp * tmp;
tmp = .61 * (((int) def->green) - (int) colortable[i].green);
distance += tmp * tmp;
tmp = .11 * (((int) def->blue) - (int) colortable[i].blue);
distance += tmp * tmp;
if (distance < closestDistance) {
closest = i;
closestDistance = distance;
}
}
}
if (XAllocColor(display, cmap, &colortable[closest]) != 0) {
*def = colortable[closest];
break;
}
found[closest] = TRUE;
}
free(colortable);
free(found);
if (attempts < cmap_size) {
return TRUE;
} else {
return FALSE;
}
}
static Boolean
AllocateAnsiColor(XtermWidget pTerm,
ColorRes * res,
char *spec)
{
XColor def;
register TScreen *screen = &pTerm->screen;
Colormap cmap = pTerm->core.colormap;
if (XParseColor(screen->display, cmap, spec, &def)
&& (XAllocColor(screen->display, cmap, &def)
|| find_closest_color(screen->display, cmap, &def))) {
SET_COLOR_RES(res, def.pixel);
TRACE(("AllocateAnsiColor[%d] %s (pixel %#lx)\n",
(res - screen->Acolors), spec, def.pixel));
res->mode = True;
return (TRUE);
}
TRACE(("AllocateAnsiColor %s (failed)\n", spec));
return (FALSE);
}
#if OPT_COLOR_RES
Pixel
xtermGetColorRes(ColorRes * res)
{
if (!res->mode) {
TRACE(("xtermGetColorRes for Acolors[%d]\n",
res - term->screen.Acolors));
if (!AllocateAnsiColor(term, res, res->resource)) {
res->value = term->screen.foreground;
res->mode = -True;
fprintf(stderr,
"%s: Cannot allocate color %s\n",
xterm_name,
res->resource);
}
}
return res->value;
}
#endif
static Boolean
ChangeAnsiColorRequest(
XtermWidget pTerm,
register char *buf,
int final)
{
char *name;
int color;
int r = False;
TRACE(("ChangeAnsiColorRequest string='%s'\n", buf));
while (buf && *buf) {
name = strchr(buf, ';');
if (name == NULL)
break;
*name = '\0';
name++;
color = atoi(buf);
if (color < 0 || color >= NUM_ANSI_COLORS)
break;
buf = strchr(name, ';');
if (buf) {
*buf = '\0';
buf++;
}
if (!strcmp(name, "?"))
ReportAnsiColorRequest(pTerm, color, final);
else {
TRACE(("ChangeAnsiColor for Acolors[%d]\n", color));
if (!AllocateAnsiColor(pTerm, &(pTerm->screen.Acolors[color]), name))
break;
r = True;
}
}
if (r)
ChangeAnsiColors(pTerm);
return (r);
}
#else
#define find_closest_color(display, cmap, def) 0
#endif
void
do_osc(Char * oscbuf, int len GCC_UNUSED, int final)
{
register TScreen *screen = &(term->screen);
register int mode;
register Char *cp;
int state = 0;
char *buf = 0;
mode = 0;
for (cp = oscbuf; *cp != '\0'; cp++) {
switch (state) {
case 0:
if (isdigit(*cp)) {
mode = 10 * mode + (*cp - '0');
if (mode > 65535)
return;
break;
}
case 1:
if (*cp != ';')
return;
state = 2;
break;
case 2:
buf = (char *) cp;
state = 3;
default:
if (ansi_table[CharOf(*cp)] != CASE_PRINT)
return;
}
}
if (buf == 0)
return;
switch (mode) {
case 0:
Changename(buf);
Changetitle(buf);
break;
case 1:
Changename(buf);
break;
case 2:
Changetitle(buf);
break;
case 3:
ChangeXprop(buf);
break;
#if OPT_ISO_COLORS
case 4:
ChangeAnsiColorRequest(term, buf, final);
break;
#endif
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
if (term->misc.dynamicColors)
ChangeColorsRequest(term, mode - 10, buf, final);
break;
case 30:
case 31:
break;
#ifdef ALLOWLOGGING
case 46:
#ifdef ALLOWLOGFILECHANGES
if (buf != 0
&& strcmp(buf, "?")
&& ((cp = malloc((unsigned) strlen(buf) + 1)) != NULL)) {
strcpy(cp, buf);
if (screen->logfile)
free(screen->logfile);
screen->logfile = cp;
break;
}
#endif
Bell(XkbBI_Info, 0);
Bell(XkbBI_Info, 0);
break;
#endif
case 50:
if (buf != 0 && !strcmp(buf, "?")) {
int num = screen->menu_font_number;
unparseputc1(OSC, screen->respond);
unparseputs("50", screen->respond);
if ((buf = screen->menu_font_names[num]) != 0) {
unparseputc(';', screen->respond);
unparseputs(buf, screen->respond);
}
unparseputc1(final, screen->respond);
} else {
if (buf != 0 && *buf == '#') {
int num = screen->menu_font_number;
int rel = 0;
if (*++buf == '+') {
rel = 1;
buf++;
} else if (*buf == '-') {
rel = -1;
buf++;
}
if (isdigit(CharOf(*buf))) {
int val = atoi(buf);
if (rel > 0)
num += val;
else if (rel < 0)
num -= val;
else
num = val;
} else if (rel) {
num += rel;
} else {
num = 0;
}
if (num < 0
|| num > fontMenu_lastBuiltin
|| (buf = screen->menu_font_names[num]) == 0) {
Bell(XkbBI_MinorError, 0);
break;
}
}
SetVTFont(fontMenu_fontescape, True, VT_FONTSET(buf, NULL, NULL, NULL));
}
break;
case 51:
break;
}
}
#ifdef SunXK_F36
#define MAX_UDK 37
#else
#define MAX_UDK 35
#endif
static struct {
char *str;
int len;
} user_keys[MAX_UDK];
static int
udk_value(char **cp)
{
int c;
for (;;) {
if ((c = **cp) != '\0')
*cp = *cp + 1;
if (c == ';' || c == '\0')
return -1;
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
}
void
reset_decudk(void)
{
int n;
for (n = 0; n < MAX_UDK; n++) {
if (user_keys[n].str != 0) {
free(user_keys[n].str);
user_keys[n].str = 0;
user_keys[n].len = 0;
}
}
}
void
do_dcs(Char * dcsbuf, size_t dcslen)
{
TScreen *screen = &term->screen;
char reply[BUFSIZ];
char *cp = (char *) dcsbuf;
Bool okay;
Bool clear_all;
Bool lock_keys;
TRACE(("do_dcs(%s:%d)\n", (char *) dcsbuf, dcslen));
if (dcslen != strlen(cp))
return;
switch (*cp) {
case '$':
okay = True;
cp++;
if (*cp++ == 'q') {
if (!strcmp(cp, "\"q")) {
sprintf(reply, "%d%s",
(screen->protected_mode == DEC_PROTECT)
&& (term->flags & PROTECTED) ? 1 : 0,
cp);
} else if (!strcmp(cp, "\"p")) {
sprintf(reply, "%d%s%s",
(screen->ansi_level ?
screen->ansi_level : 1) + 60,
(screen->ansi_level >= 2)
? (screen->control_eight_bits
? ";0" : ";1")
: "",
cp);
} else if (!strcmp(cp, "r")) {
sprintf(reply, "%d;%dr",
screen->top_marg + 1,
screen->bot_marg + 1);
} else if (!strcmp(cp, "m")) {
strcpy(reply, "0");
if (term->flags & BOLD)
strcat(reply, ";1");
if (term->flags & UNDERLINE)
strcat(reply, ";4");
if (term->flags & BLINK)
strcat(reply, ";5");
if (term->flags & INVERSE)
strcat(reply, ";7");
if (term->flags & INVISIBLE)
strcat(reply, ";8");
if_OPT_EXT_COLORS(screen, {
if (term->flags & FG_COLOR) {
if (term->cur_foreground >= 16)
sprintf(reply + strlen(reply),
";38;5;%d", term->cur_foreground);
else
sprintf(reply + strlen(reply),
";%d%d",
term->cur_foreground >= 8 ? 9 : 3,
term->cur_foreground >= 8 ?
term->cur_foreground - 8 :
term->cur_foreground);
}
if (term->flags & BG_COLOR) {
if (term->cur_background >= 16)
sprintf(reply + strlen(reply),
";48;5;%d", term->cur_foreground);
else
sprintf(reply + strlen(reply),
";%d%d",
term->cur_background >= 8 ? 10 : 4,
term->cur_background >= 8 ?
term->cur_background - 8 :
term->cur_background);
}
});
if_OPT_ISO_TRADITIONAL_COLORS(screen, {
if (term->flags & FG_COLOR)
sprintf(reply + strlen(reply),
";%d%d",
term->cur_foreground >= 8 ? 9 : 3,
term->cur_foreground >= 8 ?
term->cur_foreground - 8 :
term->cur_foreground);
if (term->flags & BG_COLOR)
sprintf(reply + strlen(reply),
";%d%d",
term->cur_background >= 8 ? 10 : 4,
term->cur_background >= 8 ?
term->cur_background - 8 :
term->cur_background);
});
strcat(reply, "m");
} else
okay = False;
unparseputc1(DCS, screen->respond);
unparseputc(okay ? '1' : '0', screen->respond);
unparseputc('$', screen->respond);
unparseputc('r', screen->respond);
if (okay)
cp = reply;
unparseputs(cp, screen->respond);
unparseputc1(ST, screen->respond);
} else {
unparseputc(CAN, screen->respond);
}
break;
#if OPT_TCAP_QUERY
case '+':
cp++;
if (*cp == 'q') {
unsigned state;
int code;
char *tmp;
++cp;
code = xtermcapKeycode(cp, &state);
unparseputc1(DCS, screen->respond);
unparseputc(code >= 0 ? '1' : '0', screen->respond);
unparseputc('+', screen->respond);
unparseputc('r', screen->respond);
for (tmp = cp; *tmp; ++tmp)
unparseputc(*tmp, screen->respond);
if (code >= 0) {
unparseputc('=', screen->respond);
screen->tc_query = code;
if (code == XK_COLORS) {
# if OPT_256_COLORS
unparseputc('2', screen->respond);
unparseputc('5', screen->respond);
unparseputc('6', screen->respond);
# elif OPT_88_COLORS
unparseputc('8', screen->respond);
unparseputc('8', screen->respond);
# else
unparseputc('1', screen->respond);
unparseputc('6', screen->respond);
# endif
} else {
XKeyEvent event;
event.state = state;
Input(&(term->keyboard), screen, &event, False);
}
screen->tc_query = -1;
}
unparseputc1(ST, screen->respond);
}
break;
#endif
default:
if (isdigit(CharOf(*cp))) {
clear_all = True;
lock_keys = True;
if (*cp == '0') {
cp++;
} else if (*cp == '1') {
cp++;
clear_all = False;
}
if (*cp == ';')
cp++;
else if (*cp != '|')
return;
if (*cp == '0') {
cp++;
} else if (*cp == '1') {
cp++;
lock_keys = False;
}
if (*cp++ != '|')
return;
if (clear_all)
reset_decudk();
while (*cp) {
char *base = cp;
char *str = (char *) malloc(strlen(cp) + 2);
unsigned key = 0;
int lo, hi;
int len = 0;
while (isdigit(CharOf(*cp)))
key = (key * 10) + (*cp++ - '0');
if (*cp == '/') {
cp++;
while ((hi = udk_value(&cp)) >= 0
&& (lo = udk_value(&cp)) >= 0) {
str[len++] = (hi << 4) | lo;
}
}
if (len > 0 && key < MAX_UDK) {
if (user_keys[key].str != 0)
free(user_keys[key].str);
user_keys[key].str = str;
user_keys[key].len = len;
} else {
free(str);
}
if (*cp == ';')
cp++;
if (cp == base)
break;
}
}
break;
}
}
char *
udk_lookup(int keycode, int *len)
{
if (keycode >= 0 && keycode < MAX_UDK) {
*len = user_keys[keycode].len;
return user_keys[keycode].str;
}
return 0;
}
static void
ChangeGroup(String attribute, char *value)
{
Arg args[1];
char *name = (value != 0) ? (char *) value : "";
TRACE(("ChangeGroup(attribute=%s, value=%s)\n", attribute, name));
#if OPT_SAME_NAME
if (sameName) {
char *buf;
XtSetArg(args[0], attribute, &buf);
XtGetValues(toplevel, args, 1);
if (strcmp(name, buf) == 0)
return;
}
#endif
XtSetArg(args[0], attribute, name);
XtSetValues(toplevel, args, 1);
}
void
Changename(register char *name)
{
if (name == 0)
name = "";
#if OPT_ZICONBEEP
if (zIconBeep && zIconBeep_flagged) {
char *newname = (char *) malloc(strlen(name) + 4 + 1);
if (!newname) {
fprintf(stderr, "malloc failed in Changename\n");
return;
}
strcpy(newname, "*** ");
strcat(newname, name);
ChangeGroup(XtNiconName, newname);
free(newname);
} else
#endif
ChangeGroup(XtNiconName, name);
}
void
Changetitle(register char *name)
{
ChangeGroup(XtNtitle, name);
}
#define Strlen(s) strlen((char *)(s))
void
ChangeXprop(register char *buf)
{
Display *dpy = XtDisplay(toplevel);
Window w = XtWindow(toplevel);
XTextProperty text_prop;
Atom aprop;
Char *pchEndPropName = (Char *) strchr(buf, '=');
if (pchEndPropName)
*pchEndPropName = '\0';
aprop = XInternAtom(dpy, buf, False);
if (pchEndPropName == NULL) {
XDeleteProperty(dpy, w, aprop);
} else {
text_prop.value = pchEndPropName + 1;
text_prop.encoding = XA_STRING;
text_prop.format = 8;
text_prop.nitems = Strlen(text_prop.value);
XSetTextProperty(dpy, w, &text_prop, aprop);
}
}
ScrnColors *pOldColors = NULL;
static Boolean
GetOldColors(XtermWidget pTerm)
{
int i;
if (pOldColors == NULL) {
pOldColors = (ScrnColors *) XtMalloc(sizeof(ScrnColors));
if (pOldColors == NULL) {
fprintf(stderr, "allocation failure in GetOldColors\n");
return (FALSE);
}
pOldColors->which = 0;
for (i = 0; i < NCOLORS; i++) {
pOldColors->colors[i] = 0;
pOldColors->names[i] = NULL;
}
GetColors(pTerm, pOldColors);
}
return (TRUE);
}
static void
ReportColorRequest(XtermWidget pTerm, int ndx, int final)
{
XColor color;
Colormap cmap = pTerm->core.colormap;
char buffer[80];
GetOldColors(pTerm);
color.pixel = pOldColors->colors[ndx];
TRACE(("ReportColors %d: %#lx\n", ndx, pOldColors->colors[ndx]));
XQueryColor(term->screen.display, cmap, &color);
sprintf(buffer, "%d;rgb:%04x/%04x/%04x", ndx + 10,
color.red,
color.green,
color.blue);
unparseputc1(OSC, pTerm->screen.respond);
unparseputs(buffer, pTerm->screen.respond);
unparseputc1(final, pTerm->screen.respond);
}
static Boolean
UpdateOldColors(
XtermWidget pTerm GCC_UNUSED,
ScrnColors * pNew)
{
int i;
for (i = 0; i < NCOLORS; i++) {
if (COLOR_DEFINED(pNew, i)) {
if (pOldColors->names[i] != NULL) {
XtFree(pOldColors->names[i]);
pOldColors->names[i] = NULL;
}
if (pNew->names[i]) {
pOldColors->names[i] = pNew->names[i];
}
pOldColors->colors[i] = pNew->colors[i];
}
}
return (TRUE);
}
void
ReverseOldColors(void)
{
register ScrnColors *pOld = pOldColors;
Pixel tmpPix;
char *tmpName;
if (pOld) {
if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) {
pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG];
if (pOld->names[TEXT_CURSOR]) {
XtFree(pOldColors->names[TEXT_CURSOR]);
pOld->names[TEXT_CURSOR] = NULL;
}
if (pOld->names[TEXT_BG]) {
tmpName = XtMalloc(strlen(pOld->names[TEXT_BG]) + 1);
if (tmpName) {
strcpy(tmpName, pOld->names[TEXT_BG]);
pOld->names[TEXT_CURSOR] = tmpName;
}
}
}
EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix);
EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName);
EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix);
EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName);
EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix);
EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName);
}
return;
}
static Boolean
AllocateColor(
XtermWidget pTerm,
ScrnColors * pNew,
int ndx,
char *name)
{
XColor def;
register TScreen *screen = &pTerm->screen;
Colormap cmap = pTerm->core.colormap;
char *newName;
if (XParseColor(screen->display, cmap, name, &def)
&& (XAllocColor(screen->display, cmap, &def)
|| find_closest_color(screen->display, cmap, &def))
&& (newName = XtMalloc(strlen(name) + 1)) != 0) {
SET_COLOR_VALUE(pNew, ndx, def.pixel);
strcpy(newName, name);
SET_COLOR_NAME(pNew, ndx, newName);
TRACE(("AllocateColor #%d: %s (pixel %#lx)\n", ndx, newName, def.pixel));
return (TRUE);
}
TRACE(("AllocateColor #%d: %s (failed)\n", ndx, name));
return (FALSE);
}
static Boolean
ChangeColorsRequest(
XtermWidget pTerm,
int start,
register char *names,
int final)
{
char *thisName;
ScrnColors newColors;
int i, ndx;
TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names));
if ((pOldColors == NULL)
&& (!GetOldColors(pTerm))) {
return (FALSE);
}
newColors.which = 0;
for (i = 0; i < NCOLORS; i++) {
newColors.names[i] = NULL;
}
for (i = start; i < NCOLORS; i++) {
if (term->misc.re_verse)
ndx = OPPOSITE_COLOR(i);
else
ndx = i;
if ((names == NULL) || (names[0] == '\0')) {
newColors.names[ndx] = NULL;
} else {
if (names[0] == ';')
thisName = NULL;
else
thisName = names;
names = strchr(names, ';');
if (names != NULL) {
*names = '\0';
names++;
}
if (thisName != 0 && !strcmp(thisName, "?"))
ReportColorRequest(pTerm, ndx, final);
else if (!pOldColors->names[ndx]
|| (thisName
&& strcmp(thisName, pOldColors->names[ndx]))) {
AllocateColor(pTerm, &newColors, ndx, thisName);
}
}
}
if (newColors.which == 0)
return (TRUE);
ChangeColors(pTerm, &newColors);
UpdateOldColors(pTerm, &newColors);
return (TRUE);
}
#ifndef DEBUG
#endif
void
Panic(char *s GCC_UNUSED, int a GCC_UNUSED)
{
#ifdef DEBUG
if (debug) {
fprintf(stderr, "%s: PANIC!\t", xterm_name);
fprintf(stderr, s, a);
fputs("\r\n", stderr);
fflush(stderr);
}
#endif
}
char *
SysErrorMsg(int n)
{
register char *s = strerror(n);
return s ? s : "unknown error";
}
void
SysError(int i)
{
static const char *table[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
,"main: ioctl() failed on FIONBIO"
,"main: ioctl() failed on F_GETFL"
,"main: ioctl() failed on F_SETFL"
,"spawn: open() failed on /dev/tty"
,"spawn: ioctl() failed on TIOCGETP"
,0
,"spawn: ptsname() failed"
,"spawn: open() failed on ptsname"
,"spawn: ioctl() failed on I_PUSH/\"ptem\""
,"spawn: ioctl() failed on I_PUSH/\"consem\""
,"spawn: ioctl() failed on I_PUSH/\"ldterm\""
,"spawn: ioctl() failed on I_PUSH/\"ttcompat\""
,"spawn: ioctl() failed on TIOCSETP"
,"spawn: ioctl() failed on TIOCSETC"
,"spawn: ioctl() failed on TIOCSETD"
,"spawn: ioctl() failed on TIOCSLTC"
,"spawn: ioctl() failed on TIOCLSET"
,"spawn: initgroups() failed"
,"spawn: fork() failed"
,"spawn: exec() failed"
,0
,"get_pty: not enough ptys"
,0
,"waiting for initial map"
,"spawn: setuid() failed"
,"spawn: can't initialize window"
,0, 0, 0, 0, 0, 0, 0, 0, 0
,"spawn: ioctl() failed on TIOCKSET"
,"spawn: ioctl() failed on TIOCKSETC"
,"spawn: realloc of ttydev failed"
,"luit: command-line malloc failed"
,"in_put: select() failed"
,0, 0, 0
,"VTInit: can't initialize window"
,0, 0
,"HandleKeymapChange: malloc failed"
,0, 0
,"Tinput: select() failed"
,0, 0, 0
,"TekInit: can't initialize window"
,0, 0, 0, 0, 0, 0
,"SaltTextAway: malloc() failed"
,0, 0, 0, 0, 0, 0, 0, 0
,"StartLog: exec() failed"
,0, 0
,"xerror: XError event"
,"xioerror: X I/O error"
,0, 0, 0, 0, 0
,"Alloc: calloc() failed on base"
,"Alloc: calloc() failed on rows"
,"ScreenResize: realloc() failed on alt base"
,0, 0, 0
,"ScreenResize: malloc() or realloc() failed"
,0, 0, 0, 0, 0
,"ScrnPointers: malloc/realloc() failed"
,0, 0, 0, 0, 0, 0, 0
,"ScrollBarOn: realloc() failed on base"
,"ScrollBarOn: realloc() failed on rows"
,0, 0, 0, 0, 0, 0, 0, 0, 0
,"my_memmove: malloc/realloc failed"
};
int oerrno;
oerrno = errno;
fprintf(stderr, "%s: Error %d, errno %d: ", xterm_name, i, oerrno);
fprintf(stderr, "%s\n", SysErrorMsg(oerrno));
if ((Cardinal) i < XtNumber(table) && table[i] != 0) {
fprintf(stderr, "Reason: %s\n", table[i]);
}
Cleanup(i);
}
static void
Sleep(int msec)
{
static struct timeval select_timeout;
select_timeout.tv_sec = 0;
select_timeout.tv_usec = msec * 1000;
select(0, 0, 0, 0, &select_timeout);
}
void
Cleanup(int code)
{
static Boolean cleaning;
register TScreen *screen;
if (cleaning) {
hold_screen = 0;
return;
}
cleaning = TRUE;
TRACE(("Cleanup %d\n", code));
screen = &term->screen;
if (hold_screen) {
hold_screen = 2;
while (hold_screen) {
xevents();
Sleep(10);
}
}
#if OPT_SESSION_MGT
if (resource.sessionMgt) {
XtVaSetValues(toplevel,
XtNjoinSession, False,
(XtPointer *) 0);
}
#endif
if (screen->pid > 1) {
(void) kill_process_group(screen->pid, SIGHUP);
}
Exit(code);
}
void
xtermSetenv(register char *var, register char *value)
{
register int envindex = 0;
register size_t len = strlen(var);
TRACE(("xtermSetenv(var=%s, value=%s)\n", var, value));
while (environ[envindex] != NULL) {
if (strncmp(environ[envindex], var, len) == 0) {
environ[envindex] = (char *) malloc((unsigned) len
+ strlen(value) + 1);
strcpy(environ[envindex], var);
strcat(environ[envindex], value);
return;
}
envindex++;
}
TRACE(("...expanding env to %d\n", envindex + 1));
environ[envindex] = (char *) malloc((unsigned) len + strlen(value) + 1);
(void) strcpy(environ[envindex], var);
strcat(environ[envindex], value);
environ[++envindex] = NULL;
}
int
xerror(Display * d, register XErrorEvent * ev)
{
fprintf(stderr, "%s: warning, error event received:\n", xterm_name);
(void) XmuPrintDefaultErrorMessage(d, ev, stderr);
Exit(ERROR_XERROR);
return 0;
}
int
xioerror(Display * dpy)
{
(void) fprintf(stderr,
"%s: fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n",
xterm_name, errno, SysErrorMsg(errno),
DisplayString(dpy));
Exit(ERROR_XIOERROR);
return 0;
}
void
xt_error(String message)
{
(void) fprintf(stderr, "%s Xt error: %s\n", ProgramName, message);
exit(1);
}
int
XStrCmp(char *s1, char *s2)
{
if (s1 && s2)
return (strcmp(s1, s2));
if (s1 && *s1)
return (1);
if (s2 && *s2)
return (-1);
return (0);
}
#if OPT_TEK4014
static void
withdraw_window(Display * dpy, Window w, int scr)
{
TRACE(("withdraw_window %#lx\n", (long) w));
(void) XmuUpdateMapHints(dpy, w, NULL);
XWithdrawWindow(dpy, w, scr);
return;
}
#endif
void
set_vt_visibility(Boolean on)
{
register TScreen *screen = &term->screen;
TRACE(("set_vt_visibility(%d)\n", on));
if (on) {
if (!screen->Vshow && term) {
VTInit();
XtMapWidget(XtParent(term));
#if OPT_TOOLBAR
XtMapWidget(SHELL_OF(term));
#endif
screen->Vshow = TRUE;
}
}
#if OPT_TEK4014
else {
if (screen->Vshow && term) {
withdraw_window(XtDisplay(term),
XtWindow(SHELL_OF(term)),
XScreenNumberOfScreen(XtScreen(term)));
screen->Vshow = FALSE;
}
}
set_vthide_sensitivity();
set_tekhide_sensitivity();
update_vttekmode();
update_tekshow();
update_vtshow();
#endif
return;
}
#if OPT_TEK4014
void
set_tek_visibility(Boolean on)
{
register TScreen *screen = &term->screen;
TRACE(("set_tek_visibility(%d)\n", on));
if (on) {
if (!screen->Tshow && (tekWidget || TekInit())) {
Widget tekParent = SHELL_OF(tekWidget);
XtRealizeWidget(tekParent);
XtMapWidget(tekParent);
XtOverrideTranslations(tekParent,
XtParseTranslationTable
("<Message>WM_PROTOCOLS: DeleteWindow()"));
(void) XSetWMProtocols(XtDisplay(tekParent),
XtWindow(tekParent),
&wm_delete_window, 1);
screen->Tshow = TRUE;
}
} else {
if (screen->Tshow && tekWidget) {
withdraw_window(XtDisplay(tekWidget),
XtWindow(SHELL_OF(tekWidget)),
XScreenNumberOfScreen(XtScreen(tekWidget)));
screen->Tshow = FALSE;
}
}
set_tekhide_sensitivity();
set_vthide_sensitivity();
update_vtshow();
update_tekshow();
update_vttekmode();
return;
}
void
end_tek_mode(void)
{
register TScreen *screen = &term->screen;
if (screen->TekEmu) {
#ifdef ALLOWLOGGING
if (screen->logging) {
FlushLog(screen);
screen->logstart = DecodedData(&VTbuffer);
}
#endif
longjmp(Tekend, 1);
}
return;
}
void
end_vt_mode(void)
{
register TScreen *screen = &term->screen;
if (!screen->TekEmu) {
#ifdef ALLOWLOGGING
if (screen->logging && TekPtyData()) {
FlushLog(screen);
screen->logstart = DecodedData(Tbuffer);
}
#endif
screen->TekEmu = TRUE;
longjmp(VTend, 1);
}
return;
}
void
switch_modes(Bool tovt)
{
if (tovt) {
if (TekRefresh)
dorefresh();
end_tek_mode();
} else {
end_vt_mode();
}
}
void
hide_vt_window(void)
{
register TScreen *screen = &term->screen;
set_vt_visibility(FALSE);
if (!screen->TekEmu)
switch_modes(False);
}
void
hide_tek_window(void)
{
register TScreen *screen = &term->screen;
set_tek_visibility(FALSE);
TekRefresh = (TekLink *) 0;
if (screen->TekEmu)
switch_modes(True);
}
#endif
static const char *
skip_punct(const char *s)
{
while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') {
++s;
}
return s;
}
static int
cmp_options(const void *a, const void *b)
{
return strcmp(skip_punct(((const OptionHelp *) a)->opt),
skip_punct(((const OptionHelp *) b)->opt));
}
static int
cmp_resources(const void *a, const void *b)
{
return strcmp(((const XrmOptionDescRec *) a)->option,
((const XrmOptionDescRec *) b)->option);
}
XrmOptionDescRec *
sortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count)
{
static XrmOptionDescRec *res_array = 0;
if (res_array == 0) {
Cardinal j;
res_array = (XrmOptionDescRec *) calloc(res_count, sizeof(*res_array));
for (j = 0; j < res_count; j++)
res_array[j] = descs[j];
qsort(res_array, res_count, sizeof(*res_array), cmp_resources);
}
return res_array;
}
OptionHelp *
sortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs)
{
static OptionHelp *opt_array = 0;
if (opt_array == 0) {
Cardinal opt_count, j, k;
#if OPT_TRACE
XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs);
int code;
char *mesg;
#else
(void) k;
(void) descs;
(void) numDescs;
#endif
for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) {
;
}
opt_array = (OptionHelp *) calloc(opt_count + 1, sizeof(OptionHelp));
for (j = 0; j < opt_count; j++)
opt_array[j] = options[j];
qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options);
#if OPT_TRACE
for (j = 0; j < opt_count; j++) {
if (!strncmp(opt_array[j].opt, "-/+", 3)) {
char *name = opt_array[j].opt + 3;
for (k = 0; k < numDescs; ++k) {
char *value = res_array[k].value;
if (res_array[k].option[0] == '-') {
code = -1;
} else if (res_array[k].option[0] == '+') {
code = 1;
} else {
code = 0;
}
if (x_strindex(opt_array[j].desc, "inhibit") != 0)
code = -code;
if (code != 0
&& res_array[k].value != 0
&& !strcmp(name, res_array[k].option + 1)) {
if (((code < 0) && !strcmp(value, "on"))
|| ((code > 0) && !strcmp(value, "off"))
|| ((code > 0) && !strcmp(value, "0"))) {
mesg = "turn on/off";
} else {
mesg = "turn off/on";
}
if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) {
if (strncmp(opt_array[j].desc, "turn ", 5)) {
char *s = malloc(strlen(mesg)
+ 2
+ strlen(opt_array[j].desc));
if (s != 0) {
sprintf(s, "%s %s", mesg, opt_array[j].desc);
opt_array[j].desc = s;
}
} else {
TRACE(("OOPS "));
}
}
TRACE(("%s: %s %s: %s (%s)\n",
mesg,
res_array[k].option,
res_array[k].value,
opt_array[j].opt,
opt_array[j].desc));
break;
}
}
}
}
#endif
}
return opt_array;
}