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