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