os.c revision 89019
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
37#if HAVE_TIME_T
38#define time_type	time_t
39#else
40#define	time_type	long
41#endif
42
43/*
44 * BSD setjmp() saves (and longjmp() restores) the signal mask.
45 * This costs a system call or two per setjmp(), so if possible we clear the
46 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
47 * On other systems, setjmp() doesn't affect the signal mask and so
48 * _setjmp() does not exist; we just use setjmp().
49 */
50#if HAVE__SETJMP && HAVE_SIGSETMASK
51#define SET_JUMP	_setjmp
52#define LONG_JUMP	_longjmp
53#else
54#define SET_JUMP	setjmp
55#define LONG_JUMP	longjmp
56#endif
57
58public int reading;
59
60static jmp_buf read_label;
61
62extern int sigs;
63
64/*
65 * Like read() system call, but is deliberately interruptible.
66 * A call to intread() from a signal handler will interrupt
67 * any pending iread().
68 */
69	public int
70iread(fd, buf, len)
71	int fd;
72	char *buf;
73	unsigned int len;
74{
75	register int n;
76
77#if MSDOS_COMPILER==WIN32C
78	if (ABORT_SIGS())
79		return (READ_INTR);
80#else
81#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
82	if (kbhit())
83	{
84		int c;
85
86		c = getch();
87		if (c == '\003')
88			return (READ_INTR);
89		ungetch(c);
90	}
91#endif
92#endif
93	if (SET_JUMP(read_label))
94	{
95		/*
96		 * We jumped here from intread.
97		 */
98		reading = 0;
99#if HAVE_SIGPROCMASK
100		{
101		  sigset_t mask;
102		  sigemptyset(&mask);
103		  sigprocmask(SIG_SETMASK, &mask, NULL);
104		}
105#else
106#if HAVE_SIGSETMASK
107		sigsetmask(0);
108#else
109#ifdef _OSK
110		sigmask(~0);
111#endif
112#endif
113#endif
114		return (READ_INTR);
115	}
116
117	flush();
118	reading = 1;
119#if MSDOS_COMPILER==DJGPPC
120	if (isatty(fd))
121	{
122		/*
123		 * Don't try reading from a TTY until a character is
124		 * available, because that makes some background programs
125		 * believe DOS is busy in a way that prevents those
126		 * programs from working while "less" waits.
127		 */
128		fd_set readfds;
129
130		FD_ZERO(&readfds);
131		FD_SET(fd, &readfds);
132		if (select(fd+1, &readfds, 0, 0, 0) == -1)
133			return (-1);
134	}
135#endif
136	n = read(fd, buf, len);
137#if 1
138	/*
139	 * This is a kludge to workaround a problem on some systems
140	 * where terminating a remote tty connection causes read() to
141	 * start returning 0 forever, instead of -1.
142	 */
143	{
144		extern int ignore_eoi;
145		if (!ignore_eoi)
146		{
147			static int consecutive_nulls = 0;
148			if (n == 0)
149				consecutive_nulls++;
150			else
151				consecutive_nulls = 0;
152			if (consecutive_nulls > 20)
153				quit(QUIT_ERROR);
154		}
155	}
156#endif
157	reading = 0;
158	if (n < 0)
159		return (-1);
160	return (n);
161}
162
163/*
164 * Interrupt a pending iread().
165 */
166	public void
167intread()
168{
169	LONG_JUMP(read_label, 1);
170}
171
172/*
173 * Return the current time.
174 */
175#if HAVE_TIME
176	public long
177get_time()
178{
179	time_type t;
180
181	time(&t);
182	return (t);
183}
184#endif
185
186
187#if !HAVE_STRERROR
188/*
189 * Local version of strerror, if not available from the system.
190 */
191	static char *
192strerror(err)
193	int err;
194{
195#if HAVE_SYS_ERRLIST
196	static char buf[16];
197	extern char *sys_errlist[];
198	extern int sys_nerr;
199
200	if (err < sys_nerr)
201		return sys_errlist[err];
202	sprintf(buf, "Error %d", err);
203	return buf;
204#else
205	return ("cannot open");
206#endif
207}
208#endif
209
210/*
211 * errno_message: Return an error message based on the value of "errno".
212 */
213	public char *
214errno_message(filename)
215	char *filename;
216{
217	register char *p;
218	register char *m;
219#if HAVE_ERRNO
220#if MUST_DEFINE_ERRNO
221	extern int errno;
222#endif
223	p = strerror(errno);
224#else
225	p = "cannot open";
226#endif
227	m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char));
228	sprintf(m, "%s: %s", filename, p);
229	return (m);
230}
231
232/*
233 * Return the ratio of two POSITIONS, as a percentage.
234 * {{ Assumes a POSITION is a long int. }}
235 */
236	public int
237percentage(num, den)
238	POSITION num, den;
239{
240	POSITION num100 = num * 100;
241
242	if (num100 / 100 == num)
243		return (num100 / den);
244	else
245		return (num / (den / 100));
246}
247
248/*
249 * Return the specified percentage of a POSITION.
250 */
251	public POSITION
252percent_pos(pos, percent)
253	POSITION pos;
254	int percent;
255{
256	POSITION result100;
257
258	if (percent == 0)
259		return (0);
260	else if ((result100 = pos * percent) / percent == pos)
261		return (result100 / 100);
262	else
263		return (percent * (pos / 100));
264}
265
266#if !HAVE_STRCHR
267/*
268 * strchr is used by regexp.c.
269 */
270	char *
271strchr(s, c)
272	char *s;
273	int c;
274{
275	for ( ;  *s != '\0';  s++)
276		if (*s == c)
277			return (s);
278	if (c == '\0')
279		return (s);
280	return (NULL);
281}
282#endif
283
284#if !HAVE_MEMCPY
285	VOID_POINTER
286memcpy(dst, src, len)
287	VOID_POINTER dst;
288	VOID_POINTER src;
289	int len;
290{
291	char *dstp = (char *) dst;
292	char *srcp = (char *) src;
293	int i;
294
295	for (i = 0;  i < len;  i++)
296		dstp[i] = srcp[i];
297	return (dst);
298}
299#endif
300
301#ifdef _OSK_MWC32
302
303/*
304 * This implements an ANSI-style intercept setup for Microware C 3.2
305 */
306	public int
307os9_signal(type, handler)
308	int type;
309	RETSIGTYPE (*handler)();
310{
311	intercept(handler);
312}
313
314#include <sgstat.h>
315
316	int
317isatty(f)
318	int f;
319{
320	struct sgbuf sgbuf;
321
322	if (_gs_opt(f, &sgbuf) < 0)
323		return -1;
324	return (sgbuf.sg_class == 0);
325}
326
327#endif
328