1 /* 2 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice in the documentation and/or other materials provided with 12 * the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 28 /* 29 * Operating system dependent routines. 30 * 31 * Most of the stuff in here is based on Unix, but an attempt 32 * has been made to make things work on other operating systems. 33 * This will sometimes result in a loss of functionality, unless 34 * someone rewrites code specifically for the new operating system. 35 * 36 * The makefile provides defines to decide whether various 37 * Unix features are present. 38 */ 39 40 #include "less.h" 41 #include <limits.h> 42 #include <signal.h> 43 #include <setjmp.h> 44 #if HAVE_TIME_H 45 #include <time.h> 46 #endif 47 #if HAVE_ERRNO_H 48 #include <errno.h> 49 #endif 50 #if HAVE_VALUES_H 51 #include <values.h> 52 #endif 53 54 #if HAVE_TIME_T 55 #define time_type time_t 56 #else 57 #define time_type long 58 #endif 59 60 /* 61 * BSD setjmp() saves (and longjmp() restores) the signal mask. 62 * This costs a system call or two per setjmp(), so if possible we clear the 63 * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. 64 * On other systems, setjmp() doesn't affect the signal mask and so 65 * _setjmp() does not exist; we just use setjmp(). 66 */ 67 #if HAVE__SETJMP && HAVE_SIGSETMASK 68 #define SET_JUMP _setjmp 69 #define LONG_JUMP _longjmp 70 #else 71 #define SET_JUMP setjmp 72 #define LONG_JUMP longjmp 73 #endif 74 75 public int reading; 76 77 static jmp_buf read_label; 78 79 /* 80 * Like read() system call, but is deliberately interruptible. 81 * A call to intread() from a signal handler will interrupt 82 * any pending iread(). 83 */ 84 public int 85 iread(fd, buf, len) 86 int fd; 87 char *buf; 88 unsigned int len; 89 { 90 register int n; 91 92 #if MSOFTC 93 if (kbhit()) 94 { 95 int c; 96 97 c = getch(); 98 if (c == '\003') 99 return (READ_INTR); 100 ungetch(c); 101 } 102 #endif 103 if (SET_JUMP(read_label)) 104 { 105 /* 106 * We jumped here from intread. 107 */ 108 reading = 0; 109 #if HAVE_SIGSETMASK 110 sigsetmask(0); 111 #endif 112 return (READ_INTR); 113 } 114 115 flush(); 116 reading = 1; 117 n = read(fd, buf, len); 118 reading = 0; 119 if (n < 0) 120 return (-1); 121 return (n); 122 } 123 124 /* 125 * Interrupt a pending iread(). 126 */ 127 public void 128 intread() 129 { 130 LONG_JUMP(read_label, 1); 131 } 132 133 /* 134 * Return the current time. 135 */ 136 #if HAVE_TIME 137 public long 138 get_time() 139 { 140 time_type t; 141 142 time(&t); 143 return (t); 144 } 145 #endif 146 147 148 #if !HAVE_STRERROR 149 /* 150 * Local version of strerror, if not available from the system. 151 */ 152 static char * 153 strerror(err) 154 int err; 155 { 156 #if HAVE_SYS_ERRLIST 157 static char buf[16]; 158 extern char *sys_errlist[]; 159 extern int sys_nerr; 160 161 if (err < sys_nerr) 162 return sys_errlist[err]; 163 sprintf(buf, "Error %d", err); 164 return buf; 165 #else 166 return ("cannot open"); 167 #endif 168 } 169 #endif 170 171 /* 172 * errno_message: Return an error message based on the value of "errno". 173 */ 174 public char * 175 errno_message(filename) 176 char *filename; 177 { 178 register char *p; 179 register char *m; 180 #if HAVE_ERRNO 181 extern int errno; 182 p = strerror(errno); 183 #else 184 p = "cannot open"; 185 #endif 186 m = (char *) ecalloc(strlen(filename) + strlen(p) + 3, sizeof(char)); 187 sprintf(m, "%s: %s", filename, p); 188 return (m); 189 } 190 191 /* 192 * Return the largest possible number that can fit in a POSITION. 193 */ 194 #ifdef QUAD_MAX 195 static POSITION 196 get_maxpos() 197 { 198 return (QUAD_MAX); 199 } 200 #else 201 static POSITION 202 get_maxpos() 203 { 204 POSITION n, n2; 205 206 /* 207 * Keep doubling n until we overflow. 208 * {{ This actually only returns the largest power of two that 209 * can fit in a POSITION, but percentage() doesn't really need 210 * it any more accurate than that. }} 211 */ 212 n2 = 128; /* Hopefully no maxpos is less than 128! */ 213 do { 214 n = n2; 215 n2 *= 2; 216 } while (n2 / 2 == n); 217 return (n); 218 } 219 #endif 220 221 /* 222 * Return the ratio of two POSITIONs, as a percentage. 223 */ 224 public int 225 percentage(num, den) 226 POSITION num, den; 227 { 228 static POSITION maxpos100 = 0; 229 230 if (maxpos100 == 0) 231 maxpos100 = get_maxpos() / 100; 232 if (num > maxpos100) 233 return (num / (den/100)); 234 else 235 return (100*num / den); 236 } 237