diff options
Diffstat (limited to 'contrib/less/os.c')
-rw-r--r-- | contrib/less/os.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/contrib/less/os.c b/contrib/less/os.c new file mode 100644 index 0000000..4c532e9 --- /dev/null +++ b/contrib/less/os.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 1984-2000 Mark Nudelman + * + * You may distribute under the terms of either the GNU General Public + * License or the Less License, as specified in the README file. + * + * For more information about less, or for information on how to + * contact the author, see the README file. + */ + + +/* + * Operating system dependent routines. + * + * Most of the stuff in here is based on Unix, but an attempt + * has been made to make things work on other operating systems. + * This will sometimes result in a loss of functionality, unless + * someone rewrites code specifically for the new operating system. + * + * The makefile provides defines to decide whether various + * Unix features are present. + */ + +#include "less.h" +#include <signal.h> +#include <setjmp.h> +#if HAVE_TIME_H +#include <time.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_VALUES_H +#include <values.h> +#endif +#if HAVE_LIMITS_H +#include <limits.h> +#endif + +#if HAVE_TIME_T +#define time_type time_t +#else +#define time_type long +#endif + +/* + * BSD setjmp() saves (and longjmp() restores) the signal mask. + * This costs a system call or two per setjmp(), so if possible we clear the + * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. + * On other systems, setjmp() doesn't affect the signal mask and so + * _setjmp() does not exist; we just use setjmp(). + */ +#if HAVE__SETJMP && HAVE_SIGSETMASK +#define SET_JUMP _setjmp +#define LONG_JUMP _longjmp +#else +#define SET_JUMP setjmp +#define LONG_JUMP longjmp +#endif + +public int reading; + +static jmp_buf read_label; + +extern int sigs; + +/* + * Like read() system call, but is deliberately interruptible. + * A call to intread() from a signal handler will interrupt + * any pending iread(). + */ + public int +iread(fd, buf, len) + int fd; + char *buf; + unsigned int len; +{ + register int n; + +#if MSDOS_COMPILER==WIN32C + if (ABORT_SIGS()) + return (READ_INTR); +#else +#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC + if (kbhit()) + { + int c; + + c = getch(); + if (c == '\003') + return (READ_INTR); + ungetch(c); + } +#endif +#endif + if (SET_JUMP(read_label)) + { + /* + * We jumped here from intread. + */ + reading = 0; +#if HAVE_SIGSETMASK + sigsetmask(0); +#else +#ifdef _OSK + sigmask(~0); +#endif +#endif + return (READ_INTR); + } + + flush(); + reading = 1; +#if MSDOS_COMPILER==DJGPPC + if (isatty(fd)) + { + /* + * Don't try reading from a TTY until a character is + * available, because that makes some background programs + * believe DOS is busy in a way that prevents those + * programs from working while "less" waits. + */ + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + if (select(fd+1, &readfds, 0, 0, 0) == -1) + return (-1); + } +#endif + n = read(fd, buf, len); +#if 1 + /* + * This is a kludge to workaround a problem on some systems + * where terminating a remote tty connection causes read() to + * start returning 0 forever, instead of -1. + */ + { + extern int ignore_eoi; + if (!ignore_eoi) + { + static int consecutive_nulls = 0; + if (n == 0) + consecutive_nulls++; + else + consecutive_nulls = 0; + if (consecutive_nulls > 20) + quit(QUIT_ERROR); + } + } +#endif + reading = 0; + if (n < 0) + return (-1); + return (n); +} + +/* + * Interrupt a pending iread(). + */ + public void +intread() +{ + LONG_JUMP(read_label, 1); +} + +/* + * Return the current time. + */ +#if HAVE_TIME + public long +get_time() +{ + time_type t; + + time(&t); + return (t); +} +#endif + + +#if !HAVE_STRERROR +/* + * Local version of strerror, if not available from the system. + */ + static char * +strerror(err) + int err; +{ +#if HAVE_SYS_ERRLIST + static char buf[16]; + extern char *sys_errlist[]; + extern int sys_nerr; + + if (err < sys_nerr) + return sys_errlist[err]; + sprintf(buf, "Error %d", err); + return buf; +#else + return ("cannot open"); +#endif +} +#endif + +/* + * errno_message: Return an error message based on the value of "errno". + */ + public char * +errno_message(filename) + char *filename; +{ + register char *p; + register char *m; +#if HAVE_ERRNO +#if MUST_DEFINE_ERRNO + extern int errno; +#endif + p = strerror(errno); +#else + p = "cannot open"; +#endif + m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char)); + sprintf(m, "%s: %s", filename, p); + return (m); +} + +/* + * Return the largest possible number that can fit in a long. + */ + static long +get_maxlong() +{ +#ifdef LONG_MAX + return (LONG_MAX); +#else +#ifdef MAXLONG + return (MAXLONG); +#else + long n, n2; + + /* + * Keep doubling n until we overflow. + * {{ This actually only returns the largest power of two that + * can fit in a long, but percentage() doesn't really need + * it any more accurate than that. }} + */ + n2 = 128; /* Hopefully no maxlong is less than 128! */ + do { + n = n2; + n2 *= 2; + } while (n2 / 2 == n); + return (n); +#endif +#endif +} + +/* + * Return the ratio of two POSITIONS, as a percentage. + * {{ Assumes a POSITION is a long int. }} + */ + public int +percentage(num, den) + POSITION num, den; +{ + if (num <= get_maxlong() / 100) + return ((100 * num) / den); + else + return (num / (den / 100)); +} + +/* + * Return the specified percentage of a POSITION. + * {{ Assumes a POSITION is a long int. }} + */ + public POSITION +percent_pos(pos, percent) + POSITION pos; + int percent; +{ + if (pos <= get_maxlong() / 100) + return ((percent * pos) / 100); + else + return (percent * (pos / 100)); +} + +#ifdef _OSK_MWC32 + +/* + * This implements an ANSI-style intercept setup for Microware C 3.2 + */ + public int +os9_signal(type, handler) + int type; + RETSIGTYPE (*handler)(); +{ + intercept(handler); +} + +#include <sgstat.h> + + public int +isatty(f) + int f; +{ + struct sgbuf sgbuf; + + if (_gs_opt(f, &sgbuf) < 0) + return -1; + return (sgbuf.sg_class == 0); +} + +#endif |