os.c revision 89019
160786Sps/*
260786Sps * Copyright (C) 1984-2000  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;
21960786Sps#if HAVE_ERRNO
22060786Sps#if MUST_DEFINE_ERRNO
22160786Sps	extern int errno;
22260786Sps#endif
22360786Sps	p = strerror(errno);
22460786Sps#else
22560786Sps	p = "cannot open";
22660786Sps#endif
22760786Sps	m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char));
22860786Sps	sprintf(m, "%s: %s", filename, p);
22960786Sps	return (m);
23060786Sps}
23160786Sps
23260786Sps/*
23360786Sps * Return the ratio of two POSITIONS, as a percentage.
23460786Sps * {{ Assumes a POSITION is a long int. }}
23560786Sps */
23660786Sps	public int
23760786Spspercentage(num, den)
23860786Sps	POSITION num, den;
23960786Sps{
24089019Sps	POSITION num100 = num * 100;
24189019Sps
24289019Sps	if (num100 / 100 == num)
24389019Sps		return (num100 / den);
24460786Sps	else
24560786Sps		return (num / (den / 100));
24660786Sps}
24760786Sps
24860786Sps/*
24960786Sps * Return the specified percentage of a POSITION.
25060786Sps */
25160786Sps	public POSITION
25260786Spspercent_pos(pos, percent)
25360786Sps	POSITION pos;
25460786Sps	int percent;
25560786Sps{
25689019Sps	POSITION result100;
25789019Sps
25889019Sps	if (percent == 0)
25989019Sps		return (0);
26089019Sps	else if ((result100 = pos * percent) / percent == pos)
26189019Sps		return (result100 / 100);
26260786Sps	else
26360786Sps		return (percent * (pos / 100));
26460786Sps}
26560786Sps
26689019Sps#if !HAVE_STRCHR
26789019Sps/*
26889019Sps * strchr is used by regexp.c.
26989019Sps */
27089019Sps	char *
27189019Spsstrchr(s, c)
27289019Sps	char *s;
27389019Sps	int c;
27489019Sps{
27589019Sps	for ( ;  *s != '\0';  s++)
27689019Sps		if (*s == c)
27789019Sps			return (s);
27889019Sps	if (c == '\0')
27989019Sps		return (s);
28089019Sps	return (NULL);
28189019Sps}
28289019Sps#endif
28389019Sps
28489019Sps#if !HAVE_MEMCPY
28589019Sps	VOID_POINTER
28689019Spsmemcpy(dst, src, len)
28789019Sps	VOID_POINTER dst;
28889019Sps	VOID_POINTER src;
28989019Sps	int len;
29089019Sps{
29189019Sps	char *dstp = (char *) dst;
29289019Sps	char *srcp = (char *) src;
29389019Sps	int i;
29489019Sps
29589019Sps	for (i = 0;  i < len;  i++)
29689019Sps		dstp[i] = srcp[i];
29789019Sps	return (dst);
29889019Sps}
29989019Sps#endif
30089019Sps
30160786Sps#ifdef _OSK_MWC32
30260786Sps
30360786Sps/*
30460786Sps * This implements an ANSI-style intercept setup for Microware C 3.2
30560786Sps */
30660786Sps	public int
30760786Spsos9_signal(type, handler)
30860786Sps	int type;
30960786Sps	RETSIGTYPE (*handler)();
31060786Sps{
31160786Sps	intercept(handler);
31260786Sps}
31360786Sps
31460786Sps#include <sgstat.h>
31560786Sps
31689019Sps	int
31760786Spsisatty(f)
31860786Sps	int f;
31960786Sps{
32060786Sps	struct sgbuf sgbuf;
32160786Sps
32260786Sps	if (_gs_opt(f, &sgbuf) < 0)
32360786Sps		return -1;
32460786Sps	return (sgbuf.sg_class == 0);
32560786Sps}
32660786Sps
32760786Sps#endif
328