sima/autoconf/
sima/hosts/i386/
sima/mudlib/
sima/mudlib/kernel/
sima/mudlib/obj/
sima/mudlib/sys/
sima/synhash/mips/
/* System-specific functions */

#include "config.h"

#include "machine.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif

#include "common.h"
#include "comm.h"

#ifdef sun
time_t time PROT((time_t *));
#endif


/*
 * Return a random number in the range 0 .. n-1
 */
int random_number(n)
    int n;
{
#ifdef RANDOM
    return random() % n;
#else /* RANDOM */
#ifdef DRAND48
    return (int)(drand48() * n);
#else /* DRAND48 */
#ifdef RAND
    return rand() % n;
#else
    extern int current_time;

    return current_time % n;	/* Suit yourself :-) */
#endif /* RAND */
#endif /* DRAND48 */
#endif /* RANDOM */
}

/* On a SUN Sparc I, a negative time offset of 22 seconds between two
 * sucessive calls to time() has been observed. Negative time offsets
 * can mess up the call_out tables. Since they also could mess up the
 * mudlib, completely hide them by forcing the visible time to continue
 * to run in positive direction.
 */

mp_int get_current_time() {
    /* Don't write ever to total_alarms outside the interrupt, to avoid
     * race conditions.
     */
    extern volatile mp_int total_alarms;

    static mp_int last_time = 0;
    static mp_int noted_alarms = 0;

    mp_int offset;
    mp_int now;

    offset = total_alarms - noted_alarms >> 1;
    /* allow one alarm to happen without force-incrementing the time, so
     * that no time anomaly due to race conditions occurs.
     */
    noted_alarms += offset;
    last_time += offset;
    now = (mp_int)time((time_t *)NULL);	/* Just use the old time() for now */
    if (now >= last_time) {
	last_time = now;
	return now;
    }
    debug_message("Time anomaly, %ld seconds.\n", (long)(last_time - now));
    return last_time;
}

/*
 * high-speed processing of select() output. Consider searching a single
 * descriptor in a sea of 2000...
 */
void walk_fdset(fd_set *set, int n) {
    int *p, mask;
    int offset, s;

    p = (int*)set;
    offset = 0;
    do {
	mask = *p++;
	if (mask) {
	    s = ffs(mask);
	    do {
		struct fd_entry *fpe;

		s--;
		mask &= ~(1 << s);
		s += offset;
		fpe = &fd_table[s];
		(*fpe->f)(fpe, s);
	    } while (s = ffs(mask));
	}
	offset += 8*sizeof(*p);
    } while (--n);
}

/*
 * The functions below fix up some deficiencies of various platforms
 */


#ifdef STRTOL_BROKEN
#define DIGIT(x)	(isdigit(x) ? (x) - '0' : \
			islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
#define MBASE	('z' - 'a' + 1 + 10)

long
strtol(str, ptr, base)
#ifdef STRTOL_CONST_CHARP
const
#endif
register char *str;
char **ptr;
register int base;
{
    register long val;
    register int c;
    int xx, neg = 0;

    if (ptr != (char **)0)
	*ptr = (char*)str; /* in case no number is formed */
    if (base < 0 || base > MBASE)
	return (0); /* base is invalid -- should be a fatal error */
    if (!isalnum(c = *str)) {
	while (isspace(c))
		c = *++str;
	switch (c) {
	  case '-':
	    neg++;
	  case '+': /* fall-through */
	    c = *++str;
	}
    }
    if (base == 0)
	if (c != '0')
	    base = 10;
	else if (str[1] == 'x' || str[1] == 'X')
	    base = 16;
	else
	    base = 8;
    /*
     * for any base > 10, the digits incrementally following
     *	9 are assumed to be "abc...z" or "ABC...Z"
     */
    if (!isalnum(c) || (xx = DIGIT(c)) >= base)
	return (0); /* no number formed */
    if (base == 10) {
	/* accumulate neg avoids surprises near MAXLONG */
	for (val = '0'-c; isdigit(c = *++str); )
	    /* multiplication with a constant can be optimized */
	    val = 10 * val +'0'-c;
    } else if (base == 16) {
	/* str[1] might be '0', thus we must not access str[2] without check. */
	if (c == '0' && (str[1] == 'x' || str[1] == 'X') && isxdigit(str[2]))
	    c = *(str += 2); /* skip over leading "0x" or "0X" */
	for (val = -DIGIT(c); isalnum(c = *++str) && (xx = DIGIT(c)) < 16; )
	    val = (val << 4) - xx;
    } else {
	for (val = -DIGIT(c); isalnum(c = *++str) && (xx = DIGIT(c)) < base; )
	    val = base * val - xx;
    }
    if (ptr != (char **)0)
	*ptr = (char *)str;
    return (neg ? val : -val);
}
#endif /* STRTOL_BROKEN */

#ifndef HAVE_MEMSET
char *memset (s, c, n)
    char *s;
    int c, n;
{
#ifdef HAVE_BZERO
    if(c == 0)
	bzero(s, n);
    else
#endif
    {
	while(--n >= 0)
	    *s++ = c;
    }
}
#endif /* !HAVE_MEMSET */


#if !defined(HAVE_CRYPT) && !defined(HAVE__CRYPT)
#include "hosts/crypt.c"
#endif

#if 0 /* If you can't get crypt to compile,  you can use this dummy */
char * crypt(pass,salt)
    char *pass, *salt;
{
    return pass;
}
#endif

#ifndef HAVE_MEMMEM
/* This implementation is not very efficient, but still better than the old
 * match_string() .
 */
char *memmem(needle, needlelen, haystack, haystacklen)
    const void *needle, *haystack;
    size_t needlelen, haystacklen;
{
    mp_int i;

    i = haystacklen - needlelen;
    if (i >= 0) do {
	if ( !memcmp(needle, haystack, needlelen) )
	    return haystack;
	haystack = (char*)haystack + 1;
    } while (--i >= 0);
    return 0;
}
#endif /* !HAVE_MEMMEM */

#if !defined(HAVE_MEMMOVE) && !defined(OVERLAPPING_BCOPY)
void move_memory(dest, src, n)
    char *dest, *src;
    size_t n; /* might be unsigned */
{
    if (!n)
	return;
    if (dest > src) {
	dest += n;
	src  += n;
	do
	    *--dest = *--src;
	while (--n);
    } else {
	do
	    *dest++ = *src++;
	while (--n);
    }
}
#endif /* !HAVE_MEMMOVE */