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