os.c revision 161475
1/* 2 * Copyright (C) 1984-2005 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 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 58public int reading; 59 60static jmp_buf read_label; 61 62extern int sigs; 63 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 70iread(fd, buf, len) 71 int fd; 72 char *buf; 73 unsigned int len; 74{ 75 register int n; 76 77#if MSDOS_COMPILER==WIN32C 78 if (ABORT_SIGS()) 79 return (READ_INTR); 80#else 81#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 82 if (kbhit()) 83 { 84 int c; 85 86 c = getch(); 87 if (c == '\003') 88 return (READ_INTR); 89 ungetch(c); 90 } 91#endif 92#endif 93 if (SET_JUMP(read_label)) 94 { 95 /* 96 * We jumped here from intread. 97 */ 98 reading = 0; 99#if HAVE_SIGPROCMASK 100 { 101 sigset_t mask; 102 sigemptyset(&mask); 103 sigprocmask(SIG_SETMASK, &mask, NULL); 104 } 105#else 106#if HAVE_SIGSETMASK 107 sigsetmask(0); 108#else 109#ifdef _OSK 110 sigmask(~0); 111#endif 112#endif 113#endif 114 return (READ_INTR); 115 } 116 117 flush(); 118 reading = 1; 119#if MSDOS_COMPILER==DJGPPC 120 if (isatty(fd)) 121 { 122 /* 123 * Don't try reading from a TTY until a character is 124 * available, because that makes some background programs 125 * believe DOS is busy in a way that prevents those 126 * programs from working while "less" waits. 127 */ 128 fd_set readfds; 129 130 FD_ZERO(&readfds); 131 FD_SET(fd, &readfds); 132 if (select(fd+1, &readfds, 0, 0, 0) == -1) 133 return (-1); 134 } 135#endif 136 n = read(fd, buf, len); 137#if 1 138 /* 139 * This is a kludge to workaround a problem on some systems 140 * where terminating a remote tty connection causes read() to 141 * start returning 0 forever, instead of -1. 142 */ 143 { 144 extern int ignore_eoi; 145 if (!ignore_eoi) 146 { 147 static int consecutive_nulls = 0; 148 if (n == 0) 149 consecutive_nulls++; 150 else 151 consecutive_nulls = 0; 152 if (consecutive_nulls > 20) 153 quit(QUIT_ERROR); 154 } 155 } 156#endif 157 reading = 0; 158 if (n < 0) 159 return (-1); 160 return (n); 161} 162 163/* 164 * Interrupt a pending iread(). 165 */ 166 public void 167intread() 168{ 169 LONG_JUMP(read_label, 1); 170} 171 172/* 173 * Return the current time. 174 */ 175#if HAVE_TIME 176 public long 177get_time() 178{ 179 time_type t; 180 181 time(&t); 182 return (t); 183} 184#endif 185 186 187#if !HAVE_STRERROR 188/* 189 * Local version of strerror, if not available from the system. 190 */ 191 static char * 192strerror(err) 193 int err; 194{ 195#if HAVE_SYS_ERRLIST 196 static char buf[16]; 197 extern char *sys_errlist[]; 198 extern int sys_nerr; 199 200 if (err < sys_nerr) 201 return sys_errlist[err]; 202 sprintf(buf, "Error %d", err); 203 return buf; 204#else 205 return ("cannot open"); 206#endif 207} 208#endif 209 210/* 211 * errno_message: Return an error message based on the value of "errno". 212 */ 213 public char * 214errno_message(filename) 215 char *filename; 216{ 217 register char *p; 218 register char *m; 219 int len; 220#if HAVE_ERRNO 221#if MUST_DEFINE_ERRNO 222 extern int errno; 223#endif 224 p = strerror(errno); 225#else 226 p = "cannot open"; 227#endif 228 len = strlen(filename) + strlen(p) + 3; 229 m = (char *) ecalloc(len, sizeof(char)); 230 SNPRINTF2(m, len, "%s: %s", filename, p); 231 return (m); 232} 233 234/* 235 * Return the ratio of two POSITIONS, as a percentage. 236 * {{ Assumes a POSITION is a long int. }} 237 */ 238 public int 239percentage(num, den) 240 POSITION num, den; 241{ 242 POSITION num100 = num * 100; 243 244 if (num100 / 100 == num) 245 return (num100 / den); 246 else 247 return (num / (den / 100)); 248} 249 250/* 251 * Return the specified percentage of a POSITION. 252 */ 253 public POSITION 254percent_pos(pos, percent) 255 POSITION pos; 256 int percent; 257{ 258 POSITION result100; 259 260 if (percent == 0) 261 return (0); 262 else if ((result100 = pos * percent) / percent == pos) 263 return (result100 / 100); 264 else 265 return (percent * (pos / 100)); 266} 267 268#if !HAVE_STRCHR 269/* 270 * strchr is used by regexp.c. 271 */ 272 char * 273strchr(s, c) 274 char *s; 275 int c; 276{ 277 for ( ; *s != '\0'; s++) 278 if (*s == c) 279 return (s); 280 if (c == '\0') 281 return (s); 282 return (NULL); 283} 284#endif 285 286#if !HAVE_MEMCPY 287 VOID_POINTER 288memcpy(dst, src, len) 289 VOID_POINTER dst; 290 VOID_POINTER src; 291 int len; 292{ 293 char *dstp = (char *) dst; 294 char *srcp = (char *) src; 295 int i; 296 297 for (i = 0; i < len; i++) 298 dstp[i] = srcp[i]; 299 return (dst); 300} 301#endif 302 303#ifdef _OSK_MWC32 304 305/* 306 * This implements an ANSI-style intercept setup for Microware C 3.2 307 */ 308 public int 309os9_signal(type, handler) 310 int type; 311 RETSIGTYPE (*handler)(); 312{ 313 intercept(handler); 314} 315 316#include <sgstat.h> 317 318 int 319isatty(f) 320 int f; 321{ 322 struct sgbuf sgbuf; 323 324 if (_gs_opt(f, &sgbuf) < 0) 325 return -1; 326 return (sgbuf.sg_class == 0); 327} 328 329#endif 330