os.c revision 161475
113244Sgraichen/*
213244Sgraichen * Copyright (C) 1984-2005  Mark Nudelman
313244Sgraichen *
413244Sgraichen * You may distribute under the terms of either the GNU General Public
513244Sgraichen * License or the Less License, as specified in the README file.
613244Sgraichen *
713244Sgraichen * For more information about less, or for information on how to
813244Sgraichen * contact the author, see the README file.
913244Sgraichen */
1013244Sgraichen
1113244Sgraichen
1213244Sgraichen/*
1313244Sgraichen * Operating system dependent routines.
1413244Sgraichen *
1513244Sgraichen * Most of the stuff in here is based on Unix, but an attempt
1613244Sgraichen * has been made to make things work on other operating systems.
1713244Sgraichen * This will sometimes result in a loss of functionality, unless
1813244Sgraichen * someone rewrites code specifically for the new operating system.
1913244Sgraichen *
2013244Sgraichen * The makefile provides defines to decide whether various
2113244Sgraichen * Unix features are present.
2213244Sgraichen */
2313244Sgraichen
2413244Sgraichen#include "less.h"
2513244Sgraichen#include <signal.h>
2613244Sgraichen#include <setjmp.h>
2713244Sgraichen#if HAVE_TIME_H
2813244Sgraichen#include <time.h>
2930160Scharnier#endif
3036817Sache#if HAVE_ERRNO_H
3113244Sgraichen#include <errno.h>
3213244Sgraichen#endif
3313244Sgraichen#if HAVE_VALUES_H
3413244Sgraichen#include <values.h>
3513244Sgraichen#endif
3613244Sgraichen
3713244Sgraichen#if HAVE_TIME_T
3813244Sgraichen#define time_type	time_t
3913460Sgraichen#else
4013460Sgraichen#define	time_type	long
4113244Sgraichen#endif
4213460Sgraichen
4313460Sgraichen/*
4413460Sgraichen * BSD setjmp() saves (and longjmp() restores) the signal mask.
4513244Sgraichen * This costs a system call or two per setjmp(), so if possible we clear the
4613244Sgraichen * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
4713244Sgraichen * On other systems, setjmp() doesn't affect the signal mask and so
4813244Sgraichen * _setjmp() does not exist; we just use setjmp().
4930160Scharnier */
5030160Scharnier#if HAVE__SETJMP && HAVE_SIGSETMASK
5130160Scharnier#define SET_JUMP	_setjmp
5230160Scharnier#define LONG_JUMP	_longjmp
5330160Scharnier#else
5430160Scharnier#define SET_JUMP	setjmp
5513244Sgraichen#define LONG_JUMP	longjmp
5613244Sgraichen#endif
5713244Sgraichen
5816240Salexpublic int reading;
5913244Sgraichen
6013244Sgraichenstatic jmp_buf read_label;
6113244Sgraichen
6213244Sgraichenextern int sigs;
6313244Sgraichen
6413244Sgraichen/*
6513244Sgraichen * Like read() system call, but is deliberately interruptible.
6613244Sgraichen * A call to intread() from a signal handler will interrupt
6713244Sgraichen * any pending iread().
6813244Sgraichen */
6913244Sgraichen	public int
7013244Sgraicheniread(fd, buf, len)
7113244Sgraichen	int fd;
7213460Sgraichen	char *buf;
7313244Sgraichen	unsigned int len;
7413244Sgraichen{
7513244Sgraichen	register int n;
7613244Sgraichen
7713244Sgraichen#if MSDOS_COMPILER==WIN32C
7825443Sache	if (ABORT_SIGS())
7913244Sgraichen		return (READ_INTR);
8013244Sgraichen#else
8113244Sgraichen#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
8213244Sgraichen	if (kbhit())
8313244Sgraichen	{
8413244Sgraichen		int c;
8513244Sgraichen
8636817Sache		c = getch();
8713244Sgraichen		if (c == '\003')
8813244Sgraichen			return (READ_INTR);
8913244Sgraichen		ungetch(c);
9013244Sgraichen	}
9113244Sgraichen#endif
9213244Sgraichen#endif
9335915Shoek	if (SET_JUMP(read_label))
9413244Sgraichen	{
9513244Sgraichen		/*
9625443Sache		 * We jumped here from intread.
9713460Sgraichen		 */
9813460Sgraichen		reading = 0;
9913244Sgraichen#if HAVE_SIGPROCMASK
10013244Sgraichen		{
10116240Salex		  sigset_t mask;
10216240Salex		  sigemptyset(&mask);
10316240Salex		  sigprocmask(SIG_SETMASK, &mask, NULL);
10413244Sgraichen		}
10516240Salex#else
10616240Salex#if HAVE_SIGSETMASK
10716240Salex		sigsetmask(0);
10816240Salex#else
10916240Salex#ifdef _OSK
11016240Salex		sigmask(~0);
11116240Salex#endif
11236817Sache#endif
11316240Salex#endif
11416240Salex		return (READ_INTR);
11516240Salex	}
11616240Salex
11725443Sache	flush();
11813244Sgraichen	reading = 1;
11916240Salex#if MSDOS_COMPILER==DJGPPC
12013244Sgraichen	if (isatty(fd))
12113244Sgraichen	{
12213244Sgraichen		/*
12313244Sgraichen		 * Don't try reading from a TTY until a character is
12413244Sgraichen		 * available, because that makes some background programs
12513244Sgraichen		 * believe DOS is busy in a way that prevents those
12630160Scharnier		 * programs from working while "less" waits.
12730160Scharnier		 */
12813244Sgraichen		fd_set readfds;
12925443Sache
13013244Sgraichen		FD_ZERO(&readfds);
13113244Sgraichen		FD_SET(fd, &readfds);
13213244Sgraichen		if (select(fd+1, &readfds, 0, 0, 0) == -1)
13313244Sgraichen			return (-1);
13413244Sgraichen	}
13513244Sgraichen#endif
13616240Salex	n = read(fd, buf, len);
13713244Sgraichen#if 1
13813244Sgraichen	/*
13916240Salex	 * This is a kludge to workaround a problem on some systems
14013244Sgraichen	 * where terminating a remote tty connection causes read() to
14113244Sgraichen	 * start returning 0 forever, instead of -1.
14213244Sgraichen	 */
14313244Sgraichen	{
14435920Shoek		extern int ignore_eoi;
14513244Sgraichen		if (!ignore_eoi)
14613244Sgraichen		{
14713244Sgraichen			static int consecutive_nulls = 0;
14813244Sgraichen			if (n == 0)
14913244Sgraichen				consecutive_nulls++;
15013244Sgraichen			else
15113244Sgraichen				consecutive_nulls = 0;
15213244Sgraichen			if (consecutive_nulls > 20)
15313244Sgraichen				quit(QUIT_ERROR);
15413244Sgraichen		}
15513244Sgraichen	}
15613244Sgraichen#endif
15713244Sgraichen	reading = 0;
15813244Sgraichen	if (n < 0)
15913244Sgraichen		return (-1);
16013244Sgraichen	return (n);
16113244Sgraichen}
16234584Spst
16313244Sgraichen/*
16413244Sgraichen * Interrupt a pending iread().
16513244Sgraichen */
16613244Sgraichen	public void
16713244Sgraichenintread()
16813244Sgraichen{
16935920Shoek	LONG_JUMP(read_label, 1);
17013244Sgraichen}
17113244Sgraichen
17235920Shoek/*
17313244Sgraichen * Return the current time.
17413244Sgraichen */
17535920Shoek#if HAVE_TIME
17635920Shoek	public long
17735920Shoekget_time()
17835920Shoek{
17935920Shoek	time_type t;
18035920Shoek
18135920Shoek	time(&t);
18235920Shoek	return (t);
18335920Shoek}
18435920Shoek#endif
18536817Sache
18613244Sgraichen
18713244Sgraichen#if !HAVE_STRERROR
18813244Sgraichen/*
18913244Sgraichen * Local version of strerror, if not available from the system.
19013244Sgraichen */
19113244Sgraichen	static char *
19213244Sgraichenstrerror(err)
19316240Salex	int err;
19413244Sgraichen{
19513244Sgraichen#if HAVE_SYS_ERRLIST
19613244Sgraichen	static char buf[16];
19713244Sgraichen	extern char *sys_errlist[];
19813244Sgraichen	extern int sys_nerr;
19913244Sgraichen
20013244Sgraichen	if (err < sys_nerr)
20113244Sgraichen		return sys_errlist[err];
20213358Sgraichen	sprintf(buf, "Error %d", err);
20313244Sgraichen	return buf;
20413244Sgraichen#else
20513244Sgraichen	return ("cannot open");
20613244Sgraichen#endif
20713244Sgraichen}
20816240Salex#endif
20913244Sgraichen
21013244Sgraichen/*
21113244Sgraichen * errno_message: Return an error message based on the value of "errno".
21213244Sgraichen */
21334584Spst	public char *
21413244Sgraichenerrno_message(filename)
21513244Sgraichen	char *filename;
21635920Shoek{
21735920Shoek	register char *p;
21813244Sgraichen	register char *m;
21913244Sgraichen	int len;
22013244Sgraichen#if HAVE_ERRNO
22113244Sgraichen#if MUST_DEFINE_ERRNO
22213244Sgraichen	extern int errno;
22313244Sgraichen#endif
22413244Sgraichen	p = strerror(errno);
22513244Sgraichen#else
22613244Sgraichen	p = "cannot open";
22734584Spst#endif
22834584Spst	len = strlen(filename) + strlen(p) + 3;
22934584Spst	m = (char *) ecalloc(len, sizeof(char));
23013244Sgraichen	SNPRINTF2(m, len, "%s: %s", filename, p);
23113244Sgraichen	return (m);
23213244Sgraichen}
23313244Sgraichen
23413244Sgraichen/*
23516240Salex * Return the ratio of two POSITIONS, as a percentage.
23613244Sgraichen * {{ Assumes a POSITION is a long int. }}
23735917Shoek */
23813244Sgraichen	public int
23913244Sgraichenpercentage(num, den)
24013244Sgraichen	POSITION num, den;
24113244Sgraichen{
24213244Sgraichen	POSITION num100 = num * 100;
24313244Sgraichen
24416240Salex	if (num100 / 100 == num)
24513244Sgraichen		return (num100 / den);
24613244Sgraichen	else
24713244Sgraichen		return (num / (den / 100));
24813244Sgraichen}
24913244Sgraichen
25016174Salex/*
25113244Sgraichen * Return the specified percentage of a POSITION.
25213244Sgraichen */
25325518Sbrian	public POSITION
25413244Sgraichenpercent_pos(pos, percent)
25513244Sgraichen	POSITION pos;
25613244Sgraichen	int percent;
25713244Sgraichen{
25813244Sgraichen	POSITION result100;
25913460Sgraichen
26013460Sgraichen	if (percent == 0)
26113244Sgraichen		return (0);
26213244Sgraichen	else if ((result100 = pos * percent) / percent == pos)
26313244Sgraichen		return (result100 / 100);
26413244Sgraichen	else
26513244Sgraichen		return (percent * (pos / 100));
26613244Sgraichen}
26713244Sgraichen
26813244Sgraichen#if !HAVE_STRCHR
26913244Sgraichen/*
27013244Sgraichen * strchr is used by regexp.c.
27113244Sgraichen */
27213244Sgraichen	char *
27313244Sgraichenstrchr(s, c)
27425518Sbrian	char *s;
27525518Sbrian	int c;
27630160Scharnier{
27725518Sbrian	for ( ;  *s != '\0';  s++)
27813244Sgraichen		if (*s == c)
27913244Sgraichen			return (s);
28013244Sgraichen	if (c == '\0')
28125518Sbrian		return (s);
28225518Sbrian	return (NULL);
28330160Scharnier}
28425518Sbrian#endif
28513244Sgraichen
28613244Sgraichen#if !HAVE_MEMCPY
28713244Sgraichen	VOID_POINTER
28813244Sgraichenmemcpy(dst, src, len)
28913460Sgraichen	VOID_POINTER dst;
29013460Sgraichen	VOID_POINTER src;
29130160Scharnier	int len;
29213460Sgraichen{
29313244Sgraichen	char *dstp = (char *) dst;
29413244Sgraichen	char *srcp = (char *) src;
29513244Sgraichen	int i;
29613244Sgraichen
29713244Sgraichen	for (i = 0;  i < len;  i++)
29813244Sgraichen		dstp[i] = srcp[i];
29913244Sgraichen	return (dst);
30013244Sgraichen}
30113244Sgraichen#endif
30213460Sgraichen
30313460Sgraichen#ifdef _OSK_MWC32
30430160Scharnier
30513460Sgraichen/*
30613244Sgraichen * This implements an ANSI-style intercept setup for Microware C 3.2
30713244Sgraichen */
30813244Sgraichen	public int
30913244Sgraichenos9_signal(type, handler)
31013244Sgraichen	int type;
31113244Sgraichen	RETSIGTYPE (*handler)();
31213244Sgraichen{
31325518Sbrian	intercept(handler);
31425518Sbrian}
31530160Scharnier
31625518Sbrian#include <sgstat.h>
31713244Sgraichen
31813244Sgraichen	int
31913244Sgraichenisatty(f)
32013244Sgraichen	int f;
32113460Sgraichen{
32230160Scharnier	struct sgbuf sgbuf;
32313460Sgraichen
32413244Sgraichen	if (_gs_opt(f, &sgbuf) < 0)
32513244Sgraichen		return -1;
32625518Sbrian	return (sgbuf.sg_class == 0);
32725518Sbrian}
32830160Scharnier
32925518Sbrian#endif
33013460Sgraichen