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