os.c revision 170256
160786Sps/* 2170256Sdelphij * Copyright (C) 1984-2007 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 77170256Sdelphijstart: 7860786Sps#if MSDOS_COMPILER==WIN32C 7960786Sps if (ABORT_SIGS()) 8060786Sps return (READ_INTR); 8160786Sps#else 8260786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 8360786Sps if (kbhit()) 8460786Sps { 8560786Sps int c; 8660786Sps 8760786Sps c = getch(); 8860786Sps if (c == '\003') 8960786Sps return (READ_INTR); 9060786Sps ungetch(c); 9160786Sps } 9260786Sps#endif 9360786Sps#endif 9460786Sps if (SET_JUMP(read_label)) 9560786Sps { 9660786Sps /* 9760786Sps * We jumped here from intread. 9860786Sps */ 9960786Sps reading = 0; 10063128Sps#if HAVE_SIGPROCMASK 10163128Sps { 10263128Sps sigset_t mask; 10363128Sps sigemptyset(&mask); 10463128Sps sigprocmask(SIG_SETMASK, &mask, NULL); 10563128Sps } 10663128Sps#else 10760786Sps#if HAVE_SIGSETMASK 10860786Sps sigsetmask(0); 10960786Sps#else 11060786Sps#ifdef _OSK 11160786Sps sigmask(~0); 11260786Sps#endif 11360786Sps#endif 11463128Sps#endif 11560786Sps return (READ_INTR); 11660786Sps } 11760786Sps 11860786Sps flush(); 11960786Sps reading = 1; 12060786Sps#if MSDOS_COMPILER==DJGPPC 12160786Sps if (isatty(fd)) 12260786Sps { 12360786Sps /* 12460786Sps * Don't try reading from a TTY until a character is 12560786Sps * available, because that makes some background programs 12660786Sps * believe DOS is busy in a way that prevents those 12760786Sps * programs from working while "less" waits. 12860786Sps */ 12960786Sps fd_set readfds; 13060786Sps 13160786Sps FD_ZERO(&readfds); 13260786Sps FD_SET(fd, &readfds); 13360786Sps if (select(fd+1, &readfds, 0, 0, 0) == -1) 13460786Sps return (-1); 13560786Sps } 13660786Sps#endif 13760786Sps n = read(fd, buf, len); 13860786Sps#if 1 13960786Sps /* 14060786Sps * This is a kludge to workaround a problem on some systems 14160786Sps * where terminating a remote tty connection causes read() to 14260786Sps * start returning 0 forever, instead of -1. 14360786Sps */ 14460786Sps { 14560786Sps extern int ignore_eoi; 14660786Sps if (!ignore_eoi) 14760786Sps { 14860786Sps static int consecutive_nulls = 0; 14960786Sps if (n == 0) 15060786Sps consecutive_nulls++; 15160786Sps else 15260786Sps consecutive_nulls = 0; 15360786Sps if (consecutive_nulls > 20) 15460786Sps quit(QUIT_ERROR); 15560786Sps } 15660786Sps } 15760786Sps#endif 15860786Sps reading = 0; 15960786Sps if (n < 0) 160170256Sdelphij { 161170256Sdelphij#if HAVE_ERRNO 162170256Sdelphij /* 163170256Sdelphij * Certain values of errno indicate we should just retry the read. 164170256Sdelphij */ 165170256Sdelphij#if MUST_DEFINE_ERRNO 166170256Sdelphij extern int errno; 167170256Sdelphij#endif 168170256Sdelphij#ifdef EINTR 169170256Sdelphij if (errno == EINTR) 170170256Sdelphij goto start; 171170256Sdelphij#endif 172170256Sdelphij#ifdef EAGAIN 173170256Sdelphij if (errno == EAGAIN) 174170256Sdelphij goto start; 175170256Sdelphij#endif 176170256Sdelphij#endif 17760786Sps return (-1); 178170256Sdelphij } 17960786Sps return (n); 18060786Sps} 18160786Sps 18260786Sps/* 18360786Sps * Interrupt a pending iread(). 18460786Sps */ 18560786Sps public void 18660786Spsintread() 18760786Sps{ 18860786Sps LONG_JUMP(read_label, 1); 18960786Sps} 19060786Sps 19160786Sps/* 19260786Sps * Return the current time. 19360786Sps */ 19460786Sps#if HAVE_TIME 19560786Sps public long 19660786Spsget_time() 19760786Sps{ 19860786Sps time_type t; 19960786Sps 20060786Sps time(&t); 20160786Sps return (t); 20260786Sps} 20360786Sps#endif 20460786Sps 20560786Sps 20660786Sps#if !HAVE_STRERROR 20760786Sps/* 20860786Sps * Local version of strerror, if not available from the system. 20960786Sps */ 21060786Sps static char * 21160786Spsstrerror(err) 21260786Sps int err; 21360786Sps{ 21460786Sps#if HAVE_SYS_ERRLIST 21560786Sps static char buf[16]; 21660786Sps extern char *sys_errlist[]; 21760786Sps extern int sys_nerr; 21860786Sps 21960786Sps if (err < sys_nerr) 22060786Sps return sys_errlist[err]; 22160786Sps sprintf(buf, "Error %d", err); 22260786Sps return buf; 22360786Sps#else 22460786Sps return ("cannot open"); 22560786Sps#endif 22660786Sps} 22760786Sps#endif 22860786Sps 22960786Sps/* 23060786Sps * errno_message: Return an error message based on the value of "errno". 23160786Sps */ 23260786Sps public char * 23360786Spserrno_message(filename) 23460786Sps char *filename; 23560786Sps{ 23660786Sps register char *p; 23760786Sps register char *m; 238161475Sdelphij int len; 23960786Sps#if HAVE_ERRNO 24060786Sps#if MUST_DEFINE_ERRNO 24160786Sps extern int errno; 24260786Sps#endif 24360786Sps p = strerror(errno); 24460786Sps#else 24560786Sps p = "cannot open"; 24660786Sps#endif 247161475Sdelphij len = strlen(filename) + strlen(p) + 3; 248161475Sdelphij m = (char *) ecalloc(len, sizeof(char)); 249161475Sdelphij SNPRINTF2(m, len, "%s: %s", filename, p); 25060786Sps return (m); 25160786Sps} 25260786Sps 25360786Sps/* 25460786Sps * Return the ratio of two POSITIONS, as a percentage. 25560786Sps * {{ Assumes a POSITION is a long int. }} 25660786Sps */ 25760786Sps public int 25860786Spspercentage(num, den) 25960786Sps POSITION num, den; 26060786Sps{ 26189019Sps POSITION num100 = num * 100; 26289019Sps 26389019Sps if (num100 / 100 == num) 26489019Sps return (num100 / den); 26560786Sps else 26660786Sps return (num / (den / 100)); 26760786Sps} 26860786Sps 26960786Sps/* 27060786Sps * Return the specified percentage of a POSITION. 27160786Sps */ 27260786Sps public POSITION 273170256Sdelphijpercent_pos(pos, percent, fraction) 27460786Sps POSITION pos; 27560786Sps int percent; 276170256Sdelphij long fraction; 27760786Sps{ 278170256Sdelphij /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 279170256Sdelphij long perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 280170256Sdelphij POSITION temp; 28189019Sps 282170256Sdelphij if (perden == 0) 28389019Sps return (0); 284170256Sdelphij temp = pos * perden; /* This might overflow. */ 285170256Sdelphij if (temp / perden == pos) 286170256Sdelphij /* No overflow */ 287170256Sdelphij return (temp / NUM_FRAC_DENOM); 28860786Sps else 289170256Sdelphij /* Above calculation overflows; 290170256Sdelphij * use a method that is less precise but won't overflow. */ 291170256Sdelphij return (perden * (pos / NUM_FRAC_DENOM)); 29260786Sps} 29360786Sps 29489019Sps#if !HAVE_STRCHR 29589019Sps/* 29689019Sps * strchr is used by regexp.c. 29789019Sps */ 29889019Sps char * 29989019Spsstrchr(s, c) 30089019Sps char *s; 30189019Sps int c; 30289019Sps{ 30389019Sps for ( ; *s != '\0'; s++) 30489019Sps if (*s == c) 30589019Sps return (s); 30689019Sps if (c == '\0') 30789019Sps return (s); 30889019Sps return (NULL); 30989019Sps} 31089019Sps#endif 31189019Sps 31289019Sps#if !HAVE_MEMCPY 31389019Sps VOID_POINTER 31489019Spsmemcpy(dst, src, len) 31589019Sps VOID_POINTER dst; 31689019Sps VOID_POINTER src; 31789019Sps int len; 31889019Sps{ 31989019Sps char *dstp = (char *) dst; 32089019Sps char *srcp = (char *) src; 32189019Sps int i; 32289019Sps 32389019Sps for (i = 0; i < len; i++) 32489019Sps dstp[i] = srcp[i]; 32589019Sps return (dst); 32689019Sps} 32789019Sps#endif 32889019Sps 32960786Sps#ifdef _OSK_MWC32 33060786Sps 33160786Sps/* 33260786Sps * This implements an ANSI-style intercept setup for Microware C 3.2 33360786Sps */ 33460786Sps public int 33560786Spsos9_signal(type, handler) 33660786Sps int type; 33760786Sps RETSIGTYPE (*handler)(); 33860786Sps{ 33960786Sps intercept(handler); 34060786Sps} 34160786Sps 34260786Sps#include <sgstat.h> 34360786Sps 34489019Sps int 34560786Spsisatty(f) 34660786Sps int f; 34760786Sps{ 34860786Sps struct sgbuf sgbuf; 34960786Sps 35060786Sps if (_gs_opt(f, &sgbuf) < 0) 35160786Sps return -1; 35260786Sps return (sgbuf.sg_class == 0); 35360786Sps} 35460786Sps 35560786Sps#endif 356