Import less-436.
[dragonfly.git] / contrib / less / os.c
blobffa495d39dcfcefeda21a6436a7fc9c6171ecbd7
1 /*
2 * Copyright (C) 1984-2009 Mark Nudelman
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.
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
13 * Operating system dependent routines.
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.
20 * The makefile provides defines to decide whether various
21 * Unix features are present.
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
37 #if HAVE_TIME_T
38 #define time_type time_t
39 #else
40 #define time_type long
41 #endif
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().
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
58 public int reading;
60 static jmp_buf read_label;
62 extern int sigs;
65 * Like read() system call, but is deliberately interruptible.
66 * A call to intread() from a signal handler will interrupt
67 * any pending iread().
69 public int
70 iread(fd, buf, len)
71 int fd;
72 char *buf;
73 unsigned int len;
75 register int n;
77 start:
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())
85 int c;
87 c = getch();
88 if (c == '\003')
89 return (READ_INTR);
90 ungetch(c);
92 #endif
93 #endif
94 if (SET_JUMP(read_label))
97 * We jumped here from intread.
99 reading = 0;
100 #if HAVE_SIGPROCMASK
102 sigset_t mask;
103 sigemptyset(&mask);
104 sigprocmask(SIG_SETMASK, &mask, NULL);
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);
118 flush();
119 reading = 1;
120 #if MSDOS_COMPILER==DJGPPC
121 if (isatty(fd))
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.
129 fd_set readfds;
131 FD_ZERO(&readfds);
132 FD_SET(fd, &readfds);
133 if (select(fd+1, &readfds, 0, 0, 0) == -1)
134 return (-1);
136 #endif
137 n = read(fd, buf, len);
138 #if 1
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.
145 extern int ignore_eoi;
146 if (!ignore_eoi)
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);
157 #endif
158 reading = 0;
159 if (n < 0)
161 #if HAVE_ERRNO
163 * Certain values of errno indicate we should just retry the read.
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);
179 return (n);
183 * Interrupt a pending iread().
185 public void
186 intread()
188 LONG_JUMP(read_label, 1);
192 * Return the current time.
194 #if HAVE_TIME
195 public long
196 get_time()
198 time_type t;
200 time(&t);
201 return (t);
203 #endif
206 #if !HAVE_STRERROR
208 * Local version of strerror, if not available from the system.
210 static char *
211 strerror(err)
212 int err;
214 #if HAVE_SYS_ERRLIST
215 static char buf[16];
216 extern char *sys_errlist[];
217 extern int sys_nerr;
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
227 #endif
230 * errno_message: Return an error message based on the value of "errno".
232 public char *
233 errno_message(filename)
234 char *filename;
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);
254 * Return the ratio of two POSITIONS, as a percentage.
255 * {{ Assumes a POSITION is a long int. }}
257 public int
258 percentage(num, den)
259 POSITION num, den;
261 POSITION num100 = num * 100;
263 if (num100 / 100 == num)
264 return (num100 / den);
265 else
266 return (num / (den / 100));
270 * Return the specified percentage of a POSITION.
272 public POSITION
273 percent_pos(pos, percent, fraction)
274 POSITION pos;
275 int percent;
276 long fraction;
278 /* 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;
282 if (perden == 0)
283 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));
294 #if !HAVE_STRCHR
296 * strchr is used by regexp.c.
298 char *
299 strchr(s, c)
300 char *s;
301 int c;
303 for ( ; *s != '\0'; s++)
304 if (*s == c)
305 return (s);
306 if (c == '\0')
307 return (s);
308 return (NULL);
310 #endif
312 #if !HAVE_MEMCPY
313 VOID_POINTER
314 memcpy(dst, src, len)
315 VOID_POINTER dst;
316 VOID_POINTER src;
317 int len;
319 char *dstp = (char *) dst;
320 char *srcp = (char *) src;
321 int i;
323 for (i = 0; i < len; i++)
324 dstp[i] = srcp[i];
325 return (dst);
327 #endif
329 #ifdef _OSK_MWC32
332 * This implements an ANSI-style intercept setup for Microware C 3.2
334 public int
335 os9_signal(type, handler)
336 int type;
337 RETSIGTYPE (*handler)();
339 intercept(handler);
342 #include <sgstat.h>
344 int
345 isatty(f)
346 int f;
348 struct sgbuf sgbuf;
350 if (_gs_opt(f, &sgbuf) < 0)
351 return -1;
352 return (sgbuf.sg_class == 0);
355 #endif