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