os.c revision 170256
160786Sps/*
2170256Sdelphij * Copyright (C) 1984-2007  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 *
760786Sps * For more information about less, or for information on how to
860786Sps * contact the author, see the README file.
960786Sps */
1060786Sps
1160786Sps
1260786Sps/*
1360786Sps * Operating system dependent routines.
1460786Sps *
1560786Sps * Most of the stuff in here is based on Unix, but an attempt
1660786Sps * has been made to make things work on other operating systems.
1760786Sps * This will sometimes result in a loss of functionality, unless
1860786Sps * someone rewrites code specifically for the new operating system.
1960786Sps *
2060786Sps * The makefile provides defines to decide whether various
2160786Sps * Unix features are present.
2260786Sps */
2360786Sps
2460786Sps#include "less.h"
2560786Sps#include <signal.h>
2660786Sps#include <setjmp.h>
2760786Sps#if HAVE_TIME_H
2860786Sps#include <time.h>
2960786Sps#endif
3060786Sps#if HAVE_ERRNO_H
3160786Sps#include <errno.h>
3260786Sps#endif
3360786Sps#if HAVE_VALUES_H
3460786Sps#include <values.h>
3560786Sps#endif
3660786Sps
3760786Sps#if HAVE_TIME_T
3860786Sps#define time_type	time_t
3960786Sps#else
4060786Sps#define	time_type	long
4160786Sps#endif
4260786Sps
4360786Sps/*
4460786Sps * BSD setjmp() saves (and longjmp() restores) the signal mask.
4560786Sps * This costs a system call or two per setjmp(), so if possible we clear the
4660786Sps * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
4760786Sps * On other systems, setjmp() doesn't affect the signal mask and so
4860786Sps * _setjmp() does not exist; we just use setjmp().
4960786Sps */
5060786Sps#if HAVE__SETJMP && HAVE_SIGSETMASK
5160786Sps#define SET_JUMP	_setjmp
5260786Sps#define LONG_JUMP	_longjmp
5360786Sps#else
5460786Sps#define SET_JUMP	setjmp
5560786Sps#define LONG_JUMP	longjmp
5660786Sps#endif
5760786Sps
5860786Spspublic int reading;
5960786Sps
6060786Spsstatic jmp_buf read_label;
6160786Sps
6260786Spsextern int sigs;
6360786Sps
6460786Sps/*
6560786Sps * Like read() system call, but is deliberately interruptible.
6660786Sps * A call to intread() from a signal handler will interrupt
6760786Sps * any pending iread().
6860786Sps */
6960786Sps	public int
7060786Spsiread(fd, buf, len)
7160786Sps	int fd;
7260786Sps	char *buf;
7360786Sps	unsigned int len;
7460786Sps{
7560786Sps	register int n;
7660786Sps
77170256Sdelphijstart:
7860786Sps#if MSDOS_COMPILER==WIN32C
7960786Sps	if (ABORT_SIGS())
8060786Sps		return (READ_INTR);
8160786Sps#else
8260786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
8360786Sps	if (kbhit())
8460786Sps	{
8560786Sps		int c;
8660786Sps
8760786Sps		c = getch();
8860786Sps		if (c == '\003')
8960786Sps			return (READ_INTR);
9060786Sps		ungetch(c);
9160786Sps	}
9260786Sps#endif
9360786Sps#endif
9460786Sps	if (SET_JUMP(read_label))
9560786Sps	{
9660786Sps		/*
9760786Sps		 * We jumped here from intread.
9860786Sps		 */
9960786Sps		reading = 0;
10063128Sps#if HAVE_SIGPROCMASK
10163128Sps		{
10263128Sps		  sigset_t mask;
10363128Sps		  sigemptyset(&mask);
10463128Sps		  sigprocmask(SIG_SETMASK, &mask, NULL);
10563128Sps		}
10663128Sps#else
10760786Sps#if HAVE_SIGSETMASK
10860786Sps		sigsetmask(0);
10960786Sps#else
11060786Sps#ifdef _OSK
11160786Sps		sigmask(~0);
11260786Sps#endif
11360786Sps#endif
11463128Sps#endif
11560786Sps		return (READ_INTR);
11660786Sps	}
11760786Sps
11860786Sps	flush();
11960786Sps	reading = 1;
12060786Sps#if MSDOS_COMPILER==DJGPPC
12160786Sps	if (isatty(fd))
12260786Sps	{
12360786Sps		/*
12460786Sps		 * Don't try reading from a TTY until a character is
12560786Sps		 * available, because that makes some background programs
12660786Sps		 * believe DOS is busy in a way that prevents those
12760786Sps		 * programs from working while "less" waits.
12860786Sps		 */
12960786Sps		fd_set readfds;
13060786Sps
13160786Sps		FD_ZERO(&readfds);
13260786Sps		FD_SET(fd, &readfds);
13360786Sps		if (select(fd+1, &readfds, 0, 0, 0) == -1)
13460786Sps			return (-1);
13560786Sps	}
13660786Sps#endif
13760786Sps	n = read(fd, buf, len);
13860786Sps#if 1
13960786Sps	/*
14060786Sps	 * This is a kludge to workaround a problem on some systems
14160786Sps	 * where terminating a remote tty connection causes read() to
14260786Sps	 * start returning 0 forever, instead of -1.
14360786Sps	 */
14460786Sps	{
14560786Sps		extern int ignore_eoi;
14660786Sps		if (!ignore_eoi)
14760786Sps		{
14860786Sps			static int consecutive_nulls = 0;
14960786Sps			if (n == 0)
15060786Sps				consecutive_nulls++;
15160786Sps			else
15260786Sps				consecutive_nulls = 0;
15360786Sps			if (consecutive_nulls > 20)
15460786Sps				quit(QUIT_ERROR);
15560786Sps		}
15660786Sps	}
15760786Sps#endif
15860786Sps	reading = 0;
15960786Sps	if (n < 0)
160170256Sdelphij	{
161170256Sdelphij#if HAVE_ERRNO
162170256Sdelphij		/*
163170256Sdelphij		 * Certain values of errno indicate we should just retry the read.
164170256Sdelphij		 */
165170256Sdelphij#if MUST_DEFINE_ERRNO
166170256Sdelphij		extern int errno;
167170256Sdelphij#endif
168170256Sdelphij#ifdef EINTR
169170256Sdelphij		if (errno == EINTR)
170170256Sdelphij			goto start;
171170256Sdelphij#endif
172170256Sdelphij#ifdef EAGAIN
173170256Sdelphij		if (errno == EAGAIN)
174170256Sdelphij			goto start;
175170256Sdelphij#endif
176170256Sdelphij#endif
17760786Sps		return (-1);
178170256Sdelphij	}
17960786Sps	return (n);
18060786Sps}
18160786Sps
18260786Sps/*
18360786Sps * Interrupt a pending iread().
18460786Sps */
18560786Sps	public void
18660786Spsintread()
18760786Sps{
18860786Sps	LONG_JUMP(read_label, 1);
18960786Sps}
19060786Sps
19160786Sps/*
19260786Sps * Return the current time.
19360786Sps */
19460786Sps#if HAVE_TIME
19560786Sps	public long
19660786Spsget_time()
19760786Sps{
19860786Sps	time_type t;
19960786Sps
20060786Sps	time(&t);
20160786Sps	return (t);
20260786Sps}
20360786Sps#endif
20460786Sps
20560786Sps
20660786Sps#if !HAVE_STRERROR
20760786Sps/*
20860786Sps * Local version of strerror, if not available from the system.
20960786Sps */
21060786Sps	static char *
21160786Spsstrerror(err)
21260786Sps	int err;
21360786Sps{
21460786Sps#if HAVE_SYS_ERRLIST
21560786Sps	static char buf[16];
21660786Sps	extern char *sys_errlist[];
21760786Sps	extern int sys_nerr;
21860786Sps
21960786Sps	if (err < sys_nerr)
22060786Sps		return sys_errlist[err];
22160786Sps	sprintf(buf, "Error %d", err);
22260786Sps	return buf;
22360786Sps#else
22460786Sps	return ("cannot open");
22560786Sps#endif
22660786Sps}
22760786Sps#endif
22860786Sps
22960786Sps/*
23060786Sps * errno_message: Return an error message based on the value of "errno".
23160786Sps */
23260786Sps	public char *
23360786Spserrno_message(filename)
23460786Sps	char *filename;
23560786Sps{
23660786Sps	register char *p;
23760786Sps	register char *m;
238161475Sdelphij	int len;
23960786Sps#if HAVE_ERRNO
24060786Sps#if MUST_DEFINE_ERRNO
24160786Sps	extern int errno;
24260786Sps#endif
24360786Sps	p = strerror(errno);
24460786Sps#else
24560786Sps	p = "cannot open";
24660786Sps#endif
247161475Sdelphij	len = strlen(filename) + strlen(p) + 3;
248161475Sdelphij	m = (char *) ecalloc(len, sizeof(char));
249161475Sdelphij	SNPRINTF2(m, len, "%s: %s", filename, p);
25060786Sps	return (m);
25160786Sps}
25260786Sps
25360786Sps/*
25460786Sps * Return the ratio of two POSITIONS, as a percentage.
25560786Sps * {{ Assumes a POSITION is a long int. }}
25660786Sps */
25760786Sps	public int
25860786Spspercentage(num, den)
25960786Sps	POSITION num, den;
26060786Sps{
26189019Sps	POSITION num100 = num * 100;
26289019Sps
26389019Sps	if (num100 / 100 == num)
26489019Sps		return (num100 / den);
26560786Sps	else
26660786Sps		return (num / (den / 100));
26760786Sps}
26860786Sps
26960786Sps/*
27060786Sps * Return the specified percentage of a POSITION.
27160786Sps */
27260786Sps	public POSITION
273170256Sdelphijpercent_pos(pos, percent, fraction)
27460786Sps	POSITION pos;
27560786Sps	int percent;
276170256Sdelphij	long fraction;
27760786Sps{
278170256Sdelphij	/* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */
279170256Sdelphij	long perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100);
280170256Sdelphij	POSITION temp;
28189019Sps
282170256Sdelphij	if (perden == 0)
28389019Sps		return (0);
284170256Sdelphij	temp = pos * perden;  /* This might overflow. */
285170256Sdelphij	if (temp / perden == pos)
286170256Sdelphij		/* No overflow */
287170256Sdelphij		return (temp / NUM_FRAC_DENOM);
28860786Sps	else
289170256Sdelphij		/* Above calculation overflows;
290170256Sdelphij		 * use a method that is less precise but won't overflow. */
291170256Sdelphij		return (perden * (pos / NUM_FRAC_DENOM));
29260786Sps}
29360786Sps
29489019Sps#if !HAVE_STRCHR
29589019Sps/*
29689019Sps * strchr is used by regexp.c.
29789019Sps */
29889019Sps	char *
29989019Spsstrchr(s, c)
30089019Sps	char *s;
30189019Sps	int c;
30289019Sps{
30389019Sps	for ( ;  *s != '\0';  s++)
30489019Sps		if (*s == c)
30589019Sps			return (s);
30689019Sps	if (c == '\0')
30789019Sps		return (s);
30889019Sps	return (NULL);
30989019Sps}
31089019Sps#endif
31189019Sps
31289019Sps#if !HAVE_MEMCPY
31389019Sps	VOID_POINTER
31489019Spsmemcpy(dst, src, len)
31589019Sps	VOID_POINTER dst;
31689019Sps	VOID_POINTER src;
31789019Sps	int len;
31889019Sps{
31989019Sps	char *dstp = (char *) dst;
32089019Sps	char *srcp = (char *) src;
32189019Sps	int i;
32289019Sps
32389019Sps	for (i = 0;  i < len;  i++)
32489019Sps		dstp[i] = srcp[i];
32589019Sps	return (dst);
32689019Sps}
32789019Sps#endif
32889019Sps
32960786Sps#ifdef _OSK_MWC32
33060786Sps
33160786Sps/*
33260786Sps * This implements an ANSI-style intercept setup for Microware C 3.2
33360786Sps */
33460786Sps	public int
33560786Spsos9_signal(type, handler)
33660786Sps	int type;
33760786Sps	RETSIGTYPE (*handler)();
33860786Sps{
33960786Sps	intercept(handler);
34060786Sps}
34160786Sps
34260786Sps#include <sgstat.h>
34360786Sps
34489019Sps	int
34560786Spsisatty(f)
34660786Sps	int f;
34760786Sps{
34860786Sps	struct sgbuf sgbuf;
34960786Sps
35060786Sps	if (_gs_opt(f, &sgbuf) < 0)
35160786Sps		return -1;
35260786Sps	return (sgbuf.sg_class == 0);
35360786Sps}
35460786Sps
35560786Sps#endif
356