160786Sps/* 2240121Sdelphij * Copyright (C) 1984-2012 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 * 7240121Sdelphij * For more information, see the README file. 860786Sps */ 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#if HAVE_TIME_T 3760786Sps#define time_type time_t 3860786Sps#else 3960786Sps#define time_type long 4060786Sps#endif 4160786Sps 4260786Sps/* 4360786Sps * BSD setjmp() saves (and longjmp() restores) the signal mask. 4460786Sps * This costs a system call or two per setjmp(), so if possible we clear the 4560786Sps * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 4660786Sps * On other systems, setjmp() doesn't affect the signal mask and so 4760786Sps * _setjmp() does not exist; we just use setjmp(). 4860786Sps */ 4960786Sps#if HAVE__SETJMP && HAVE_SIGSETMASK 5060786Sps#define SET_JUMP _setjmp 5160786Sps#define LONG_JUMP _longjmp 5260786Sps#else 5360786Sps#define SET_JUMP setjmp 5460786Sps#define LONG_JUMP longjmp 5560786Sps#endif 5660786Sps 5760786Spspublic int reading; 5860786Sps 5960786Spsstatic jmp_buf read_label; 6060786Sps 6160786Spsextern int sigs; 6260786Sps 6360786Sps/* 6460786Sps * Like read() system call, but is deliberately interruptible. 6560786Sps * A call to intread() from a signal handler will interrupt 6660786Sps * any pending iread(). 6760786Sps */ 6860786Sps public int 6960786Spsiread(fd, buf, len) 7060786Sps int fd; 7160786Sps char *buf; 7260786Sps unsigned int len; 7360786Sps{ 7460786Sps register int n; 7560786Sps 76170256Sdelphijstart: 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) 159170256Sdelphij { 160170256Sdelphij#if HAVE_ERRNO 161170256Sdelphij /* 162170256Sdelphij * Certain values of errno indicate we should just retry the read. 163170256Sdelphij */ 164170256Sdelphij#if MUST_DEFINE_ERRNO 165170256Sdelphij extern int errno; 166170256Sdelphij#endif 167170256Sdelphij#ifdef EINTR 168170256Sdelphij if (errno == EINTR) 169170256Sdelphij goto start; 170170256Sdelphij#endif 171170256Sdelphij#ifdef EAGAIN 172170256Sdelphij if (errno == EAGAIN) 173170256Sdelphij goto start; 174170256Sdelphij#endif 175170256Sdelphij#endif 17660786Sps return (-1); 177170256Sdelphij } 17860786Sps return (n); 17960786Sps} 18060786Sps 18160786Sps/* 18260786Sps * Interrupt a pending iread(). 18360786Sps */ 18460786Sps public void 18560786Spsintread() 18660786Sps{ 18760786Sps LONG_JUMP(read_label, 1); 18860786Sps} 18960786Sps 19060786Sps/* 19160786Sps * Return the current time. 19260786Sps */ 19360786Sps#if HAVE_TIME 19460786Sps public long 19560786Spsget_time() 19660786Sps{ 19760786Sps time_type t; 19860786Sps 19960786Sps time(&t); 20060786Sps return (t); 20160786Sps} 20260786Sps#endif 20360786Sps 20460786Sps 20560786Sps#if !HAVE_STRERROR 20660786Sps/* 20760786Sps * Local version of strerror, if not available from the system. 20860786Sps */ 20960786Sps static char * 21060786Spsstrerror(err) 21160786Sps int err; 21260786Sps{ 21360786Sps#if HAVE_SYS_ERRLIST 21460786Sps static char buf[16]; 21560786Sps extern char *sys_errlist[]; 21660786Sps extern int sys_nerr; 21760786Sps 21860786Sps if (err < sys_nerr) 21960786Sps return sys_errlist[err]; 22060786Sps sprintf(buf, "Error %d", err); 22160786Sps return buf; 22260786Sps#else 22360786Sps return ("cannot open"); 22460786Sps#endif 22560786Sps} 22660786Sps#endif 22760786Sps 22860786Sps/* 22960786Sps * errno_message: Return an error message based on the value of "errno". 23060786Sps */ 23160786Sps public char * 23260786Spserrno_message(filename) 23360786Sps char *filename; 23460786Sps{ 23560786Sps register char *p; 23660786Sps register char *m; 237161475Sdelphij int len; 23860786Sps#if HAVE_ERRNO 23960786Sps#if MUST_DEFINE_ERRNO 24060786Sps extern int errno; 24160786Sps#endif 24260786Sps p = strerror(errno); 24360786Sps#else 24460786Sps p = "cannot open"; 24560786Sps#endif 246161475Sdelphij len = strlen(filename) + strlen(p) + 3; 247161475Sdelphij m = (char *) ecalloc(len, sizeof(char)); 248161475Sdelphij SNPRINTF2(m, len, "%s: %s", filename, p); 24960786Sps return (m); 25060786Sps} 25160786Sps 252221715Sdelphij/* #define HAVE_FLOAT 0 */ 253221715Sdelphij 254221715Sdelphij static POSITION 255221715Sdelphijmuldiv(val, num, den) 256221715Sdelphij POSITION val, num, den; 257221715Sdelphij{ 258221715Sdelphij#if HAVE_FLOAT 259221715Sdelphij double v = (((double) val) * num) / den; 260221715Sdelphij return ((POSITION) (v + 0.5)); 261221715Sdelphij#else 262221715Sdelphij POSITION v = ((POSITION) val) * num; 263221715Sdelphij 264221715Sdelphij if (v / num == val) 265221715Sdelphij /* No overflow */ 266221715Sdelphij return (POSITION) (v / den); 267221715Sdelphij else 268221715Sdelphij /* Above calculation overflows; 269221715Sdelphij * use a method that is less precise but won't overflow. */ 270221715Sdelphij return (POSITION) (val / (den / num)); 271221715Sdelphij#endif 272221715Sdelphij} 273221715Sdelphij 27460786Sps/* 27560786Sps * Return the ratio of two POSITIONS, as a percentage. 27660786Sps * {{ Assumes a POSITION is a long int. }} 27760786Sps */ 27860786Sps public int 27960786Spspercentage(num, den) 28060786Sps POSITION num, den; 28160786Sps{ 282221715Sdelphij return (int) muldiv(num, (POSITION) 100, den); 28360786Sps} 28460786Sps 28560786Sps/* 28660786Sps * Return the specified percentage of a POSITION. 28760786Sps */ 28860786Sps public POSITION 289170256Sdelphijpercent_pos(pos, percent, fraction) 29060786Sps POSITION pos; 29160786Sps int percent; 292170256Sdelphij long fraction; 29360786Sps{ 294170256Sdelphij /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 295221715Sdelphij POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 29689019Sps 297170256Sdelphij if (perden == 0) 29889019Sps return (0); 299221715Sdelphij return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); 30060786Sps} 30160786Sps 30289019Sps#if !HAVE_STRCHR 30389019Sps/* 30489019Sps * strchr is used by regexp.c. 30589019Sps */ 30689019Sps char * 30789019Spsstrchr(s, c) 30889019Sps char *s; 30989019Sps int c; 31089019Sps{ 31189019Sps for ( ; *s != '\0'; s++) 31289019Sps if (*s == c) 31389019Sps return (s); 31489019Sps if (c == '\0') 31589019Sps return (s); 31689019Sps return (NULL); 31789019Sps} 31889019Sps#endif 31989019Sps 32089019Sps#if !HAVE_MEMCPY 32189019Sps VOID_POINTER 32289019Spsmemcpy(dst, src, len) 32389019Sps VOID_POINTER dst; 32489019Sps VOID_POINTER src; 32589019Sps int len; 32689019Sps{ 32789019Sps char *dstp = (char *) dst; 32889019Sps char *srcp = (char *) src; 32989019Sps int i; 33089019Sps 33189019Sps for (i = 0; i < len; i++) 33289019Sps dstp[i] = srcp[i]; 33389019Sps return (dst); 33489019Sps} 33589019Sps#endif 33689019Sps 33760786Sps#ifdef _OSK_MWC32 33860786Sps 33960786Sps/* 34060786Sps * This implements an ANSI-style intercept setup for Microware C 3.2 34160786Sps */ 34260786Sps public int 34360786Spsos9_signal(type, handler) 34460786Sps int type; 34560786Sps RETSIGTYPE (*handler)(); 34660786Sps{ 34760786Sps intercept(handler); 34860786Sps} 34960786Sps 35060786Sps#include <sgstat.h> 35160786Sps 35289019Sps int 35360786Spsisatty(f) 35460786Sps int f; 35560786Sps{ 35660786Sps struct sgbuf sgbuf; 35760786Sps 35860786Sps if (_gs_opt(f, &sgbuf) < 0) 35960786Sps return -1; 36060786Sps return (sgbuf.sg_class == 0); 36160786Sps} 36260786Sps 36360786Sps#endif 364