usr.sbin/makefs/hammer2: Remove redundant hammer2_inode_modify()
[dragonfly.git] / contrib / less / os.c
blob22b97de34b1c9a9701216d920a5c42a4f8ad58c1
1 /*
2 * Copyright (C) 1984-2022 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, see the README file.
8 */
12 * Operating system dependent routines.
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.
19 * The makefile provides defines to decide whether various
20 * Unix features are present.
23 #include "less.h"
24 #include <signal.h>
25 #include <setjmp.h>
26 #if MSDOS_COMPILER==WIN32C
27 #include <windows.h>
28 #endif
29 #if HAVE_TIME_H
30 #include <time.h>
31 #endif
32 #if HAVE_ERRNO_H
33 #include <errno.h>
34 #endif
35 #if HAVE_VALUES_H
36 #include <values.h>
37 #endif
39 #if HAVE_POLL && !MSDOS_COMPILER && !defined(__APPLE__)
40 #define USE_POLL 1
41 #else
42 #define USE_POLL 0
43 #endif
44 #if USE_POLL
45 #include <poll.h>
46 #endif
49 * BSD setjmp() saves (and longjmp() restores) the signal mask.
50 * This costs a system call or two per setjmp(), so if possible we clear the
51 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
52 * On other systems, setjmp() doesn't affect the signal mask and so
53 * _setjmp() does not exist; we just use setjmp().
55 #if HAVE__SETJMP && HAVE_SIGSETMASK
56 #define SET_JUMP _setjmp
57 #define LONG_JUMP _longjmp
58 #else
59 #define SET_JUMP setjmp
60 #define LONG_JUMP longjmp
61 #endif
63 public int reading;
64 public int consecutive_nulls = 0;
66 static jmp_buf read_label;
68 extern int sigs;
69 extern int ignore_eoi;
70 extern int exit_F_on_close;
71 #if !MSDOS_COMPILER
72 extern int tty;
73 #endif
75 #if USE_POLL
77 * Return true if one of the events has occurred on the specified file.
79 static int
80 poll_events(fd, events)
81 int fd;
82 int events;
84 struct pollfd poller = { fd, events, 0 };
85 int n = poll(&poller, 1, 0);
86 if (n <= 0)
87 return 0;
88 return (poller.revents & events);
90 #endif
93 * Like read() system call, but is deliberately interruptible.
94 * A call to intread() from a signal handler will interrupt
95 * any pending iread().
97 public int
98 iread(fd, buf, len)
99 int fd;
100 unsigned char *buf;
101 unsigned int len;
103 int n;
105 start:
106 #if MSDOS_COMPILER==WIN32C
107 if (ABORT_SIGS())
108 return (READ_INTR);
109 #else
110 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
111 if (kbhit())
113 int c;
115 c = getch();
116 if (c == '\003')
117 return (READ_INTR);
118 ungetch(c);
120 #endif
121 #endif
122 if (SET_JUMP(read_label))
125 * We jumped here from intread.
127 reading = 0;
128 #if HAVE_SIGPROCMASK
130 sigset_t mask;
131 sigemptyset(&mask);
132 sigprocmask(SIG_SETMASK, &mask, NULL);
134 #else
135 #if HAVE_SIGSETMASK
136 sigsetmask(0);
137 #else
138 #ifdef _OSK
139 sigmask(~0);
140 #endif
141 #endif
142 #endif
143 return (READ_INTR);
146 flush();
147 reading = 1;
148 #if MSDOS_COMPILER==DJGPPC
149 if (isatty(fd))
152 * Don't try reading from a TTY until a character is
153 * available, because that makes some background programs
154 * believe DOS is busy in a way that prevents those
155 * programs from working while "less" waits.
157 fd_set readfds;
159 FD_ZERO(&readfds);
160 FD_SET(fd, &readfds);
161 if (select(fd+1, &readfds, 0, 0, 0) == -1)
163 reading = 0;
164 return (-1);
167 #endif
168 #if USE_POLL
169 if (ignore_eoi && fd != tty)
171 int close_events = exit_F_on_close ? POLLERR|POLLHUP : POLLERR;
172 if (poll_events(tty, POLLIN) && getchr() == CONTROL('X'))
174 sigs |= S_INTERRUPT;
175 reading = 0;
176 return (READ_INTR);
178 if (poll_events(fd, close_events))
180 sigs |= S_INTERRUPT;
181 reading = 0;
182 return (READ_INTR);
185 #else
186 #if MSDOS_COMPILER==WIN32C
187 if (win32_kbhit() && WIN32getch() == CONTROL('X'))
189 sigs |= S_INTERRUPT;
190 reading = 0;
191 return (READ_INTR);
193 #endif
194 #endif
195 n = read(fd, buf, len);
196 reading = 0;
197 #if 1
199 * This is a kludge to workaround a problem on some systems
200 * where terminating a remote tty connection causes read() to
201 * start returning 0 forever, instead of -1.
204 if (!ignore_eoi)
206 if (n == 0)
207 consecutive_nulls++;
208 else
209 consecutive_nulls = 0;
210 if (consecutive_nulls > 20)
211 quit(QUIT_ERROR);
214 #endif
215 if (n < 0)
217 #if HAVE_ERRNO
219 * Certain values of errno indicate we should just retry the read.
221 #if MUST_DEFINE_ERRNO
222 extern int errno;
223 #endif
224 #ifdef EINTR
225 if (errno == EINTR)
226 goto start;
227 #endif
228 #ifdef EAGAIN
229 if (errno == EAGAIN)
230 goto start;
231 #endif
232 #endif
233 return (-1);
235 return (n);
239 * Interrupt a pending iread().
241 public void
242 intread(VOID_PARAM)
244 LONG_JUMP(read_label, 1);
248 * Return the current time.
250 #if HAVE_TIME
251 public time_type
252 get_time(VOID_PARAM)
254 time_type t;
256 time(&t);
257 return (t);
259 #endif
262 #if !HAVE_STRERROR
264 * Local version of strerror, if not available from the system.
266 static char *
267 strerror(err)
268 int err;
270 static char buf[INT_STRLEN_BOUND(int)+12];
271 #if HAVE_SYS_ERRLIST
272 extern char *sys_errlist[];
273 extern int sys_nerr;
275 if (err < sys_nerr)
276 return sys_errlist[err];
277 #endif
278 sprintf(buf, "Error %d", err);
279 return buf;
281 #endif
284 * errno_message: Return an error message based on the value of "errno".
286 public char *
287 errno_message(filename)
288 char *filename;
290 char *p;
291 char *m;
292 int len;
293 #if HAVE_ERRNO
294 #if MUST_DEFINE_ERRNO
295 extern int errno;
296 #endif
297 p = strerror(errno);
298 #else
299 p = "cannot open";
300 #endif
301 len = (int) (strlen(filename) + strlen(p) + 3);
302 m = (char *) ecalloc(len, sizeof(char));
303 SNPRINTF2(m, len, "%s: %s", filename, p);
304 return (m);
307 /* #define HAVE_FLOAT 0 */
309 static POSITION
310 muldiv(val, num, den)
311 POSITION val, num, den;
313 #if HAVE_FLOAT
314 double v = (((double) val) * num) / den;
315 return ((POSITION) (v + 0.5));
316 #else
317 POSITION v = ((POSITION) val) * num;
319 if (v / num == val)
320 /* No overflow */
321 return (POSITION) (v / den);
322 else
323 /* Above calculation overflows;
324 * use a method that is less precise but won't overflow. */
325 return (POSITION) (val / (den / num));
326 #endif
330 * Return the ratio of two POSITIONS, as a percentage.
331 * {{ Assumes a POSITION is a long int. }}
333 public int
334 percentage(num, den)
335 POSITION num;
336 POSITION den;
338 return (int) muldiv(num, (POSITION) 100, den);
342 * Return the specified percentage of a POSITION.
344 public POSITION
345 percent_pos(pos, percent, fraction)
346 POSITION pos;
347 int percent;
348 long fraction;
350 /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */
351 POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100);
353 if (perden == 0)
354 return (0);
355 return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM);
358 #if !HAVE_STRCHR
360 * strchr is used by regexp.c.
362 char *
363 strchr(s, c)
364 char *s;
365 int c;
367 for ( ; *s != '\0'; s++)
368 if (*s == c)
369 return (s);
370 if (c == '\0')
371 return (s);
372 return (NULL);
374 #endif
376 #if !HAVE_MEMCPY
377 VOID_POINTER
378 memcpy(dst, src, len)
379 VOID_POINTER dst;
380 VOID_POINTER src;
381 int len;
383 char *dstp = (char *) dst;
384 char *srcp = (char *) src;
385 int i;
387 for (i = 0; i < len; i++)
388 dstp[i] = srcp[i];
389 return (dst);
391 #endif
393 #ifdef _OSK_MWC32
396 * This implements an ANSI-style intercept setup for Microware C 3.2
398 public int
399 os9_signal(type, handler)
400 int type;
401 RETSIGTYPE (*handler)();
403 intercept(handler);
406 #include <sgstat.h>
408 int
409 isatty(f)
410 int f;
412 struct sgbuf sgbuf;
414 if (_gs_opt(f, &sgbuf) < 0)
415 return -1;
416 return (sgbuf.sg_class == 0);
419 #endif
421 public void
422 sleep_ms(ms)
423 int ms;
425 #if MSDOS_COMPILER==WIN32C
426 Sleep(ms);
427 #else
428 #if HAVE_NANOSLEEP
429 int sec = ms / 1000;
430 struct timespec t = { sec, (ms - sec*1000) * 1000000 };
431 nanosleep(&t, NULL);
432 #else
433 #if HAVE_USLEEP
434 usleep(ms);
435 #else
436 sleep((ms+999) / 1000);
437 #endif
438 #endif
439 #endif