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