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