/** 
   -- Words making sense in POSIX-like systems only.
  
    Copyright (C) Tektronix, Inc. 1998 - 2001. All rights reserved.
  
    @see     GNU LGPL
    @author  Tektronix CTE                %derived_by: guidod %
    @version %version: bln_mpt1!5.22 %
      (%date_modified: Tue Nov 13 17:07:02 2001 %)
  
    @description
                This file exports a set of system words for 
                a posixish OS environment. So should do
                any alternative wordset you might create for your OS.
 */
/*@{*/
#if defined(__version_control__) && defined(__GNUC__)
static char* id __attribute__((unused)) = 
"@(#) $Id: %full_filespec:  posix-ext.c~bln_mpt1!5.22:csrc:bln_12xx!1 % $";
#endif

#define _P4_SOURCE 1

#include <pfe/pfe-base.h>
#include <pfe/def-xtra.h>

#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <time.h>

#ifdef VxWorks
#include <sysLib.h>
#endif

#if defined PFE_HAVE_WINBASE_H 
/* --target mingw32msvc */
# undef LP
# undef CONTEXT
# include <windows.h>
#endif

/* ntohl() */
#ifndef HOST_WIN32
/* FIXME: #ifdef PFE_HAVE_NETINET_IN_H */
#include <netinet/in.h>
/* FIXME: #endif */
#else
/* well, here's a highlevel copy... */
/* (btw, #include <winsock.h> ... would make a dependency on -lws32 !!!) */
# if PFE_BYTEORDER+0 == 4321
# define ntohl(x)        (x)
# define ntohs(x)        (x)
# define htonl(x)        (x)
# define htons(x)        (x)
# else
# define ntohl(x)       ((((x) & 0x000000ff) << 24) | \
                         (((x) & 0x0000ff00) <<  8) | \
                         (((x) & 0x00ff0000) >>  8) | \
                         (((x) & 0xff000000) >> 24))

# define htonl(x)       ((((x) & 0x000000ff) << 24) | \
                         (((x) & 0x0000ff00) <<  8) | \
                         (((x) & 0x00ff0000) >>  8) | \
                         (((x) & 0xff000000) >> 24))

# define ntohs(x)       ((((x) & 0x00ff) << 8) | \
                         (((x) & 0xff00) >> 8))

# define htons(x)       ((((x) & 0x00ff) << 8) | \
                         (((x) & 0xff00) >> 8))
# endif
#endif

#include <pfe/_nonansi.h>
#include <pfe/_missing.h>
#include <pfe/logging.h>

/** 
   CLOCKS_PER_SEC - usually one million ticks, but can be
   <i>very</i> different on a specific system. Exported
   as a constant. see => CLOCK
 */  /*"CLK_TCK"*/
#ifdef  CLOCKS_PER_SEC_BUG
#undef  CLOCKS_PER_SEC
#define CLOCKS_PER_SEC sysClkRateGet()
#endif


#if !(defined SYS_EMX || defined HOST_OS_WATCOM)

#define DEFINED_ignore_line
/** #! ( "...<eol>" -- ) 
   ignores the rest of the line,
   defining `#!' is used to support forth scripts 
   executed by the unix kernel
 */
FCode (p4_ignore_line)
{
    p4_refill ();
}
#endif
/** CLOCK ( --- ticks ) 
   return clock() 
 */
static
FCode (clock)                   
{
    FX_PUSH(clock());
}
/** 
   helper function - both arg pointers MUST be given
 */
_export void
p4_gettimeofday (p4ucell* sec, p4ucell* usec)
{
# ifdef PFE_HAVE_VXWORKS_H
# define PFE_HAVE_CLOCK_GETTIME
# endif

# if defined PFE_HAVE_CLOCK_GETTIME
    struct timespec tv;
    clock_gettime (CLOCK_REALTIME, &tv);
    if (usec) *usec = tv.tv_nsec/1000;
    *sec  = tv.tv_sec;
# elif defined PFE_HAVE_WINBASE_H
    SYSTEMTIME stime;
    GetSystemTime (&stime);
    if (usec) *usec = stime.wMilliseconds*1000;
    *sec = time(0);
# elif defined PFE_HAVE_UNISTD_H || defined PFE_HAVE_GETTIMEOFDAY
    struct timeval tv;
    gettimeofday (&tv, 0);
    if (usec) *usec = tv.tv_usec;
    *sec = tv.tv_sec;
# else
    if (usec) *usec = 0;
    *sec = time(0);
# endif
}
;
/** GETTIMEOFDAY ( -- double-time )
   returns SVR/BSD gettimeofday(2). 
   Never defined on 16-bit systems, hence
   => TIME&DATE is more portable.
 */
static
FCode (gettimeofday)
{
    FX_2ROOM;
    p4_gettimeofday (&SP[0], &SP[1]);
}
/** "ENVIRONMENT CLK_TCK" ( -- HZ )
   the system's scheduler heartbeat clock (a.k.a. jiffies a.k.a. HZ)
   for every function that expects time-values in ticks.
 */
static FCode(p4__clk_tck)
{
# if defined CLOCKS_PER_SEC
    FX_PUSH (CLOCKS_PER_SEC);
# elif defined CLK_TCK
    FX_PUSH (CLK_TCK);
# else
    /* including HOST_OS_AIX1 */
    FX_PUSH (1000000); /* just a guess :-) */
# endif
}
#if 0 #define PFE_NTOHS_DIRECT 1 #endif
/** NTOHS ( w -- w' )
   if current host-encoding is bigendian, this is a NOOP
   otherwise byteswap the lower 16-bit bits of the topofstack.
   see => W@ and => W!
   (on some platforms, the upper bits are erased, on others not)
 */ 
FCode (p4_ntohs)
{
# ifdef PFE_NTOHS_DIRECT
    *(unsigned short**)SP = ntohs (*(unsigned short**)SP);
# else
    register p4ucell item = *SP;
    *SP = ntohs (item);
# endif
}
/** NTOHL ( l -- l' )
   if current host-encoding is bigendian, this is a NOOP
   otherwise byteswap the lower 32-bit bits of the topofstack.
   see => L@ and => L! (being usually just => @ and => ! )
   (on some platforms, the upper bits are erased, on others not)
 */ 
FCode (p4_ntohl)
{
# ifdef PFE_NTOHS_DIRECT
    *(unsigned long**)SP = ntohl (*(unsigned long**)SP);
# else
    register p4ucell item = *SP;
    *SP = ntohl (item);
# endif
}
P4_LISTWORDS (posix) =
{
    P4_INTO ("EXTENSIONS", 0),
# ifdef DEFINED_ignore_line
    P4_FXco ("#!",		p4_ignore_line),
# endif
    P4_FXco ("CLOCK",		clock),
    P4_FXco ("GETTIMEOFDAY",	gettimeofday),

    P4_FXco ("NTOHL",                   p4_ntohl),
    P4_FXco ("HTONL",                   p4_ntohl),
    P4_FXco ("NTOHS",                   p4_ntohs),
    P4_FXco ("HTONS",                   p4_ntohs),

    P4_INTO ("ENVIRONMENT", 0 ),
    P4_FXCO ("CLK_TCK",		p4__clk_tck),

}
; P4_COUNTWORDS (posix, "POSIX'like words");
/*@}*/