1 /* 2 * Copyright (C) 1984-2002 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 58 public int reading; 59 60 static jmp_buf read_label; 61 62 extern 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 70 iread(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 167 intread() 168 { 169 LONG_JUMP(read_label, 1); 170 } 171 172 /* 173 * Return the current time. 174 */ 175 #if HAVE_TIME 176 public long 177 get_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 * 192 strerror(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 * 214 errno_message(filename) 215 char *filename; 216 { 217 register char *p; 218 register char *m; 219 #if HAVE_ERRNO 220 #if MUST_DEFINE_ERRNO 221 extern int errno; 222 #endif 223 p = strerror(errno); 224 #else 225 p = "cannot open"; 226 #endif 227 m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char)); 228 sprintf(m, "%s: %s", filename, p); 229 return (m); 230 } 231 232 /* 233 * Return the ratio of two POSITIONS, as a percentage. 234 * {{ Assumes a POSITION is a long int. }} 235 */ 236 public int 237 percentage(num, den) 238 POSITION num, den; 239 { 240 POSITION num100 = num * 100; 241 242 if (num100 / 100 == num) 243 return (num100 / den); 244 else 245 return (num / (den / 100)); 246 } 247 248 /* 249 * Return the specified percentage of a POSITION. 250 */ 251 public POSITION 252 percent_pos(pos, percent) 253 POSITION pos; 254 int percent; 255 { 256 POSITION result100; 257 258 if (percent == 0) 259 return (0); 260 else if ((result100 = pos * percent) / percent == pos) 261 return (result100 / 100); 262 else 263 return (percent * (pos / 100)); 264 } 265 266 #if !HAVE_STRCHR 267 /* 268 * strchr is used by regexp.c. 269 */ 270 char * 271 strchr(s, c) 272 char *s; 273 int c; 274 { 275 for ( ; *s != '\0'; s++) 276 if (*s == c) 277 return (s); 278 if (c == '\0') 279 return (s); 280 return (NULL); 281 } 282 #endif 283 284 #if !HAVE_MEMCPY 285 VOID_POINTER 286 memcpy(dst, src, len) 287 VOID_POINTER dst; 288 VOID_POINTER src; 289 int len; 290 { 291 char *dstp = (char *) dst; 292 char *srcp = (char *) src; 293 int i; 294 295 for (i = 0; i < len; i++) 296 dstp[i] = srcp[i]; 297 return (dst); 298 } 299 #endif 300 301 #ifdef _OSK_MWC32 302 303 /* 304 * This implements an ANSI-style intercept setup for Microware C 3.2 305 */ 306 public int 307 os9_signal(type, handler) 308 int type; 309 RETSIGTYPE (*handler)(); 310 { 311 intercept(handler); 312 } 313 314 #include <sgstat.h> 315 316 int 317 isatty(f) 318 int f; 319 { 320 struct sgbuf sgbuf; 321 322 if (_gs_opt(f, &sgbuf) < 0) 323 return -1; 324 return (sgbuf.sg_class == 0); 325 } 326 327 #endif 328