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