os.c revision 60786
1/*
2 * Copyright (C) 1984-2000  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12/*
13 * Operating system dependent routines.
14 *
15 * Most of the stuff in here is based on Unix, but an attempt
16 * has been made to make things work on other operating systems.
17 * This will sometimes result in a loss of functionality, unless
18 * someone rewrites code specifically for the new operating system.
19 *
20 * The makefile provides defines to decide whether various
21 * Unix features are present.
22 */
23
24#include "less.h"
25#include <signal.h>
26#include <setjmp.h>
27#if HAVE_TIME_H
28#include <time.h>
29#endif
30#if HAVE_ERRNO_H
31#include <errno.h>
32#endif
33#if HAVE_VALUES_H
34#include <values.h>
35#endif
36#if HAVE_LIMITS_H
37#include <limits.h>
38#endif
39
40#if HAVE_TIME_T
41#define time_type	time_t
42#else
43#define	time_type	long
44#endif
45
46/*
47 * BSD setjmp() saves (and longjmp() restores) the signal mask.
48 * This costs a system call or two per setjmp(), so if possible we clear the
49 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
50 * On other systems, setjmp() doesn't affect the signal mask and so
51 * _setjmp() does not exist; we just use setjmp().
52 */
53#if HAVE__SETJMP && HAVE_SIGSETMASK
54#define SET_JUMP	_setjmp
55#define LONG_JUMP	_longjmp
56#else
57#define SET_JUMP	setjmp
58#define LONG_JUMP	longjmp
59#endif
60
61public int reading;
62
63static jmp_buf read_label;
64
65extern int sigs;
66
67/*
68 * Like read() system call, but is deliberately interruptible.
69 * A call to intread() from a signal handler will interrupt
70 * any pending iread().
71 */
72	public int
73iread(fd, buf, len)
74	int fd;
75	char *buf;
76	unsigned int len;
77{
78	register int n;
79
80#if MSDOS_COMPILER==WIN32C
81	if (ABORT_SIGS())
82		return (READ_INTR);
83#else
84#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
85	if (kbhit())
86	{
87		int c;
88
89		c = getch();
90		if (c == '\003')
91			return (READ_INTR);
92		ungetch(c);
93	}
94#endif
95#endif
96	if (SET_JUMP(read_label))
97	{
98		/*
99		 * We jumped here from intread.
100		 */
101		reading = 0;
102#if HAVE_SIGSETMASK
103		sigsetmask(0);
104#else
105#ifdef _OSK
106		sigmask(~0);
107#endif
108#endif
109		return (READ_INTR);
110	}
111
112	flush();
113	reading = 1;
114#if MSDOS_COMPILER==DJGPPC
115	if (isatty(fd))
116	{
117		/*
118		 * Don't try reading from a TTY until a character is
119		 * available, because that makes some background programs
120		 * believe DOS is busy in a way that prevents those
121		 * programs from working while "less" waits.
122		 */
123		fd_set readfds;
124
125		FD_ZERO(&readfds);
126		FD_SET(fd, &readfds);
127		if (select(fd+1, &readfds, 0, 0, 0) == -1)
128			return (-1);
129	}
130#endif
131	n = read(fd, buf, len);
132#if 1
133	/*
134	 * This is a kludge to workaround a problem on some systems
135	 * where terminating a remote tty connection causes read() to
136	 * start returning 0 forever, instead of -1.
137	 */
138	{
139		extern int ignore_eoi;
140		if (!ignore_eoi)
141		{
142			static int consecutive_nulls = 0;
143			if (n == 0)
144				consecutive_nulls++;
145			else
146				consecutive_nulls = 0;
147			if (consecutive_nulls > 20)
148				quit(QUIT_ERROR);
149		}
150	}
151#endif
152	reading = 0;
153	if (n < 0)
154		return (-1);
155	return (n);
156}
157
158/*
159 * Interrupt a pending iread().
160 */
161	public void
162intread()
163{
164	LONG_JUMP(read_label, 1);
165}
166
167/*
168 * Return the current time.
169 */
170#if HAVE_TIME
171	public long
172get_time()
173{
174	time_type t;
175
176	time(&t);
177	return (t);
178}
179#endif
180
181
182#if !HAVE_STRERROR
183/*
184 * Local version of strerror, if not available from the system.
185 */
186	static char *
187strerror(err)
188	int err;
189{
190#if HAVE_SYS_ERRLIST
191	static char buf[16];
192	extern char *sys_errlist[];
193	extern int sys_nerr;
194
195	if (err < sys_nerr)
196		return sys_errlist[err];
197	sprintf(buf, "Error %d", err);
198	return buf;
199#else
200	return ("cannot open");
201#endif
202}
203#endif
204
205/*
206 * errno_message: Return an error message based on the value of "errno".
207 */
208	public char *
209errno_message(filename)
210	char *filename;
211{
212	register char *p;
213	register char *m;
214#if HAVE_ERRNO
215#if MUST_DEFINE_ERRNO
216	extern int errno;
217#endif
218	p = strerror(errno);
219#else
220	p = "cannot open";
221#endif
222	m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char));
223	sprintf(m, "%s: %s", filename, p);
224	return (m);
225}
226
227/*
228 * Return the largest possible number that can fit in a long.
229 */
230	static long
231get_maxlong()
232{
233#ifdef LONG_MAX
234	return (LONG_MAX);
235#else
236#ifdef MAXLONG
237	return (MAXLONG);
238#else
239	long n, n2;
240
241	/*
242	 * Keep doubling n until we overflow.
243	 * {{ This actually only returns the largest power of two that
244	 *    can fit in a long, but percentage() doesn't really need
245	 *    it any more accurate than that. }}
246	 */
247	n2 = 128;  /* Hopefully no maxlong is less than 128! */
248	do {
249		n = n2;
250		n2 *= 2;
251	} while (n2 / 2 == n);
252	return (n);
253#endif
254#endif
255}
256
257/*
258 * Return the ratio of two POSITIONS, as a percentage.
259 * {{ Assumes a POSITION is a long int. }}
260 */
261	public int
262percentage(num, den)
263	POSITION num, den;
264{
265	if (num <= get_maxlong() / 100)
266		return ((100 * num) / den);
267	else
268		return (num / (den / 100));
269}
270
271/*
272 * Return the specified percentage of a POSITION.
273 * {{ Assumes a POSITION is a long int. }}
274 */
275	public POSITION
276percent_pos(pos, percent)
277	POSITION pos;
278	int percent;
279{
280	if (pos <= get_maxlong() / 100)
281		return ((percent * pos) / 100);
282	else
283		return (percent * (pos / 100));
284}
285
286#ifdef _OSK_MWC32
287
288/*
289 * This implements an ANSI-style intercept setup for Microware C 3.2
290 */
291	public int
292os9_signal(type, handler)
293	int type;
294	RETSIGTYPE (*handler)();
295{
296	intercept(handler);
297}
298
299#include <sgstat.h>
300
301	public int
302isatty(f)
303	int f;
304{
305	struct sgbuf sgbuf;
306
307	if (_gs_opt(f, &sgbuf) < 0)
308		return -1;
309	return (sgbuf.sg_class == 0);
310}
311
312#endif
313