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