1 /*
2  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice in the documentation and/or other materials provided with
12  *    the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 
28 /*
29  * Operating system dependent routines.
30  *
31  * Most of the stuff in here is based on Unix, but an attempt
32  * has been made to make things work on other operating systems.
33  * This will sometimes result in a loss of functionality, unless
34  * someone rewrites code specifically for the new operating system.
35  *
36  * The makefile provides defines to decide whether various
37  * Unix features are present.
38  */
39 
40 #include "less.h"
41 #include <signal.h>
42 #include <setjmp.h>
43 #if HAVE_TIME_H
44 #include <time.h>
45 #endif
46 #if HAVE_ERRNO_H
47 #include <errno.h>
48 #endif
49 #if HAVE_VALUES_H
50 #include <values.h>
51 #endif
52 
53 #if HAVE_TIME_T
54 #define time_type	time_t
55 #else
56 #define	time_type	long
57 #endif
58 
59 /*
60  * BSD setjmp() saves (and longjmp() restores) the signal mask.
61  * This costs a system call or two per setjmp(), so if possible we clear the
62  * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
63  * On other systems, setjmp() doesn't affect the signal mask and so
64  * _setjmp() does not exist; we just use setjmp().
65  */
66 #if HAVE__SETJMP && HAVE_SIGSETMASK
67 #define SET_JUMP	_setjmp
68 #define LONG_JUMP	_longjmp
69 #else
70 #define SET_JUMP	setjmp
71 #define LONG_JUMP	longjmp
72 #endif
73 
74 public int reading;
75 
76 static jmp_buf read_label;
77 
78 /*
79  * Like read() system call, but is deliberately interruptible.
80  * A call to intread() from a signal handler will interrupt
81  * any pending iread().
82  */
83 	public int
iread(fd,buf,len)84 iread(fd, buf, len)
85 	int fd;
86 	char *buf;
87 	unsigned int len;
88 {
89 	register int n;
90 
91 #if MSOFTC
92 	if (kbhit())
93 	{
94 		int c;
95 
96 		c = getch();
97 		if (c == '\003')
98 			return (READ_INTR);
99 		ungetch(c);
100 	}
101 #endif
102 	if (SET_JUMP(read_label))
103 	{
104 		/*
105 		 * We jumped here from intread.
106 		 */
107 		reading = 0;
108 #if HAVE_SIGSETMASK
109 		sigsetmask(0);
110 #endif
111 		return (READ_INTR);
112 	}
113 
114 	flush();
115 	reading = 1;
116 	n = read(fd, buf, len);
117 	reading = 0;
118 	if (n < 0)
119 		return (-1);
120 	return (n);
121 }
122 
123 /*
124  * Interrupt a pending iread().
125  */
126 	public void
intread()127 intread()
128 {
129 	LONG_JUMP(read_label, 1);
130 }
131 
132 /*
133  * Return the current time.
134  */
135 #if HAVE_TIME
136 	public long
get_time()137 get_time()
138 {
139 	time_type t;
140 
141 	time(&t);
142 	return (t);
143 }
144 #endif
145 
146 
147 #if !HAVE_STRERROR
148 /*
149  * Local version of strerror, if not available from the system.
150  */
151 	static char *
strerror(err)152 strerror(err)
153 	int err;
154 {
155 #if HAVE_SYS_ERRLIST
156 	static char buf[16];
157 	extern char *sys_errlist[];
158 	extern int sys_nerr;
159 
160 	if (err < sys_nerr)
161 		return sys_errlist[err];
162 	sprintf(buf, "Error %d", err);
163 	return buf;
164 #else
165 	return ("cannot open");
166 #endif
167 }
168 #endif
169 
170 /*
171  * errno_message: Return an error message based on the value of "errno".
172  */
173 	public char *
errno_message(filename)174 errno_message(filename)
175 	char *filename;
176 {
177 	register char *p;
178 	register char *m;
179 #if HAVE_ERRNO
180 	extern int errno;
181 	p = strerror(errno);
182 #else
183 	p = "cannot open";
184 #endif
185 	m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char));
186 	sprintf(m, "%s: %s", filename, p);
187 	return (m);
188 }
189 
190 /*
191  * Return the largest possible number that can fit in a long.
192  */
193 #ifdef MAXLONG
194 	static long
get_maxlong()195 get_maxlong()
196 {
197 	return (MAXLONG);
198 }
199 #else
200 	static long
get_maxlong()201 get_maxlong()
202 {
203 	long n, n2;
204 
205 	/*
206 	 * Keep doubling n until we overflow.
207 	 * {{ This actually only returns the largest power of two that
208 	 *    can fit in a long, but percentage() doesn't really need
209 	 *    it any more accurate than that. }}
210 	 */
211 	n2 = 128;  /* Hopefully no maxlong is less than 128! */
212 	do {
213 		n = n2;
214 		n2 *= 2;
215 	} while (n2 / 2 == n);
216 	return (n);
217 }
218 #endif
219 
220 /*
221  * Return the ratio of two longs, as a percentage.
222  */
223 	public int
percentage(num,den)224 percentage(num, den)
225 	long num, den;
226 {
227 	static long maxlong100 = 0;
228 
229 	if (maxlong100 == 0)
230 		maxlong100 = get_maxlong() / 100;
231 	if (num > maxlong100)
232 		return (num / (den/100));
233 	else
234 		return (100*num / den);
235 }
236