os.c revision 161475
113244Sgraichen/* 213244Sgraichen * Copyright (C) 1984-2005 Mark Nudelman 313244Sgraichen * 413244Sgraichen * You may distribute under the terms of either the GNU General Public 513244Sgraichen * License or the Less License, as specified in the README file. 613244Sgraichen * 713244Sgraichen * For more information about less, or for information on how to 813244Sgraichen * contact the author, see the README file. 913244Sgraichen */ 1013244Sgraichen 1113244Sgraichen 1213244Sgraichen/* 1313244Sgraichen * Operating system dependent routines. 1413244Sgraichen * 1513244Sgraichen * Most of the stuff in here is based on Unix, but an attempt 1613244Sgraichen * has been made to make things work on other operating systems. 1713244Sgraichen * This will sometimes result in a loss of functionality, unless 1813244Sgraichen * someone rewrites code specifically for the new operating system. 1913244Sgraichen * 2013244Sgraichen * The makefile provides defines to decide whether various 2113244Sgraichen * Unix features are present. 2213244Sgraichen */ 2313244Sgraichen 2413244Sgraichen#include "less.h" 2513244Sgraichen#include <signal.h> 2613244Sgraichen#include <setjmp.h> 2713244Sgraichen#if HAVE_TIME_H 2813244Sgraichen#include <time.h> 2930160Scharnier#endif 3036817Sache#if HAVE_ERRNO_H 3113244Sgraichen#include <errno.h> 3213244Sgraichen#endif 3313244Sgraichen#if HAVE_VALUES_H 3413244Sgraichen#include <values.h> 3513244Sgraichen#endif 3613244Sgraichen 3713244Sgraichen#if HAVE_TIME_T 3813244Sgraichen#define time_type time_t 3913460Sgraichen#else 4013460Sgraichen#define time_type long 4113244Sgraichen#endif 4213460Sgraichen 4313460Sgraichen/* 4413460Sgraichen * BSD setjmp() saves (and longjmp() restores) the signal mask. 4513244Sgraichen * This costs a system call or two per setjmp(), so if possible we clear the 4613244Sgraichen * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 4713244Sgraichen * On other systems, setjmp() doesn't affect the signal mask and so 4813244Sgraichen * _setjmp() does not exist; we just use setjmp(). 4930160Scharnier */ 5030160Scharnier#if HAVE__SETJMP && HAVE_SIGSETMASK 5130160Scharnier#define SET_JUMP _setjmp 5230160Scharnier#define LONG_JUMP _longjmp 5330160Scharnier#else 5430160Scharnier#define SET_JUMP setjmp 5513244Sgraichen#define LONG_JUMP longjmp 5613244Sgraichen#endif 5713244Sgraichen 5816240Salexpublic int reading; 5913244Sgraichen 6013244Sgraichenstatic jmp_buf read_label; 6113244Sgraichen 6213244Sgraichenextern int sigs; 6313244Sgraichen 6413244Sgraichen/* 6513244Sgraichen * Like read() system call, but is deliberately interruptible. 6613244Sgraichen * A call to intread() from a signal handler will interrupt 6713244Sgraichen * any pending iread(). 6813244Sgraichen */ 6913244Sgraichen public int 7013244Sgraicheniread(fd, buf, len) 7113244Sgraichen int fd; 7213460Sgraichen char *buf; 7313244Sgraichen unsigned int len; 7413244Sgraichen{ 7513244Sgraichen register int n; 7613244Sgraichen 7713244Sgraichen#if MSDOS_COMPILER==WIN32C 7825443Sache if (ABORT_SIGS()) 7913244Sgraichen return (READ_INTR); 8013244Sgraichen#else 8113244Sgraichen#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 8213244Sgraichen if (kbhit()) 8313244Sgraichen { 8413244Sgraichen int c; 8513244Sgraichen 8636817Sache c = getch(); 8713244Sgraichen if (c == '\003') 8813244Sgraichen return (READ_INTR); 8913244Sgraichen ungetch(c); 9013244Sgraichen } 9113244Sgraichen#endif 9213244Sgraichen#endif 9335915Shoek if (SET_JUMP(read_label)) 9413244Sgraichen { 9513244Sgraichen /* 9625443Sache * We jumped here from intread. 9713460Sgraichen */ 9813460Sgraichen reading = 0; 9913244Sgraichen#if HAVE_SIGPROCMASK 10013244Sgraichen { 10116240Salex sigset_t mask; 10216240Salex sigemptyset(&mask); 10316240Salex sigprocmask(SIG_SETMASK, &mask, NULL); 10413244Sgraichen } 10516240Salex#else 10616240Salex#if HAVE_SIGSETMASK 10716240Salex sigsetmask(0); 10816240Salex#else 10916240Salex#ifdef _OSK 11016240Salex sigmask(~0); 11116240Salex#endif 11236817Sache#endif 11316240Salex#endif 11416240Salex return (READ_INTR); 11516240Salex } 11616240Salex 11725443Sache flush(); 11813244Sgraichen reading = 1; 11916240Salex#if MSDOS_COMPILER==DJGPPC 12013244Sgraichen if (isatty(fd)) 12113244Sgraichen { 12213244Sgraichen /* 12313244Sgraichen * Don't try reading from a TTY until a character is 12413244Sgraichen * available, because that makes some background programs 12513244Sgraichen * believe DOS is busy in a way that prevents those 12630160Scharnier * programs from working while "less" waits. 12730160Scharnier */ 12813244Sgraichen fd_set readfds; 12925443Sache 13013244Sgraichen FD_ZERO(&readfds); 13113244Sgraichen FD_SET(fd, &readfds); 13213244Sgraichen if (select(fd+1, &readfds, 0, 0, 0) == -1) 13313244Sgraichen return (-1); 13413244Sgraichen } 13513244Sgraichen#endif 13616240Salex n = read(fd, buf, len); 13713244Sgraichen#if 1 13813244Sgraichen /* 13916240Salex * This is a kludge to workaround a problem on some systems 14013244Sgraichen * where terminating a remote tty connection causes read() to 14113244Sgraichen * start returning 0 forever, instead of -1. 14213244Sgraichen */ 14313244Sgraichen { 14435920Shoek extern int ignore_eoi; 14513244Sgraichen if (!ignore_eoi) 14613244Sgraichen { 14713244Sgraichen static int consecutive_nulls = 0; 14813244Sgraichen if (n == 0) 14913244Sgraichen consecutive_nulls++; 15013244Sgraichen else 15113244Sgraichen consecutive_nulls = 0; 15213244Sgraichen if (consecutive_nulls > 20) 15313244Sgraichen quit(QUIT_ERROR); 15413244Sgraichen } 15513244Sgraichen } 15613244Sgraichen#endif 15713244Sgraichen reading = 0; 15813244Sgraichen if (n < 0) 15913244Sgraichen return (-1); 16013244Sgraichen return (n); 16113244Sgraichen} 16234584Spst 16313244Sgraichen/* 16413244Sgraichen * Interrupt a pending iread(). 16513244Sgraichen */ 16613244Sgraichen public void 16713244Sgraichenintread() 16813244Sgraichen{ 16935920Shoek LONG_JUMP(read_label, 1); 17013244Sgraichen} 17113244Sgraichen 17235920Shoek/* 17313244Sgraichen * Return the current time. 17413244Sgraichen */ 17535920Shoek#if HAVE_TIME 17635920Shoek public long 17735920Shoekget_time() 17835920Shoek{ 17935920Shoek time_type t; 18035920Shoek 18135920Shoek time(&t); 18235920Shoek return (t); 18335920Shoek} 18435920Shoek#endif 18536817Sache 18613244Sgraichen 18713244Sgraichen#if !HAVE_STRERROR 18813244Sgraichen/* 18913244Sgraichen * Local version of strerror, if not available from the system. 19013244Sgraichen */ 19113244Sgraichen static char * 19213244Sgraichenstrerror(err) 19316240Salex int err; 19413244Sgraichen{ 19513244Sgraichen#if HAVE_SYS_ERRLIST 19613244Sgraichen static char buf[16]; 19713244Sgraichen extern char *sys_errlist[]; 19813244Sgraichen extern int sys_nerr; 19913244Sgraichen 20013244Sgraichen if (err < sys_nerr) 20113244Sgraichen return sys_errlist[err]; 20213358Sgraichen sprintf(buf, "Error %d", err); 20313244Sgraichen return buf; 20413244Sgraichen#else 20513244Sgraichen return ("cannot open"); 20613244Sgraichen#endif 20713244Sgraichen} 20816240Salex#endif 20913244Sgraichen 21013244Sgraichen/* 21113244Sgraichen * errno_message: Return an error message based on the value of "errno". 21213244Sgraichen */ 21334584Spst public char * 21413244Sgraichenerrno_message(filename) 21513244Sgraichen char *filename; 21635920Shoek{ 21735920Shoek register char *p; 21813244Sgraichen register char *m; 21913244Sgraichen int len; 22013244Sgraichen#if HAVE_ERRNO 22113244Sgraichen#if MUST_DEFINE_ERRNO 22213244Sgraichen extern int errno; 22313244Sgraichen#endif 22413244Sgraichen p = strerror(errno); 22513244Sgraichen#else 22613244Sgraichen p = "cannot open"; 22734584Spst#endif 22834584Spst len = strlen(filename) + strlen(p) + 3; 22934584Spst m = (char *) ecalloc(len, sizeof(char)); 23013244Sgraichen SNPRINTF2(m, len, "%s: %s", filename, p); 23113244Sgraichen return (m); 23213244Sgraichen} 23313244Sgraichen 23413244Sgraichen/* 23516240Salex * Return the ratio of two POSITIONS, as a percentage. 23613244Sgraichen * {{ Assumes a POSITION is a long int. }} 23735917Shoek */ 23813244Sgraichen public int 23913244Sgraichenpercentage(num, den) 24013244Sgraichen POSITION num, den; 24113244Sgraichen{ 24213244Sgraichen POSITION num100 = num * 100; 24313244Sgraichen 24416240Salex if (num100 / 100 == num) 24513244Sgraichen return (num100 / den); 24613244Sgraichen else 24713244Sgraichen return (num / (den / 100)); 24813244Sgraichen} 24913244Sgraichen 25016174Salex/* 25113244Sgraichen * Return the specified percentage of a POSITION. 25213244Sgraichen */ 25325518Sbrian public POSITION 25413244Sgraichenpercent_pos(pos, percent) 25513244Sgraichen POSITION pos; 25613244Sgraichen int percent; 25713244Sgraichen{ 25813244Sgraichen POSITION result100; 25913460Sgraichen 26013460Sgraichen if (percent == 0) 26113244Sgraichen return (0); 26213244Sgraichen else if ((result100 = pos * percent) / percent == pos) 26313244Sgraichen return (result100 / 100); 26413244Sgraichen else 26513244Sgraichen return (percent * (pos / 100)); 26613244Sgraichen} 26713244Sgraichen 26813244Sgraichen#if !HAVE_STRCHR 26913244Sgraichen/* 27013244Sgraichen * strchr is used by regexp.c. 27113244Sgraichen */ 27213244Sgraichen char * 27313244Sgraichenstrchr(s, c) 27425518Sbrian char *s; 27525518Sbrian int c; 27630160Scharnier{ 27725518Sbrian for ( ; *s != '\0'; s++) 27813244Sgraichen if (*s == c) 27913244Sgraichen return (s); 28013244Sgraichen if (c == '\0') 28125518Sbrian return (s); 28225518Sbrian return (NULL); 28330160Scharnier} 28425518Sbrian#endif 28513244Sgraichen 28613244Sgraichen#if !HAVE_MEMCPY 28713244Sgraichen VOID_POINTER 28813244Sgraichenmemcpy(dst, src, len) 28913460Sgraichen VOID_POINTER dst; 29013460Sgraichen VOID_POINTER src; 29130160Scharnier int len; 29213460Sgraichen{ 29313244Sgraichen char *dstp = (char *) dst; 29413244Sgraichen char *srcp = (char *) src; 29513244Sgraichen int i; 29613244Sgraichen 29713244Sgraichen for (i = 0; i < len; i++) 29813244Sgraichen dstp[i] = srcp[i]; 29913244Sgraichen return (dst); 30013244Sgraichen} 30113244Sgraichen#endif 30213460Sgraichen 30313460Sgraichen#ifdef _OSK_MWC32 30430160Scharnier 30513460Sgraichen/* 30613244Sgraichen * This implements an ANSI-style intercept setup for Microware C 3.2 30713244Sgraichen */ 30813244Sgraichen public int 30913244Sgraichenos9_signal(type, handler) 31013244Sgraichen int type; 31113244Sgraichen RETSIGTYPE (*handler)(); 31213244Sgraichen{ 31325518Sbrian intercept(handler); 31425518Sbrian} 31530160Scharnier 31625518Sbrian#include <sgstat.h> 31713244Sgraichen 31813244Sgraichen int 31913244Sgraichenisatty(f) 32013244Sgraichen int f; 32113460Sgraichen{ 32230160Scharnier struct sgbuf sgbuf; 32313460Sgraichen 32413244Sgraichen if (_gs_opt(f, &sgbuf) < 0) 32513244Sgraichen return -1; 32625518Sbrian return (sgbuf.sg_class == 0); 32725518Sbrian} 32830160Scharnier 32925518Sbrian#endif 33013460Sgraichen