/* **********************************************************************
 * *	                                                                *
 * *  Various sig_() Routines for Code Porting                          *
 * *                                                                    *
 * **********************************************************************
 * File: libs/user/sig_subs.c
 *
 *              COPYRIGHT (c) 1994, 1998, 1999, 2002  BY
 *         SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 *
 * Collection of minor cover routines that provide customized calls to
 * standard library/system functions.
 */
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utsname.h>

#define INCLUDE_STDIO_PROTOTYPES 1
#define INCLUDE_SYSUTSNAME_PROTOTYPES 1
#include "sigtypes.h"
#include "user_lib.h"

#include "user_def.h"

/* ------------------------------
 * Create a private memory area.  This interface is mostly for FORTRAN,
 * since C can malloc directly.  We keep track of the allocations and
 * frees, to provide additional error checking.
 *
 * Entry Parameters
 *   SIZE_A   Size
 *
 * Exit Parameters
 *   ADDR_A   Address of mapped area
 *   Return Status
 */
static struct {
  void* addr ; size_t size ;
} inuse[SIG_MALLOC_MAX] = {{0,},} ;

MESSAGE sig_malloc
  (const UINT4 size_a,
   void**   addr_a)
{
  int ii ;
  for( ii=0 ; ii < SIG_MALLOC_MAX ; ii++ ) {
    if( inuse[ii].addr == 0 ) {
      if( NULL == (*addr_a = malloc( (size_t)size_a )) ) {
	return errno_to_message_va( errno, 2, "sig_malloc(%d)", size_a ) ;
      } else {
	inuse[ii].addr = *addr_a ;
	inuse[ii].size =  size_a ;
	return SS_NORMAL ;
      }
    }
  }
  return USER_SIG_MALLOC ;
}

/* ------------------------------
 * Free a private memory area.  This interface is mostly for FORTRAN,
 * since C can free directly
 *
 * Entry Parameters
 *   ADDR_A   Address of mapped area
 *
 * Exit Parameters
 *   Return Status
 */
MESSAGE sig_free
  (void* addr_a)
{
  int ii ;
  for( ii=0 ; ii<SIG_MALLOC_MAX ; ii++ ) {
    if( addr_a == inuse[ii].addr ) {
      inuse[ii].addr = 0 ;
      free( addr_a ) ;
      return SS_NORMAL ;
    }
  }
  return USER_SIG_FREE ;
}

/* ------------------------------
 * Portable version of rand() random number generator.  The problem is
 * that FORTRANs define either ran() or rand() as their intrinsic random
 * number generator.  This prevents calling rand() directly from the C
 * library.
 */
int sig_rand() {
  return ( rand() & 0x7FFF ) ;
}

/* ------------------------------
 * Is this machine byte swapped (i.e. not DEC convention) ?
 */
UINT2 sig_os_byteswap() {
  union { UINT2 word ; UINT1 chars[2] ; } utest ;
  utest.word = 0x1234 ; return( utest.chars[0] == 0x12 ) ;
}

/* ------------------------------
 * Set up a channel opened to a serial line for I/O.
 */      
MESSAGE sig_init_serial
  (const char *sdevice_a,
   FILE **pstream_a,
   UINT2 lwrite_a     /* TRUE if you are going to write, else FALSE */
   )
{
  MESSAGE istatus; char smode[10]; int ierror;

  istatus = SS_NORMAL;

  if (lwrite_a)
    { strcpy( smode, "w" );}
  else
    { strcpy( smode, "r" );}

  *pstream_a = fopen( sdevice_a, smode );
  if (*pstream_a == NULL)
    {
      istatus = errno_to_message_va( errno, 1, sdevice_a ) ;
      return istatus;
    }
  ierror = setvbuf( *pstream_a, NULL, _IONBF, 0 );
  if (ierror != 0)
    {
      istatus = errno_to_message_va( errno, 1, sdevice_a );
      return istatus;
    }
  
  return istatus;
}

/* ------------------------------
 * Reentrant cover for uname() that is guaranteed to return quickly
 * after the first time it is called.  This allows it to be used in
 * critical sections of code where having unknown delays would not be
 * acceptable.
 */
static struct utsname utsname_c = {{0}} ;
static UINT1 lUtsnameValid_c = FALSE ;

MESSAGE sig_uname( struct utsname *pName_a )
{
  MESSAGE istatus = SS_NORMAL ;
  if( ! lUtsnameValid_c ) {
    struct utsname name ;
    if( uname( &name ) < 0 ) {
      istatus = errno_to_message_va( errno, 1, "uname()" ) ;
    } else {
      utsname_c = name ; lUtsnameValid_c = TRUE ;
    }
  }
  if( pName_a ) *pName_a = utsname_c ; return( istatus ) ;
}
