//
// Asura_PlatformBasics.h
//
// Created by KJFL - Wednesday, February 04, 2004
//
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_PLATFORMBASICS_H__
#define __ASURA_PLATFORMBASICS_H__

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>
#include <psptypes.h>

#if defined __GNUC__ && !defined __SNC__
#include <allegrex.h>
#include <vfpu_intrinsics.h>
#endif

#if defined __GNUC__ && !defined __SNC__
/*
    Useful when one just wants to do a scalar operation,
    usually just on the X element.
*/
#define VFPU_VDS_X (VFPU_VD_X|VFPU_VS_X)
#define VFPU_VDST_X (VFPU_VD_X|VFPU_VS_X|VFPU_VT_X)

// RJT NOTE: GCC3 and GCC4 use different constraints for intrinsic types
// (GCC4 was happy with a #define for C or j, but GCC3 required full expansion of each case)
#if ( __GNUC__ > 3 )	// GCC3
	#define VFPU_C		"C"
	#define VFPU_EQL_C	"=C"
	#define VFPU_PLS_C	"+C"
	#define VFPU_AND_C	"=&C"
#else	// GCC4
	#define VFPU_C		"j"
	#define VFPU_EQL_C	"=j"
	#define VFPU_PLS_C	"+j"
	#define VFPU_AND_C	"=&j"
#endif

/*
    Useful to avoid using the 'vfpu_v4(float)' builtin constructor,
    which seem to cause compiler problems.
*/
static __inline__ const vfpu_v4 vfpu_v4_s(register const float fX)
{
    register vfpu_v4 afT;
	__asm__ ("mtv %1,%x0" : VFPU_PLS_C (afT) : "r" (fX));
	return afT;
}

static __inline__ const vfpu_v4 vfpu_v4_q(register const float fX)
{
	register vfpu_v4 afT;
	__asm__ ("mtv %1,%x0\n\tvmov.q %0,%0[X,X,X,X]" : VFPU_PLS_C (afT) : "r" (fX));
	return afT;
}
#endif

typedef char Asura_Char;

#if defined __SNC__
#define ASURA_UNICODE_CHAR_DISTINCT_TYPE		1
typedef wchar_t Asura_UnicodeChar;
#endif

#if defined __GNUC__ && !defined __SNC__
/*
  The bad news here is that the Sony GCC uses UCS-4 'wchar_t' and so
  does the precompiled Sony 'glibc', so we must make sure our type is 2
  bytes (LSB too, but that's another kettle of worms :->).

  The type should be 'short unsigned', but we must use 'wchar_t' and specify
  '-fshort-wchar' because of the wide char and string constants...
*/
#define ASURA_UNICODE_CHAR_DISTINCT_TYPE 1
typedef wchar_t Asura_UnicodeChar;
#endif

#if defined __SNC__
/*
  Most of the wide char functions are available in the SNC runtime
  libraries but inexplicably some of them aren't in the header.
*/
extern "C" int iswalpha(wint_t iC);
extern "C" int iswalnum(wint_t iC);
extern "C" int iswdigit(wint_t iC);
extern "C" int iswlower(wint_t iC);
extern "C" int iswspace(wint_t iC);
extern "C" int iswxdigit(wint_t iC);

extern "C" wint_t towlower(wint_t iC);
extern "C" wint_t towupper(wint_t iC);

/*
  We need to declare this because we need to implement them
  ourselves, as they are not standard (probably Microsoftisms).
*/

extern "C" int wcsicmp(const Asura_UnicodeChar* wszA,
    const Asura_UnicodeChar* wszB);

extern "C" int wcsnicmp(const Asura_UnicodeChar* wszA,
    const Asura_UnicodeChar* wszB,size_t uMax);
#endif

// ARC - 21 November 2006 16:19:28 - Added for debug variable system
#define wcsrchr(A,B)	(Asura_UnicodeChar_FindCharRev((A),(B)))
// ARC - 21 November 2006 16:18:25 - Added for wcsrchr
extern "C" Asura_UnicodeChar* Asura_UnicodeChar_FindCharRev
(const Asura_UnicodeChar* wszHaystack, Asura_UnicodeChar wNeedle);

#if (defined __GNUC__ && !defined __SNC__)
/*
  Since with GCC we have that 'Asura_UnicodeChar' is not 'wchar_t', at
  least not the one with which 'libc' has been compiled, we need to
  provide our own wide char string functions.
*/

/*
  We do not need to wrap the UCS-4 GCC wide char type functions
  because they take 'wint_t', not 'wchar_t', and an 'Asura_UnicodeChar'
  will be automagically widened to 'wint_t', and UCS-2 is guaranteed
  to be a subset of UCS-4.
*/
extern "C"
{
    #include <wctype.h>
}
extern "C" int wcsicmp(const Asura_UnicodeChar* wszA,
    const Asura_UnicodeChar* wszB);

extern "C" int wcsnicmp(const Asura_UnicodeChar* wszA,
    const Asura_UnicodeChar* wszB,size_t uMax);

/*
  Desperate measure, as 'wcscpy' etc. are C linkage functions and we can
  neither overload it nor avoid including the header that defines it as
  taking 'wchar_t' pointers
*/

#define wcslen(A)		(Asura_UnicodeChar_Len((A)))
#define wcscmp(A,B)		(Asura_UnicodeChar_Cmp((A),(B)))
#define wcsncmp(A,B,N)	(Asura_UnicodeChar_CmpN((A),(B),(N)))
#define wcschr(A,C)		(Asura_UnicodeChar_FindChar((A),(C)))
#define wcscpy(A,B)		(Asura_UnicodeChar_CopyTo((A),(B)))
#define wcsncpy(A,B,N)	(Asura_UnicodeChar_CopyToMax((A),(B),(N)))
#define wcscat(A,B)		(Asura_UnicodeChar_Cat((A),(B)))
// these are already defined
// wcsicmp
// wcsnicmp
// wcsrchr

// prevent using any of these by accident
#define btowc (A)					Asura_UnicodeErrorNotImplemented (A)
#define wctob (A)					Asura_UnicodeErrorNotImplemented (A)
#define mbrlen (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define mbrtowc (A,B,C,D)			Asura_UnicodeErrorNotImplemented (A,B,C,D)
#define _mbrtowc_r (A,B,C,D,E)		Asura_UnicodeErrorNotImplemented (A,B,C,D,E)
#define mbsinit (A)					Asura_UnicodeErrorNotImplemented (A)
#define mbsrtowcs (A,B,C,D)			Asura_UnicodeErrorNotImplemented (A,B,C,D)
#define wcrtomb (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define _wcrtomb_r (A,B,C,D)		Asura_UnicodeErrorNotImplemented (A,B,C,D)
#define wcsrtombs (A,B,C,D)			Asura_UnicodeErrorNotImplemented (A,B,C,D)
#define _wcsrtombs_r (A,B,C,D,E)	Asura_UnicodeErrorNotImplemented (A,B,C,D,E)
#define wcscoll (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcscspn (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcslcat (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wcslcpy (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wcsncat (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wcsnlen (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcspbrk (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcsspn (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcsstr (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcswidth (A,B)				Asura_UnicodeErrorNotImplemented (A,B)
#define wcwidth (A)					Asura_UnicodeErrorNotImplemented (A)
#define wmemchr (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wmemcmp (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wmemcpy (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)
#define wmemmove (A,B,C)			Asura_UnicodeErrorNotImplemented (A,B,C)
#define wmemset (A,B,C)				Asura_UnicodeErrorNotImplemented (A,B,C)


extern "C" int Asura_UnicodeChar_Len(const Asura_UnicodeChar* wszA);

extern "C" int Asura_UnicodeChar_Cmp
    (const Asura_UnicodeChar* wszA,const Asura_UnicodeChar* wszB);
extern "C" int Asura_UnicodeChar_CmpN
(const Asura_UnicodeChar* wszA,const Asura_UnicodeChar* wszB, size_t uMax);

extern "C" Asura_UnicodeChar* Asura_UnicodeChar_FindChar
    (const Asura_UnicodeChar* wszA,Asura_UnicodeChar wC);

extern "C" Asura_UnicodeChar* Asura_UnicodeChar_CopyTo
    (Asura_UnicodeChar* wszA,const Asura_UnicodeChar* wszB);
extern "C" Asura_UnicodeChar* Asura_UnicodeChar_CopyToMax
    (Asura_UnicodeChar* wszA,const Asura_UnicodeChar* wszB,size_t uMax);

extern "C" Asura_UnicodeChar* Asura_UnicodeChar_Cat
	(Asura_UnicodeChar* wszA,const Asura_UnicodeChar* wszB);
#endif

#if (!defined __GNUC__ && !defined __SNC__)
#error unanticipated wide char situation for PSP
#endif

#endif

