//
// Copyright (C) 2000, 2001 Andrey Slepuhin <pooh@msu.ru>
//
// libp++ is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// libp++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libp++; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// $Source$
// $Revision$
// $Date$
// Author: Andrey Slepuhin <pooh@msu.ru>

#ifndef __pxx_common_hh__
#define __pxx_common_hh__

//
// This is needed to allow the use of macros for integer constant
//  initialization.
#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#define __STDC_FORMAT_MACROS

#ifndef _MSC_VER
#include <inttypes.h>
#include <unistd.h>    // ssize_t in FreeBSD
#else
#include <stddef.h>    // for integer types like intptr_t and size_t
#include <io.h>        // for _access()
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#ifdef WINDOWS
#include <malloc.h>    // for _alloca()
#endif

#ifdef _MSC_VER
#define WSTRPREFIX  L
#else
#define WSTRPREFIX  L""
#endif

#ifdef _MSC_VER
#define snprintf             _snprintf
#define alloca               _alloca
#define __PRETTY_FUNCTION__  __FUNCTION__

#ifdef  _WIN64
typedef __int64    ssize_t;
#else
typedef _W64 int   ssize_t;
#endif

#ifdef  _WIN64
#define __PRIPTR_PREFIX      "l"
#else
#define __PRIPTR_PREFIX
#endif

/* Macros for printing `intptr_t' and `uintptr_t'.  */
#define PRIdPTR        __PRIPTR_PREFIX "d"
#define PRIiPTR        __PRIPTR_PREFIX "i"
#define PRIoPTR        __PRIPTR_PREFIX "o"
#define PRIuPTR        __PRIPTR_PREFIX "u"
#define PRIxPTR        __PRIPTR_PREFIX "x"
#define PRIXPTR        __PRIPTR_PREFIX "X"

typedef          __int8         int8_t;
typedef          __int16        int16_t;
typedef          __int32        int32_t;
typedef          __int64        int64_t;

typedef unsigned __int8         uint8_t;
typedef unsigned __int16        uint16_t;
typedef unsigned __int32        uint32_t;
typedef unsigned __int64        uint64_t;

/* Values to test for integral types holding `void *' pointer.  */
#if _WIN64
# define INTPTR_MIN            (-9223372036854775807L-1)
# define INTPTR_MAX            (9223372036854775807L)
# define UINTPTR_MAX           (18446744073709551615UL)
#else
# define INTPTR_MIN            (-2147483647-1)
# define INTPTR_MAX            (2147483647)
# define UINTPTR_MAX           (4294967295U)
#endif

#if __WIN64
# define __INT64_C(c)  c ## L
# define __UINT64_C(c) c ## UL
#else
# define __INT64_C(c)  c ## LL
# define __UINT64_C(c) c ## ULL
#endif

#ifdef _UI32_MAX
# define UINT32_MAX             _UI32_MAX
#else
# define UINT32_MAX             (4294967295U)
#endif
#ifdef _UI64_MAX
# define UINT64_MAX             _UI64_MAX
#else
# define UINT64_MAX             (__UINT64_C(18446744073709551615))
#endif

/* Limit of `size_t' type.  */
#ifndef SIZE_MAX
#if __WIN64
# define SIZE_MAX              (18446744073709551615UL)
#else
# define SIZE_MAX              (4294967295U)
#endif
#endif

#define F_OK 0
#define W_OK 2
#define R_OK 4
#define X_OK 4  // How to check whether a file is executable in Windows?

//#define NOGDI

#endif // _MSC_VER

namespace pxx
{

#ifndef DEBUG
#define DEBUG 0
#endif

#ifndef PARANOIA
#define PARANOIA 0
#endif

//
// Define macros for uintptr_t type.
#if UINTPTR_MAX == UINT32_MAX
#define UINTPTR_C(x) UINT32_C(x)
#elif UINTPTR_MAX == UINT64_MAX
#define UINTPTR_C(x) UINT64_C(x)
#else
#error "Unsupported pointer size"
#endif

//
// Useful macros.
#define null (0)
#define self (*this)
#define zref(_type) (*((_type*)(0)))

//
// A macro to use in a case of fatal errors. Prints a message and source file
// information (function name, file name and line number).
#define FATAL \
  fprintf( \
    stderr,"Fatal error in %s\nat %s:%d\n", \
    __PRETTY_FUNCTION__, __FILE__, __LINE__ \
  ), \
  pxx::fatal

#define PMETHOD \
  fprintf(stderr, "%p: %s\n", this, __PRETTY_FUNCTION__)

#define TRY(a) \
  try { \
    a; \
  } catch (pxx::SysError const& err) { \
    FATAL("System error code = %d", err.get_code()); \
  }

#define NO_COPY_CTOR(cls) \
  cls (cls const&) ;

#define NO_ASSIGN(cls) \
  cls& operator = (cls const&) ;

extern unsigned debug_level ;

//
// A function to be called when fatal error occured. By default exit is called.
extern void (*terminate) (int _error_code) ;
//
// A function to print fatal error messages.
extern void fatal (char const* _fmt, ...) ;
//
// A function to print debug messages.
extern void dprint (unsigned _level, char const* _fmt, ...) ;
//
// A memory page size. Should be initialized at runtime due to architectures
// with a variable page size.
extern size_t& page_size ;
//
// An array containing ceilings of binary logarythms of small integers.
extern size_t (&orders)[256] ;
//
// An array containing exponents of 2.
extern size_t (&exps_of_two)[sizeof(size_t) * 8] ;

//
// This function returns a ceiling of a binary logarythm of its argument.
inline size_t get_order (size_t _size) ;
//
// This function checks whether a pointer is properly aligned. The second
// argument should be an exponent of 2.
inline bool ptr_is_aligned (void const* _ptr, uintptr_t _align) ;
//
// This function aligns a pointer, rounding it to a smaller value.
inline void* ptr_align (void const* _ptr, uintptr_t _align) ;
//
// This function aligns an integer size, rounding it to a higher value.
inline size_t size_align (size_t _size, size_t _align) ;
//
// These functions implement bit operations on pointer values.
inline void* ptr_and (void const* _p1, void const* _p2) ;
inline void* ptr_or (void const* _p1, void const* _p2) ;
inline void* ptr_xor (void const* _p1, void const* _p2) ;
//
// This function finds the least significant bit by which two pointers differ
// and returns an integer where this bit is set.
inline uintptr_t ptr_diff (void const* _p1, void const* _p2) ;
//
// Pointer arithmetic.
template <typename type_t>
  inline type_t* ptr_add_offset (type_t* _ptr, ssize_t _value) ;
template <typename type_t>
  inline type_t* ptr_sub_offset (type_t* _ptr, ssize_t _value) ;
template <typename type1_t, typename type2_t>
  inline ssize_t ptr_sub (type1_t* _ptr1, type2_t* _ptr2) ;

//
// We provide our own maximum and minimum macros to avoid naming conflicts
#define pxx_max(a,b) ((a) > (b) ? (a) : (b))
#define pxx_min(a,b) ((a) < (b) ? (a) : (b))

///
/// This enumeration type used as argument of constructors of some data types
/// may indicate that constructor argument is static constant data that
/// shouldn't be copied.
typedef enum
{
  const_data,
  non_const_data
} const_t ;

typedef enum
{
  mode_read = 1,
  mode_write = 2,
  mode_append = mode_read | 4,
  mode_read_write = mode_read | mode_write
} io_mode_t ;

//class Init ;
//extern Init* __pinit ;
//static Init* __static_pinit = __pinit ;

}

#endif // __pxx_common_hh__
