1 /* 2 * Copyright (C) 1984-2011 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 #if HAVE_TIME_H 27 #include <time.h> 28 #endif 29 #if HAVE_ERRNO_H 30 #include <errno.h> 31 #endif 32 #if HAVE_VALUES_H 33 #include <values.h> 34 #endif 35 36 #if HAVE_TIME_T 37 #define time_type time_t 38 #else 39 #define time_type long 40 #endif 41 42 extern volatile sig_atomic_t sigs; 43 44 /* 45 * Like read() system call, but is deliberately interruptible. 46 */ 47 public int 48 iread(fd, buf, len) 49 int fd; 50 char *buf; 51 unsigned int len; 52 { 53 register int n; 54 55 start: 56 #if MSDOS_COMPILER==WIN32C 57 if (ABORT_SIGS()) 58 return (READ_INTR); 59 #else 60 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 61 if (kbhit()) 62 { 63 int c; 64 65 c = getch(); 66 if (c == '\003') 67 return (READ_INTR); 68 ungetch(c); 69 } 70 #endif 71 #endif 72 73 flush(); 74 #if MSDOS_COMPILER==DJGPPC 75 if (isatty(fd)) 76 { 77 /* 78 * Don't try reading from a TTY until a character is 79 * available, because that makes some background programs 80 * believe DOS is busy in a way that prevents those 81 * programs from working while "less" waits. 82 */ 83 fd_set readfds; 84 85 FD_ZERO(&readfds); 86 FD_SET(fd, &readfds); 87 if (select(fd+1, &readfds, 0, 0, 0) == -1) 88 return (-1); 89 } 90 #endif 91 n = read(fd, buf, len); 92 #if 1 93 /* 94 * This is a kludge to workaround a problem on some systems 95 * where terminating a remote tty connection causes read() to 96 * start returning 0 forever, instead of -1. 97 */ 98 { 99 extern int ignore_eoi; 100 if (!ignore_eoi) 101 { 102 static int consecutive_nulls = 0; 103 if (n == 0) 104 consecutive_nulls++; 105 else 106 consecutive_nulls = 0; 107 if (consecutive_nulls > 20) 108 quit(QUIT_ERROR); 109 } 110 } 111 #endif 112 if (n < 0) 113 { 114 #if HAVE_ERRNO 115 /* 116 * Certain values of errno indicate we should just retry the read. 117 */ 118 #if MUST_DEFINE_ERRNO 119 extern int errno; 120 #endif 121 #ifdef EINTR 122 if (errno == EINTR) 123 return (READ_INTR); 124 #endif 125 #ifdef EAGAIN 126 if (errno == EAGAIN) 127 goto start; 128 #endif 129 #endif 130 return (-1); 131 } 132 return (n); 133 } 134 135 /* 136 * Return the current time. 137 */ 138 #if HAVE_TIME 139 public long 140 get_time() 141 { 142 time_type t; 143 144 time(&t); 145 return (t); 146 } 147 #endif 148 149 150 #if !HAVE_STRERROR 151 /* 152 * Local version of strerror, if not available from the system. 153 */ 154 static char * 155 strerror(err) 156 int err; 157 { 158 #if HAVE_SYS_ERRLIST 159 static char buf[16]; 160 extern char *sys_errlist[]; 161 extern int sys_nerr; 162 163 if (err < sys_nerr) 164 return sys_errlist[err]; 165 snprintf(buf, sizeof(buf), "Error %d", err); 166 return buf; 167 #else 168 return ("cannot open"); 169 #endif 170 } 171 #endif 172 173 /* 174 * errno_message: Return an error message based on the value of "errno". 175 */ 176 public char * 177 errno_message(filename) 178 char *filename; 179 { 180 register char *p; 181 register char *m; 182 size_t len; 183 #if HAVE_ERRNO 184 #if MUST_DEFINE_ERRNO 185 extern int errno; 186 #endif 187 p = strerror(errno); 188 #else 189 p = "cannot open"; 190 #endif 191 len = strlen(filename) + strlen(p) + 3; 192 m = (char *) ecalloc(len, sizeof(char)); 193 SNPRINTF2(m, len, "%s: %s", filename, p); 194 return (m); 195 } 196 197 /* #define HAVE_FLOAT 0 */ 198 199 static POSITION 200 muldiv(val, num, den) 201 POSITION val, num, den; 202 { 203 #if HAVE_FLOAT 204 double v = (((double) val) * num) / den; 205 return ((POSITION) (v + 0.5)); 206 #else 207 POSITION v = ((POSITION) val) * num; 208 209 if (v / num == val) 210 /* No overflow */ 211 return (POSITION) (v / den); 212 else 213 /* Above calculation overflows; 214 * use a method that is less precise but won't overflow. */ 215 return (POSITION) (val / (den / num)); 216 #endif 217 } 218 219 /* 220 * Return the ratio of two POSITIONS, as a percentage. 221 * {{ Assumes a POSITION is a long int. }} 222 */ 223 public int 224 percentage(num, den) 225 POSITION num, den; 226 { 227 return (int) muldiv(num, (POSITION) 100, den); 228 } 229 230 /* 231 * Return the specified percentage of a POSITION. 232 */ 233 public POSITION 234 percent_pos(pos, percent, fraction) 235 POSITION pos; 236 int percent; 237 long fraction; 238 { 239 /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 240 POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 241 242 if (perden == 0) 243 return (0); 244 return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); 245 } 246 247 #if !HAVE_STRCHR 248 /* 249 * strchr is used by regexp.c. 250 */ 251 char * 252 strchr(s, c) 253 char *s; 254 int c; 255 { 256 for ( ; *s != '\0'; s++) 257 if (*s == c) 258 return (s); 259 if (c == '\0') 260 return (s); 261 return (NULL); 262 } 263 #endif 264 265 #if !HAVE_MEMCPY 266 VOID_POINTER 267 memcpy(dst, src, len) 268 VOID_POINTER dst; 269 VOID_POINTER src; 270 int len; 271 { 272 char *dstp = (char *) dst; 273 char *srcp = (char *) src; 274 int i; 275 276 for (i = 0; i < len; i++) 277 dstp[i] = srcp[i]; 278 return (dst); 279 } 280 #endif 281 282 #ifdef _OSK_MWC32 283 284 /* 285 * This implements an ANSI-style intercept setup for Microware C 3.2 286 */ 287 public int 288 os9_signal(type, handler) 289 int type; 290 RETSIGTYPE (*handler)(); 291 { 292 intercept(handler); 293 } 294 295 #include <sgstat.h> 296 297 int 298 isatty(f) 299 int f; 300 { 301 struct sgbuf sgbuf; 302 303 if (_gs_opt(f, &sgbuf) < 0) 304 return -1; 305 return (sgbuf.sg_class == 0); 306 } 307 308 #endif 309