os.c revision 89019
160786Sps/* 260786Sps * Copyright (C) 1984-2000 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Operating system dependent routines. 1460786Sps * 1560786Sps * Most of the stuff in here is based on Unix, but an attempt 1660786Sps * has been made to make things work on other operating systems. 1760786Sps * This will sometimes result in a loss of functionality, unless 1860786Sps * someone rewrites code specifically for the new operating system. 1960786Sps * 2060786Sps * The makefile provides defines to decide whether various 2160786Sps * Unix features are present. 2260786Sps */ 2360786Sps 2460786Sps#include "less.h" 2560786Sps#include <signal.h> 2660786Sps#include <setjmp.h> 2760786Sps#if HAVE_TIME_H 2860786Sps#include <time.h> 2960786Sps#endif 3060786Sps#if HAVE_ERRNO_H 3160786Sps#include <errno.h> 3260786Sps#endif 3360786Sps#if HAVE_VALUES_H 3460786Sps#include <values.h> 3560786Sps#endif 3660786Sps 3760786Sps#if HAVE_TIME_T 3860786Sps#define time_type time_t 3960786Sps#else 4060786Sps#define time_type long 4160786Sps#endif 4260786Sps 4360786Sps/* 4460786Sps * BSD setjmp() saves (and longjmp() restores) the signal mask. 4560786Sps * This costs a system call or two per setjmp(), so if possible we clear the 4660786Sps * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 4760786Sps * On other systems, setjmp() doesn't affect the signal mask and so 4860786Sps * _setjmp() does not exist; we just use setjmp(). 4960786Sps */ 5060786Sps#if HAVE__SETJMP && HAVE_SIGSETMASK 5160786Sps#define SET_JUMP _setjmp 5260786Sps#define LONG_JUMP _longjmp 5360786Sps#else 5460786Sps#define SET_JUMP setjmp 5560786Sps#define LONG_JUMP longjmp 5660786Sps#endif 5760786Sps 5860786Spspublic int reading; 5960786Sps 6060786Spsstatic jmp_buf read_label; 6160786Sps 6260786Spsextern int sigs; 6360786Sps 6460786Sps/* 6560786Sps * Like read() system call, but is deliberately interruptible. 6660786Sps * A call to intread() from a signal handler will interrupt 6760786Sps * any pending iread(). 6860786Sps */ 6960786Sps public int 7060786Spsiread(fd, buf, len) 7160786Sps int fd; 7260786Sps char *buf; 7360786Sps unsigned int len; 7460786Sps{ 7560786Sps register int n; 7660786Sps 7760786Sps#if MSDOS_COMPILER==WIN32C 7860786Sps if (ABORT_SIGS()) 7960786Sps return (READ_INTR); 8060786Sps#else 8160786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 8260786Sps if (kbhit()) 8360786Sps { 8460786Sps int c; 8560786Sps 8660786Sps c = getch(); 8760786Sps if (c == '\003') 8860786Sps return (READ_INTR); 8960786Sps ungetch(c); 9060786Sps } 9160786Sps#endif 9260786Sps#endif 9360786Sps if (SET_JUMP(read_label)) 9460786Sps { 9560786Sps /* 9660786Sps * We jumped here from intread. 9760786Sps */ 9860786Sps reading = 0; 9963128Sps#if HAVE_SIGPROCMASK 10063128Sps { 10163128Sps sigset_t mask; 10263128Sps sigemptyset(&mask); 10363128Sps sigprocmask(SIG_SETMASK, &mask, NULL); 10463128Sps } 10563128Sps#else 10660786Sps#if HAVE_SIGSETMASK 10760786Sps sigsetmask(0); 10860786Sps#else 10960786Sps#ifdef _OSK 11060786Sps sigmask(~0); 11160786Sps#endif 11260786Sps#endif 11363128Sps#endif 11460786Sps return (READ_INTR); 11560786Sps } 11660786Sps 11760786Sps flush(); 11860786Sps reading = 1; 11960786Sps#if MSDOS_COMPILER==DJGPPC 12060786Sps if (isatty(fd)) 12160786Sps { 12260786Sps /* 12360786Sps * Don't try reading from a TTY until a character is 12460786Sps * available, because that makes some background programs 12560786Sps * believe DOS is busy in a way that prevents those 12660786Sps * programs from working while "less" waits. 12760786Sps */ 12860786Sps fd_set readfds; 12960786Sps 13060786Sps FD_ZERO(&readfds); 13160786Sps FD_SET(fd, &readfds); 13260786Sps if (select(fd+1, &readfds, 0, 0, 0) == -1) 13360786Sps return (-1); 13460786Sps } 13560786Sps#endif 13660786Sps n = read(fd, buf, len); 13760786Sps#if 1 13860786Sps /* 13960786Sps * This is a kludge to workaround a problem on some systems 14060786Sps * where terminating a remote tty connection causes read() to 14160786Sps * start returning 0 forever, instead of -1. 14260786Sps */ 14360786Sps { 14460786Sps extern int ignore_eoi; 14560786Sps if (!ignore_eoi) 14660786Sps { 14760786Sps static int consecutive_nulls = 0; 14860786Sps if (n == 0) 14960786Sps consecutive_nulls++; 15060786Sps else 15160786Sps consecutive_nulls = 0; 15260786Sps if (consecutive_nulls > 20) 15360786Sps quit(QUIT_ERROR); 15460786Sps } 15560786Sps } 15660786Sps#endif 15760786Sps reading = 0; 15860786Sps if (n < 0) 15960786Sps return (-1); 16060786Sps return (n); 16160786Sps} 16260786Sps 16360786Sps/* 16460786Sps * Interrupt a pending iread(). 16560786Sps */ 16660786Sps public void 16760786Spsintread() 16860786Sps{ 16960786Sps LONG_JUMP(read_label, 1); 17060786Sps} 17160786Sps 17260786Sps/* 17360786Sps * Return the current time. 17460786Sps */ 17560786Sps#if HAVE_TIME 17660786Sps public long 17760786Spsget_time() 17860786Sps{ 17960786Sps time_type t; 18060786Sps 18160786Sps time(&t); 18260786Sps return (t); 18360786Sps} 18460786Sps#endif 18560786Sps 18660786Sps 18760786Sps#if !HAVE_STRERROR 18860786Sps/* 18960786Sps * Local version of strerror, if not available from the system. 19060786Sps */ 19160786Sps static char * 19260786Spsstrerror(err) 19360786Sps int err; 19460786Sps{ 19560786Sps#if HAVE_SYS_ERRLIST 19660786Sps static char buf[16]; 19760786Sps extern char *sys_errlist[]; 19860786Sps extern int sys_nerr; 19960786Sps 20060786Sps if (err < sys_nerr) 20160786Sps return sys_errlist[err]; 20260786Sps sprintf(buf, "Error %d", err); 20360786Sps return buf; 20460786Sps#else 20560786Sps return ("cannot open"); 20660786Sps#endif 20760786Sps} 20860786Sps#endif 20960786Sps 21060786Sps/* 21160786Sps * errno_message: Return an error message based on the value of "errno". 21260786Sps */ 21360786Sps public char * 21460786Spserrno_message(filename) 21560786Sps char *filename; 21660786Sps{ 21760786Sps register char *p; 21860786Sps register char *m; 21960786Sps#if HAVE_ERRNO 22060786Sps#if MUST_DEFINE_ERRNO 22160786Sps extern int errno; 22260786Sps#endif 22360786Sps p = strerror(errno); 22460786Sps#else 22560786Sps p = "cannot open"; 22660786Sps#endif 22760786Sps m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char)); 22860786Sps sprintf(m, "%s: %s", filename, p); 22960786Sps return (m); 23060786Sps} 23160786Sps 23260786Sps/* 23360786Sps * Return the ratio of two POSITIONS, as a percentage. 23460786Sps * {{ Assumes a POSITION is a long int. }} 23560786Sps */ 23660786Sps public int 23760786Spspercentage(num, den) 23860786Sps POSITION num, den; 23960786Sps{ 24089019Sps POSITION num100 = num * 100; 24189019Sps 24289019Sps if (num100 / 100 == num) 24389019Sps return (num100 / den); 24460786Sps else 24560786Sps return (num / (den / 100)); 24660786Sps} 24760786Sps 24860786Sps/* 24960786Sps * Return the specified percentage of a POSITION. 25060786Sps */ 25160786Sps public POSITION 25260786Spspercent_pos(pos, percent) 25360786Sps POSITION pos; 25460786Sps int percent; 25560786Sps{ 25689019Sps POSITION result100; 25789019Sps 25889019Sps if (percent == 0) 25989019Sps return (0); 26089019Sps else if ((result100 = pos * percent) / percent == pos) 26189019Sps return (result100 / 100); 26260786Sps else 26360786Sps return (percent * (pos / 100)); 26460786Sps} 26560786Sps 26689019Sps#if !HAVE_STRCHR 26789019Sps/* 26889019Sps * strchr is used by regexp.c. 26989019Sps */ 27089019Sps char * 27189019Spsstrchr(s, c) 27289019Sps char *s; 27389019Sps int c; 27489019Sps{ 27589019Sps for ( ; *s != '\0'; s++) 27689019Sps if (*s == c) 27789019Sps return (s); 27889019Sps if (c == '\0') 27989019Sps return (s); 28089019Sps return (NULL); 28189019Sps} 28289019Sps#endif 28389019Sps 28489019Sps#if !HAVE_MEMCPY 28589019Sps VOID_POINTER 28689019Spsmemcpy(dst, src, len) 28789019Sps VOID_POINTER dst; 28889019Sps VOID_POINTER src; 28989019Sps int len; 29089019Sps{ 29189019Sps char *dstp = (char *) dst; 29289019Sps char *srcp = (char *) src; 29389019Sps int i; 29489019Sps 29589019Sps for (i = 0; i < len; i++) 29689019Sps dstp[i] = srcp[i]; 29789019Sps return (dst); 29889019Sps} 29989019Sps#endif 30089019Sps 30160786Sps#ifdef _OSK_MWC32 30260786Sps 30360786Sps/* 30460786Sps * This implements an ANSI-style intercept setup for Microware C 3.2 30560786Sps */ 30660786Sps public int 30760786Spsos9_signal(type, handler) 30860786Sps int type; 30960786Sps RETSIGTYPE (*handler)(); 31060786Sps{ 31160786Sps intercept(handler); 31260786Sps} 31360786Sps 31460786Sps#include <sgstat.h> 31560786Sps 31689019Sps int 31760786Spsisatty(f) 31860786Sps int f; 31960786Sps{ 32060786Sps struct sgbuf sgbuf; 32160786Sps 32260786Sps if (_gs_opt(f, &sgbuf) < 0) 32360786Sps return -1; 32460786Sps return (sgbuf.sg_class == 0); 32560786Sps} 32660786Sps 32760786Sps#endif 328