f1eec4e92bc3b2a6da61d065d5ffb7737eed87f0
[dragonfly.git] / contrib / less / os.c
1 /*
2  * Copyright (C) 1984-2014  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         char *buf;
66         unsigned int len;
67 {
68         register 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         register char *p;
230         register 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, den;
275 {
276         return (int) muldiv(num,  (POSITION) 100, den);
277 }
278
279 /*
280  * Return the specified percentage of a POSITION.
281  */
282         public POSITION
283 percent_pos(pos, percent, fraction)
284         POSITION pos;
285         int percent;
286         long fraction;
287 {
288         /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */
289         POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100);
290
291         if (perden == 0)
292                 return (0);
293         return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM);
294 }
295
296 #if !HAVE_STRCHR
297 /*
298  * strchr is used by regexp.c.
299  */
300         char *
301 strchr(s, c)
302         char *s;
303         int c;
304 {
305         for ( ;  *s != '\0';  s++)
306                 if (*s == c)
307                         return (s);
308         if (c == '\0')
309                 return (s);
310         return (NULL);
311 }
312 #endif
313
314 #if !HAVE_MEMCPY
315         VOID_POINTER
316 memcpy(dst, src, len)
317         VOID_POINTER dst;
318         VOID_POINTER src;
319         int len;
320 {
321         char *dstp = (char *) dst;
322         char *srcp = (char *) src;
323         int i;
324
325         for (i = 0;  i < len;  i++)
326                 dstp[i] = srcp[i];
327         return (dst);
328 }
329 #endif
330
331 #ifdef _OSK_MWC32
332
333 /*
334  * This implements an ANSI-style intercept setup for Microware C 3.2
335  */
336         public int 
337 os9_signal(type, handler)
338         int type;
339         RETSIGTYPE (*handler)();
340 {
341         intercept(handler);
342 }
343
344 #include <sgstat.h>
345
346         int 
347 isatty(f)
348         int f;
349 {
350         struct sgbuf sgbuf;
351
352         if (_gs_opt(f, &sgbuf) < 0)
353                 return -1;
354         return (sgbuf.sg_class == 0);
355 }
356         
357 #endif