/* 
   NSObjCRuntime.h

   Interface to ObjC runtime

   Copyright (C) 1995, 1997 Free Software Foundation, Inc.

   Author:	Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
   Date:	1995
   
   H.N.Schaller, Dec 2005 - API revised to be compatible to 10.4
 
   This file is part of the mySTEP Library and is provided
   under the terms of the GNU Library General Public License.
*/ 

#ifndef _mySTEP_H_NSObjCRuntime
#define _mySTEP_H_NSObjCRuntime

// include all important standard C libraries

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>

#ifndef mySTEP_MAJOR_VERSION
#define mySTEP_MAJOR_VERSION	2
#define mySTEP_MINOR_VERSION	0
#endif

#define main objc_main						// redefine main() to objc_main()

// libobjc interface

// common

#include <objc/objc.h>
#include <objc/objc-api.h>
#include <objc/Protocol.h>

#ifdef __linux__			
// those from gcc but not available on MacOS X

#include <objc/encoding.h>
#include <objc/sarray.h>
#include <objc/thr.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#endif

#ifdef __APPLE__			
// MacOS X - translate libobjc to MacOS X calling conventions

#include <objc/objc-class.h>
#include <objc/objc-load.h>
#include <objc/objc-runtime.h>

#define arglist_t marg_list
#define retval_t void *

#define objc_malloc(A) malloc(A)
#define objc_free(A) free(A)
#define objc_calloc(A, B) calloc((A), (B))
#define objc_realloc(A, B) realloc((A), (B))

#define objc_get_class(NAME) ((Class)objc_lookUpClass((const char *) NAME))
#define objc_msg_lookup(OBJECT, SELECTOR) (class_getInstanceMethod(objc_get_class(OBJECT), SELECTOR)->method_imp)
#define objc_lookup_class(CLASS) ((Class)objc_lookUpClass((const char *) CLASS))

#define objc_sizeof_type(A) 1
#define objc_alignof_type(A) 1
#define objc_skip_typespec(A) (A)

#define objc_verror(OBJECT, CODE, FORMAT, ...)

#define objc_check_undefineds(FILE)
#define objc_invalidate_dtable(CLASS)
#define objc_initialize_loading(FILE) (0)

#define objc_load_callback(CLASS, CATEGORY)
#define objc_load_module(NAME, FILE, CALLBACK, HEADER, DEBUG) (0)
#define objc_dynamic_find_file(ADDRESS) (0)

#define objc_thread_set_data(THREAD)
#define objc_thread_get_data() (0)
#define objc_thread_detach(SELECTOR, THREAD, ARG) NULL
#define objc_thread_exit()

#define class_get_class_name(CLASS) "class name"
#define class_get_class_method(CLASS, SELECTOR) (void *)(class_getClassMethod(CLASS, SELECTOR)->method_imp)
#define class_get_instance_method(CLASS, SELECTOR) (void *)(class_getInstanceMethod(CLASS, SELECTOR)->method_imp)
#define class_get_meta_class(CLASS) Nil
#define class_get_super_class(CLASS) Nil
#define class_get_instance_size(CLASS) 10
#define class_get_version(CLASS) 1
#define class_is_class(CLASS) YES
#define class_pose_as(CLASS1, CLASS2)
#define class_set_version(CLASS, VERSION)

#define CLS_ISCLASS(PTR) NO
#define CLS_ISMETA(PTR) NO

#define object_get_class(OBJECT) Nil
#define object_is_instance(OBJECT) YES
#define object_is_class(OBJECT) NO
#define object_get_class_name(OBJECT) "class name"
#define object_get_super_class(OBJECT) (Class) Nil

#define method_get_imp(METHOD) METHOD
#define METHOD_NULL ((IMP) NULL)

#define sel_get_typed_uid(name, types) ((SEL)name)
#define sel_get_any_uid(name) ((SEL)name)
#define sel_get_any_typed_uid(X) ((SEL)name)
#define sel_get_name(X) (char *) (X)
#define sel_get_type(X) "x"
#define sel_types_match(A, B) NO
#define sel_register_typed_name(NAME, TYPE) ((SEL)name)

#if 1	// FIXME: required to compile mframe.m on MacOS X - BUT DOES NOT WORK!!!

typedef void *objc_mutex_t;
typedef void *objc_condition_t;
typedef int __avword;
typedef void *av_alist;

#define av_start_ptr(alist, imp, type, retval) 
#define av_ptr(alist, type, anObject) 
#define _av_start_struct(alist, imp, size, split, retval)
#define av_start_void(alist, imp)
#define av_call(alist)

// differes from GNU definition!
#define _C_CONST	'c'
#define _C_IN		'i'
#define _C_INOUT	'j'
#define _C_OUT		'o'
#define _C_BYCOPY	'b'
#define _C_ONEWAY	'-'
#define _C_BYREF	'r'

#define _C_LNG_LNG	'1'
#define _C_ULNG_LNG	'2'
#define _C_ATOM		'a'

#define _F_CONST	0x01
#define _F_IN		0x02
#define _F_INOUT	0x04
#define _F_OUT		0x08
#define _F_BYCOPY	0x10
#define _F_ONEWAY	0x20
#define _F_BYREF	0x40

#endif

// #define mframe_next_arg(TYPES, INFO) TYPES

#else

// additional interfaces for gcc runtime

// struct NSArgumentInfo;
// const char *mframe_next_arg(const char *typePtr, struct NSArgumentInfo *info); // Step through method encoding information extracting details.
// BOOL mframe_decode_return(const char *type, void* buffer, void* retframe); // Copy the return value from retframe into the specified buffer.
// void *mframe_handle_return(const char* type, void* retval, arglist_t argFrame); // Return the value of the specified type in retval using argFrame
// arglist_t mframe_create_argframe(const char *types, void** retbuf);
// void mframe_destroy_argframe(const char *types, arglist_t argframe);

int objc_check_undefineds(FILE *errorStream);
void objc_invalidate_dtable(Class class);
int objc_initialize_loading(FILE *errorStream);
void objc_load_callback(Class class, Category *category);
long objc_load_module(const char *filename,
					  FILE *errorStream,
					  void (*loadCallback)(Class, Category*),
					  void **header,
					  char *debugFilename);
char *objc_dynamic_find_file(const void *address);

#endif

#define ROUND(V, A)  ({ typeof(V) __v=(V); typeof(A) __a=(A); \
	__a*((__v+__a-1)/__a); })

#define OBJC_MALLOC(VAR, TYPE, NUM) \
((VAR) = (TYPE *) objc_malloc ((unsigned)(NUM)*sizeof(TYPE))) 
#define OBJC_REALLOC(VAR, TYPE, NUM) \
((VAR) = (TYPE *) objc_realloc ((VAR), (unsigned)(NUM)*sizeof(TYPE)))
#define OBJC_FREE(PTR) objc_free (PTR)


#ifndef	YES
#define YES	1
#endif

#ifndef	NO
#define NO	0
#endif

#ifndef nil
#define nil (void *) 0
#endif

#ifndef Nil
#define Nil (Class) 0
#endif

#ifndef	INLINE
#define	INLINE inline
#endif

#ifndef ABS
#define ABS(a) ({typeof(a) _a = (a); _a < 0 ? -_a : _a; })
#endif

#ifndef SIGN
#define SIGN(x)  ({typeof(x) _x = (x); _x > 0 ? 1 : (_x == 0 ? 0 : -1); })
#endif

#ifndef SEL_EQ
#ifdef __linux__
#define SEL_EQ(sel1, sel2)	sel_eq(sel1, sel2)
#else
#define SEL_EQ(sel1, sel2)	(sel1 == sel2)
#endif
#endif

#ifndef MAX
#define MAX(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b;})
#endif

#ifndef MIN
#define MIN(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b;})
#endif

#define Strlen strlen
#define Strcmp strcmp

#ifndef PTR2LONG
#define PTR2LONG(P) (((char*)(P))-(char*)0)
#endif

#ifndef LONG2PTR
#define LONG2PTR(L) (((char*)0)+(L))
#endif

//
//	RETAIN(), RELEASE(), and AUTORELEASE() are placeholders for the
//	(possible)  future day when we have garbage collecting.
//
#define	RETAIN(object)		[object retain]
#define	RELEASE(object)		[object release]
#define	AUTORELEASE(object)	[object autorelease]
#define	DESTROY(object)		{ id o=(object); object=nil; [o release]; }	// recursion safe destroy

//
//	ASSIGN(object,value) assignes the value to the object
//	with appropriate retain and release operations.
//  note: value may be an expression that allocates/copies etc. new objects - must be called only once!
//  note: retain first if we assign the same value as we have already assigned!
//
#define	ASSIGN(object,value) ({ id temp=(value); \
if (temp) \
	[(temp) retain]; \
								if (object) \
									[(object) release]; \
										object = (temp);	})
//
// Method that must be implemented by a subclass
//
#define SUBCLASS  [self _subclass:_cmd];

//
// Method that is not implemented and should not be called
//
#define NIMP  [self _nimp:_cmd];
#define SHOULDNIMP NIMP

//*****************************************************************************
//
// 		Define a wrapper structure around each NSObject to store the
//		reference count locally. 
//
//*****************************************************************************

typedef struct obj_layout_unpadded			// Define a structure to hold data
{											// locally before the start of each
    unsigned retained;						// object
} unp;

#define	UNP sizeof(unp)
#ifdef ALIGN
#undef ALIGN
#endif
#define	ALIGN __alignof__(double)	

// Now do the REAL version - using
											// the other version to determine
typedef struct _object_layout 				// what padding if any is required
{											// to get the alignment of the
    unsigned retained;						// structure correct.
    char padding[ALIGN - ((UNP % ALIGN) ? (UNP % ALIGN) : ALIGN)];
	// the bytes defined by NSObject follow here
} *_object_layout;

@class NSArchiver;
@class NSCoder;
@class NSPortCoder;
@class NSMethodSignature;
@class NSRecursiveLock;
@class NSString;
@class NSInvocation;

extern SEL NSSelectorFromString(NSString *aSelectorName);
extern Class NSClassFromString(NSString *aClassName);
extern NSString *NSStringFromSelector(SEL aSelector);
extern NSString *NSStringFromClass(Class aClass);
extern const char *NSGetSizeAndAlignment(const char *typePtr,
										 unsigned int *sizep,
										 unsigned int *alignp);

extern void NSLog (NSString *format, ...);
extern void NSLogv(NSString *format, va_list args);

unsigned NSPageSize(void);
unsigned NSLogPageSize(void);
unsigned NSRoundDownToMultipleOfPageSize(unsigned bytes);
unsigned NSRoundUpToMultipleOfPageSize(unsigned bytes);
unsigned NSRealMemoryAvailable();
void *NSAllocateMemoryPages(unsigned bytes);
void NSDeallocateMemoryPages(void *ptr, unsigned bytes);
void NSCopyMemoryPages(const void *source, void *dest, unsigned bytes);

#ifdef DEBUG
#define NSDebugLog(format, args...)	NSLog(format, args...)
#else
#define NSDebugLog(format, args...)
#endif

// Global lock to be used by classes when operating on any 
// global data that invoke other methods which also access 
// global; thus, creating the potential for deadlock.

extern NSRecursiveLock *mstep_global_lock;

static INLINE BOOL
_classIsKindOfClass(Class c, Class aClass)
{
	for (;c != Nil; c = class_get_super_class(c))
		if (c == aClass)
			return YES;

    return NO;
}

#endif /* _mySTEP_H_NSObjCRuntime */
