ldmud-3.3.719/
ldmud-3.3.719/doc/
ldmud-3.3.719/doc/efun.de/
ldmud-3.3.719/doc/efun/
ldmud-3.3.719/doc/man/
ldmud-3.3.719/doc/other/
ldmud-3.3.719/mud/
ldmud-3.3.719/mud/heaven7/
ldmud-3.3.719/mud/lp-245/
ldmud-3.3.719/mud/lp-245/banish/
ldmud-3.3.719/mud/lp-245/doc/
ldmud-3.3.719/mud/lp-245/doc/examples/
ldmud-3.3.719/mud/lp-245/doc/sefun/
ldmud-3.3.719/mud/lp-245/log/
ldmud-3.3.719/mud/lp-245/obj/Go/
ldmud-3.3.719/mud/lp-245/players/lars/
ldmud-3.3.719/mud/lp-245/room/death/
ldmud-3.3.719/mud/lp-245/room/maze1/
ldmud-3.3.719/mud/lp-245/room/sub/
ldmud-3.3.719/mud/lp-245/secure/
ldmud-3.3.719/mud/sticklib/
ldmud-3.3.719/mud/sticklib/src/
ldmud-3.3.719/mudlib/deprecated/
ldmud-3.3.719/mudlib/uni-crasher/
ldmud-3.3.719/pkg/
ldmud-3.3.719/pkg/debugger/
ldmud-3.3.719/pkg/diff/
ldmud-3.3.719/pkg/misc/
ldmud-3.3.719/src/
ldmud-3.3.719/src/autoconf/
ldmud-3.3.719/src/ptmalloc/
ldmud-3.3.719/src/util/
ldmud-3.3.719/src/util/erq/
ldmud-3.3.719/src/util/indent/hosts/next/
ldmud-3.3.719/src/util/xerq/
ldmud-3.3.719/src/util/xerq/lpc/
ldmud-3.3.719/src/util/xerq/lpc/www/
ldmud-3.3.719/test/generic/
ldmud-3.3.719/test/inc/
ldmud-3.3.719/test/t-0000398/
ldmud-3.3.719/test/t-0000548/
ldmud-3.3.719/test/t-030925/
ldmud-3.3.719/test/t-040413/
ldmud-3.3.719/test/t-041124/
ldmud-3.3.719/test/t-language/
/*---------------------------------------------------------------------------
 * Portability code.
 *
 *---------------------------------------------------------------------------
 * Implementation of missing system functions, as well as wrappers to
 * system functions with known bugs.
 *
 * The functions in here should be host-independent, though at the moment
 * some aren't.
 *---------------------------------------------------------------------------
 */

#include "driver.h"

#include <ctype.h>
#include "my-rusage.h"
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <locale.h>
#include <time.h>

#include "backend.h"
#include "main.h"


/*-------------------------------------------------------------------------*/

char current_time_stamp[21] = { 0 };
  /* Static buffer for the last timestamp computed by time_stamp().
   * This is for use only by those functions which must avoid memory
   * operations - all other functions should use time_stamp() itself.
   */

/*-------------------------------------------------------------------------*/
mp_int
get_current_time (void)

/* The function time() can't really be trusted to return an integer.
 * But this game uses the 'current_time', which is an integer number
 * of seconds. To make this more portable, the following functions
 * should be defined in such a way as to return the number of seconds since
 * some chosen year. The old behaviour of time() is to return the number
 * of seconds since 1970.
 *
 * On a SUN Sparc I, a negative time offset of 22 seconds between two
 * sucessive calls to time() has been observed. Similar discrepancies can
 * occur whenever a system clock is set, e.g. by automatic synchronisation
 * via ntp. These 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.
 */

{
    /* Don't write ever to total_alarms outside the interrupt, to avoid
     * race conditions.
     */
    static mp_int last_time = 0;
    static mp_int noted_alarms = 0;

    mp_int offset;
    mp_int now;
    mp_int total_alarms_now = total_alarms;

    offset = (total_alarms_now - noted_alarms) >> 1;
    noted_alarms = total_alarms_now;
    /* The division by two forces last_time to run at about 1/4 real time
     * so that the computer clock can catch up eventually. Furthermore it
     * allows to miss one single alarm to race conditions (total_alarms is
     * incremented in time, but after we read it) without causing a time
     * anomaly.
     */
    last_time += offset;
    now = (mp_int)time(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;
} /* get_current_time() */

/*-------------------------------------------------------------------------*/
char *
time_fstring (mp_int t, const char* str, Bool localized)
/* Return a textual representation of the time <t> according to the format
 * string <str>. Doesn't cache because it would be necessary to 
 * save the format string and compare.
 * If localized is true, this function sets the locale according to the 
 * environment variable before calling strftime and resets it afterwards.
 * TODO: It would be nicer to allocate the result buffer dynamically
 * TODO::for using longer format strings. */
{
    static char result[512];
    struct tm *tm;

    time_t ti = (time_t)t;
    tm = localtime(&ti);
    if (!tm)
        return NULL;

    if (!localized) {
        setlocale(LC_TIME, "C");
        strftime(result, sizeof(result)-1, str, tm);
        setlocale(LC_TIME, "");
    }
    else
       strftime(result, sizeof(result)-1, str, tm);
    
    return result;
} /* time_fstring() */

/*-------------------------------------------------------------------------*/
char *
utime_string (mp_int t, mp_int ut)

/* Return a textual representation of the time <t> secs:<ut> microseconds. */

{
    static char result[80];
    struct tm *tm;
    size_t len;

    time_t ti = (time_t)t;
    tm = localtime(&ti);
    if (!tm)
        return NULL;

    len = strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S:", tm);
    sprintf(result+len, "%06"PRIdMPINT, ut);
    strftime(result+len+6, sizeof(result)-7-len, " %Y", tm);

    return result;
} /* utime_string() */

/*-------------------------------------------------------------------------*/
char *
time_stamp (void)

/* Return a textual representation of the current time
 * in the form "YYYY.MM.DD HH:MM:SS".
 * Result is a pointer curent_time_stamp[].
 *
 * Putting this function in strfuns is not a good idea, because
 * it is need by almost every module anyway.
 */

{
    mp_int t;
    struct tm *tm;

    static mp_int last_time = -1;

    t = get_current_time();
    if (t != last_time)
    {
        time_t ti = (time_t)t;
        last_time = t;
        tm = localtime(&ti);
        strftime( current_time_stamp, sizeof(current_time_stamp),
                  "%Y.%m.%d %H:%M:%S", tm);
    }
    return current_time_stamp;
} /* time_stamp() */

/*-------------------------------------------------------------------------*/
char *
xmemmem ( const char *haystack, size_t haystacklen
        , const char *needle, size_t needlelen
        )

/* Find the first occurance of <needle> (of length <needlelen>) in
 * <haystack> (of <haystacklen> length) and return a pointer to it.
 * A needle of length 0 is always found at <haystack>.
 * If not found, return NULL.
 *
#ifndef HAVE_MEMMEM
 * This function is a GNU/Linux extension, but up to and including
 * glibc 2 it wasn't implemented correctly. Since it is also used
 * only in the get_dir() implementation, we don't even bother to
 * use the glibc implementation.
#endif
 */

{
    mp_int i;

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

/*-------------------------------------------------------------------------*/
#ifdef STRTOL_BROKEN

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

#ifdef STRTOL_CONST_CHARP
long
strtol(register const char *str, char **ptr, register int base)
#else
long
strtol(register char *str, char **ptr, register int base)
#endif
{
    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_STRCSPN

size_t
strcspn(const char *s, const char *set)
{
    register char *t, *s, c, d;

    s = start;
    while (c = *s)
    {
        t = set;
        while (d = *t++) {
            if (c == d)
                return s - start;
        }
        s++;
    }
}
#endif /* !HAVE_STRCSPN */

/*-------------------------------------------------------------------------*/
#ifndef HAVE_STRDUP

char *
strdup (const char *str)

/* Copy <str> into a freshly allocated memory block and return that one.
 */

{
    char *copy = malloc(strlen(str)+1);
    if (!copy)
        fatal("strdup failed\n");
    strcpy(copy, str);
    return copy;
}

#endif /* !HAVE_STRDUP */

/*-------------------------------------------------------------------------*/
#ifndef HAVE_MEMSET

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

#endif /* !HAVE_MEMSET */

/*-------------------------------------------------------------------------*/
#if !defined(HAVE_MEMMOVE) && !defined(OVERLAPPING_BCOPY)

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

/*-------------------------------------------------------------------------*/
#if !defined(HAVE_GETRUSAGE)

#include <sys/times.h>
int
getrusage (int who, struct rusage *rusage)
{
    struct tms buffer;

    if (who != RUSAGE_SELF) {

        errno = EINVAL;
        return -1;
    }
    if (times(&buffer)==-1) {
        /* pass errno */
        return -1;
    }
    rusage->ru_utime = buffer.tms_utime;
    rusage->ru_stime = buffer.tms_stime;
    return 0;
}
#endif /* getrusage implemented using times() */

#if defined(CYGWIN)
/*-----------------------------------------------------------------------
** void init_rusage (void)
** int getrusage (int who, struct rusage *rusage)
**
** Get information about resource utilization, well, at least some
** idea of the time spent in the gamedriver.
** Reason is that some wiz use the efun getrusage() to measure times
** in subseconds.
*/

static clock_t first_clock;

void
init_rusage (void) {
  first_clock = clock();
}

int
getrusage (int who, struct rusage *rusage) {
  if (who != RUSAGE_SELF) {
    errno = EINVAL;
    return -1;
  }
  memset (rusage, 0, sizeof (struct rusage));
  rusage->ru_utime.tv_sec = (clock() - first_clock) / CLK_TCK;
  rusage->ru_utime.tv_usec =
    ((clock() - first_clock) % CLK_TCK) * (1000000 / CLK_TCK);
  return 0;
}

#endif /* CYGWIN */

/***************************************************************************/