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