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