From 93d231d5a255a98a2e873fd8dd47159bafcb5f8a Mon Sep 17 00:00:00 2001
From: "H. William Welliver III" <bill@welliver.org>
Date: Sat, 6 Jan 2007 18:37:18 -0500
Subject: [PATCH] first attempt at an Objective-C embedding framework for Pike.
 note that we don't have much in the way of autoconfified variables yet.

Rev: src/Makefile.in:1.457
Rev: src/OCPikeInterpreter.h:1.1
Rev: src/OCPikeInterpreter.m:1.1
---
 src/Makefile.in         |  32 ++++-
 src/OCPikeInterpreter.h |  42 +++++++
 src/OCPikeInterpreter.m | 262 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 334 insertions(+), 2 deletions(-)
 create mode 100644 src/OCPikeInterpreter.h
 create mode 100644 src/OCPikeInterpreter.m

diff --git a/src/Makefile.in b/src/Makefile.in
index 88802411c7..571da65759 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,5 +1,5 @@
 #
-# $Id: Makefile.in,v 1.456 2006/09/29 12:43:59 grubba Exp $
+# $Id: Makefile.in,v 1.457 2007/01/06 23:37:18 bill Exp $
 #
 
 # This line is needed on some machines.
@@ -281,6 +281,12 @@ compiler-warnings : clean
 	@echo 'End of summary'
 	@echo '--------------'
 
+framework: OCPikeInterpreter.o $(OBJ) modules/linker_options @STATIC_POST_MODULES_LINKOPTS@
+	@echo "Linking Pike.framework";\
+	gcc -o Pike OCPikeInterpreter.o $(OBJ) `cat modules/linker_options @STATIC_POST_MODULES_LINKOPTS@` -framework Cocoa -Wl,-single_module \
+	  -undefined dynamic_lookup -compatibility_version 1 -current_version 1 -dynamiclib -mmacosx-version-min=10.4 \
+	  -isysroot /Developer/SDKs/MacOSX10.4u.sdk 
+
 libpike.so: $(OBJ) modules/linker_options @STATIC_POST_MODULES_LINKOPTS@
 	@echo "Linking libpike.so";\
 	if $(TMP_BINDIR)/smartlink "$(LDSHARED)" $(LDFLAGS) -o libpike.@SO@ \
@@ -438,7 +444,7 @@ undump_modules: delete_dumped_modules
 	-rm dumpversion 2>/dev/null
 
 .SUFFIXES:
-.SUFFIXES: .c .h .o .cmod .symlist .pp .pph .protos .h_src .wxs .wixobj .msi .msm
+.SUFFIXES: .c .h .o .m .mmod .cmod .symlist .pp .pph .protos .h_src .wxs .wixobj .msi .msm
 
 .c.pp:
 	$(CPP) $(PREFLAGS) -DPMOD_EXPORT=PMOD_EXPORT \
@@ -482,6 +488,28 @@ undump_modules: delete_dumped_modules
 	  fi; \
 	fi
 
+.m.o:
+	@echo "Compiling `echo '$<' | sed -e 's|^$(PIKE_SRC_DIR)/||'`" ; \
+	rm -f $@.fail >/dev/null 2>&1; \
+	if test "x$@" = "xinterpret.o"; then EXTRAFLAGS="$(INTERPRET_DEOPTIMIZE)"; else EXTRAFLAGS=; fi; \
+	if $(CC) $(CFLAGS) $$EXTRAFLAGS -fobjc-exceptions -c $< -o $@ ; then : ; else \
+	  status=$$?; \
+	  if test x"@noopt_retry@" = xyes ; then \
+	    echo "WARNING: Compiler failure! Trying without optimization!" >&2;\
+	    echo "$(CC) $(PREFLAGS) $(CFLAGS) $$EXTRAFLAGS -fobjc-exceptions -c $< -o $@" >$@.fail ;\
+	    if NO_ULIMIT=yes $(CC) $(PREFLAGS) $(NOOPTFLAGS) $$EXTRAFLAGS -c $< -o $@ ; then : ; else \
+	      status=$$?; \
+	      echo "Compilation command was:" >&2;\
+	      echo "$(CC) $(PREFLAGS) $(NOOPTFLAGS) $$EXTRAFLAGS -fobjc-exceptions -c $< -o $@" >&2 ;\
+	      exit $$status; \
+	    fi; \
+	  else \
+	    echo "Compilation command was:" >&2;\
+	    echo "$(CC) $(PREFLAGS) $(CFLAGS) $$EXTRAFLAGS -fobjc-exceptions -c $< -o $@" >&2 ;\
+	    exit $$status; \
+	  fi; \
+	fi
+
 #
 # Please note that this must be accompanied by a dependency rule as
 # The .c file will not be created in the SOURCE directory otherwise.
diff --git a/src/OCPikeInterpreter.h b/src/OCPikeInterpreter.h
new file mode 100644
index 0000000000..c189e65409
--- /dev/null
+++ b/src/OCPikeInterpreter.h
@@ -0,0 +1,42 @@
+/* Standard Pike include files. */
+#include "bignum.h"
+#include "array.h"
+#include "builtin_functions.h"
+#include "constants.h"
+#include "interpret.h"
+#include "mapping.h"
+#include "multiset.h"
+#include "module_support.h"
+#include "object.h"
+#include "pike_macros.h"
+#include "pike_types.h"
+#include "program.h"
+#include "stralloc.h"
+#include "svalue.h"
+#include "threads.h"
+#include "version.h"
+#include "operators.h"
+
+/* Objective-C includes */
+#import <Foundation/NSObject.h>
+#import <Foundation/NSException.h>
+
+
+
+@interface OCPikeInterpreter : NSObject
+{
+  int is_started;
+  id master_location;
+  JMP_BUF jmploc;
+}
+
++ (OCPikeInterpreter *)sharedInterpreter;
+- (id)init;
+- (void)setMaster:(id)master;
+- (BOOL)startInterpreter;
+- (BOOL)isStarted;
+- (BOOL)stopInterpreter;
+- (struct program *)compileString: (id)code;
+- (struct svalue *)evalString: (id)expression;
+
+@end /* interface OCPikeInterpreter */
diff --git a/src/OCPikeInterpreter.m b/src/OCPikeInterpreter.m
new file mode 100644
index 0000000000..5eb057eae6
--- /dev/null
+++ b/src/OCPikeInterpreter.m
@@ -0,0 +1,262 @@
+#import "OCPikeInterpreter.h"
+#import <Foundation/NSString.h>
+#import <Foundation/NSBundle.h>
+
+static void set_master(const char *file)
+{
+  if (strlen(file) >= MAXPATHLEN*2 ) {
+    fprintf(stderr, "Too long path to master: \"%s\" (limit:%"PRINTPTRDIFFT"d)\n",
+            file, MAXPATHLEN*2 );
+    exit(1);
+  }
+//  strcpy(master_location, file);
+}
+
+
+static void set_default_master(void)
+{
+}
+
+
+
+@implementation OCPikeInterpreter
+- (id) init {
+	
+    static OCPikeInterpreter *sharedInstance = nil;
+	
+    if (sharedInstance) {
+        [self autorelease];
+        self = [sharedInstance retain];
+    } else {
+        self = [super init];
+        if (self) {
+            sharedInstance = [self retain];
+			master_location = NULL;
+        }
+    }
+
+    return self;
+}
+
++(OCPikeInterpreter *)sharedInterpreter
+{
+	static OCPikeInterpreter * sharedInstance = nil;
+	
+	if ( sharedInstance == nil )
+		sharedInstance = [[self alloc] init];
+	
+	return sharedInstance;
+}
+
+
+- (void)setMaster:(id) master
+{
+	  if ([master length] >= MAXPATHLEN*2 ) {
+	    fprintf(stderr, "Too long path to master: \"%s\" (limit:%"PRINTPTRDIFFT"d)\n",
+	            [master UTF8String], MAXPATHLEN*2 );
+	    exit(1);
+	  }
+	master_location = [master copy];
+}
+
+- (BOOL)startInterpreter
+{
+  	JMP_BUF back;
+	int num = 0;
+	struct object *m;
+    char ** argv = NULL;
+	
+	id ml;
+	id this_bundle;
+	this_bundle = [NSBundle bundleForClass: [self class]];
+
+	if(!this_bundle || this_bundle == nil)
+	{
+		NSException * exception = [NSException exceptionWithName:@"Error finding bundle!" reason:@"bundleForClass: returned nil." userInfo: nil];
+		@throw exception;
+	}
+		
+	if(!master_location)
+	{
+ 	  ml = [[NSMutableString alloc] initWithCapacity: 200];
+	  [ml setString: [this_bundle resourcePath]];
+	  [ml appendString: @"/lib/master.pike"];
+
+	  [self setMaster: ml];
+		
+	  [ml release];
+    }
+
+	init_pike(argv, [master_location UTF8String]);
+	init_pike_runtime(exit);
+
+	add_pike_string_constant("__embedded_resource_directory",
+								[[this_bundle resourcePath] UTF8String],
+								strlen([[this_bundle resourcePath] UTF8String]));
+								
+	add_pike_string_constant("__master_cookie",
+	                           [master_location UTF8String], 
+				strlen([master_location UTF8String]));
+
+	  if(SETJMP(jmploc))
+	  {
+	    if(throw_severity == THROW_EXIT)
+	    {
+	      num=throw_value.u.integer;
+	    }else{
+	      if (throw_value.type == T_OBJECT &&
+	          throw_value.u.object->prog == master_load_error_program &&
+	          !get_master()) {  
+	        /* Report this specific error in a nice way. Since there's no
+	         * master it'd be reported with a raw error dump otherwise. */
+	        struct generic_error_struct *err;
+
+	        dynamic_buffer buf;
+	        dynbuf_string s;
+	        struct svalue t;
+
+	        *(Pike_sp++) = throw_value;
+	        dmalloc_touch_svalue(Pike_sp-1);
+	        throw_value.type=T_INT;  
+	        err = (struct generic_error_struct *)
+	          get_storage (Pike_sp[-1].u.object, generic_error_program);
+
+	        t.type = PIKE_T_STRING;
+	        t.u.string = err->error_message;
+
+	        init_buf(&buf);
+	        describe_svalue(&t,0,0);
+	        s=complex_free_buf(&buf);
+
+	        fputs(s.str, stderr);
+	        free(s.str);
+	      } 
+	      else
+	        call_handle_error();
+	    }
+	  }else{
+
+
+	    if ((m = load_pike_master())) {
+	      back.severity=THROW_EXIT;
+//	      pike_push_argv(argc, argv);
+	      pike_push_env();
+
+		}
+   return YES;
+}
+  return NO;
+}
+
+- (BOOL)stopInterpreter
+{
+	UNSETJMP(jmploc);
+	pike_do_exit(0);	
+    return YES;	
+}
+
+- (struct program *)compileString: (id)code
+{
+	struct program * p = NULL;
+	push_text([code UTF8String]);
+    f_utf8_to_string(1);
+	f_compile(1);
+	if(Pike_sp[-1].type==T_PROGRAM)
+	{
+  	  p = Pike_sp[-1].u.program;
+	  add_ref(p);
+    }
+	pop_n_elems(1);
+	return p;	
+}
+
+- (struct svalue *)evalString: (id)expression
+{
+    int i;
+    struct object * o;
+    struct program * p;
+    struct svalue * s;
+
+	id c = [[NSMutableString alloc] initWithCapacity: 200];
+	[c retain];
+	[c setString: @"mixed foo(){ return("];
+	[c appendString: expression];
+	[c appendString: @");}"];
+
+    p = [self compileString: c];
+
+    [c release];
+
+    if(!p) return NULL;
+ 
+	i=find_identifier("foo", p);
+
+    o = low_clone(p);
+
+    apply_low(o, i, 0);
+
+    s = malloc(sizeof(struct svalue));
+    assign_svalue(s, Pike_sp-1);    
+    if(o)
+      free_object(o);
+    free_program(p);
+    pop_stack();
+
+    return s;
+}
+
+- (BOOL)isStarted
+{
+	return (is_started?YES:NO);
+}
+
+@end /* OCPikeInterpreter */
+
+/*
+
+	following is a simple example of how to use OCPikeInterpreter to embed a pike interpreter into your application.
+
+      gcc -o PikeInterpreter OCPikeInterpreter.o  -framework Cocoa  -Wl,-single_module -compatibility_version 1 \
+        -current_version 1 -install_name /Users/hww3/Library/Frameworks/PikeInterpreter.framework/Versions/A/PikeInterpreter \
+        -dynamiclib -mmacosx-version-min=10.4 -isysroot /Developer/SDKs/MacOSX10.4u.sdk ../../Pike/7.7/build/libpike.dylib
+	  gcc -I /usr/local/pike/7.7.30/include/pike/ -I . -Ilibffi -Ilibffi/include -F PikeInterpreter -c test.m -o test.o
+	  gcc test.o -o test -framework PikeInterpreter -L/Users/hww3/Pike/7.7/build -framework Foundation -lpike -lobjc
+
+
+*/
+
+/*
+#import <PikeInterpreter/OCPikeInterpreter.h>
+#import <Foundation/NSString.h>
+
+int main()
+{
+  id i;
+  struct svalue * sv;
+
+  // required for console mode objective c applications
+  NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
+
+  // these 3 lines set up and start the interpreter.
+  i = [OCPikeInterpreter sharedInterpreter];
+  [i setMaster: @"/usr/local/pike/7.7.30/lib/master.pike"];
+  [i startInterpreter];
+
+  // ok, now that we have things set up, let's use it.
+  // first, an example of calling pike c level apis directly.  
+  f_version(0);
+  printf("%s\n", Pike_sp[-1].u.string->str);
+  pop_stack();
+
+  // next, we'll demonstrate one of the convenience functions available
+  sv = [i evalString: @"1+2"];
+  printf("type: %d, value: %d\n", sv->type, sv->u.integer);
+  free_svalue(sv);
+
+  // finally, we clean up.
+  [i stopInterpreter];
+  [innerPool release];
+  return 0;
+}
+
+*/
-- 
GitLab