rust-most/vendor/most-5.1.0/src/sysdep.c

774 lines
16 KiB
C

/*
This file is part of MOST.
Copyright (c) 1991, 1999, 2002, 2005-2018, 2019 John E. Davis
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc., 675
Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
/*
* HISTORY
* {1} 19-Mar-91 Henk D. Davids <hdavids@mswe.dnet.ms.philips.nl>
* History started. Added default input file name so you do not
* have to specify name or type if you want it to be *.
* Changes indicated by "-hdd" in comment.
*
* 2. 4/4/91 John E. Davis
* I added code to read the teminal size for unix systems-- at least it
* works on a sun4 (BSD ?). In addition I have also recently added file
* deletion code for both unix and vms.
*/
#ifdef VMS
# include <ssdef.h>
# include <rmsdef.h>
# include <dvidef.h>
# include <jpidef.h>
# include <libdef.h>
# include <descrip.h>
# include <iodef.h>
# include <ttdef.h>
# include <starlet.h>
/* #include <unixlib.h> */
#endif /* VMS */
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <slang.h>
#include "jdmacros.h"
#ifdef unix
# include <signal.h>
# ifdef SYSV
# include <sys/types.h>
# include <fcntl.h>
# endif
# include <sys/file.h>
#endif
#ifdef __os2__
# include <signal.h>
#endif
#ifdef __WIN32__
#include <windows.h>
/* Sleep is defined badly in MSVC... */
# ifdef _MSC_VER
# define sleep(n) _sleep((n)*1000)
# else
# ifdef sleep
# undef sleep
# endif
# define sleep(x) if(x)Sleep((x)*1000)
# endif
#endif
#include <string.h>
#include "sysdep.h"
#include "display.h"
#include "window.h"
#include "most.h"
#ifdef VMS
typedef struct
{
/* I/O status block */
short i_cond; /* Condition value */
short i_xfer; /* Transfer count */
long i_info; /* Device information */
}
iosb;
typedef struct
{
/* Terminal characteristics */
char t_class; /* Terminal class */
char t_type; /* Terminal type */
short t_width; /* Terminal width in characters */
long t_mandl; /* Terminal's mode and length */
long t_extend; /* Extended terminal characteristics */
}
termchar;
static short TTY_CHANNEL_GLOBAL;
static int zero = 0;
#else
int TTY_DESCR;
#endif /* VMS */
/*
*
*
* SHELL COMMANDS
*
*/
#ifdef VMS
/* these two from emacs source */
# if 0
static define_logical_name (char *varname, char *string)
{
static char sstring[200], svarname[200];
struct dsc$descriptor_s strdsc =
{strlen (string), DSC$K_DTYPE_T, DSC$K_CLASS_S, sstring};
struct dsc$descriptor_s envdsc =
{strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, svarname};
struct dsc$descriptor_s lnmdsc =
{7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
strcpy(sstring, string); strcpy(svarname, varname);
LIB$SET_LOGICAL (&envdsc, &strdsc, &lnmdsc, 0, 0);
}
static delete_logical_name (char *varname)
{
struct dsc$descriptor_s envdsc =
{strlen (varname), DSC$K_DTYPE_T, DSC$K_CLASS_S, varname};
struct dsc$descriptor_s lnmdsc =
{7, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$JOB"};
LIB$DELETE_LOGICAL (&envdsc, &lnmdsc);
}
int most_do_emacs_command()
{
unsigned long pid;
char *pidstr;
if((pidstr = getenv("EMACS_PID")) != NULL)
{
(void) sscanf(pidstr,"%X",&pid);
if (lib$attach(&pid) == SS$_NORMAL) /* we attach to emacs */
return(1);
else
return(0);
/* printf("Can't attach to pid %X\n",pid); */
}
else return(0);
}
# endif /* if 0 */
static unsigned long SHELL_PID = 0;
/* returns 0 on success */
int most_do_shell_command()
{
/* here we try to attach to the parent otherwise just spawn a new one */
unsigned long parent_pid;
unsigned long status = 0;
char str[80];
$DESCRIPTOR(MOST_$_descr, "MOST > ");
if (Most_Secure_Mode)
{
most_message ("Spawning not permitted in secure mode.", 1);
return 0;
}
parent_pid = getppid();
if (parent_pid && (parent_pid != 0xffffffffU))
/* we attach to parent */
status = lib$attach(&parent_pid);
else if (SHELL_PID && (SHELL_PID != 0xffffffffU))
/* try to attach to previous shell */
status = lib$attach (&SHELL_PID);
if (status != SS$_NORMAL) /* others fail so spawn a new shell */
{
status = 0;
SLtt_write_string("Spawning MOST DCL SUBPROCESS (Logout when finished)...");
lib$spawn(0,0,0,0,0,&SHELL_PID,&status,0,0,0,&MOST_$_descr);
/* if we attach back, status may come back unchanged */
if ((status != 0) && (status != SS$_NORMAL))
{
sprintf(str,"Unable to spawn subprocess. Error = %X", status);
most_message(str,1);
return(0);
}
}
most_message(" ",0); /* make sure message window is restored */
return(1);
}
#endif /* VMS */
/*
* FILE IO
*
*/
#ifdef VMS
int most_expand_file_name(char *file,char *expanded_file)
{
unsigned long status;
static int context = 0, len = 0;
static char inputname[MAX_PATHLEN] = "";
$DESCRIPTOR(file_desc,inputname);
$DESCRIPTOR(default_dsc,"SYS$DISK:[]*.*;");
static struct dsc$descriptor_s result =
{0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL};
if (strcmp(inputname, file))
{
if (context)
{
lib$find_file_end(&context);
}
context = 0;
strcpy(inputname, file);
len = strlen(inputname);
}
file_desc.dsc$w_length = len;
status = lib$find_file(&file_desc,&result,&context,
&default_dsc,0,0,&zero);
if (status == RMS$_NORMAL)
{
memcpy(expanded_file, result.dsc$a_pointer, result.dsc$w_length);
expanded_file[result.dsc$w_length] = '\0';
}
else
expanded_file[0] = '\0'; /* so file comes back as zero width */
return status;
}
#endif /* VMS */
/*
*
*
* Terminal IO
*
*/
#ifdef VMS
/*
* Exit Handler Control Block
*/
static struct argument_block
{
int forward_link;
int (*exit_routine)();
int arg_count;
int *status_address;
int exit_status;
}
Exit_Block =
{
0,
NULL,
1,
&Exit_Block.exit_status,
0
};
#endif /* VMS */
#ifdef unix
# include <sys/time.h>
# if !defined(sun)
# include <sys/ioctl.h>
# endif
# ifndef NO_UNISTD_H
# include <unistd.h>
# endif
# if HAS_TERMIOS
# include <termios.h>
# endif
# ifdef SYSV
# include <sys/termio.h>
# include <sys/stream.h>
# include <sys/ptem.h>
# include <sys/tty.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
# include <errno.h>
#if defined(SIGHUP) && !defined(IBMPC_SYSTEM)
static void unix_hangup(int sig)
{
most_exit_error ("most: Exiting on signal %d.", sig);
}
#endif
#endif /* unix */
static int Want_Window_Size_Change;
static int Most_TTY_Inited = 0;
#ifdef REAL_UNIX_SYSTEM
static int handle_interrupts (void)
{
if (Want_Window_Size_Change)
most_resize_display ();
return 0;
}
#endif
#ifdef SIGWINCH
static void sigwinch_handler (int sig)
{
(void) sig;
Want_Window_Size_Change = 1;
(void) SLsignal_intr (SIGWINCH, sigwinch_handler);
}
#endif
#if defined(SIGBUS) && MOST_HAS_MMAP
static void sigbus_handler (int sig)
{
(void) sig;
most_reset_tty ();
most_reset_display ();
fprintf (stderr, "SIGBUS caught--- fatal error\n");
if ((Most_Buf != NULL)
&& Most_Buf->is_mmaped)
fprintf (stderr, "This may be due to a modified memory mapped file\n");
exit (1);
}
#endif
void most_resize_display (void)
{
Want_Window_Size_Change = 0;
if (Most_Display_Inited == 0)
return;
most_get_term_dimensions(&SLtt_Screen_Cols, &SLtt_Screen_Rows);
if (Most_Win != NULL)
most_one_window ();
#if SLANG_VERSION > 10305
SLsmg_reinit_smg ();
#else
SLsmg_reset_smg ();
SLsmg_init_smg ();
#endif
most_redraw_display ();
}
static int init_tty (void)
{
#if defined(REAL_UNIX_SYSTEM)
SLsig_block_signals ();
#endif
if (-1 == SLang_init_tty (7, 0, 1))
{
fprintf (stderr, "most: failed to init terminal.\n");
exit (1);
}
#if !defined(IBMPC_SYSTEM)
SLtt_enable_cursor_keys ();
#endif
#if defined(REAL_UNIX_SYSTEM)
SLsig_unblock_signals ();
SLang_getkey_intr_hook = handle_interrupts;
#endif
return 0;
}
void most_init_tty (void)
{
int i;
if (Most_TTY_Inited) return;
(void) init_tty ();
#if !defined(IBMPC_SYSTEM)
SLsig_block_signals ();
#endif
for (i = 1; i < 32; i++)
{
switch (i)
{
#ifdef SIGHUP
case SIGHUP:
#endif
#ifdef SIGQUIT
case SIGQUIT:
#endif
#ifdef SIGTERM
case SIGTERM:
# ifdef REAL_UNIX_SYSTEM
SLsignal_intr (i, unix_hangup);
# else
(void) i;
# endif
break;
#endif
#ifdef SIGWINCH
case SIGWINCH:
(void) SLsignal_intr (SIGWINCH, sigwinch_handler);
break;
#endif
#if defined(SIGBUS) && MOST_HAS_MMAP
case SIGBUS:
(void) SLsignal_intr (SIGBUS, sigbus_handler);
break;
#endif
#ifdef SIGCONT
case SIGCONT:
#endif
#ifdef SIGTSTP
case SIGTSTP:
#endif
#ifdef SIGINT
case SIGINT:
#endif
#ifdef SIGCHLD
case SIGCHLD:
#endif
default:
break;
#ifdef SIGPIPE
case SIGPIPE:
(void) SLsignal_intr (SIGPIPE, SIG_IGN);
break;
#endif
}
}
SLang_set_abort_signal (NULL);
Most_TTY_Inited = 1;
#if !defined(IBMPC_SYSTEM)
SLsig_unblock_signals ();
#endif
}
void most_reset_tty (void)
{
if (Most_TTY_Inited == 0) return;
SLang_reset_tty ();
Most_TTY_Inited = 0;
}
int most_reinit_terminal (void)
{
if (Most_TTY_Inited == 0)
return 0;
most_reset_tty ();
(void) init_tty ();
Most_TTY_Inited = 1;
return 0;
}
/* slang uses select to wait for terminal input. If SIGINT is
* generated, then slang returns ^G and sets SLKeyBoard_Quit
* to 1 bypassing the read altogether. If most was used in
* conjunction with xargs (find . -print | xargs most) and ^G
* is pressed, a SIGINT will be generated killing xargs and
* leaving most an orphan unable to access the terminal.
* Unfortunately, the select call will continue to time-out
* causing most continue running in the background. To
* workaround this problem, exit if the terminal is not in the
* same process group as most.
*/
static void check_if_foreground (void)
{
#if defined(HAVE_GETPGRP) && defined(HAVE_TCGETPGRP)
pid_t pgid = getpgrp ();
if ((SLang_TT_Read_FD != -1)
&& (pgid != tcgetpgrp (SLang_TT_Read_FD)))
{
most_exit_error ("\007Fatal Error: Most is not in the terminal's process group.");
}
#endif
}
int most_getkey()
{
unsigned int ch;
static int last_was_sigint;
/* This non-sense involving last_was_sigint is to handle a race condition.
* The shell may not have had time to change the pgids, so sleep a bit
* here. Yea, its ugly and does not really solve the problem...
*/
if (last_was_sigint)
{
sleep (1);
check_if_foreground ();
last_was_sigint = 0;
}
ch = SLang_getkey ();
if (ch == SLANG_GETKEY_ERROR)
most_exit_error ("most: getkey error.");
if (SLKeyBoard_Quit)
{
check_if_foreground ();
last_was_sigint = 1;
}
SLKeyBoard_Quit = 0;
SLang_set_error (0);
return (int) ch;
}
/*
*
* Misc Termial stuff
*
*
*/
/* This is to get the size of the terminal */
void most_get_term_dimensions(int *cols, int *rows)
{
SLtt_get_screen_size ();
*rows = SLtt_Screen_Rows;
*cols = SLtt_Screen_Cols;
}
/* returns 0 on failure, 1 on sucess */
int most_delete_file(char *filename)
{
#ifdef VMS
return (1 + delete(filename)); /* 0: sucess; -1 failure */
#else
return(1 + remove(filename));
#endif
}
/* This routine converts unix type names to vms names */
#ifdef VMS
static int locate(char ch, char *string)
{
int i;
char c;
i = 0;
while (c = string[i++], (c != ch) && (c != '\0'));
if (c == ch) return(i); else return (0);
}
char *most_unix2vms(char *file)
{
int i,device,j,first,last;
static char vms_name[MAX_PATHLEN];
char ch;
if (locate('[',file)) return(file); /* vms_name syntax */
if (!locate('/',file)) return(file); /* vms_name syntax */
/* search for the ':' which means a device is present */
device = locate(':',file);
i = 0;
if (device)
{
while (ch = file[i], i < device) vms_name[i++] = ch;
}
j = i;
/* go from the end looking for a '/' and mark it */
i = strlen(file) - 1;
while(ch = file[i], ch != '/' && i-- >= 0);
if (ch == '/')
{
file[i] = ']';
last = 0;
}
else last = 1;
i = j;
vms_name[j++] = '[';
vms_name[j++] = '.';
first = 0;
while(ch = file[i++], ch != '\0')
{
switch (ch)
{
case '.':
if (last) vms_name[j++] = '.';
if (last) break;
ch = file[i++];
if (ch == '.')
{
if (!first) j--; /* overwrite the dot */
vms_name[j++] = '-';
}
else if (ch == '/'); /* './' combinations-- do nothing */
else if (ch == ']')
{
last = 1;
if (vms_name[j-1] == '.') j--;
vms_name[j++] = ']';
}
else vms_name[j++] = '.';
break;
case '/':
if (first)
{
vms_name[j++] = '.';
}
else
{
first = 1;
/* if '/' is first char or follows a colon do nothing */
if ((i!=1) && (file[i-2] != ':'))
{
vms_name[j++] = '.';
}
else j--; /* overwrite the '.' following '[' */
}
break;
case ']':
last = 1;
if (vms_name[j-1] == '.') j--;
vms_name[j++] = ']';
break;
default:
vms_name[j++] = ch;
}
}
return (vms_name);
}
/*
main(int argc, char **argv)
{
puts(unix2vms(argv[1]));
}
*/
#endif /* VMS */
#include <time.h>
char *most_get_time()
{
time_t clk;
char *the_time;
clk = time((time_t *) 0);
the_time = (char *) ctime(&clk);
/* returns the form Sun Sep 16 01:03:52 1985\n\0 */
the_time[24] = '\0';
return(the_time);
}
void most_set_width (int width, int redraw)
{
#ifdef IBMPC_SYSTEM
(void) width; (void) redraw;
#else
#ifdef VMS
short fd;
int status;
iosb iostatus;
static termchar tc; /* Terminal characteristics */
$DESCRIPTOR( devnam, "SYS$ERROR");
#else
# ifdef TIOCGWINSZ
struct winsize wind_struct;
# endif
#endif
/* Switching physical terminal to narrow/wide mode.*/
if(width <= 80)
{
width = 80;
most_narrow_width();
}
else
{
width = 132;
most_wide_width();
}
SLtt_Screen_Cols = width;
#ifdef VMS
/* Assign input to a channel */
status = sys$assign(&devnam, &fd, 0, 0);
if ((status & 1) == 0)
exit(status);
/* Get current terminal characteristics */
status = sys$qiow( /* Queue and wait */
0, /* Wait on event flag zero */
fd, /* Channel to input terminal */
IO$_SENSEMODE, /* Get current characteristic */
&iostatus, /* Status after operation */
0, 0, /* No AST service */
&tc, /* Terminal characteristics buf */
sizeof(tc), /* Size of the buffer */
0, 0, 0, 0); /* P3-P6 unused */
/*set terminal characteristics */
tc.t_width=width;
status = sys$qiow( /* Queue and wait */
0, /* Wait on event flag zero */
fd, /* Channel to input terminal */
IO$_SETMODE, /* Get current characteristic */
&iostatus, /* Status after operation */
0, 0, /* No AST service */
&tc, /* Terminal characteristics buf */
sizeof(tc), /* Size of the buffer */
0, 0, 0, 0); /* P3-P6 unused */
if( (sys$dassgn(fd) & 1)==0)
exit(status);
/* here we redraw the screen, on unix, we assume that the terminal
* driver sends the appropriate signal that most catches to redraw so we
* do not redraw because it is likely that screen will be redrawn twice */
if (redraw)
most_resize_display ();
#else
(void) redraw;
# ifdef TIOCGWINSZ
/* this may need work on other unix-- works for sun4 */
if (-1 != ioctl(TTY_DESCR,TIOCGWINSZ,&wind_struct))
{
wind_struct.ws_col = width;
ioctl(TTY_DESCR,TIOCSWINSZ,&wind_struct);
}
# endif
#endif /* VMS */
#endif /* NOT IBMPC_SYSTEM */
}