]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/less/os.c
Note r317395 as merged.
[FreeBSD/FreeBSD.git] / contrib / less / os.c
1 /*
2  * Copyright (C) 1984-2015  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(int fd, char *buf, unsigned int len)
64 {
65         int n;
66
67 start:
68 #if MSDOS_COMPILER==WIN32C
69         if (ABORT_SIGS())
70                 return (READ_INTR);
71 #else
72 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
73         if (kbhit())
74         {
75                 int c;
76                 
77                 c = getch();
78                 if (c == '\003')
79                         return (READ_INTR);
80                 ungetch(c);
81         }
82 #endif
83 #endif
84         if (SET_JUMP(read_label))
85         {
86                 /*
87                  * We jumped here from intread.
88                  */
89                 reading = 0;
90 #if HAVE_SIGPROCMASK
91                 {
92                   sigset_t mask;
93                   sigemptyset(&mask);
94                   sigprocmask(SIG_SETMASK, &mask, NULL);
95                 }
96 #else
97 #if HAVE_SIGSETMASK
98                 sigsetmask(0);
99 #else
100 #ifdef _OSK
101                 sigmask(~0);
102 #endif
103 #endif
104 #endif
105                 return (READ_INTR);
106         }
107
108         flush();
109         reading = 1;
110 #if MSDOS_COMPILER==DJGPPC
111         if (isatty(fd))
112         {
113                 /*
114                  * Don't try reading from a TTY until a character is
115                  * available, because that makes some background programs
116                  * believe DOS is busy in a way that prevents those
117                  * programs from working while "less" waits.
118                  */
119                 fd_set readfds;
120
121                 FD_ZERO(&readfds);
122                 FD_SET(fd, &readfds);
123                 if (select(fd+1, &readfds, 0, 0, 0) == -1)
124                         return (-1);
125         }
126 #endif
127         n = read(fd, buf, len);
128 #if 1
129         /*
130          * This is a kludge to workaround a problem on some systems
131          * where terminating a remote tty connection causes read() to
132          * start returning 0 forever, instead of -1.
133          */
134         {
135                 extern int ignore_eoi;
136                 if (!ignore_eoi)
137                 {
138                         static int consecutive_nulls = 0;
139                         if (n == 0)
140                                 consecutive_nulls++;
141                         else
142                                 consecutive_nulls = 0;
143                         if (consecutive_nulls > 20)
144                                 quit(QUIT_ERROR);
145                 }
146         }
147 #endif
148         reading = 0;
149         if (n < 0)
150         {
151 #if HAVE_ERRNO
152                 /*
153                  * Certain values of errno indicate we should just retry the read.
154                  */
155 #if MUST_DEFINE_ERRNO
156                 extern int errno;
157 #endif
158 #ifdef EINTR
159                 if (errno == EINTR)
160                         goto start;
161 #endif
162 #ifdef EAGAIN
163                 if (errno == EAGAIN)
164                         goto start;
165 #endif
166 #endif
167                 return (-1);
168         }
169         return (n);
170 }
171
172 /*
173  * Interrupt a pending iread().
174  */
175         public void
176 intread(void)
177 {
178         LONG_JUMP(read_label, 1);
179 }
180
181 /*
182  * Return the current time.
183  */
184 #if HAVE_TIME
185         public time_type
186 get_time(void)
187 {
188         time_type t;
189
190         time(&t);
191         return (t);
192 }
193 #endif
194
195
196 #if !HAVE_STRERROR
197 /*
198  * Local version of strerror, if not available from the system.
199  */
200         static char *
201 strerror(int err)
202 {
203 #if HAVE_SYS_ERRLIST
204         static char buf[16];
205         extern char *sys_errlist[];
206         extern int sys_nerr;
207   
208         if (err < sys_nerr)
209                 return sys_errlist[err];
210         sprintf(buf, "Error %d", err);
211         return buf;
212 #else
213         return ("cannot open");
214 #endif
215 }
216 #endif
217
218 /*
219  * errno_message: Return an error message based on the value of "errno".
220  */
221         public char *
222 errno_message(char *filename)
223 {
224         char *p;
225         char *m;
226         int len;
227 #if HAVE_ERRNO
228 #if MUST_DEFINE_ERRNO
229         extern int errno;
230 #endif
231         p = strerror(errno);
232 #else
233         p = "cannot open";
234 #endif
235         len = (int) (strlen(filename) + strlen(p) + 3);
236         m = (char *) ecalloc(len, sizeof(char));
237         SNPRINTF2(m, len, "%s: %s", filename, p);
238         return (m);
239 }
240
241 /* #define HAVE_FLOAT 0 */
242
243         static POSITION
244 muldiv(POSITION val, POSITION num, POSITION den)
245 {
246 #if HAVE_FLOAT
247         double v = (((double) val) * num) / den;
248         return ((POSITION) (v + 0.5));
249 #else
250         POSITION v = ((POSITION) val) * num;
251
252         if (v / num == val)
253                 /* No overflow */
254                 return (POSITION) (v / den);
255         else
256                 /* Above calculation overflows; 
257                  * use a method that is less precise but won't overflow. */
258                 return (POSITION) (val / (den / num));
259 #endif
260 }
261
262 /*
263  * Return the ratio of two POSITIONS, as a percentage.
264  * {{ Assumes a POSITION is a long int. }}
265  */
266         public int
267 percentage(POSITION num, POSITION den)
268 {
269         return (int) muldiv(num,  (POSITION) 100, den);
270 }
271
272 /*
273  * Return the specified percentage of a POSITION.
274  */
275         public POSITION
276 percent_pos(POSITION pos, int percent, long fraction)
277 {
278         /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */
279         POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100);
280
281         if (perden == 0)
282                 return (0);
283         return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM);
284 }
285
286 #if !HAVE_STRCHR
287 /*
288  * strchr is used by regexp.c.
289  */
290         char *
291 strchr(s, c)
292         char *s;
293         int c;
294 {
295         for ( ;  *s != '\0';  s++)
296                 if (*s == c)
297                         return (s);
298         if (c == '\0')
299                 return (s);
300         return (NULL);
301 }
302 #endif
303
304 #if !HAVE_MEMCPY
305         VOID_POINTER
306 memcpy(dst, src, len)
307         VOID_POINTER dst;
308         VOID_POINTER src;
309         int len;
310 {
311         char *dstp = (char *) dst;
312         char *srcp = (char *) src;
313         int i;
314
315         for (i = 0;  i < len;  i++)
316                 dstp[i] = srcp[i];
317         return (dst);
318 }
319 #endif
320
321 #ifdef _OSK_MWC32
322
323 /*
324  * This implements an ANSI-style intercept setup for Microware C 3.2
325  */
326         public int 
327 os9_signal(int type, RETSIGTYPE (*handler)())
328 {
329         intercept(handler);
330 }
331
332 #include <sgstat.h>
333
334         int 
335 isatty(f)
336         int f;
337 {
338         struct sgbuf sgbuf;
339
340         if (_gs_opt(f, &sgbuf) < 0)
341                 return -1;
342         return (sgbuf.sg_class == 0);
343 }
344         
345 #endif