Index: TODO ================================================================== --- TODO +++ TODO @@ -5,19 +5,17 @@ Tests for OFNumber. OFBase64 OFDirectory -OFDictionary OFSortedArray OFThread OFStack OFQueue -OFPlugin OFXMLParser OFSortedQueue OFTLSSocket OFXMPPClient Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -15,10 +15,17 @@ LIBS="$LIBS -lobjc" AC_DEFINE(OF_CONFIG_H, 1, [Define so that we know we got our config.h]) BUILDSYS_LIB +AC_DEFINE_UNQUOTED(PLUGIN_SUFFIX, "$PLUGIN_SUFFIX", [Suffix for plugins]) + +if test x"$PLUGIN_SUFFIX" != "x"; then + AC_SUBST(OFPLUGIN_M, "OFPlugin.m") + AC_SUBST(OFPLUGIN, "OFPlugin") +fi + AC_C_BIGENDIAN([AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian])]) AC_MSG_CHECKING(for SIZE_MAX) AC_EGREP_CPP(yes, [ #include @@ -40,10 +47,12 @@ size_max="SIZE_T_MAX"], [ AC_MSG_RESULT(no) size_max="((size_t)-1)"]) AC_DEFINE_UNQUOTED(SIZE_MAX, $size_max, [Maximum value for size_t])]) +AC_CHECK_LIB(dl, dlopen, LIBS="$LIBS -ldl") + AC_CHECK_HEADER(objc/runtime.h, [AC_DEFINE(HAVE_OBJC_RUNTIME_H, 1, [Whether we have objc/runtime.h])]) AC_CHECK_LIB(objc, sel_get_name, [AC_DEFINE(HAVE_SEL_GET_NAME, 1, [Whether we have sel_get_name])]) AC_CHECK_LIB(objc, sel_getName, @@ -51,11 +60,11 @@ AC_CHECK_FUNC(asprintf, [ have_asprintf="yes" AC_DEFINE(HAVE_ASPRINTF, 1, "Whether we have asprintf")], [ have_asprintf="no" - AC_SUBST(ASPRINTF, "asprintf.c")]) + AC_SUBST(ASPRINTF_C, "asprintf.c")]) AC_MSG_CHECKING(whether snprintf returns something useful) AC_CACHE_VAL(ac_cv_snprintf_useful_ret, [ AC_TRY_RUN([ #include Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,4 +1,6 @@ -ASPRINTF = @ASPRINTF@ +ASPRINTF_C = @ASPRINTF_C@ +OFPLUGIN = @OFPLUGIN@ +OFPLUGIN_M = @OFPLUGIN_M@ WS2_LIBS = @WS2_LIBS@ TESTS = @TESTS@ TEST_LAUNCHER = @TEST_LAUNCHER@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -11,14 +11,15 @@ OFHashes.m \ OFFile.m \ OFList.m \ OFNumber.m \ OFObject.m \ + ${OFPLUGIN_M} \ OFString.m \ OFTCPSocket.m \ OFXMLFactory.m \ - ${ASPRINTF} + ${ASPRINTF_C} INCLUDESTMP = ${SRCS:.c=.h} INCLUDES = ${INCLUDESTMP:.m=.h} \ OFMacros.h \ OFStream.h ADDED src/OFPlugin.h Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "OFObject.h" + +/** + * The OFPlugin class provides a system for loading plugins at runtime. + */ +@interface OFPlugin: OFObject +{ + void *handle; + id plugin; +} + +/** + * Loads an OFPlugin from a file. + * + * \param path Path to the OFPlugin file. The suffix is appended automatically. + * \return A new autoreleased OFPlugin + */ ++ pluginFromFile: (const char*)path; + +/** + * Initializes an already allocated OFPlugin from a file. + * + * \param path Path to the OFPlugin file. The suffix is appended automatically. + * \return An initialized OFPlugin + */ +- initFromFile: (const char*)path; +@end ADDED src/OFPlugin.m Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "config.h" + +#include +#include +#include + +#import "OFPlugin.h" +#import "OFExceptions.h" + +@implementation OFPlugin ++ pluginFromFile: (const char*)path +{ + return [[[OFPlugin alloc] initFromFile: path] autorelease]; +} + +- initFromFile: (const char*)path +{ + char *file; + size_t pathlen, suffixlen; + id (*init_plugin)(); + Class c; + + if ((self = [super init])) { + pathlen = strlen(path); + suffixlen = strlen(PLUGIN_SUFFIX); + + if ((file = malloc(pathlen + suffixlen + 1)) == NULL) { + c = [self class]; + [super free]; + @throw [OFNoMemException newWithClass: c + andSize: pathlen + + suffixlen + 1]; + } + memcpy(file, path, pathlen); + memcpy(file + pathlen, PLUGIN_SUFFIX, suffixlen); + file[pathlen + suffixlen] = 0; + + if ((handle = dlopen(file, RTLD_NOW)) == NULL || + (init_plugin = dlsym(handle, "init_plugin")) == NULL || + (plugin = init_plugin()) == nil) { + free(file); + c = [self class]; + [super free]; + @throw [OFInitializationFailedException + newWithClass: c]; + } + free(file); + } + + return self; +} + +- free +{ + [plugin free]; + dlclose(handle); + + return [super free]; +} + +#ifdef __objc_INCLUDE_GNU +- (retval_t)forward: (SEL)selector + : (arglist_t)args +#else +- (id)forward: (SEL)selector + : (marg_list)args +#endif +{ + return [plugin performv: selector + : args]; +} + +- (IMP)methodFor: (SEL)selector +{ + if ([self respondsTo: selector]) + return [self methodFor: selector]; + else + return [plugin methodFor: selector]; +} +@end Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,11 +1,14 @@ +include ../extra.mk + SUBDIRS = OFObject \ OFAutoreleasePool \ OFArray \ OFDictionary \ OFHashes \ + ${OFPLUGIN} \ OFString \ OFTCPSocket \ OFList \ OFXMLFactory include ../buildsys.mk ADDED tests/OFPlugin/Makefile Index: tests/OFPlugin/Makefile ================================================================== --- tests/OFPlugin/Makefile +++ tests/OFPlugin/Makefile @@ -0,0 +1,25 @@ +SUBDIRS = TestPlugin + +PROG_NOINST = ofplugin${PROG_SUFFIX} +SRCS = OFPlugin.m + +include ../../buildsys.mk +include ../../extra.mk + +CPPFLAGS += -I../../src -I../.. +LIBS := -L../../src -lobjfw ${LIBS} + +.PHONY: run + +all: run +run: subdirs ${PROG_NOINST} + rm -f libobjfw.so.1 libobjfw.so.1.0 libobjfw.dll libobjfw.dylib + ln -s ../../src/libobjfw.so libobjfw.so.1 + ln -s ../../src/libobjfw.so libobjfw.so.1.0 + ln -s ../../src/libobjfw.dll libobjfw.dll + ln -s ../../src/libobjfw.dylib libobjfw.dylib + LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ + DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ + ${TEST_LAUNCHER} ./${PROG_NOINST}; EXIT=$$?; \ + rm -f libobjfw.so.1 libobjfw.so.1.0 libobjfw.dll libobjfw.dylib; \ + exit $$EXIT ADDED tests/OFPlugin/OFPlugin.m Index: tests/OFPlugin/OFPlugin.m ================================================================== --- tests/OFPlugin/OFPlugin.m +++ tests/OFPlugin/OFPlugin.m @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "config.h" + +#import "OFPlugin.h" +#import "TestPlugin/TestPlugin.h" + +int +main() +{ + OFPlugin *plugin; + + plugin = [OFPlugin pluginFromFile: "TestPlugin/TestPlugin"]; + [plugin test]; + + return 0; +} ADDED tests/OFPlugin/TestPlugin/Makefile Index: tests/OFPlugin/TestPlugin/Makefile ================================================================== --- tests/OFPlugin/TestPlugin/Makefile +++ tests/OFPlugin/TestPlugin/Makefile @@ -0,0 +1,9 @@ +PLUGIN_NOINST = TestPlugin${PLUGIN_SUFFIX} +SRCS = TestPlugin.m + +include ../../../buildsys.mk +include ../../../extra.mk + +CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../../../src +OBJCFLAGS += ${PLUGIN_CFLAGS} +LDFLAGS += ${PLUGIN_LDFLAGS} ADDED tests/OFPlugin/TestPlugin/TestPlugin.h Index: tests/OFPlugin/TestPlugin/TestPlugin.h ================================================================== --- tests/OFPlugin/TestPlugin/TestPlugin.h +++ tests/OFPlugin/TestPlugin/TestPlugin.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "OFObject.h" + +@protocol TestPlugin +- (void)test; +@end + +@interface TestPlugin: OFObject +@end ADDED tests/OFPlugin/TestPlugin/TestPlugin.m Index: tests/OFPlugin/TestPlugin/TestPlugin.m ================================================================== --- tests/OFPlugin/TestPlugin/TestPlugin.m +++ tests/OFPlugin/TestPlugin/TestPlugin.m @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include + +#import "TestPlugin.h" + +@implementation TestPlugin +- (void)test +{ + puts("Test successfull!"); +} +@end + +id +init_plugin() +{ + return [TestPlugin new]; +}