/*
 *      Interactive disassembler (IDA).
 *      Copyright (c) 1990-97 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              E-mail: ig@estar.msk.su
 *                              FIDO:   2:5020/209
 *
 */

#ifndef _PRO_H
#define _PRO_H
#pragma pack(push, 1)

//
//      This is the first header included in IDA project.
//      It defines the most common types, functions and data.
//      Also, it tries to make system dependent definitions.
//

#include <stdlib.h>     /* size_t, NULL, memory */
#include <string.h>     /* str... */
#include <fcntl.h>      /* O_... */
#include <stdarg.h>
#include <stddef.h>
#include <assert.h>
#if defined(__BORLANDC__)
#  include <io.h>         /* open, ... */
#  include <dir.h>        /* mkdir */
#  include <alloc.h>
#  include <new.h>
#define WIN32_LEAN_AND_MEAN
#else
#if defined(__WATCOMC__) || defined(_MSC_VER)
#  include <io.h>         /* open, ... */
#  include <direct.h>     /* mkdir */
#else
#  include <unistd.h>     /* open, ... */
#  include <sys/stat.h>   /* mkdir */
#endif
#endif
#include <sys/types.h>  /* uchar, ... */

/* Unfortunately, the following is incompatible with STL
   We have to stop using it :(((

#ifndef __NOT_ONLY_PRO_FUNCS__
#define __ONLY_PRO_FUNCS__    // force usage of wrapper functions
#endif

*/

#if !defined(__WATCOMC__)
#define STL_SUPPORT_PRESENT
#endif

/*==================================================*/
#ifdef __cplusplus
#define C_INCLUDE       extern "C" {
#define C_INCLUDE_END   }
#else
#define C_INCLUDE
#define C_INCLUDE_END
#endif

/*==================================================*/
#if !defined(__OS2__) && !defined(__MSDOS__) && !defined(__NT__)
#error "Please define one of: __NT__, __OS2__, __MSDOS__"
#endif

/*==================================================*/
#ifndef MAXSTR
#define MAXSTR 1024
#endif

/*==================================================*/

#define __MF__  0               // Byte sex of our platform
                                // (Most significant byte First)
                                // 0 - little endian (Intel 80x86)
                                // 1 - big endian (PowerPC)

/*==================================================*/
/* Macro to avoid of message 'Parameter ... is never used' */
#if defined(__BORLANDC__) && !defined(__NT__) || defined(__WATCOMC__)
#define qnotused(x)     (x=x)
#else
#define qnotused(x)
#endif

/*==================================================*/
#ifdef __WATCOMC__
#define CONST_CAST(x)   (x)
#else
#define CONST_CAST(x)   const_cast<x>
#endif

/*==================================================*/
#if defined(__IDP__) && defined(__NT__) // for modules
#define idaapi          __stdcall
#define idaman          extern "C"
#define ida_export      idaapi
#define ida_export_data __declspec(dllimport)
#elif defined(__NT__)                   // for the kernel
#define idaapi          __stdcall
#define idaman          extern "C"
#define ida_export      idaapi
#define ida_export_data
#else                                   // for watcom
#define idaapi
#define idaman          extern
#define ida_export
#define ida_export_data
#endif

/*==================================================*/
#if (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) || defined(__DOS16__)

typedef int bool;
const bool false = 0;
const bool true = 1;

#endif

/*==================================================*/
/* uchar, ... */
/*--------------------------------------------------*/
typedef unsigned char  uchar;
typedef unsigned short ushort;
typedef unsigned int   uint;
typedef unsigned long  ulong;

#if defined(__BORLANDC__) || defined(_MSC_VER)
#define __HAS_LONGLONG__
#endif
#include <llong.hpp>

typedef          char   int8;
typedef signed   char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef unsigned short  uint16;
typedef          long   int32;
typedef unsigned long   uint32;
typedef longlong        int64;
typedef ulonglong       uint64;

inline bool can_place32(uint64 a) { return a == (uint64)(uint32)low(a); }
inline bool can_place32(int64 a)  { return a == ( int64)( int32)low(a); }

/*==================================================*/
/* error codes */
/*--------------------------------------------------*/

#define eOk        0    /* No error             */
#define eOS        1    /* OS error, see errno  */
#define eDiskFull  2    /* Disk Full            */
#define eReadError 3    /* Read Error           */

typedef int error_t;

/*--------------------------------------------------*/
/* internal code of last error occured              */
/* see err.h for error handling functions           */
idaman error_t ida_export_data qerrno;

/*==================================================*/
/* type of OS */
/*--------------------------------------------------*/
typedef enum
{
   osMSDOS,
   osAIX_RISC,
   osOS2,
   osNT
} ostype_t;

/*--------------------------------------------------*/
extern ostype_t ostype;

/*==================================================*/
/* memory */
/*--------------------------------------------------*/
idaman void *ida_export qalloc( size_t size );
idaman void *ida_export qrealloc( void *alloc, size_t newsize );
idaman void *ida_export qcalloc( size_t nitems, size_t itemsize );
idaman void  ida_export qfree( void *alloc );
idaman char *ida_export qstrdup( const char *string );
#define qnew(t)        ((t*)qalloc(sizeof(t)))
#define qnewarray(t,n) ((t*)qcalloc((n),sizeof(t)))
#define qnumber(a)     (sizeof(a)/sizeof((a)[0]))

#ifdef __ONLY_PRO_FUNCS__
#define malloc          dont_use_this_function
#define calloc          dont_use_this_function
#define realloc         dont_use_this_function
#define free            dont_use_this_function
#define strdup          dont_use_this_function
#endif
/*==================================================*/
/* file name */
/*--------------------------------------------------*/
/* maximum number of characters in path and file specification */
#ifdef __MSDOS__
#define QMAXPATH        _MAX_PATH
#define QMAXFILE        (_MAX_FNAME+_MAX_EXT)
#else
#define QMAXPATH        255     /* POSIX standard */
#define QMAXFILE        255     /* POSIX standard is 14 */
#endif
/*--------------------------------------------------*/
/* construct 'path' from component's list terminated by NULL, return 'path'.
   if 'path'==NULL then pointer to static array will be returned,
   qmakepath( NULL, NULL ) just returns pointer to static array.
*/
idaman char *ida_export vqmakepath( char *path, const char *s1, va_list );
inline char *qmakepath( char *path, const char *s1, ... )
{
  va_list va;
  va_start(va, s1);
  char *code = vqmakepath(path, s1, va);
  va_end(va);
  return code;
}

/*--------------------------------------------------*/
/* split 'path' into 'dir' and 'file' parts, you may specify NULL
   as 'dir'/'file' parameters. 'path' may be changed.
   return file part.
*/
idaman char *ida_export qsplitpath( char *path, char **dir, char **file );
/*--------------------------------------------------*/
/* construct filename from base name and extension, return 'file'.
   if 'file'==NULL then pointer to static array will be returned,
   qmakefile( NULL, NULL, NULL ) just returns pointer to static array.
*/
idaman char *ida_export qmakefile( char *file, const char *base, const char *ext );
/*--------------------------------------------------*/
/* split filename to base name and extension, you may specify NULL
   as 'base'/'ext' parameters. 'file' may be changed.
   return base part.
*/
idaman char *      ida_export qsplitfile( char *file, char **base, char **ext );
idaman int         ida_export qisabspath(const char *file);
idaman const char *ida_export basename(const char *path);
char *qmake_full_path(char *dst, const char *src);

/* Delimiter of directory lists */
#ifdef __UNIX__
#define DELIMITER       ":"     /* Unix   */
#else
#define DELIMITER       ";"     /* MS DOS */
#endif

/*==================================================*/
/* input/output */
/*--------------------------------------------------*/
#if !defined(__MSDOS__) && !defined(__OS2__) && !defined(__NT__) && !defined(_MSC_VER)
#define O_BINARY        0
#endif

#ifndef SEEK_SET
#define SEEK_SET        0
#define SEEK_CUR        1
#define SEEK_END        2
#endif
/*--------------------------------------------------*/
/* you should use these functions for file i/o                */
/* they do the same as their counterparts from Clib.          */
/* the only difference is that they set 'qerrno' variable too */

idaman int   ida_export qopen( const char *file, int mode );     /* open existing file */
idaman int   ida_export qcreate( const char *file, int stat );   /* create new file with O_RDWR */
idaman int   ida_export qread( int h, void *buf, size_t n );
idaman int   ida_export qwrite( int h, const void *buf, size_t n );
idaman long  ida_export qtell( int h );
idaman long  ida_export qseek( int h, long offset, int whence );
idaman int   ida_export qclose( int h );
idaman ulong ida_export qfilesize( const char *fname );
idaman ulong ida_export qfilelength( int h );
idaman int   ida_export qchsize( int h, unsigned long fsize );
idaman int   ida_export qmkdir( const char *file, int mode );
#define qfileexist(p)   ( access( (p), 0 ) == 0 )

#ifdef __ONLY_PRO_FUNCS__
#define open            dont_use_this_function
// netnode::create clashes with the following definition
//#define create          dont_use_this_function
#define read            dont_use_this_function
#define write           dont_use_this_function
#define tell            dont_use_this_function
#define lseek           dont_use_this_function
#define close           dont_use_this_function
#define filelength      dont_use_this_function
#define mkdir           dont_use_this_function
#define system          dont_use_this_function
#define min             dont_use_this_function
#define max             dont_use_this_function
#define atexit          dont_use_this_function
#define exit            dont_use_this_function
#endif

/*==================================================*/
/* strings */
/*--------------------------------------------------*/
idaman char *ida_export stpcpyq( char *dest, const char *src );
#if !defined(__BORLANDC__)
#define stpcpy stpcpyq
#endif
#if !defined(__BORLANDC__) && !defined(_MSC_VER)
idaman char *ida_export strlwr( char *s );
idaman char *ida_export strupr( char *s );
#endif
/*--------------------------------------------------*/
idaman char *ida_export strleft( char *s, int len );
idaman char *ida_export strright( char *s, int len );
idaman char *ida_export strcenter( char *s, int len );
idaman char *ida_export strpad( char *s, int len );
idaman char *ida_export strpadc( char *s, int len, char c );
idaman char *ida_export strprepadc( char *s, int len, char c );
idaman char *ida_export strclip( char *s );
idaman char *ida_export strclipc( char *s, char clipchar );
idaman char *ida_export strpreclip( char *s );
idaman char *ida_export strfill(char *s, char chr, int count);
idaman char *ida_export strcompact(char *string);
// qstrncpy makes sure that there is a terminating zero
// nb: this function doesn't fill the whole buffer zeroes as strncpy does
idaman char *ida_export qstrncpy(char *dst, const char *src, size_t dstsize);
// qstpncpy returns pointer to the end of the destination
// todo: export it!
idaman char *qstpncpy(char *dst, const char *src, size_t dstsize);

/*--------------------------------------------------*/
#if !defined(__IDP__)
// BCC has bad definition of snprintf
// The kernel is compiled by BCC
//#if defined(__BORLANDC__) && __BORLANDC__ >= 0x0540
//#define SNPRINTF_PRESENT bad implementation :(((
//#include <stdio.h>              // snprintf is here
//#endif
#if defined(__BORLANDC__)
#include <stdio.h>
#endif

#if defined(__GNUC__)
#define SNPRINTF_PRESENT
#endif

#if defined(_MSC_VER)
#define SNPRINTF_PRESENT
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#endif

#if !defined(SNPRINTF_PRESENT)
#include <stdio.h>
#undef  snprintf
#define snprintf qsnprintf
#undef  vsnprintf
#define vsnprintf qvsnprintf
idaman int ida_export vsnprintf(char *buffer, size_t n, const char *format, va_list va);
inline int snprintf(char *buffer, size_t n, const char *format, ...)
{
  va_list va;
  va_start(va, format);
  int code = vsnprintf(buffer, n, format, va);
  va_end(va);
  return code;
}

#endif

/*==================================================*/
/* Replace all entries of 'char1' by 'char2' in string
   'str'
*/
idaman char *ida_export strrpl( char *str, int char1, int char2 );

/*==================================================*/
/* system call with parameters substitution */
/*--------------------------------------------------*/
idaman void ida_export qexit(int code);
idaman void ida_export qatexit(void (idaapi *func)(void));

/*==================================================*/
/* universal min, max */
/*--------------------------------------------------*/
#define qmin(a,b) ( (a) < (b)? (a): (b) )
#define qmax(a,b) ( (a) > (b)? (a): (b) )

/*==================================================*/
/* Add-ins for 2/4 byte read/writes.
        h - file handle
        res - value read from file
        size - size of value in bytes (1,2,4)
        mostfirst - is MSB first? (0/1)

   All these functions return 0 - Ok */

idaman int ida_export readbytes(int h,ulong *res,int size,int mostfirst);
idaman int ida_export writebytes(int h,ulong l,int size,int mostfirst);

idaman int ida_export read2bytes(int h,ushort *res,int mostfirst);
#define read4bytes(h,res,mostfirst)     readbytes(h,res,4,mostfirst)
#define write2bytes(h,l,mostfirst)      writebytes(h,l,2,mostfirst)
#define write4bytes(h,l,mostfirst)      writebytes(h,l,4,mostfirst)

/*==================================================*/
#ifdef __cplusplus
inline ulong swap32(ulong x)
{ return (x>>24) | (x<<24) | ((x>>8) & 0x0000FF00L) | ((x<<8) & 0x00FF0000L); }
inline ushort swap16(ushort x)
{ return ushort((x<<8) | (x>>8)); }
#else
#define swap32(x) ulong((x>>24) | (x<<24) | ((x>>8) & 0x0000FF00L) | ((x<<8) & 0x00FF0000L))
#define swap16(x) ushort((x<<8) | (x>>8))
#endif

// append a string to the buffer checking the buffer size
#define APPEND(buf, end, name)                    \
  do                                              \
  {                                               \
    const char *in = name;                        \
    while ( 1 )                                   \
    {                                             \
      if ( buf >= end )                           \
      {                                           \
        buf = end-1;                              \
        buf[0] = '\0';                            \
        break;                                    \
      }                                           \
      if ( (*buf = *in++) == 0 )                  \
        break;                                    \
      buf++;                                      \
    }                                             \
  } while ( 0 )

/*==================================================*/
// STL replacement templates
#ifdef __WATCOMC__ // since watcom doesn't support stl, implement simple vector right here

class exception {};
class bad_alloc : public exception {};

template <class T> class vector
{
  T *array;
  size_t n, alloc;
  vector<T> &assign(const vector<T> &x)
  {
    if ( x.n > 0 )
    {
      array = (T*)qalloc(x.alloc * sizeof(T));
      if ( array != NULL )
      {
        alloc = x.alloc;
        for ( int i=0; i < x.n; i++ )
          array[i] = x.array[i];
        n = x.n;
      }
    }
    return *this;
  }
public:
  vector(void) : array(NULL), n(0), alloc(0) {}
  vector(const vector<T> &x) : array(NULL), n(0), alloc(0) { assign(x); }
  ~vector(void) { clear(); }
  void push_back(const T &x)
  {
    if ( n >= alloc )
    {
      int m = qmax(8, alloc * 2);
      T *a = (T*)qrealloc(array, m * sizeof(T));
      if ( a == NULL ) throw bad_alloc();
      array = a;
      alloc = m;
    }
    new (array+n) T(x); // create a new element in the vector
    n++;
  }
  int size(void) const { return n; }
  const T &operator[](int idx) const { return array[idx]; }
        T &operator[](int idx)       { return array[idx]; }
  void clear(void)
  {
    if ( n > 0 )
    {
      for ( int i=0; i < n; i++ )
        array[i].~T();
      qfree(array);
      array = NULL;
      alloc = 0;
      n = 0;
    }
  }
  vector<T> &operator=(const vector<T> &x)
  {
    clear();
    return assign(x);
  }
  void resize(size_t s, const T &x)
  {
    if ( s < n )
    {
      while ( n > s )
        array[--n].~T();
    }
    else if ( s >= alloc )
    {
      T *a = (T*)qrealloc(array, s * sizeof(T));
      if ( a == NULL ) throw bad_alloc();
      array = a;
      alloc = s;
    }
    while ( n < s )
    {
      new(array+n) T(x);
      n++;
    }
  }
};

class string    // implement simple string class
{
  vector<char> body;
public:
  string(void) {
  }
  string(const char *ptr)
  {
    size_t len = strlen(ptr) + 1;
    body.resize(len, '\0');
    memcpy(&body[0], ptr, len);
  }
  string(const char *ptr, size_t len)
  {
    body.resize(len, '\0');
    memcpy(&body[0], ptr, len);
  }
  size_t length(void) const { size_t l = body.size(); return l ? l - 1 : 0; }
  const char *c_str(void) const { return body.size() ? &body[0] : ""; }
};

#endif // __WATCOMC__

#pragma pack(pop)
#endif /* _PRO_H */
