os.c revision 60786
1/* 2 * Copyright (C) 1984-2000 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 about less, or for information on how to 8 * contact the author, see the README file. 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#if HAVE_LIMITS_H 37#include <limits.h> 38#endif 39 40#if HAVE_TIME_T 41#define time_type time_t 42#else 43#define time_type long 44#endif 45 46/* 47 * BSD setjmp() saves (and longjmp() restores) the signal mask. 48 * This costs a system call or two per setjmp(), so if possible we clear the 49 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 50 * On other systems, setjmp() doesn't affect the signal mask and so 51 * _setjmp() does not exist; we just use setjmp(). 52 */ 53#if HAVE__SETJMP && HAVE_SIGSETMASK 54#define SET_JUMP _setjmp 55#define LONG_JUMP _longjmp 56#else 57#define SET_JUMP setjmp 58#define LONG_JUMP longjmp 59#endif 60 61public int reading; 62 63static jmp_buf read_label; 64 65extern int sigs; 66 67/* 68 * Like read() system call, but is deliberately interruptible. 69 * A call to intread() from a signal handler will interrupt 70 * any pending iread(). 71 */ 72 public int 73iread(fd, buf, len) 74 int fd; 75 char *buf; 76 unsigned int len; 77{ 78 register int n; 79 80#if MSDOS_COMPILER==WIN32C 81 if (ABORT_SIGS()) 82 return (READ_INTR); 83#else 84#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 85 if (kbhit()) 86 { 87 int c; 88 89 c = getch(); 90 if (c == '\003') 91 return (READ_INTR); 92 ungetch(c); 93 } 94#endif 95#endif 96 if (SET_JUMP(read_label)) 97 { 98 /* 99 * We jumped here from intread. 100 */ 101 reading = 0; 102#if HAVE_SIGSETMASK 103 sigsetmask(0); 104#else 105#ifdef _OSK 106 sigmask(~0); 107#endif 108#endif 109 return (READ_INTR); 110 } 111 112 flush(); 113 reading = 1; 114#if MSDOS_COMPILER==DJGPPC 115 if (isatty(fd)) 116 { 117 /* 118 * Don't try reading from a TTY until a character is 119 * available, because that makes some background programs 120 * believe DOS is busy in a way that prevents those 121 * programs from working while "less" waits. 122 */ 123 fd_set readfds; 124 125 FD_ZERO(&readfds); 126 FD_SET(fd, &readfds); 127 if (select(fd+1, &readfds, 0, 0, 0) == -1) 128 return (-1); 129 } 130#endif 131 n = read(fd, buf, len); 132#if 1 133 /* 134 * This is a kludge to workaround a problem on some systems 135 * where terminating a remote tty connection causes read() to 136 * start returning 0 forever, instead of -1. 137 */ 138 { 139 extern int ignore_eoi; 140 if (!ignore_eoi) 141 { 142 static int consecutive_nulls = 0; 143 if (n == 0) 144 consecutive_nulls++; 145 else 146 consecutive_nulls = 0; 147 if (consecutive_nulls > 20) 148 quit(QUIT_ERROR); 149 } 150 } 151#endif 152 reading = 0; 153 if (n < 0) 154 return (-1); 155 return (n); 156} 157 158/* 159 * Interrupt a pending iread(). 160 */ 161 public void 162intread() 163{ 164 LONG_JUMP(read_label, 1); 165} 166 167/* 168 * Return the current time. 169 */ 170#if HAVE_TIME 171 public long 172get_time() 173{ 174 time_type t; 175 176 time(&t); 177 return (t); 178} 179#endif 180 181 182#if !HAVE_STRERROR 183/* 184 * Local version of strerror, if not available from the system. 185 */ 186 static char * 187strerror(err) 188 int err; 189{ 190#if HAVE_SYS_ERRLIST 191 static char buf[16]; 192 extern char *sys_errlist[]; 193 extern int sys_nerr; 194 195 if (err < sys_nerr) 196 return sys_errlist[err]; 197 sprintf(buf, "Error %d", err); 198 return buf; 199#else 200 return ("cannot open"); 201#endif 202} 203#endif 204 205/* 206 * errno_message: Return an error message based on the value of "errno". 207 */ 208 public char * 209errno_message(filename) 210 char *filename; 211{ 212 register char *p; 213 register char *m; 214#if HAVE_ERRNO 215#if MUST_DEFINE_ERRNO 216 extern int errno; 217#endif 218 p = strerror(errno); 219#else 220 p = "cannot open"; 221#endif 222 m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char)); 223 sprintf(m, "%s: %s", filename, p); 224 return (m); 225} 226 227/* 228 * Return the largest possible number that can fit in a long. 229 */ 230 static long 231get_maxlong() 232{ 233#ifdef LONG_MAX 234 return (LONG_MAX); 235#else 236#ifdef MAXLONG 237 return (MAXLONG); 238#else 239 long n, n2; 240 241 /* 242 * Keep doubling n until we overflow. 243 * {{ This actually only returns the largest power of two that 244 * can fit in a long, but percentage() doesn't really need 245 * it any more accurate than that. }} 246 */ 247 n2 = 128; /* Hopefully no maxlong is less than 128! */ 248 do { 249 n = n2; 250 n2 *= 2; 251 } while (n2 / 2 == n); 252 return (n); 253#endif 254#endif 255} 256 257/* 258 * Return the ratio of two POSITIONS, as a percentage. 259 * {{ Assumes a POSITION is a long int. }} 260 */ 261 public int 262percentage(num, den) 263 POSITION num, den; 264{ 265 if (num <= get_maxlong() / 100) 266 return ((100 * num) / den); 267 else 268 return (num / (den / 100)); 269} 270 271/* 272 * Return the specified percentage of a POSITION. 273 * {{ Assumes a POSITION is a long int. }} 274 */ 275 public POSITION 276percent_pos(pos, percent) 277 POSITION pos; 278 int percent; 279{ 280 if (pos <= get_maxlong() / 100) 281 return ((percent * pos) / 100); 282 else 283 return (percent * (pos / 100)); 284} 285 286#ifdef _OSK_MWC32 287 288/* 289 * This implements an ANSI-style intercept setup for Microware C 3.2 290 */ 291 public int 292os9_signal(type, handler) 293 int type; 294 RETSIGTYPE (*handler)(); 295{ 296 intercept(handler); 297} 298 299#include <sgstat.h> 300 301 public int 302isatty(f) 303 int f; 304{ 305 struct sgbuf sgbuf; 306 307 if (_gs_opt(f, &sgbuf) < 0) 308 return -1; 309 return (sgbuf.sg_class == 0); 310} 311 312#endif 313