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 61 public int reading; 62 63 static jmp_buf read_label; 64 65 extern 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 73 iread(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 162 intread() 163 { 164 LONG_JUMP(read_label, 1); 165 } 166 167 /* 168 * Return the current time. 169 */ 170 #if HAVE_TIME 171 public long 172 get_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 * 187 strerror(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 * 209 errno_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 231 get_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 262 percentage(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 276 percent_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 292 os9_signal(type, handler) 293 int type; 294 RETSIGTYPE (*handler)(); 295 { 296 intercept(handler); 297 } 298 299 #include <sgstat.h> 300 301 public int 302 isatty(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