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