os.c revision 355504
1238730Sdelphij/* 2355504Sdelphij * Copyright (C) 1984-2019 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * Operating system dependent routines. 1360786Sps * 1460786Sps * Most of the stuff in here is based on Unix, but an attempt 1560786Sps * has been made to make things work on other operating systems. 1660786Sps * This will sometimes result in a loss of functionality, unless 1760786Sps * someone rewrites code specifically for the new operating system. 1860786Sps * 1960786Sps * The makefile provides defines to decide whether various 2060786Sps * Unix features are present. 2160786Sps */ 2260786Sps 2360786Sps#include "less.h" 2460786Sps#include <signal.h> 2560786Sps#include <setjmp.h> 2660786Sps#if HAVE_TIME_H 2760786Sps#include <time.h> 2860786Sps#endif 2960786Sps#if HAVE_ERRNO_H 3060786Sps#include <errno.h> 3160786Sps#endif 3260786Sps#if HAVE_VALUES_H 3360786Sps#include <values.h> 3460786Sps#endif 3560786Sps 3660786Sps/* 3760786Sps * BSD setjmp() saves (and longjmp() restores) the signal mask. 3860786Sps * This costs a system call or two per setjmp(), so if possible we clear the 3960786Sps * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 4060786Sps * On other systems, setjmp() doesn't affect the signal mask and so 4160786Sps * _setjmp() does not exist; we just use setjmp(). 4260786Sps */ 4360786Sps#if HAVE__SETJMP && HAVE_SIGSETMASK 4460786Sps#define SET_JUMP _setjmp 4560786Sps#define LONG_JUMP _longjmp 4660786Sps#else 4760786Sps#define SET_JUMP setjmp 4860786Sps#define LONG_JUMP longjmp 4960786Sps#endif 5060786Sps 5160786Spspublic int reading; 5260786Sps 5360786Spsstatic jmp_buf read_label; 5460786Sps 5560786Spsextern int sigs; 5660786Sps 5760786Sps/* 5860786Sps * Like read() system call, but is deliberately interruptible. 5960786Sps * A call to intread() from a signal handler will interrupt 6060786Sps * any pending iread(). 6160786Sps */ 6260786Sps public int 6360786Spsiread(fd, buf, len) 6460786Sps int fd; 65330570Sdelphij unsigned char *buf; 6660786Sps unsigned int len; 6760786Sps{ 68330570Sdelphij int n; 6960786Sps 70170256Sdelphijstart: 7160786Sps#if MSDOS_COMPILER==WIN32C 7260786Sps if (ABORT_SIGS()) 7360786Sps return (READ_INTR); 7460786Sps#else 7560786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 7660786Sps if (kbhit()) 7760786Sps { 7860786Sps int c; 7960786Sps 8060786Sps c = getch(); 8160786Sps if (c == '\003') 8260786Sps return (READ_INTR); 8360786Sps ungetch(c); 8460786Sps } 8560786Sps#endif 8660786Sps#endif 8760786Sps if (SET_JUMP(read_label)) 8860786Sps { 8960786Sps /* 9060786Sps * We jumped here from intread. 9160786Sps */ 9260786Sps reading = 0; 9363128Sps#if HAVE_SIGPROCMASK 9463128Sps { 9563128Sps sigset_t mask; 9663128Sps sigemptyset(&mask); 9763128Sps sigprocmask(SIG_SETMASK, &mask, NULL); 9863128Sps } 9963128Sps#else 10060786Sps#if HAVE_SIGSETMASK 10160786Sps sigsetmask(0); 10260786Sps#else 10360786Sps#ifdef _OSK 10460786Sps sigmask(~0); 10560786Sps#endif 10660786Sps#endif 10763128Sps#endif 10860786Sps return (READ_INTR); 10960786Sps } 11060786Sps 11160786Sps flush(); 11260786Sps reading = 1; 11360786Sps#if MSDOS_COMPILER==DJGPPC 11460786Sps if (isatty(fd)) 11560786Sps { 11660786Sps /* 11760786Sps * Don't try reading from a TTY until a character is 11860786Sps * available, because that makes some background programs 11960786Sps * believe DOS is busy in a way that prevents those 12060786Sps * programs from working while "less" waits. 12160786Sps */ 12260786Sps fd_set readfds; 12360786Sps 12460786Sps FD_ZERO(&readfds); 12560786Sps FD_SET(fd, &readfds); 12660786Sps if (select(fd+1, &readfds, 0, 0, 0) == -1) 12760786Sps return (-1); 12860786Sps } 12960786Sps#endif 13060786Sps n = read(fd, buf, len); 13160786Sps#if 1 13260786Sps /* 13360786Sps * This is a kludge to workaround a problem on some systems 13460786Sps * where terminating a remote tty connection causes read() to 13560786Sps * start returning 0 forever, instead of -1. 13660786Sps */ 13760786Sps { 13860786Sps extern int ignore_eoi; 13960786Sps if (!ignore_eoi) 14060786Sps { 14160786Sps static int consecutive_nulls = 0; 14260786Sps if (n == 0) 14360786Sps consecutive_nulls++; 14460786Sps else 14560786Sps consecutive_nulls = 0; 14660786Sps if (consecutive_nulls > 20) 14760786Sps quit(QUIT_ERROR); 14860786Sps } 14960786Sps } 15060786Sps#endif 15160786Sps reading = 0; 15260786Sps if (n < 0) 153170256Sdelphij { 154170256Sdelphij#if HAVE_ERRNO 155170256Sdelphij /* 156170256Sdelphij * Certain values of errno indicate we should just retry the read. 157170256Sdelphij */ 158170256Sdelphij#if MUST_DEFINE_ERRNO 159170256Sdelphij extern int errno; 160170256Sdelphij#endif 161170256Sdelphij#ifdef EINTR 162170256Sdelphij if (errno == EINTR) 163170256Sdelphij goto start; 164170256Sdelphij#endif 165170256Sdelphij#ifdef EAGAIN 166170256Sdelphij if (errno == EAGAIN) 167170256Sdelphij goto start; 168170256Sdelphij#endif 169170256Sdelphij#endif 17060786Sps return (-1); 171170256Sdelphij } 17260786Sps return (n); 17360786Sps} 17460786Sps 17560786Sps/* 17660786Sps * Interrupt a pending iread(). 17760786Sps */ 17860786Sps public void 179355504Sdelphijintread(VOID_PARAM) 18060786Sps{ 18160786Sps LONG_JUMP(read_label, 1); 18260786Sps} 18360786Sps 18460786Sps/* 18560786Sps * Return the current time. 18660786Sps */ 18760786Sps#if HAVE_TIME 188293190Sdelphij public time_type 189355504Sdelphijget_time(VOID_PARAM) 19060786Sps{ 19160786Sps time_type t; 19260786Sps 19360786Sps time(&t); 19460786Sps return (t); 19560786Sps} 19660786Sps#endif 19760786Sps 19860786Sps 19960786Sps#if !HAVE_STRERROR 20060786Sps/* 20160786Sps * Local version of strerror, if not available from the system. 20260786Sps */ 20360786Sps static char * 20460786Spsstrerror(err) 20560786Sps int err; 20660786Sps{ 20760786Sps#if HAVE_SYS_ERRLIST 20860786Sps static char buf[16]; 20960786Sps extern char *sys_errlist[]; 21060786Sps extern int sys_nerr; 21160786Sps 21260786Sps if (err < sys_nerr) 21360786Sps return sys_errlist[err]; 21460786Sps sprintf(buf, "Error %d", err); 21560786Sps return buf; 21660786Sps#else 21760786Sps return ("cannot open"); 21860786Sps#endif 21960786Sps} 22060786Sps#endif 22160786Sps 22260786Sps/* 22360786Sps * errno_message: Return an error message based on the value of "errno". 22460786Sps */ 22560786Sps public char * 22660786Spserrno_message(filename) 22760786Sps char *filename; 22860786Sps{ 229330570Sdelphij char *p; 230330570Sdelphij char *m; 231161475Sdelphij int len; 23260786Sps#if HAVE_ERRNO 23360786Sps#if MUST_DEFINE_ERRNO 23460786Sps extern int errno; 23560786Sps#endif 23660786Sps p = strerror(errno); 23760786Sps#else 23860786Sps p = "cannot open"; 23960786Sps#endif 240293190Sdelphij len = (int) (strlen(filename) + strlen(p) + 3); 241161475Sdelphij m = (char *) ecalloc(len, sizeof(char)); 242161475Sdelphij SNPRINTF2(m, len, "%s: %s", filename, p); 24360786Sps return (m); 24460786Sps} 24560786Sps 246221715Sdelphij/* #define HAVE_FLOAT 0 */ 247221715Sdelphij 248221715Sdelphij static POSITION 249221715Sdelphijmuldiv(val, num, den) 250221715Sdelphij POSITION val, num, den; 251221715Sdelphij{ 252221715Sdelphij#if HAVE_FLOAT 253221715Sdelphij double v = (((double) val) * num) / den; 254221715Sdelphij return ((POSITION) (v + 0.5)); 255221715Sdelphij#else 256221715Sdelphij POSITION v = ((POSITION) val) * num; 257221715Sdelphij 258221715Sdelphij if (v / num == val) 259221715Sdelphij /* No overflow */ 260221715Sdelphij return (POSITION) (v / den); 261221715Sdelphij else 262221715Sdelphij /* Above calculation overflows; 263221715Sdelphij * use a method that is less precise but won't overflow. */ 264221715Sdelphij return (POSITION) (val / (den / num)); 265221715Sdelphij#endif 266221715Sdelphij} 267221715Sdelphij 26860786Sps/* 26960786Sps * Return the ratio of two POSITIONS, as a percentage. 27060786Sps * {{ Assumes a POSITION is a long int. }} 27160786Sps */ 27260786Sps public int 27360786Spspercentage(num, den) 274330570Sdelphij POSITION num; 275330570Sdelphij POSITION den; 27660786Sps{ 277221715Sdelphij return (int) muldiv(num, (POSITION) 100, den); 27860786Sps} 27960786Sps 28060786Sps/* 28160786Sps * Return the specified percentage of a POSITION. 28260786Sps */ 28360786Sps public POSITION 284170256Sdelphijpercent_pos(pos, percent, fraction) 28560786Sps POSITION pos; 28660786Sps int percent; 287170256Sdelphij long fraction; 28860786Sps{ 289170256Sdelphij /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 290221715Sdelphij POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 29189019Sps 292170256Sdelphij if (perden == 0) 29389019Sps return (0); 294221715Sdelphij return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); 29560786Sps} 29660786Sps 29789019Sps#if !HAVE_STRCHR 29889019Sps/* 29989019Sps * strchr is used by regexp.c. 30089019Sps */ 30189019Sps char * 30289019Spsstrchr(s, c) 30389019Sps char *s; 30489019Sps int c; 30589019Sps{ 30689019Sps for ( ; *s != '\0'; s++) 30789019Sps if (*s == c) 30889019Sps return (s); 30989019Sps if (c == '\0') 31089019Sps return (s); 31189019Sps return (NULL); 31289019Sps} 31389019Sps#endif 31489019Sps 31589019Sps#if !HAVE_MEMCPY 31689019Sps VOID_POINTER 31789019Spsmemcpy(dst, src, len) 31889019Sps VOID_POINTER dst; 31989019Sps VOID_POINTER src; 32089019Sps int len; 32189019Sps{ 32289019Sps char *dstp = (char *) dst; 32389019Sps char *srcp = (char *) src; 32489019Sps int i; 32589019Sps 32689019Sps for (i = 0; i < len; i++) 32789019Sps dstp[i] = srcp[i]; 32889019Sps return (dst); 32989019Sps} 33089019Sps#endif 33189019Sps 33260786Sps#ifdef _OSK_MWC32 33360786Sps 33460786Sps/* 33560786Sps * This implements an ANSI-style intercept setup for Microware C 3.2 33660786Sps */ 33760786Sps public int 33860786Spsos9_signal(type, handler) 33960786Sps int type; 34060786Sps RETSIGTYPE (*handler)(); 34160786Sps{ 34260786Sps intercept(handler); 34360786Sps} 34460786Sps 34560786Sps#include <sgstat.h> 34660786Sps 34789019Sps int 34860786Spsisatty(f) 34960786Sps int f; 35060786Sps{ 35160786Sps struct sgbuf sgbuf; 35260786Sps 35360786Sps if (_gs_opt(f, &sgbuf) < 0) 35460786Sps return -1; 35560786Sps return (sgbuf.sg_class == 0); 35660786Sps} 35760786Sps 35860786Sps#endif 359