os.c revision 161475
160786Sps/* 2161475Sdelphij * Copyright (C) 1984-2005 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; 219161475Sdelphij int len; 22060786Sps#if HAVE_ERRNO 22160786Sps#if MUST_DEFINE_ERRNO 22260786Sps extern int errno; 22360786Sps#endif 22460786Sps p = strerror(errno); 22560786Sps#else 22660786Sps p = "cannot open"; 22760786Sps#endif 228161475Sdelphij len = strlen(filename) + strlen(p) + 3; 229161475Sdelphij m = (char *) ecalloc(len, sizeof(char)); 230161475Sdelphij SNPRINTF2(m, len, "%s: %s", filename, p); 23160786Sps return (m); 23260786Sps} 23360786Sps 23460786Sps/* 23560786Sps * Return the ratio of two POSITIONS, as a percentage. 23660786Sps * {{ Assumes a POSITION is a long int. }} 23760786Sps */ 23860786Sps public int 23960786Spspercentage(num, den) 24060786Sps POSITION num, den; 24160786Sps{ 24289019Sps POSITION num100 = num * 100; 24389019Sps 24489019Sps if (num100 / 100 == num) 24589019Sps return (num100 / den); 24660786Sps else 24760786Sps return (num / (den / 100)); 24860786Sps} 24960786Sps 25060786Sps/* 25160786Sps * Return the specified percentage of a POSITION. 25260786Sps */ 25360786Sps public POSITION 25460786Spspercent_pos(pos, percent) 25560786Sps POSITION pos; 25660786Sps int percent; 25760786Sps{ 25889019Sps POSITION result100; 25989019Sps 26089019Sps if (percent == 0) 26189019Sps return (0); 26289019Sps else if ((result100 = pos * percent) / percent == pos) 26389019Sps return (result100 / 100); 26460786Sps else 26560786Sps return (percent * (pos / 100)); 26660786Sps} 26760786Sps 26889019Sps#if !HAVE_STRCHR 26989019Sps/* 27089019Sps * strchr is used by regexp.c. 27189019Sps */ 27289019Sps char * 27389019Spsstrchr(s, c) 27489019Sps char *s; 27589019Sps int c; 27689019Sps{ 27789019Sps for ( ; *s != '\0'; s++) 27889019Sps if (*s == c) 27989019Sps return (s); 28089019Sps if (c == '\0') 28189019Sps return (s); 28289019Sps return (NULL); 28389019Sps} 28489019Sps#endif 28589019Sps 28689019Sps#if !HAVE_MEMCPY 28789019Sps VOID_POINTER 28889019Spsmemcpy(dst, src, len) 28989019Sps VOID_POINTER dst; 29089019Sps VOID_POINTER src; 29189019Sps int len; 29289019Sps{ 29389019Sps char *dstp = (char *) dst; 29489019Sps char *srcp = (char *) src; 29589019Sps int i; 29689019Sps 29789019Sps for (i = 0; i < len; i++) 29889019Sps dstp[i] = srcp[i]; 29989019Sps return (dst); 30089019Sps} 30189019Sps#endif 30289019Sps 30360786Sps#ifdef _OSK_MWC32 30460786Sps 30560786Sps/* 30660786Sps * This implements an ANSI-style intercept setup for Microware C 3.2 30760786Sps */ 30860786Sps public int 30960786Spsos9_signal(type, handler) 31060786Sps int type; 31160786Sps RETSIGTYPE (*handler)(); 31260786Sps{ 31360786Sps intercept(handler); 31460786Sps} 31560786Sps 31660786Sps#include <sgstat.h> 31760786Sps 31889019Sps int 31960786Spsisatty(f) 32060786Sps int f; 32160786Sps{ 32260786Sps struct sgbuf sgbuf; 32360786Sps 32460786Sps if (_gs_opt(f, &sgbuf) < 0) 32560786Sps return -1; 32660786Sps return (sgbuf.sg_class == 0); 32760786Sps} 32860786Sps 32960786Sps#endif 330