This is unix.c in view mode; [Download] [Up]
/*
* Copyright (c) 1992, 1995 John E. Davis (davis@space.mit.edu)
* All Rights Reserved.
*/
#include <config.h>
#include <stdio.h>
#include "sysdep.h"
#ifdef HAS_SUBPROCESSES
#include "jprocess.h"
#endif
#include <signal.h>
/* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
/* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
#include <sys/time.h>
#ifdef HAVE_TERMIOS_H
# if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
# undef HAVE_TERMIOS_H
# endif
#endif
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
#ifdef sun
#ifndef PENDIN
#include <sys/ioctl.h>
#endif
#else
#include <sys/ioctl.h>
#endif
#ifdef __QNX__
# include <termios.h>
# include <sys/select.h>
#endif
#ifdef SYSV
# ifndef CRAY
# include <sys/termio.h>
# include <sys/stream.h>
# include <sys/ptem.h>
# include <sys/tty.h>
# endif
#endif
#include <sys/types.h>
#include <sys/time.h>
/* Another hack for AInt uniX (AIX) */
#if defined (_AIX) && !defined (FD_SET)
# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
#endif
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
# include <sys/file.h>
# ifdef SYSV
# include <sys/fcntl.h>
# endif
#ifndef F_GETFL
# include <fcntl.h>
#endif
#include "sig.h"
#define TTY_DESC 2
static int Read_FD = TTY_DESC;
static int Max_Fd = TTY_DESC;
int Flow_Control;
int Abort_Char = 7; /* scan code for G (control) */
#ifndef HAVE_TERMIOS_H
struct ttystuff
{
struct tchars t;
struct ltchars lt;
struct sgttyb s;
};
struct ttystuff OLDTTY;
#else
struct termios OLDTTY;
#endif
#ifdef TCGETS
#define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
#define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
#else
# ifndef HAVE_TERMIOS_H
# define X(x,m) &(((struct ttystuff*)(x))->m)
# define GET_TERMIOS(fd, x) \
if(ioctl(fd, TIOCGETC, X(x,t))<0 || \
ioctl(fd, TIOCGLTC, X(x,lt))<0 || \
ioctl(fd, TIOCGETP, X(x,s))<0)exit_error("Can't get terminal info", 0)
# define SET_TERMIOS(fd, x) \
if(ioctl(fd, TIOCSETC, X(x,t))<0 || \
ioctl(fd, TIOCSLTC, X(x,lt))<0 || \
ioctl(fd, TIOCSETP, X(x,s))<0)exit_error("Can't set terminal info", 0)
# else
# define GET_TERMIOS(fd, x) tcgetattr(fd, x)
# define SET_TERMIOS(fd, x) tcsetattr(fd, TCSAFLUSH, x)
/* # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSANOW, x) */
# endif
#endif
static int Baud_Rates[20] =
{
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 0, 0, 0, 0
};
#ifdef HAS_MOUSE
static int JMouse_Fd = -1;
#endif
static int tty_inited = 0;
#define NULL_VALUE 0
void init_tty (void)
{
#ifndef HAVE_TERMIOS_H
struct ttystuff newtty;
#else
struct termios newtty;
#endif
if (Batch) return;
tty_inited = 1;
if (X_Init_Term_Hook != NULL)
{
Read_FD = (*X_Init_Term_Hook) ();
Max_Fd = Read_FD;
return;
}
tt_enable_cursor_keys();
GET_TERMIOS(Read_FD, &OLDTTY);
GET_TERMIOS(Read_FD, &newtty);
#ifndef HAVE_TERMIOS_H
newtty.s.sg_flags &= ~(ECHO);
newtty.s.sg_flags &= ~(CRMOD);
/* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
newtty.t.t_eofc = 1;
newtty.t.t_intrc = Abort_Char; /* ^G */
newtty.t.t_quitc = 255;
newtty.lt.t_suspc = 255; /* to ignore ^Z */
newtty.lt.t_dsuspc = 255; /* to ignore ^Y */
newtty.lt.t_lnextc = 255;
newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */
#else
if (*tt_Baud_Rate == 0)
{
/* Note: if this generates an compiler error, simply remove
the statement */
#ifdef HAVE_CFGETOSPEED
*tt_Baud_Rate = cfgetospeed (&newtty);
#endif
*tt_Baud_Rate = (*tt_Baud_Rate > 0) && (*tt_Baud_Rate < 19) ?
Baud_Rates[*tt_Baud_Rate] : -1;
}
newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);
#ifdef ISTRIP
/* allow 8 bit chars to pass through */
/* newtty.c_iflag &= ~ISTRIP; */
#endif
newtty.c_oflag &= ~OPOST;
/* (ONLCR | OPOST); */ /* do not map newline to cr/newline on out */
if (Flow_Control == 0) newtty.c_iflag &= ~IXON;
newtty.c_cc[VMIN] = 1;
newtty.c_cc[VTIME] = 0;
newtty.c_cc[VEOF] = 1;
newtty.c_lflag = ISIG | NOFLSH;
newtty.c_cc[VINTR] = Abort_Char; /* ^G */
newtty.c_cc[VQUIT] = NULL_VALUE;
newtty.c_cc[VSUSP] = NULL_VALUE; /* to ignore ^Z */
#ifdef VDSUSP
newtty.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
#endif
#ifdef VSWTCH
newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
#endif
#endif /* NOT HAVE_TERMIOS_H */
SET_TERMIOS(Read_FD, &newtty);
#ifdef HAS_MOUSE
if ((X_Open_Mouse_Hook != NULL)
&& ((JMouse_Fd = (*X_Open_Mouse_Hook)()) >= 0))
{
if (JMouse_Fd > Read_FD) Max_Fd = JMouse_Fd;
}
#endif
}
void reset_tty (void)
{
if (Batch) return;
if (!tty_inited) return;
if (X_Init_Term_Hook != NULL)
{
if (X_Reset_Term_Hook != NULL) (*X_Reset_Term_Hook) ();
return;
}
SET_TERMIOS(Read_FD, &OLDTTY);
/* This statement ensures init_tty will not try to change output_rate
(when coming back from suspension) */
if (*tt_Baud_Rate == 0) *tt_Baud_Rate = -1;
#ifdef HAS_MOUSE
if (X_Close_Mouse_Hook != NULL) X_Close_Mouse_Hook ();
JMouse_Fd = -1;
#endif
}
unsigned char sys_getkey (void)
{
int n = 450;
int count = 3;
unsigned char c;
#ifdef HAS_SUBPROCESSES
int all = Num_Subprocesses;
#else
int all = 0;
#endif
if (SLKeyBoard_Quit) return((int) Abort_Char);
/* sleep for 45 second and try again */
while (!SLKeyBoard_Quit && !sys_input_pending(&n, all))
{
/* update status line incase user is displaying time */
if (SLKeyBoard_Quit) break;
if (Display_Time || all)
{
JWindow->trashed = 1;
update((Line *) NULL, 0, 1);
}
}
if (SLKeyBoard_Quit) return(Abort_Char);
if (X_Read_Hook != NULL) return (X_Read_Hook ());
/* Something may have stuffed it, e.g., mouse */
if (Input_Buffer_Len) return my_getkey ();
#ifdef HAS_MOUSE
if (JMouse_Hide_Mouse_Hook != NULL) (*JMouse_Hide_Mouse_Hook) (0);
#endif
again:
while (count-- && (read(Read_FD, (char *) &c, 1) < 0) && !SLKeyBoard_Quit) sleep(1);
if (count <= 0)
{
count = 3;
if (errno == EINTR) goto again;
exit_error ("getkey(): read failed", 0);
}
/* only way for keyboard quit to be non zero is if ^G recived and sigint processed */
if (SLKeyBoard_Quit) c = Abort_Char;
SLKeyBoard_Quit = 0;
return(c);
}
#ifndef FD_SET
#define FD_SET(fd, tthis) *(tthis) |= 1 << fd
#define FD_ZERO(tthis) *(tthis) = 0
#define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
typedef int fd_set;
#endif
static fd_set Read_FD_Set;
/* If all is zero, only check for mouse or keyboard input. If all is -1,
* check for only subprocess input. Otherwise, check all input.
*/
static int sys_input_pending(int *tsecs, int all)
{
struct timeval wait;
long usecs, secs;
int ret, maxfd;
#ifdef HAS_SUBPROCESSES
int i;
#endif
if ((all >= 0) && (Input_Buffer_Len || Batch)) return(Input_Buffer_Len);
top:
secs = *tsecs / 10;
usecs = (*tsecs % 10) * 100000;
wait.tv_sec = secs;
wait.tv_usec = usecs;
if (all >= 0)
{
if (X_Input_Pending_Hook != NULL)
{
if ((*X_Input_Pending_Hook) ()) return 1;
}
FD_SET(Read_FD, &Read_FD_Set);
#ifdef HAS_MOUSE
if ((JMouse_Fd >= 0) && (JMouse_Event_Hook != NULL))
{
FD_SET (JMouse_Fd, &Read_FD_Set);
}
#endif
maxfd = Max_Fd;
}
else maxfd = -1;
#ifdef HAS_SUBPROCESSES
if (all)
{
i = 0;
while (i < Num_Subprocesses)
{
FD_SET(Subprocess_Read_fds[i][0], &Read_FD_Set);
i++;
}
if (Max_Subprocess_FD > maxfd) maxfd = Max_Subprocess_FD;
}
#endif
ret = select(maxfd + 1, &Read_FD_Set, NULL, NULL, &wait);
if (ret == 0) return 0;
#ifdef EBADF
if ((ret < 0) && (errno == EBADF))
{
/* Oh Geez. We have an invalid file descriptor. Well, there are
* several options. Here is what I am choosing: If we are selecting
* on subprocesses and the bad descriptor appears to be the subprocess
* then ignore select on suprocesses. Hopefully the subprocess child
* handlers will fire and illiminate this situation. If it is the
* mouse, then turn off the mouse. If it is the keyboard, then exit.
*/
FD_ZERO (&Read_FD_Set);
if (all >= 0)
{
#ifdef HAS_MOUSE
if ((JMouse_Fd >= 0) && (JMouse_Event_Hook != NULL))
{
if ((-1 == fcntl (JMouse_Fd, F_GETFL, 0)) && (errno == EBADF))
{
JMouse_Event_Hook = NULL;
goto top;
}
}
#endif
if ((-1 == fcntl (Read_FD, F_GETFL, 0)) && (errno == EBADF))
{
exit_error ("select: keyboard file descriptor is bad!!!", 1);
}
}
if (all == -1) return 0;
all = 0;
goto top;
}
#endif
if (all >= 0)
{
if ((X_Input_Pending_Hook != NULL) && (ret > 0)
&& (FD_ISSET(Read_FD, &Read_FD_Set)))
{
if ((*X_Input_Pending_Hook) ()) return 1;
/* Nothing there so try to time out again --- too bad select does
* not inform of of how far we got.
*/
FD_SET(Read_FD, &Read_FD_Set);
(void) select(Read_FD + 1, &Read_FD_Set, NULL, NULL, &wait);
/* try again, it could be more bogus Xpackets. Event driven systems
* are not always the way to go. */
return (*X_Input_Pending_Hook) ();
}
if (ret < 0) return 0;
if (FD_ISSET(Read_FD, &Read_FD_Set)) return ret;
/* Nothing to read from the terminal so while we are waiting
* for tty input, read from those that are available. TTY input
* always gets preference.
*/
#ifdef HAS_MOUSE
if ((JMouse_Event_Hook != NULL)
&& (JMouse_Fd >= 0) && (FD_ISSET (JMouse_Fd, &Read_FD_Set)))
{
if ((*JMouse_Event_Hook) () > 0)
{
return 1;
}
/* This is ugly. */
goto top;
}
#endif
}
/* all >= 0 */
if (ret <= 0) return 0;
#ifdef HAS_SUBPROCESSES
i = 0;
while (i < Num_Subprocesses)
{
if (FD_ISSET(Subprocess_Read_fds[i][0], &Read_FD_Set))
read_process_input (i);
i++;
}
#endif
if (all < 0) return ret;
return 0; /* no keyboard input */
}
/* This is to get the size of the terminal */
int get_term_dimensions(int *cols, int *rows)
{
#ifdef TIOCGWINSZ
struct winsize wind_struct;
if (X_Get_Term_Size_Hook == NULL)
{
if ((ioctl(1,TIOCGWINSZ,&wind_struct) < 0)
&& (ioctl(2, TIOCGWINSZ, &wind_struct) < 0)
&& (ioctl(0, TIOCGWINSZ, &wind_struct) < 0))
{
*rows = *cols = 0;
}
else
{
*cols = (int) wind_struct.ws_col;
*rows = (int) wind_struct.ws_row;
}
}
else (*X_Get_Term_Size_Hook)(cols, rows);
if (*rows <= 0) *rows = *tt_Screen_Rows;
if (*cols <= 0) *cols = *tt_Screen_Cols;
#else
if (X_Get_Term_Size_Hook == NULL)
{
*rows = *tt_Screen_Rows;
*cols = *tt_Screen_Cols;
}
else (*X_Get_Term_Size_Hook)(cols, rows);
#endif
return 0;
}
/* returns 0 on failure, 1 on sucess */
int sys_delete_file(char *filename)
{
return(1 + unlink(filename));
}
#ifdef __cplusplus
#define SIGNAL(a,b) signal((a), (SIG_PF)(b))
#else
#define SIGNAL signal
#endif
void sys_suspend(void)
{
SIGNAL (SIGTSTP, SIG_DFL);
if (Signal_Sys_Spawn_Flag) kill(0, SIGSTOP); else kill(0, SIGTSTP);
SIGNAL (SIGTSTP, sig_sys_spawn_cmd);
}
/* returns 0 if file does not exist, 1 if it is not a dir, 2 if it is */
int sys_chmod(char *file, int what, int *mode, short *uid, short *gid)
{
struct stat buf;
int m;
if (what)
{
chmod(file, *mode);
chown(file, (uid_t) *uid, (uid_t) *gid);
return(0);
}
if (stat(file, &buf) < 0) switch (errno)
{
case EACCES: return(-1); /* es = "Access denied."; break; */
case ENOENT: return(0); /* ms = "File does not exist."; */
case ENOTDIR: return(-2); /* es = "Invalid Path."; */
default: return(-3); /* "stat: unknown error."; break;*/
}
m = buf.st_mode;
*uid = buf.st_uid;
*gid = buf.st_gid;
/* AIX requires this */
#ifdef _S_IFDIR
#ifndef S_IFDIR
#define S_IFDIR _S_IFDIR
#endif
#endif
#ifndef S_ISDIR
# ifdef S_IFDIR
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# else
# define S_ISDIR(m) 0
# endif
#endif
*mode = m & 0777;
if (S_ISDIR(m)) return (2);
return(1);
}
unsigned long sys_file_mod_time(char *file)
{
struct stat buf;
if (stat(file, &buf) < 0) return(0);
return((unsigned long) buf.st_mtime);
}
/* use berkeley interface
* #include <sys/dir.h>
*/
static char Found_Dir[256];
static char Found_File[256];
static int File_Len;
#if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# define NEED_D_NAMLEN
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
static DIR *Dirp;
/* These routines should be fixed to work with wildcards like the DOS and VMS
* versions do. Unfortunately, it is a sad fact of life that Unix does NOT
* support wildcards. Strangely enough, most Unix users are totally unaware
* of this fact.
*
* To add wild card support, I need to use the regular expression package.
* Specifically, in sys_findfirst, I would need to scan the file spec for
* wild cards making the replacements: . --> \., ? -> ., and * -> .* in that
* order. I should also quote the special characters ($, etc...) but I will
* not worry about this. Finally, I will have to prefix it with '^' since
* the match will start at the beginning of the string.
*
* Remark: to implement something like a real wildcard file renaming routine
* would requires even more processing. Consider something like:
* rename *.c~ *.bak
* This mean that the first expression (*.c~) would have to be converted to:
* \(.*\)\.c~
* and the second (*.bak) would be determined to be: \1.bak where \1 is
* the expression matched by the first wildcard.
*
* After converting the wildcard file name to a regexp file name, I would then
* have to compile it and save the compiled expression for use in sys_findnext.
* There, I would use the regexp string matching routine instead of the
* strcmp which is now used.
*
* Mainly, the findfirst/findnext are used by the completion routines. This
* means that there is an implicit '.*' attached to the end of the filespec.
* This will have to be dealt with.
*/
int sys_findnext(char *file)
{
struct dirent *dp;
while (1)
{
if (NULL == (dp = readdir(Dirp))) return(0);
#ifdef NEED_D_NAMLEN
dp->d_name[dp->d_namlen] = 0;
#endif
if (!strncmp(Found_File, dp->d_name, File_Len)) break;
}
strcpy(file, Found_Dir); strcat(file, dp->d_name);
if (2 == file_status(file)) strcat(file, "/");
return(1);
}
int sys_findfirst(char *the_file)
{
char *f, *file;
file = expand_filename(the_file);
f = extract_file(file);
strcpy (Found_Dir, file);
strcpy (Found_File, f);
File_Len = strlen(f);
Found_Dir[(int) (f - file)] = 0;
if (Dirp != NULL) closedir(Dirp);
if (NULL == (Dirp = (DIR *) opendir(Found_Dir))) return(0);
strcpy(the_file, file);
return sys_findnext(the_file);
}
/* This should be made available as part of the slang library */
#include <pwd.h>
void get_passwd_info (char *name)
{
struct passwd *pwent;
char *password = NULL;
char *dir = NULL;
char *shell = NULL;
int uid = -1, gid = -1;
if (*name == 0)
{
name = getlogin ();
if (name == NULL) name = getenv ("LOGNAME");
if (name == NULL) name = getenv ("USER");
}
if ((name != NULL) && ((pwent = getpwnam (name)) != NULL))
{
password = pwent->pw_passwd;
uid = pwent->pw_uid;
gid = pwent->pw_gid;
dir = pwent->pw_dir;
shell = pwent->pw_shell;
}
if (password == NULL) password = "";
if (dir == NULL) dir = "";
if (shell == NULL) shell = "";
(void) SLang_push_string (dir);
(void) SLang_push_string (shell);
(void) SLang_push_string (password);
(void) SLang_push_integer (uid);
(void) SLang_push_integer (gid);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.