os.c revision 161475
160786Sps/*
2161475Sdelphij * Copyright (C) 1984-2005  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
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)
15960786Sps		return (-1);
16060786Sps	return (n);
16160786Sps}
16260786Sps
16360786Sps/*
16460786Sps * Interrupt a pending iread().
16560786Sps */
16660786Sps	public void
16760786Spsintread()
16860786Sps{
16960786Sps	LONG_JUMP(read_label, 1);
17060786Sps}
17160786Sps
17260786Sps/*
17360786Sps * Return the current time.
17460786Sps */
17560786Sps#if HAVE_TIME
17660786Sps	public long
17760786Spsget_time()
17860786Sps{
17960786Sps	time_type t;
18060786Sps
18160786Sps	time(&t);
18260786Sps	return (t);
18360786Sps}
18460786Sps#endif
18560786Sps
18660786Sps
18760786Sps#if !HAVE_STRERROR
18860786Sps/*
18960786Sps * Local version of strerror, if not available from the system.
19060786Sps */
19160786Sps	static char *
19260786Spsstrerror(err)
19360786Sps	int err;
19460786Sps{
19560786Sps#if HAVE_SYS_ERRLIST
19660786Sps	static char buf[16];
19760786Sps	extern char *sys_errlist[];
19860786Sps	extern int sys_nerr;
19960786Sps
20060786Sps	if (err < sys_nerr)
20160786Sps		return sys_errlist[err];
20260786Sps	sprintf(buf, "Error %d", err);
20360786Sps	return buf;
20460786Sps#else
20560786Sps	return ("cannot open");
20660786Sps#endif
20760786Sps}
20860786Sps#endif
20960786Sps
21060786Sps/*
21160786Sps * errno_message: Return an error message based on the value of "errno".
21260786Sps */
21360786Sps	public char *
21460786Spserrno_message(filename)
21560786Sps	char *filename;
21660786Sps{
21760786Sps	register char *p;
21860786Sps	register char *m;
219161475Sdelphij	int len;
22060786Sps#if HAVE_ERRNO
22160786Sps#if MUST_DEFINE_ERRNO
22260786Sps	extern int errno;
22360786Sps#endif
22460786Sps	p = strerror(errno);
22560786Sps#else
22660786Sps	p = "cannot open";
22760786Sps#endif
228161475Sdelphij	len = strlen(filename) + strlen(p) + 3;
229161475Sdelphij	m = (char *) ecalloc(len, sizeof(char));
230161475Sdelphij	SNPRINTF2(m, len, "%s: %s", filename, p);
23160786Sps	return (m);
23260786Sps}
23360786Sps
23460786Sps/*
23560786Sps * Return the ratio of two POSITIONS, as a percentage.
23660786Sps * {{ Assumes a POSITION is a long int. }}
23760786Sps */
23860786Sps	public int
23960786Spspercentage(num, den)
24060786Sps	POSITION num, den;
24160786Sps{
24289019Sps	POSITION num100 = num * 100;
24389019Sps
24489019Sps	if (num100 / 100 == num)
24589019Sps		return (num100 / den);
24660786Sps	else
24760786Sps		return (num / (den / 100));
24860786Sps}
24960786Sps
25060786Sps/*
25160786Sps * Return the specified percentage of a POSITION.
25260786Sps */
25360786Sps	public POSITION
25460786Spspercent_pos(pos, percent)
25560786Sps	POSITION pos;
25660786Sps	int percent;
25760786Sps{
25889019Sps	POSITION result100;
25989019Sps
26089019Sps	if (percent == 0)
26189019Sps		return (0);
26289019Sps	else if ((result100 = pos * percent) / percent == pos)
26389019Sps		return (result100 / 100);
26460786Sps	else
26560786Sps		return (percent * (pos / 100));
26660786Sps}
26760786Sps
26889019Sps#if !HAVE_STRCHR
26989019Sps/*
27089019Sps * strchr is used by regexp.c.
27189019Sps */
27289019Sps	char *
27389019Spsstrchr(s, c)
27489019Sps	char *s;
27589019Sps	int c;
27689019Sps{
27789019Sps	for ( ;  *s != '\0';  s++)
27889019Sps		if (*s == c)
27989019Sps			return (s);
28089019Sps	if (c == '\0')
28189019Sps		return (s);
28289019Sps	return (NULL);
28389019Sps}
28489019Sps#endif
28589019Sps
28689019Sps#if !HAVE_MEMCPY
28789019Sps	VOID_POINTER
28889019Spsmemcpy(dst, src, len)
28989019Sps	VOID_POINTER dst;
29089019Sps	VOID_POINTER src;
29189019Sps	int len;
29289019Sps{
29389019Sps	char *dstp = (char *) dst;
29489019Sps	char *srcp = (char *) src;
29589019Sps	int i;
29689019Sps
29789019Sps	for (i = 0;  i < len;  i++)
29889019Sps		dstp[i] = srcp[i];
29989019Sps	return (dst);
30089019Sps}
30189019Sps#endif
30289019Sps
30360786Sps#ifdef _OSK_MWC32
30460786Sps
30560786Sps/*
30660786Sps * This implements an ANSI-style intercept setup for Microware C 3.2
30760786Sps */
30860786Sps	public int
30960786Spsos9_signal(type, handler)
31060786Sps	int type;
31160786Sps	RETSIGTYPE (*handler)();
31260786Sps{
31360786Sps	intercept(handler);
31460786Sps}
31560786Sps
31660786Sps#include <sgstat.h>
31760786Sps
31889019Sps	int
31960786Spsisatty(f)
32060786Sps	int f;
32160786Sps{
32260786Sps	struct sgbuf sgbuf;
32360786Sps
32460786Sps	if (_gs_opt(f, &sgbuf) < 0)
32560786Sps		return -1;
32660786Sps	return (sgbuf.sg_class == 0);
32760786Sps}
32860786Sps
32960786Sps#endif
330