Annotation of src/usr.bin/less/os.c, Revision 1.1.1.3
1.1 etheisen 1: /*
1.1.1.3 ! shadchin 2: * Copyright (C) 1984-2011 Mark Nudelman
1.1 etheisen 3: *
1.1.1.2 millert 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.
1.1 etheisen 6: *
1.1.1.2 millert 7: * For more information about less, or for information on how to
8: * contact the author, see the README file.
1.1 etheisen 9: */
10:
11:
12: /*
13: * Operating system dependent routines.
14: *
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.
19: *
20: * The makefile provides defines to decide whether various
21: * Unix features are present.
22: */
23:
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
36:
37: #if HAVE_TIME_T
38: #define time_type time_t
39: #else
40: #define time_type long
41: #endif
42:
43: /*
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().
49: */
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
57:
58: public int reading;
59:
60: static jmp_buf read_label;
61:
1.1.1.2 millert 62: extern int sigs;
63:
1.1 etheisen 64: /*
65: * Like read() system call, but is deliberately interruptible.
66: * A call to intread() from a signal handler will interrupt
67: * any pending iread().
68: */
69: public int
70: iread(fd, buf, len)
71: int fd;
72: char *buf;
73: unsigned int len;
74: {
75: register int n;
76:
1.1.1.3 ! shadchin 77: start:
1.1.1.2 millert 78: #if MSDOS_COMPILER==WIN32C
79: if (ABORT_SIGS())
80: return (READ_INTR);
81: #else
82: #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
1.1 etheisen 83: if (kbhit())
84: {
85: int c;
86:
87: c = getch();
88: if (c == '\003')
89: return (READ_INTR);
90: ungetch(c);
91: }
92: #endif
1.1.1.2 millert 93: #endif
1.1 etheisen 94: if (SET_JUMP(read_label))
95: {
96: /*
97: * We jumped here from intread.
98: */
99: reading = 0;
1.1.1.2 millert 100: #if HAVE_SIGPROCMASK
101: {
102: sigset_t mask;
103: sigemptyset(&mask);
104: sigprocmask(SIG_SETMASK, &mask, NULL);
105: }
106: #else
1.1 etheisen 107: #if HAVE_SIGSETMASK
108: sigsetmask(0);
1.1.1.2 millert 109: #else
110: #ifdef _OSK
111: sigmask(~0);
112: #endif
113: #endif
1.1 etheisen 114: #endif
115: return (READ_INTR);
116: }
117:
118: flush();
119: reading = 1;
1.1.1.2 millert 120: #if MSDOS_COMPILER==DJGPPC
121: if (isatty(fd))
122: {
123: /*
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.
128: */
129: fd_set readfds;
130:
131: FD_ZERO(&readfds);
132: FD_SET(fd, &readfds);
133: if (select(fd+1, &readfds, 0, 0, 0) == -1)
134: return (-1);
135: }
136: #endif
1.1 etheisen 137: n = read(fd, buf, len);
1.1.1.2 millert 138: #if 1
139: /*
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.
143: */
144: {
145: extern int ignore_eoi;
146: if (!ignore_eoi)
147: {
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);
155: }
156: }
157: #endif
1.1 etheisen 158: reading = 0;
159: if (n < 0)
1.1.1.3 ! shadchin 160: {
! 161: #if HAVE_ERRNO
! 162: /*
! 163: * Certain values of errno indicate we should just retry the read.
! 164: */
! 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
1.1 etheisen 177: return (-1);
1.1.1.3 ! shadchin 178: }
1.1 etheisen 179: return (n);
180: }
181:
182: /*
183: * Interrupt a pending iread().
184: */
185: public void
186: intread()
187: {
188: LONG_JUMP(read_label, 1);
189: }
190:
191: /*
192: * Return the current time.
193: */
194: #if HAVE_TIME
195: public long
196: get_time()
197: {
198: time_type t;
199:
200: time(&t);
201: return (t);
202: }
203: #endif
204:
205:
206: #if !HAVE_STRERROR
207: /*
208: * Local version of strerror, if not available from the system.
209: */
210: static char *
211: strerror(err)
212: int err;
213: {
214: #if HAVE_SYS_ERRLIST
215: static char buf[16];
216: extern char *sys_errlist[];
217: extern int sys_nerr;
218:
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
226: }
227: #endif
228:
229: /*
230: * errno_message: Return an error message based on the value of "errno".
231: */
232: public char *
233: errno_message(filename)
234: char *filename;
235: {
236: register char *p;
237: register char *m;
1.1.1.3 ! shadchin 238: int len;
1.1 etheisen 239: #if HAVE_ERRNO
1.1.1.2 millert 240: #if MUST_DEFINE_ERRNO
1.1 etheisen 241: extern int errno;
1.1.1.2 millert 242: #endif
1.1 etheisen 243: p = strerror(errno);
244: #else
245: p = "cannot open";
246: #endif
1.1.1.3 ! shadchin 247: len = strlen(filename) + strlen(p) + 3;
! 248: m = (char *) ecalloc(len, sizeof(char));
! 249: SNPRINTF2(m, len, "%s: %s", filename, p);
1.1 etheisen 250: return (m);
251: }
252:
1.1.1.3 ! shadchin 253: /* #define HAVE_FLOAT 0 */
! 254:
! 255: static POSITION
! 256: muldiv(val, num, den)
! 257: POSITION val, num, den;
! 258: {
! 259: #if HAVE_FLOAT
! 260: double v = (((double) val) * num) / den;
! 261: return ((POSITION) (v + 0.5));
! 262: #else
! 263: POSITION v = ((POSITION) val) * num;
! 264:
! 265: if (v / num == val)
! 266: /* No overflow */
! 267: return (POSITION) (v / den);
! 268: else
! 269: /* Above calculation overflows;
! 270: * use a method that is less precise but won't overflow. */
! 271: return (POSITION) (val / (den / num));
! 272: #endif
! 273: }
! 274:
1.1 etheisen 275: /*
1.1.1.2 millert 276: * Return the ratio of two POSITIONS, as a percentage.
277: * {{ Assumes a POSITION is a long int. }}
1.1 etheisen 278: */
1.1.1.2 millert 279: public int
280: percentage(num, den)
281: POSITION num, den;
1.1 etheisen 282: {
1.1.1.3 ! shadchin 283: return (int) muldiv(num, (POSITION) 100, den);
1.1 etheisen 284: }
1.1.1.2 millert 285:
286: /*
287: * Return the specified percentage of a POSITION.
288: */
289: public POSITION
1.1.1.3 ! shadchin 290: percent_pos(pos, percent, fraction)
1.1.1.2 millert 291: POSITION pos;
292: int percent;
1.1.1.3 ! shadchin 293: long fraction;
1.1 etheisen 294: {
1.1.1.3 ! shadchin 295: /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */
! 296: POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100);
1.1 etheisen 297:
1.1.1.3 ! shadchin 298: if (perden == 0)
1.1.1.2 millert 299: return (0);
1.1.1.3 ! shadchin 300: return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM);
1.1.1.2 millert 301: }
302:
303: #if !HAVE_STRCHR
304: /*
305: * strchr is used by regexp.c.
306: */
307: char *
308: strchr(s, c)
309: char *s;
310: int c;
311: {
312: for ( ; *s != '\0'; s++)
313: if (*s == c)
314: return (s);
315: if (c == '\0')
316: return (s);
317: return (NULL);
318: }
319: #endif
320:
321: #if !HAVE_MEMCPY
322: VOID_POINTER
323: memcpy(dst, src, len)
324: VOID_POINTER dst;
325: VOID_POINTER src;
326: int len;
327: {
328: char *dstp = (char *) dst;
329: char *srcp = (char *) src;
330: int i;
331:
332: for (i = 0; i < len; i++)
333: dstp[i] = srcp[i];
334: return (dst);
1.1 etheisen 335: }
336: #endif
337:
1.1.1.2 millert 338: #ifdef _OSK_MWC32
339:
1.1 etheisen 340: /*
1.1.1.2 millert 341: * This implements an ANSI-style intercept setup for Microware C 3.2
1.1 etheisen 342: */
1.1.1.2 millert 343: public int
344: os9_signal(type, handler)
345: int type;
346: RETSIGTYPE (*handler)();
1.1 etheisen 347: {
1.1.1.2 millert 348: intercept(handler);
1.1 etheisen 349: }
1.1.1.2 millert 350:
351: #include <sgstat.h>
352:
353: int
354: isatty(f)
355: int f;
356: {
357: struct sgbuf sgbuf;
358:
359: if (_gs_opt(f, &sgbuf) < 0)
360: return -1;
361: return (sgbuf.sg_class == 0);
362: }
363:
364: #endif