1 /* $NetBSD: os.c,v 1.3 2011/07/03 20:14:13 tron Exp $ */ 2 3 /* 4 * Copyright (C) 1984-2011 Mark Nudelman 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information about less, or for information on how to 10 * contact the author, see the README file. 11 */ 12 13 14 /* 15 * Operating system dependent routines. 16 * 17 * Most of the stuff in here is based on Unix, but an attempt 18 * has been made to make things work on other operating systems. 19 * This will sometimes result in a loss of functionality, unless 20 * someone rewrites code specifically for the new operating system. 21 * 22 * The makefile provides defines to decide whether various 23 * Unix features are present. 24 */ 25 26 #include "less.h" 27 #include <signal.h> 28 #include <setjmp.h> 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 38 39 #if HAVE_TIME_T 40 #define time_type time_t 41 #else 42 #define time_type long 43 #endif 44 45 /* 46 * BSD setjmp() saves (and longjmp() restores) the signal mask. 47 * This costs a system call or two per setjmp(), so if possible we clear the 48 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 49 * On other systems, setjmp() doesn't affect the signal mask and so 50 * _setjmp() does not exist; we just use setjmp(). 51 */ 52 #if HAVE__SETJMP && HAVE_SIGSETMASK 53 #define SET_JUMP _setjmp 54 #define LONG_JUMP _longjmp 55 #else 56 #define SET_JUMP setjmp 57 #define LONG_JUMP longjmp 58 #endif 59 60 public int reading; 61 62 static jmp_buf read_label; 63 64 extern int sigs; 65 66 #if !HAVE_STRERROR 67 static char *strerror __P((int)); 68 #endif 69 70 /* 71 * Like read() system call, but is deliberately interruptible. 72 * A call to intread() from a signal handler will interrupt 73 * any pending iread(). 74 */ 75 public int 76 iread(fd, buf, len) 77 int fd; 78 char *buf; 79 unsigned int len; 80 { 81 register int n; 82 83 start: 84 #if MSDOS_COMPILER==WIN32C 85 if (ABORT_SIGS()) 86 return (READ_INTR); 87 #else 88 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 89 if (kbhit()) 90 { 91 int c; 92 93 c = getch(); 94 if (c == '\003') 95 return (READ_INTR); 96 ungetch(c); 97 } 98 #endif 99 #endif 100 if (SET_JUMP(read_label)) 101 { 102 /* 103 * We jumped here from intread. 104 */ 105 reading = 0; 106 #if HAVE_SIGPROCMASK 107 { 108 sigset_t mask; 109 sigemptyset(&mask); 110 sigprocmask(SIG_SETMASK, &mask, NULL); 111 } 112 #else 113 #if HAVE_SIGSETMASK 114 sigsetmask(0); 115 #else 116 #ifdef _OSK 117 sigmask(~0); 118 #endif 119 #endif 120 #endif 121 return (READ_INTR); 122 } 123 124 flush(); 125 reading = 1; 126 #if MSDOS_COMPILER==DJGPPC 127 if (isatty(fd)) 128 { 129 /* 130 * Don't try reading from a TTY until a character is 131 * available, because that makes some background programs 132 * believe DOS is busy in a way that prevents those 133 * programs from working while "less" waits. 134 */ 135 fd_set readfds; 136 137 FD_ZERO(&readfds); 138 FD_SET(fd, &readfds); 139 if (select(fd+1, &readfds, 0, 0, 0) == -1) 140 return (-1); 141 } 142 #endif 143 n = read(fd, buf, len); 144 #if 1 145 /* 146 * This is a kludge to workaround a problem on some systems 147 * where terminating a remote tty connection causes read() to 148 * start returning 0 forever, instead of -1. 149 */ 150 { 151 extern int ignore_eoi; 152 if (!ignore_eoi) 153 { 154 static int consecutive_nulls = 0; 155 if (n == 0) 156 consecutive_nulls++; 157 else 158 consecutive_nulls = 0; 159 if (consecutive_nulls > 20) 160 quit(QUIT_ERROR); 161 } 162 } 163 #endif 164 reading = 0; 165 if (n < 0) 166 { 167 #if HAVE_ERRNO 168 /* 169 * Certain values of errno indicate we should just retry the read. 170 */ 171 #if MUST_DEFINE_ERRNO 172 extern int errno; 173 #endif 174 #ifdef EINTR 175 if (errno == EINTR) 176 goto start; 177 #endif 178 #ifdef EAGAIN 179 if (errno == EAGAIN) 180 goto start; 181 #endif 182 #endif 183 return (-1); 184 } 185 return (n); 186 } 187 188 /* 189 * Interrupt a pending iread(). 190 */ 191 public void 192 intread() 193 { 194 LONG_JUMP(read_label, 1); 195 } 196 197 /* 198 * Return the current time. 199 */ 200 #if HAVE_TIME 201 public long 202 get_time() 203 { 204 time_type t; 205 206 time(&t); 207 return (t); 208 } 209 #endif 210 211 212 #if !HAVE_STRERROR 213 /* 214 * Local version of strerror, if not available from the system. 215 */ 216 static char * 217 strerror(err) 218 int err; 219 { 220 #if HAVE_SYS_ERRLIST 221 static char buf[16]; 222 extern char *sys_errlist[]; 223 extern int sys_nerr; 224 225 if (err < sys_nerr) 226 return sys_errlist[err]; 227 sprintf(buf, "Error %d", err); 228 return buf; 229 #else 230 return ("cannot open"); 231 #endif 232 } 233 #endif 234 235 /* 236 * errno_message: Return an error message based on the value of "errno". 237 */ 238 public char * 239 errno_message(filename) 240 char *filename; 241 { 242 register const char *p; 243 register char *m; 244 int len; 245 #if HAVE_ERRNO 246 #if MUST_DEFINE_ERRNO 247 extern int errno; 248 #endif 249 p = strerror(errno); 250 #else 251 p = "cannot open"; 252 #endif 253 len = strlen(filename) + strlen(p) + 3; 254 m = (char *) ecalloc(len, sizeof(char)); 255 SNPRINTF2(m, len, "%s: %s", filename, p); 256 return (m); 257 } 258 259 /* #define HAVE_FLOAT 0 */ 260 261 static POSITION 262 muldiv(val, num, den) 263 POSITION val, num, den; 264 { 265 #if HAVE_FLOAT 266 double v = (((double) val) * num) / den; 267 return ((POSITION) (v + 0.5)); 268 #else 269 POSITION v = ((POSITION) val) * num; 270 271 if (v / num == val) 272 /* No overflow */ 273 return (POSITION) (v / den); 274 else 275 /* Above calculation overflows; 276 * use a method that is less precise but won't overflow. */ 277 return (POSITION) (val / (den / num)); 278 #endif 279 } 280 281 /* 282 * Return the ratio of two POSITIONS, as a percentage. 283 * {{ Assumes a POSITION is a long int. }} 284 */ 285 public int 286 percentage(num, den) 287 POSITION num, den; 288 { 289 return (int) muldiv(num, (POSITION) 100, den); 290 } 291 292 /* 293 * Return the specified percentage of a POSITION. 294 */ 295 public POSITION 296 percent_pos(pos, percent, fraction) 297 POSITION pos; 298 int percent; 299 long fraction; 300 { 301 /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 302 POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 303 304 if (perden == 0) 305 return (0); 306 return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); 307 } 308 309 #if !HAVE_STRCHR 310 /* 311 * strchr is used by regexp.c. 312 */ 313 char * 314 strchr(s, c) 315 char *s; 316 int c; 317 { 318 for ( ; *s != '\0'; s++) 319 if (*s == c) 320 return (s); 321 if (c == '\0') 322 return (s); 323 return (NULL); 324 } 325 #endif 326 327 #if !HAVE_MEMCPY 328 VOID_POINTER 329 memcpy(dst, src, len) 330 VOID_POINTER dst; 331 VOID_POINTER src; 332 int len; 333 { 334 char *dstp = (char *) dst; 335 char *srcp = (char *) src; 336 int i; 337 338 for (i = 0; i < len; i++) 339 dstp[i] = srcp[i]; 340 return (dst); 341 } 342 #endif 343 344 #ifdef _OSK_MWC32 345 346 /* 347 * This implements an ANSI-style intercept setup for Microware C 3.2 348 */ 349 public int 350 os9_signal(type, handler) 351 int type; 352 RETSIGTYPE (*handler)(); 353 { 354 intercept(handler); 355 } 356 357 #include <sgstat.h> 358 359 int 360 isatty(f) 361 int f; 362 { 363 struct sgbuf sgbuf; 364 365 if (_gs_opt(f, &sgbuf) < 0) 366 return -1; 367 return (sgbuf.sg_class == 0); 368 } 369 370 #endif 371