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