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