1*f7cf2976SLionel Sambuc /* $NetBSD: os.c,v 1.3 2011/07/03 20:14:13 tron Exp $ */ 2*f7cf2976SLionel Sambuc 3*f7cf2976SLionel Sambuc /* 4*f7cf2976SLionel Sambuc * Copyright (C) 1984-2011 Mark Nudelman 5*f7cf2976SLionel Sambuc * 6*f7cf2976SLionel Sambuc * You may distribute under the terms of either the GNU General Public 7*f7cf2976SLionel Sambuc * License or the Less License, as specified in the README file. 8*f7cf2976SLionel Sambuc * 9*f7cf2976SLionel Sambuc * For more information about less, or for information on how to 10*f7cf2976SLionel Sambuc * contact the author, see the README file. 11*f7cf2976SLionel Sambuc */ 12*f7cf2976SLionel Sambuc 13*f7cf2976SLionel Sambuc 14*f7cf2976SLionel Sambuc /* 15*f7cf2976SLionel Sambuc * Operating system dependent routines. 16*f7cf2976SLionel Sambuc * 17*f7cf2976SLionel Sambuc * Most of the stuff in here is based on Unix, but an attempt 18*f7cf2976SLionel Sambuc * has been made to make things work on other operating systems. 19*f7cf2976SLionel Sambuc * This will sometimes result in a loss of functionality, unless 20*f7cf2976SLionel Sambuc * someone rewrites code specifically for the new operating system. 21*f7cf2976SLionel Sambuc * 22*f7cf2976SLionel Sambuc * The makefile provides defines to decide whether various 23*f7cf2976SLionel Sambuc * Unix features are present. 24*f7cf2976SLionel Sambuc */ 25*f7cf2976SLionel Sambuc 26*f7cf2976SLionel Sambuc #include "less.h" 27*f7cf2976SLionel Sambuc #include <signal.h> 28*f7cf2976SLionel Sambuc #include <setjmp.h> 29*f7cf2976SLionel Sambuc #if HAVE_TIME_H 30*f7cf2976SLionel Sambuc #include <time.h> 31*f7cf2976SLionel Sambuc #endif 32*f7cf2976SLionel Sambuc #if HAVE_ERRNO_H 33*f7cf2976SLionel Sambuc #include <errno.h> 34*f7cf2976SLionel Sambuc #endif 35*f7cf2976SLionel Sambuc #if HAVE_VALUES_H 36*f7cf2976SLionel Sambuc #include <values.h> 37*f7cf2976SLionel Sambuc #endif 38*f7cf2976SLionel Sambuc 39*f7cf2976SLionel Sambuc #if HAVE_TIME_T 40*f7cf2976SLionel Sambuc #define time_type time_t 41*f7cf2976SLionel Sambuc #else 42*f7cf2976SLionel Sambuc #define time_type long 43*f7cf2976SLionel Sambuc #endif 44*f7cf2976SLionel Sambuc 45*f7cf2976SLionel Sambuc /* 46*f7cf2976SLionel Sambuc * BSD setjmp() saves (and longjmp() restores) the signal mask. 47*f7cf2976SLionel Sambuc * This costs a system call or two per setjmp(), so if possible we clear the 48*f7cf2976SLionel Sambuc * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 49*f7cf2976SLionel Sambuc * On other systems, setjmp() doesn't affect the signal mask and so 50*f7cf2976SLionel Sambuc * _setjmp() does not exist; we just use setjmp(). 51*f7cf2976SLionel Sambuc */ 52*f7cf2976SLionel Sambuc #if HAVE__SETJMP && HAVE_SIGSETMASK 53*f7cf2976SLionel Sambuc #define SET_JUMP _setjmp 54*f7cf2976SLionel Sambuc #define LONG_JUMP _longjmp 55*f7cf2976SLionel Sambuc #else 56*f7cf2976SLionel Sambuc #define SET_JUMP setjmp 57*f7cf2976SLionel Sambuc #define LONG_JUMP longjmp 58*f7cf2976SLionel Sambuc #endif 59*f7cf2976SLionel Sambuc 60*f7cf2976SLionel Sambuc public int reading; 61*f7cf2976SLionel Sambuc 62*f7cf2976SLionel Sambuc static jmp_buf read_label; 63*f7cf2976SLionel Sambuc 64*f7cf2976SLionel Sambuc extern int sigs; 65*f7cf2976SLionel Sambuc 66*f7cf2976SLionel Sambuc #if !HAVE_STRERROR 67*f7cf2976SLionel Sambuc static char *strerror __P((int)); 68*f7cf2976SLionel Sambuc #endif 69*f7cf2976SLionel Sambuc 70*f7cf2976SLionel Sambuc /* 71*f7cf2976SLionel Sambuc * Like read() system call, but is deliberately interruptible. 72*f7cf2976SLionel Sambuc * A call to intread() from a signal handler will interrupt 73*f7cf2976SLionel Sambuc * any pending iread(). 74*f7cf2976SLionel Sambuc */ 75*f7cf2976SLionel Sambuc public int 76*f7cf2976SLionel Sambuc iread(fd, buf, len) 77*f7cf2976SLionel Sambuc int fd; 78*f7cf2976SLionel Sambuc char *buf; 79*f7cf2976SLionel Sambuc unsigned int len; 80*f7cf2976SLionel Sambuc { 81*f7cf2976SLionel Sambuc register int n; 82*f7cf2976SLionel Sambuc 83*f7cf2976SLionel Sambuc start: 84*f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C 85*f7cf2976SLionel Sambuc if (ABORT_SIGS()) 86*f7cf2976SLionel Sambuc return (READ_INTR); 87*f7cf2976SLionel Sambuc #else 88*f7cf2976SLionel Sambuc #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 89*f7cf2976SLionel Sambuc if (kbhit()) 90*f7cf2976SLionel Sambuc { 91*f7cf2976SLionel Sambuc int c; 92*f7cf2976SLionel Sambuc 93*f7cf2976SLionel Sambuc c = getch(); 94*f7cf2976SLionel Sambuc if (c == '\003') 95*f7cf2976SLionel Sambuc return (READ_INTR); 96*f7cf2976SLionel Sambuc ungetch(c); 97*f7cf2976SLionel Sambuc } 98*f7cf2976SLionel Sambuc #endif 99*f7cf2976SLionel Sambuc #endif 100*f7cf2976SLionel Sambuc if (SET_JUMP(read_label)) 101*f7cf2976SLionel Sambuc { 102*f7cf2976SLionel Sambuc /* 103*f7cf2976SLionel Sambuc * We jumped here from intread. 104*f7cf2976SLionel Sambuc */ 105*f7cf2976SLionel Sambuc reading = 0; 106*f7cf2976SLionel Sambuc #if HAVE_SIGPROCMASK 107*f7cf2976SLionel Sambuc { 108*f7cf2976SLionel Sambuc sigset_t mask; 109*f7cf2976SLionel Sambuc sigemptyset(&mask); 110*f7cf2976SLionel Sambuc sigprocmask(SIG_SETMASK, &mask, NULL); 111*f7cf2976SLionel Sambuc } 112*f7cf2976SLionel Sambuc #else 113*f7cf2976SLionel Sambuc #if HAVE_SIGSETMASK 114*f7cf2976SLionel Sambuc sigsetmask(0); 115*f7cf2976SLionel Sambuc #else 116*f7cf2976SLionel Sambuc #ifdef _OSK 117*f7cf2976SLionel Sambuc sigmask(~0); 118*f7cf2976SLionel Sambuc #endif 119*f7cf2976SLionel Sambuc #endif 120*f7cf2976SLionel Sambuc #endif 121*f7cf2976SLionel Sambuc return (READ_INTR); 122*f7cf2976SLionel Sambuc } 123*f7cf2976SLionel Sambuc 124*f7cf2976SLionel Sambuc flush(); 125*f7cf2976SLionel Sambuc reading = 1; 126*f7cf2976SLionel Sambuc #if MSDOS_COMPILER==DJGPPC 127*f7cf2976SLionel Sambuc if (isatty(fd)) 128*f7cf2976SLionel Sambuc { 129*f7cf2976SLionel Sambuc /* 130*f7cf2976SLionel Sambuc * Don't try reading from a TTY until a character is 131*f7cf2976SLionel Sambuc * available, because that makes some background programs 132*f7cf2976SLionel Sambuc * believe DOS is busy in a way that prevents those 133*f7cf2976SLionel Sambuc * programs from working while "less" waits. 134*f7cf2976SLionel Sambuc */ 135*f7cf2976SLionel Sambuc fd_set readfds; 136*f7cf2976SLionel Sambuc 137*f7cf2976SLionel Sambuc FD_ZERO(&readfds); 138*f7cf2976SLionel Sambuc FD_SET(fd, &readfds); 139*f7cf2976SLionel Sambuc if (select(fd+1, &readfds, 0, 0, 0) == -1) 140*f7cf2976SLionel Sambuc return (-1); 141*f7cf2976SLionel Sambuc } 142*f7cf2976SLionel Sambuc #endif 143*f7cf2976SLionel Sambuc n = read(fd, buf, len); 144*f7cf2976SLionel Sambuc #if 1 145*f7cf2976SLionel Sambuc /* 146*f7cf2976SLionel Sambuc * This is a kludge to workaround a problem on some systems 147*f7cf2976SLionel Sambuc * where terminating a remote tty connection causes read() to 148*f7cf2976SLionel Sambuc * start returning 0 forever, instead of -1. 149*f7cf2976SLionel Sambuc */ 150*f7cf2976SLionel Sambuc { 151*f7cf2976SLionel Sambuc extern int ignore_eoi; 152*f7cf2976SLionel Sambuc if (!ignore_eoi) 153*f7cf2976SLionel Sambuc { 154*f7cf2976SLionel Sambuc static int consecutive_nulls = 0; 155*f7cf2976SLionel Sambuc if (n == 0) 156*f7cf2976SLionel Sambuc consecutive_nulls++; 157*f7cf2976SLionel Sambuc else 158*f7cf2976SLionel Sambuc consecutive_nulls = 0; 159*f7cf2976SLionel Sambuc if (consecutive_nulls > 20) 160*f7cf2976SLionel Sambuc quit(QUIT_ERROR); 161*f7cf2976SLionel Sambuc } 162*f7cf2976SLionel Sambuc } 163*f7cf2976SLionel Sambuc #endif 164*f7cf2976SLionel Sambuc reading = 0; 165*f7cf2976SLionel Sambuc if (n < 0) 166*f7cf2976SLionel Sambuc { 167*f7cf2976SLionel Sambuc #if HAVE_ERRNO 168*f7cf2976SLionel Sambuc /* 169*f7cf2976SLionel Sambuc * Certain values of errno indicate we should just retry the read. 170*f7cf2976SLionel Sambuc */ 171*f7cf2976SLionel Sambuc #if MUST_DEFINE_ERRNO 172*f7cf2976SLionel Sambuc extern int errno; 173*f7cf2976SLionel Sambuc #endif 174*f7cf2976SLionel Sambuc #ifdef EINTR 175*f7cf2976SLionel Sambuc if (errno == EINTR) 176*f7cf2976SLionel Sambuc goto start; 177*f7cf2976SLionel Sambuc #endif 178*f7cf2976SLionel Sambuc #ifdef EAGAIN 179*f7cf2976SLionel Sambuc if (errno == EAGAIN) 180*f7cf2976SLionel Sambuc goto start; 181*f7cf2976SLionel Sambuc #endif 182*f7cf2976SLionel Sambuc #endif 183*f7cf2976SLionel Sambuc return (-1); 184*f7cf2976SLionel Sambuc } 185*f7cf2976SLionel Sambuc return (n); 186*f7cf2976SLionel Sambuc } 187*f7cf2976SLionel Sambuc 188*f7cf2976SLionel Sambuc /* 189*f7cf2976SLionel Sambuc * Interrupt a pending iread(). 190*f7cf2976SLionel Sambuc */ 191*f7cf2976SLionel Sambuc public void 192*f7cf2976SLionel Sambuc intread() 193*f7cf2976SLionel Sambuc { 194*f7cf2976SLionel Sambuc LONG_JUMP(read_label, 1); 195*f7cf2976SLionel Sambuc } 196*f7cf2976SLionel Sambuc 197*f7cf2976SLionel Sambuc /* 198*f7cf2976SLionel Sambuc * Return the current time. 199*f7cf2976SLionel Sambuc */ 200*f7cf2976SLionel Sambuc #if HAVE_TIME 201*f7cf2976SLionel Sambuc public long 202*f7cf2976SLionel Sambuc get_time() 203*f7cf2976SLionel Sambuc { 204*f7cf2976SLionel Sambuc time_type t; 205*f7cf2976SLionel Sambuc 206*f7cf2976SLionel Sambuc time(&t); 207*f7cf2976SLionel Sambuc return (t); 208*f7cf2976SLionel Sambuc } 209*f7cf2976SLionel Sambuc #endif 210*f7cf2976SLionel Sambuc 211*f7cf2976SLionel Sambuc 212*f7cf2976SLionel Sambuc #if !HAVE_STRERROR 213*f7cf2976SLionel Sambuc /* 214*f7cf2976SLionel Sambuc * Local version of strerror, if not available from the system. 215*f7cf2976SLionel Sambuc */ 216*f7cf2976SLionel Sambuc static char * 217*f7cf2976SLionel Sambuc strerror(err) 218*f7cf2976SLionel Sambuc int err; 219*f7cf2976SLionel Sambuc { 220*f7cf2976SLionel Sambuc #if HAVE_SYS_ERRLIST 221*f7cf2976SLionel Sambuc static char buf[16]; 222*f7cf2976SLionel Sambuc extern char *sys_errlist[]; 223*f7cf2976SLionel Sambuc extern int sys_nerr; 224*f7cf2976SLionel Sambuc 225*f7cf2976SLionel Sambuc if (err < sys_nerr) 226*f7cf2976SLionel Sambuc return sys_errlist[err]; 227*f7cf2976SLionel Sambuc sprintf(buf, "Error %d", err); 228*f7cf2976SLionel Sambuc return buf; 229*f7cf2976SLionel Sambuc #else 230*f7cf2976SLionel Sambuc return ("cannot open"); 231*f7cf2976SLionel Sambuc #endif 232*f7cf2976SLionel Sambuc } 233*f7cf2976SLionel Sambuc #endif 234*f7cf2976SLionel Sambuc 235*f7cf2976SLionel Sambuc /* 236*f7cf2976SLionel Sambuc * errno_message: Return an error message based on the value of "errno". 237*f7cf2976SLionel Sambuc */ 238*f7cf2976SLionel Sambuc public char * 239*f7cf2976SLionel Sambuc errno_message(filename) 240*f7cf2976SLionel Sambuc char *filename; 241*f7cf2976SLionel Sambuc { 242*f7cf2976SLionel Sambuc register const char *p; 243*f7cf2976SLionel Sambuc register char *m; 244*f7cf2976SLionel Sambuc int len; 245*f7cf2976SLionel Sambuc #if HAVE_ERRNO 246*f7cf2976SLionel Sambuc #if MUST_DEFINE_ERRNO 247*f7cf2976SLionel Sambuc extern int errno; 248*f7cf2976SLionel Sambuc #endif 249*f7cf2976SLionel Sambuc p = strerror(errno); 250*f7cf2976SLionel Sambuc #else 251*f7cf2976SLionel Sambuc p = "cannot open"; 252*f7cf2976SLionel Sambuc #endif 253*f7cf2976SLionel Sambuc len = strlen(filename) + strlen(p) + 3; 254*f7cf2976SLionel Sambuc m = (char *) ecalloc(len, sizeof(char)); 255*f7cf2976SLionel Sambuc SNPRINTF2(m, len, "%s: %s", filename, p); 256*f7cf2976SLionel Sambuc return (m); 257*f7cf2976SLionel Sambuc } 258*f7cf2976SLionel Sambuc 259*f7cf2976SLionel Sambuc /* #define HAVE_FLOAT 0 */ 260*f7cf2976SLionel Sambuc 261*f7cf2976SLionel Sambuc static POSITION 262*f7cf2976SLionel Sambuc muldiv(val, num, den) 263*f7cf2976SLionel Sambuc POSITION val, num, den; 264*f7cf2976SLionel Sambuc { 265*f7cf2976SLionel Sambuc #if HAVE_FLOAT 266*f7cf2976SLionel Sambuc double v = (((double) val) * num) / den; 267*f7cf2976SLionel Sambuc return ((POSITION) (v + 0.5)); 268*f7cf2976SLionel Sambuc #else 269*f7cf2976SLionel Sambuc POSITION v = ((POSITION) val) * num; 270*f7cf2976SLionel Sambuc 271*f7cf2976SLionel Sambuc if (v / num == val) 272*f7cf2976SLionel Sambuc /* No overflow */ 273*f7cf2976SLionel Sambuc return (POSITION) (v / den); 274*f7cf2976SLionel Sambuc else 275*f7cf2976SLionel Sambuc /* Above calculation overflows; 276*f7cf2976SLionel Sambuc * use a method that is less precise but won't overflow. */ 277*f7cf2976SLionel Sambuc return (POSITION) (val / (den / num)); 278*f7cf2976SLionel Sambuc #endif 279*f7cf2976SLionel Sambuc } 280*f7cf2976SLionel Sambuc 281*f7cf2976SLionel Sambuc /* 282*f7cf2976SLionel Sambuc * Return the ratio of two POSITIONS, as a percentage. 283*f7cf2976SLionel Sambuc * {{ Assumes a POSITION is a long int. }} 284*f7cf2976SLionel Sambuc */ 285*f7cf2976SLionel Sambuc public int 286*f7cf2976SLionel Sambuc percentage(num, den) 287*f7cf2976SLionel Sambuc POSITION num, den; 288*f7cf2976SLionel Sambuc { 289*f7cf2976SLionel Sambuc return (int) muldiv(num, (POSITION) 100, den); 290*f7cf2976SLionel Sambuc } 291*f7cf2976SLionel Sambuc 292*f7cf2976SLionel Sambuc /* 293*f7cf2976SLionel Sambuc * Return the specified percentage of a POSITION. 294*f7cf2976SLionel Sambuc */ 295*f7cf2976SLionel Sambuc public POSITION 296*f7cf2976SLionel Sambuc percent_pos(pos, percent, fraction) 297*f7cf2976SLionel Sambuc POSITION pos; 298*f7cf2976SLionel Sambuc int percent; 299*f7cf2976SLionel Sambuc long fraction; 300*f7cf2976SLionel Sambuc { 301*f7cf2976SLionel Sambuc /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ 302*f7cf2976SLionel Sambuc POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); 303*f7cf2976SLionel Sambuc 304*f7cf2976SLionel Sambuc if (perden == 0) 305*f7cf2976SLionel Sambuc return (0); 306*f7cf2976SLionel Sambuc return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); 307*f7cf2976SLionel Sambuc } 308*f7cf2976SLionel Sambuc 309*f7cf2976SLionel Sambuc #if !HAVE_STRCHR 310*f7cf2976SLionel Sambuc /* 311*f7cf2976SLionel Sambuc * strchr is used by regexp.c. 312*f7cf2976SLionel Sambuc */ 313*f7cf2976SLionel Sambuc char * 314*f7cf2976SLionel Sambuc strchr(s, c) 315*f7cf2976SLionel Sambuc char *s; 316*f7cf2976SLionel Sambuc int c; 317*f7cf2976SLionel Sambuc { 318*f7cf2976SLionel Sambuc for ( ; *s != '\0'; s++) 319*f7cf2976SLionel Sambuc if (*s == c) 320*f7cf2976SLionel Sambuc return (s); 321*f7cf2976SLionel Sambuc if (c == '\0') 322*f7cf2976SLionel Sambuc return (s); 323*f7cf2976SLionel Sambuc return (NULL); 324*f7cf2976SLionel Sambuc } 325*f7cf2976SLionel Sambuc #endif 326*f7cf2976SLionel Sambuc 327*f7cf2976SLionel Sambuc #if !HAVE_MEMCPY 328*f7cf2976SLionel Sambuc VOID_POINTER 329*f7cf2976SLionel Sambuc memcpy(dst, src, len) 330*f7cf2976SLionel Sambuc VOID_POINTER dst; 331*f7cf2976SLionel Sambuc VOID_POINTER src; 332*f7cf2976SLionel Sambuc int len; 333*f7cf2976SLionel Sambuc { 334*f7cf2976SLionel Sambuc char *dstp = (char *) dst; 335*f7cf2976SLionel Sambuc char *srcp = (char *) src; 336*f7cf2976SLionel Sambuc int i; 337*f7cf2976SLionel Sambuc 338*f7cf2976SLionel Sambuc for (i = 0; i < len; i++) 339*f7cf2976SLionel Sambuc dstp[i] = srcp[i]; 340*f7cf2976SLionel Sambuc return (dst); 341*f7cf2976SLionel Sambuc } 342*f7cf2976SLionel Sambuc #endif 343*f7cf2976SLionel Sambuc 344*f7cf2976SLionel Sambuc #ifdef _OSK_MWC32 345*f7cf2976SLionel Sambuc 346*f7cf2976SLionel Sambuc /* 347*f7cf2976SLionel Sambuc * This implements an ANSI-style intercept setup for Microware C 3.2 348*f7cf2976SLionel Sambuc */ 349*f7cf2976SLionel Sambuc public int 350*f7cf2976SLionel Sambuc os9_signal(type, handler) 351*f7cf2976SLionel Sambuc int type; 352*f7cf2976SLionel Sambuc RETSIGTYPE (*handler)(); 353*f7cf2976SLionel Sambuc { 354*f7cf2976SLionel Sambuc intercept(handler); 355*f7cf2976SLionel Sambuc } 356*f7cf2976SLionel Sambuc 357*f7cf2976SLionel Sambuc #include <sgstat.h> 358*f7cf2976SLionel Sambuc 359*f7cf2976SLionel Sambuc int 360*f7cf2976SLionel Sambuc isatty(f) 361*f7cf2976SLionel Sambuc int f; 362*f7cf2976SLionel Sambuc { 363*f7cf2976SLionel Sambuc struct sgbuf sgbuf; 364*f7cf2976SLionel Sambuc 365*f7cf2976SLionel Sambuc if (_gs_opt(f, &sgbuf) < 0) 366*f7cf2976SLionel Sambuc return -1; 367*f7cf2976SLionel Sambuc return (sgbuf.sg_class == 0); 368*f7cf2976SLionel Sambuc } 369*f7cf2976SLionel Sambuc 370*f7cf2976SLionel Sambuc #endif 371