ADDED .gitignore Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -0,0 +1,37 @@ +*.a +*.bundle +*.dll +*.dylib +*.o +*.orig +*.so +*~ +.deps +aclocal.m4 +autom4te.cache +build +buildsys.mk +config.h +config.h.in +config.log +config.status +configure +DerivedData +docs +extra.mk +generators/gen_tables +generators/gen_tables.exe +generators/CaseFolding.txt +generators/UnicodeData.txt +Info.plist +ObjFW.xcodeproj/*.mode1v3 +ObjFW.xcodeproj/*.pbxuser +ObjFW.xcodeproj/project.xcworkspace +ObjFW.xcodeproj/xcuserdata +src/objfw-defs.h +src/ObjFW +tests/tests +tests/tests.exe +tests/EBOOT.PBP +tests/PARAM.SFO +utils/objfw-config DELETED .hgignore Index: .hgignore ================================================================== --- .hgignore +++ .hgignore @@ -1,37 +0,0 @@ -syntax: glob -*.a -*.dll -*.dylib -*.impl -*.o -*.orig -*.so -*~ -.deps -aclocal.m4 -autom4te.cache -build -buildsys.mk -config.h -config.h.in -config.log -config.status -configure -DerivedData -docs -extra.mk -generators/gen_tables -generators/gen_tables.exe -generators/CaseFolding.txt -generators/UnicodeData.txt -objfw-config -ObjFW.xcodeproj/*.mode1v3 -ObjFW.xcodeproj/*.pbxuser -ObjFW.xcodeproj/project.xcworkspace -ObjFW.xcodeproj/xcuserdata -src/objfw-defs.h -src/ObjFW -tests/tests -tests/tests.exe -tests/EBOOT.PBP -tests/PARAM.SFO Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -24,11 +24,11 @@ * -framework works with objfw-compile now. + Support for QNX. * Various small fixes. ObjFW 0.5.2 -> ObjFW 0.5.3, 01.07.2011 - * Lots of bugfixes, see Mercurial log for details. (hg log -b 0.5) + * Lots of bugfixes, see Git log for details. ObjFW 0.5.1 -> ObjFW 0.5.2, 25.04.2011 * Fix double-retain in OFList. * Don't ignore the timeout in OFStreamObserver when using select(). * Do -[OFURL copy] in a try block to prevent a leak when an exception occurs. DELETED Info.plist Index: Info.plist ================================================================== --- Info.plist +++ Info.plist @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ObjFW - CFBundleName - ObjFW - CFBundleIdentifier - org.webkeks.objfw - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - FMWK - CFBundleSignature - OBJFW - CFBundleVersion - 0.7-dev - CFBundleShortVersionString - 0.7-dev - - ADDED Info.plist.in Index: Info.plist.in ================================================================== --- Info.plist.in +++ Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ObjFW + CFBundleName + ObjFW + CFBundleIdentifier + org.webkeks.objfw + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + OBJFW + CFBundleVersion + @PACKAGE_VERSION@ + CFBundleShortVersionString + @PACKAGE_VERSION@ + + Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -10,29 +10,16 @@ extra.mk include buildsys.mk tarball: - V=$$(fgrep VERSION= utils/objfw-config.in | \ - sed 's/VERSION="\(.*\)"/\1/'); \ - V2=$$(fgrep AC_INIT configure.ac | \ - sed 's/AC_INIT([^,]*,\([^,]*\),.*/\1/' | sed 's/ //'); \ - V3=$$(fgrep -A1 CFBundleVersion Info.plist | tail -1 | \ - sed 's/.*>\(.*\)<.*/\1/'); \ - V4=$$(fgrep -A1 CFBundleShortVersion Info.plist | tail -1 | \ - sed 's/.*>\(.*\)<.*/\1/'); \ - if test x"$$V2" != x"$$V" \ - -o x"$$V3" != x"$$V" \ - -o x"$$V4" != x"$$V4"; then \ - echo "Not all files have the same version number!"; \ - echo "Files: util/objfw-config.in configure.ac Info.plist"; \ - exit 1; \ - fi; \ - echo "Generating tarball for version $$V..."; \ - rm -f objfw-$$V.tar.gz; \ - rm -fr objfw-$$V; \ - hg archive objfw-$$V; \ - cp configure config.h.in objfw-$$V; \ - cd objfw-$$V && rm -f .hg_archival.txt .hgignore .hgtags && cd ..; \ - tar cf objfw-$$V.tar objfw-$$V; \ - gzip -9 objfw-$$V.tar; \ - rm -fr objfw-$$V + echo "Generating tarball for version ${PACKAGE_VERSION}..." + rm -fr tmp.tar objfw-${PACKAGE_VERSION} objfw-${PACKAGE_VERSION}.tar \ + objfw-${PACKAGE_VERSION}.tar.gz + git archive HEAD --prefix objfw-${PACKAGE_VERSION}/ -o tmp.tar + tar xf tmp.tar + rm -f tmp.tar objfw-${PACKAGE_VERSION}/.gitignore + cp configure config.h.in objfw-${PACKAGE_VERSION}/ + tar cf objfw-${PACKAGE_VERSION}.tar objfw-${PACKAGE_VERSION} + rm -fr objfw-${PACKAGE_VERSION} + gzip -9 objfw-${PACKAGE_VERSION}.tar + rm -f objfw-${PACKAGE_VERSION}.tar Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -269,10 +269,12 @@ 4B90B7A3133AD87D00BD33CB /* OFBindFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B799133AD87D00BD33CB /* OFBindFailedException.m */; }; 4B90B7A4133AD87D00BD33CB /* OFConnectionFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90B79A133AD87D00BD33CB /* OFConnectionFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B90B7A5133AD87D00BD33CB /* OFConnectionFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B79B133AD87D00BD33CB /* OFConnectionFailedException.m */; }; 4B90B7A6133AD87D00BD33CB /* OFListenFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B90B79C133AD87D00BD33CB /* OFListenFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B90B7A7133AD87D00BD33CB /* OFListenFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B90B79D133AD87D00BD33CB /* OFListenFailedException.m */; }; + 4B9361A81511000C00DCD16B /* OFThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9361A61511000C00DCD16B /* OFThreadPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B9361A91511000C00DCD16B /* OFThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B9361A71511000C00DCD16B /* OFThreadPool.m */; }; 4B989C2F13771A3700109A30 /* OFSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B989C2E13771A3700109A30 /* OFSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B9BB7BD141CDE2D000AD1CC /* OFArray_adjacentSubarray.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9BB7B9141CDE2D000AD1CC /* OFArray_adjacentSubarray.h */; }; 4B9BB7BE141CDE2D000AD1CC /* OFArray_adjacentSubarray.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BB7BA141CDE2D000AD1CC /* OFArray_adjacentSubarray.m */; }; 4B9BB7BF141CDE2D000AD1CC /* OFArray_subarray.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9BB7BB141CDE2D000AD1CC /* OFArray_subarray.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B9BB7C0141CDE2D000AD1CC /* OFArray_subarray.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BB7BC141CDE2D000AD1CC /* OFArray_subarray.m */; }; @@ -617,10 +619,12 @@ 4B90B799133AD87D00BD33CB /* OFBindFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFBindFailedException.m; path = src/exceptions/OFBindFailedException.m; sourceTree = ""; }; 4B90B79A133AD87D00BD33CB /* OFConnectionFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFConnectionFailedException.h; path = src/exceptions/OFConnectionFailedException.h; sourceTree = ""; }; 4B90B79B133AD87D00BD33CB /* OFConnectionFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFConnectionFailedException.m; path = src/exceptions/OFConnectionFailedException.m; sourceTree = ""; }; 4B90B79C133AD87D00BD33CB /* OFListenFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFListenFailedException.h; path = src/exceptions/OFListenFailedException.h; sourceTree = ""; }; 4B90B79D133AD87D00BD33CB /* OFListenFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFListenFailedException.m; path = src/exceptions/OFListenFailedException.m; sourceTree = ""; }; + 4B9361A61511000C00DCD16B /* OFThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFThreadPool.h; path = src/OFThreadPool.h; sourceTree = ""; }; + 4B9361A71511000C00DCD16B /* OFThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFThreadPool.m; path = src/OFThreadPool.m; sourceTree = ""; }; 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSeekableStream.h; path = src/OFSeekableStream.h; sourceTree = ""; }; 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSeekableStream.m; path = src/OFSeekableStream.m; sourceTree = ""; }; 4B989C2E13771A3700109A30 /* OFSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSerialization.h; path = src/OFSerialization.h; sourceTree = ""; }; 4B99250F12E0780000215DBE /* OFHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFHTTPRequest.h; path = src/OFHTTPRequest.h; sourceTree = ""; }; 4B99251012E0780000215DBE /* OFHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFHTTPRequest.m; path = src/OFHTTPRequest.m; sourceTree = ""; }; @@ -997,10 +1001,12 @@ 4B6799821099E7C50041064A /* OFTCPSocket.m */, 4BD653C3143B8489006182F0 /* OFTCPSocket+SOCKS5.h */, 4BD653C4143B8489006182F0 /* OFTCPSocket+SOCKS5.m */, 4B6799831099E7C50041064A /* OFThread.h */, 4B6799841099E7C50041064A /* OFThread.m */, + 4B9361A61511000C00DCD16B /* OFThreadPool.h */, + 4B9361A71511000C00DCD16B /* OFThreadPool.m */, 4BA02BA015041F5900002F84 /* OFTLSSocket.h */, 4B4A61F212DF5EA20048F3F2 /* OFURL.h */, 4B4A61F312DF5EA20048F3F2 /* OFURL.m */, 4BF1BCCE11C9663F0025511F /* OFXMLAttribute.h */, 4BF1BCCF11C9663F0025511F /* OFXMLAttribute.m */, @@ -1176,10 +1182,11 @@ 4B3D23DA1337FCB000DD29B8 /* OFString+URLEncoding.h in Headers */, 4B3D23DB1337FCB000DD29B8 /* OFString+XMLEscaping.h in Headers */, 4B3D23DC1337FCB000DD29B8 /* OFString+XMLUnescaping.h in Headers */, 4B3D23DD1337FCB000DD29B8 /* OFTCPSocket.h in Headers */, 4B3D23DE1337FCB000DD29B8 /* OFThread.h in Headers */, + 4B9361A81511000C00DCD16B /* OFThreadPool.h in Headers */, 4BA02BA215041F5900002F84 /* OFTLSSocket.h in Headers */, 4B3D23DF1337FCB000DD29B8 /* OFURL.h in Headers */, 4B3D23E01337FCB000DD29B8 /* OFXMLAttribute.h in Headers */, 4B49EA6D143B3A090005BBC6 /* OFXMLCDATA.h in Headers */, 4B49EA6F143B3A090005BBC6 /* OFXMLCharacters.h in Headers */, @@ -1471,10 +1478,11 @@ 4B3D23AA1337FC0D00DD29B8 /* OFString+XMLUnescaping.m in Sources */, 4B552555147AA5DB0003BF47 /* OFString_UTF8.m in Sources */, 4B3D23AB1337FC0D00DD29B8 /* OFTCPSocket.m in Sources */, 4BD653C6143B8489006182F0 /* OFTCPSocket+SOCKS5.m in Sources */, 4B3D23AC1337FC0D00DD29B8 /* OFThread.m in Sources */, + 4B9361A91511000C00DCD16B /* OFThreadPool.m in Sources */, 4B3D23AD1337FC0D00DD29B8 /* OFURL.m in Sources */, 4B3D23AE1337FC0D00DD29B8 /* OFXMLAttribute.m in Sources */, 4B49EA6E143B3A090005BBC6 /* OFXMLCDATA.m in Sources */, 4B49EA70143B3A090005BBC6 /* OFXMLCharacters.m in Sources */, 4B49EA72143B3A090005BBC6 /* OFXMLComment.m in Sources */, DELETED README Index: README ================================================================== --- README +++ README @@ -1,51 +0,0 @@ -ObjFW is a portable, lightweight framework for the Objective C language. -It enables you to write an application in Objective C that will run on -any platform supported by ObjFW without having to worry about -differences between operating systems or various frameworks that you -would otherwise need if you want to be portable. - -See https://webkeks.org/objfw for more information. - - -INSTALLATION - - To install ObjFW, just run the following commands: - - $ ./configure - $ make - $ make install - - In case you checked out ObjFW from the Mercurial repository, you need - to run the following command first: - - $ ./autogen.sh - - -BUILDING AS A MAC OS X FRAMEWORK - - It is also possible to build ObjFW as a Mac OS X framework. To do so, - just execute xcodebuild -target ObjFW in the root directory of ObjFW or open - the .xcodeproj in Xcode and choose Build -> Build from the menu. Copy the - resulting ObjFW.framework to /Library/Frameworks and you are done. - - -USING THE MAC OS X FRAMEWORK IN XCODE - - To use the Mac OS X framework in Xcode, you need to add the .framework - to your project and add the following flags to "Other C Flags": - - -fconstant-string-class=OFConstantString -fno-constant-cfstrings - - Additionally, since Xcode 4, you need to manually set the compiler to GCC - or LLVM-GCC due to bugs in Clang on OS X with using a different constant - string class. - - Optionally, if you want to use blocks, you also need to add: - - -fblocks - - -BUGS AND FEATURE REQUESTS - - If you find any bugs or have feature requests, feel free to send a - mail to js-spam@webkeks.org (remove -spam from the address!). ADDED README.md Index: README.md ================================================================== --- README.md +++ README.md @@ -0,0 +1,52 @@ +ObjFW is a portable, lightweight framework for the Objective C language. +It enables you to write an application in Objective C that will run on +any platform supported by ObjFW without having to worry about +differences between operating systems or various frameworks that you +would otherwise need if you want to be portable. + +See https://webkeks.org/objfw for more information. + + +Installation +============ + + To install ObjFW, just run the following commands: + + $ ./configure + $ make + $ make install + + In case you checked out ObjFW from the Git repository, you need to run + the following command first: + + $ ./autogen.sh + + +Building as a Mac OS X framework +================================ + + It is also possible to build ObjFW as a Mac OS X framework. To do so, + just execute xcodebuild -target ObjFW in the root directory of ObjFW + or open the .xcodeproj in Xcode and choose Build -> Build from the + menu. Copy the resulting ObjFW.framework to `/Library/Frameworks` and + you are done. + + +Using the Mac OS X framework in Xcode +===================================== + + To use the Mac OS X framework in Xcode, you need to add the .framework + to your project and add the following flags to "Other C Flags": + + -fconstant-string-class=OFConstantString -fno-constant-cfstrings + + Optionally, if you want to use blocks, you also need to add: + + -fblocks + + +Bugs and feature requests +========================= + + If you find any bugs or have feature requests, feel free to send a + mail to js-spam@webkeks.org (remove -spam from the address!). Index: buildsys.mk.in ================================================================== --- buildsys.mk.in +++ buildsys.mk.in @@ -1,10 +1,10 @@ # -# Copyright (c) 2007, 2008, 2009, 2010, 2011 +# Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 # Jonathan Schleifer # -# https://webkeks.org/hg/buildsys/ +# https://webkeks.org/git/?p=buildsys.git # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice is present in all copies. # @@ -19,11 +19,12 @@ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # -PACKAGE = @PACKAGE@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ AS = @AS@ CC = @CC@ CXX = @CXX@ CPP = @CPP@ DC = @DC@ @@ -70,17 +71,17 @@ WINDRES = @WINDRES@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ -plugindir ?= ${libdir}/${PACKAGE} +plugindir ?= ${libdir}/${PACKAGE_NAME} datarootdir = @datarootdir@ datadir = @datadir@ includedir = @includedir@ -includesubdir ?= ${PACKAGE} +includesubdir ?= ${PACKAGE_NAME} localedir = @localedir@ -localename ?= ${PACKAGE} +localename ?= ${PACKAGE_NAME} mandir = @mandir@ mansubdir ?= man1 OBJS1 = ${SRCS:.c=.o} OBJS2 = ${OBJS1:.cc=.o} @@ -146,39 +147,39 @@ sed 's/^\([^\.]*\)\.o:/\1.o \1.lib.o \1.plugin.o:/' >$@ || \ { rm -f $@; false; } pre-depend: -${PROG} ${PROG_NOINST}: ${EXT_DEPS} ${OBJS} +${PROG} ${PROG_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA} ${LINK_STATUS} - if ${LD} -o $@ ${OBJS} ${LDFLAGS} ${LIBS}; then \ + if ${LD} -o $@ ${OBJS} ${OBJS_EXTRA} ${LDFLAGS} ${LIBS}; then \ ${LINK_OK}; \ else \ ${LINK_FAILED}; \ fi -${JARFILE}: ${EXT_DEPS} ${JAR_MANIFEST} ${OBJS} +${JARFILE}: ${EXT_DEPS} ${JAR_MANIFEST} ${OBJS} ${OBJS_EXTRA} ${LINK_STATUS} if test x"${JAR_MANIFEST}" != x""; then \ - if ${JAR} cfm ${JARFILE} ${JAR_MANIFEST} ${OBJS}; then \ + if ${JAR} cfm ${JARFILE} ${JAR_MANIFEST} ${OBJS} ${OBJS_EXTRA}; then \ ${LINK_OK}; \ else \ ${LINK_FAILED}; \ fi \ else \ - if ${JAR} cf ${JARFILE} ${OBJS}; then \ + if ${JAR} cf ${JARFILE} ${OBJS} ${OBJS_EXTRA}; then \ ${LINK_OK}; \ else \ ${LINK_FAILED}; \ fi \ fi -${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} +${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LINK_STATUS}; \ objs=""; \ ars=""; \ - for i in ${LIB_OBJS}; do \ + for i in ${LIB_OBJS} ${LIB_OBJS_EXTRA}; do \ case $$i in \ *.a) \ ars="$$ars $$i" \ ;; \ *.o) \ @@ -240,16 +241,16 @@ for i in $$ars; do \ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \ rm -fr $$dir; \ done -${STATIC_LIB} ${STATIC_LIB_NOINST}: ${EXT_DEPS} ${OBJS} +${STATIC_LIB} ${STATIC_LIB_NOINST}: ${EXT_DEPS} ${OBJS} ${OBJS_EXTRA} ${LINK_STATUS} rm -f $@ objs=""; \ ars=""; \ - for i in ${OBJS}; do \ + for i in ${OBJS} ${OBJS_EXTRA}; do \ case $$i in \ *.a) \ ars="$$ars $$i" \ ;; \ *.o) \ @@ -277,16 +278,16 @@ for i in $$ars; do \ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \ rm -fr $$dir; \ done -${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} +${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LINK_STATUS} rm -f $@ objs=""; \ ars=""; \ - for i in ${LIB_OBJS}; do \ + for i in ${LIB_OBJS} ${LIB_OBJS_EXTRA}; do \ case $$i in \ *.a) \ ars="$$ars $$i" \ ;; \ *.o) \ @@ -540,11 +541,11 @@ fi \ done for i in ${DATA}; do \ ${INSTALL_STATUS}; \ - if ${MKDIR_P} $$(dirname ${DESTDIR}${datadir}/${PACKAGE}/$$i) && ${INSTALL} -m 644 $$i ${DESTDIR}${datadir}/${PACKAGE}/$$i; then \ + if ${MKDIR_P} $$(dirname ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i) && ${INSTALL} -m 644 $$i ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; then \ ${INSTALL_OK}; \ else \ ${INSTALL_FAILED}; \ fi \ done @@ -624,20 +625,20 @@ fi \ done -rmdir ${DESTDIR}${plugindir} >/dev/null 2>&1 for i in ${DATA}; do \ - if test -f ${DESTDIR}${datadir}/${PACKAGE}/$$i; then \ - if rm -f ${DESTDIR}${datadir}/${PACKAGE}/$$i; then \ + if test -f ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; then \ + if rm -f ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i; then \ ${DELETE_OK}; \ else \ ${DELETE_FAILED}; \ fi \ fi; \ - rmdir "$$(dirname ${DESTDIR}${datadir}/${PACKAGE}/$$i)" >/dev/null 2>&1 || true; \ + rmdir "$$(dirname ${DESTDIR}${datadir}/${PACKAGE_NAME}/$$i)" >/dev/null 2>&1 || true; \ done - -rmdir ${DESTDIR}${datadir}/${PACKAGE} >/dev/null 2>&1 + -rmdir ${DESTDIR}${datadir}/${PACKAGE_NAME} >/dev/null 2>&1 for i in ${PROG}; do \ if test -f ${DESTDIR}${bindir}/$$i; then \ if rm -f ${DESTDIR}${bindir}/$$i; then \ ${DELETE_OK}; \ @@ -685,11 +686,11 @@ ${DIR_ENTER}; \ ${MAKE} ${MFLAGS} clean || exit $$?; \ ${DIR_LEAVE}; \ done - for i in ${DEPS} ${OBJS} ${LIB_OBJS} ${PLUGIN_OBJS} ${PROG} ${PROG_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${PLUGIN} ${PLUGIN_NOINST} ${CLEAN_LIB} ${MO_FILES} ${CLEAN}; do \ + for i in ${DEPS} ${OBJS} ${OBJS_EXTRA} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${PLUGIN_OBJS} ${PROG} ${PROG_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${PLUGIN} ${PLUGIN_NOINST} ${CLEAN_LIB} ${MO_FILES} ${CLEAN}; do \ if test -f $$i -o -d $$i; then \ if rm -fr $$i; then \ ${DELETE_OK}; \ else \ ${DELETE_FAILED}; \ Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -648,8 +648,8 @@ dnl and add OBJCPPFLAGS to CPPFLAGS, thus we need to AC_SUBST these ourself. AC_SUBST(CPP) AC_SUBST(CPPFLAGS) AC_SUBST(PACKAGE, ObjFW) -AC_CONFIG_FILES([buildsys.mk extra.mk utils/objfw-config]) +AC_CONFIG_FILES([buildsys.mk extra.mk utils/objfw-config Info.plist]) AC_CONFIG_HEADERS([config.h src/objfw-defs.h]) AC_OUTPUT Index: generators/TableGenerator.m ================================================================== --- generators/TableGenerator.m +++ generators/TableGenerator.m @@ -60,25 +60,25 @@ OFString *line; pool2 = [[OFAutoreleasePool alloc] init]; while ((line = [file readLine])) { OFArray *split; - OFString **splitCArray; + OFString **splitObjects; of_unichar_t codep; split = [line componentsSeparatedByString: @";"]; if ([split count] != 15) { of_log(@"Invalid line: %@\n", line); [OFApplication terminateWithStatus: 1]; } - splitCArray = [split cArray]; + splitObjects = [split objects]; - codep = (of_unichar_t)[splitCArray[0] hexadecimalValue]; + codep = (of_unichar_t)[splitObjects[0] hexadecimalValue]; upperTable[codep] = - (of_unichar_t)[splitCArray[12] hexadecimalValue]; + (of_unichar_t)[splitObjects[12] hexadecimalValue]; lowerTable[codep] = - (of_unichar_t)[splitCArray[13] hexadecimalValue]; + (of_unichar_t)[splitObjects[13] hexadecimalValue]; [pool2 releaseObjects]; } [pool release]; @@ -90,32 +90,32 @@ OFFile *file = [OFFile fileWithPath: path mode: @"rb"]; OFString *line; pool2 = [[OFAutoreleasePool alloc] init]; - while ((line = [file readLine])) { + while ((line = [file readLine]) != nil) { OFArray *split; - OFString **splitCArray; + OFString **splitObjects; of_unichar_t codep; - if ([line characterAtIndex: 0] == '#') + if ([line length] == 0 || [line hasPrefix: @"#"]) continue; split = [line componentsSeparatedByString: @"; "]; if ([split count] != 4) { of_log(@"Invalid line: %s\n", line); [OFApplication terminateWithStatus: 1]; } - splitCArray = [split cArray]; + splitObjects = [split objects]; - if (![splitCArray[1] isEqual: @"S"] && - ![splitCArray[1] isEqual: @"C"]) + if (![splitObjects[1] isEqual: @"S"] && + ![splitObjects[1] isEqual: @"C"]) continue; - codep = (of_unichar_t)[splitCArray[0] hexadecimalValue]; + codep = (of_unichar_t)[splitObjects[0] hexadecimalValue]; casefoldingTable[codep] = - (of_unichar_t)[splitCArray[2] hexadecimalValue]; + (of_unichar_t)[splitObjects[2] hexadecimalValue]; [pool2 releaseObjects]; } [pool release]; Index: m4/buildsys.m4 ================================================================== --- m4/buildsys.m4 +++ m4/buildsys.m4 @@ -1,9 +1,10 @@ dnl -dnl Copyright (c) 2007 - 2009, Jonathan Schleifer +dnl Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 +dnl Jonathan Schleifer dnl -dnl https://webkeks.org/hg/buildsys/ +dnl https://webkeks.org/git/?p=buildsys.git dnl dnl Permission to use, copy, modify, and/or distribute this software for any dnl purpose with or without fee is hereby granted, provided that the above dnl copyright notice and this permission notice is present in all copies. dnl @@ -98,12 +99,12 @@ LIB_PREFIX='lib' LIB_SUFFIX='.dylib' LDFLAGS_RPATH='-Wl,-rpath,${libdir}' PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-bundle -undefined dynamic_lookup' - PLUGIN_SUFFIX='.impl' - INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$$i' + PLUGIN_SUFFIX='.bundle' + INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && install_name_tool -id ${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib' CLEAN_LIB='' ;; solaris*) AC_MSG_RESULT(Solaris) Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -48,10 +48,11 @@ OFString+URLEncoding.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ OFTCPSocket.m \ ${OFTHREAD_M} \ + OFThreadPool.m \ OFURL.m \ OFXMLAttribute.m \ OFXMLCDATA.m \ OFXMLCharacters.m \ OFXMLComment.m \ @@ -97,13 +98,13 @@ iso_8859_15.m \ windows_1252.m \ ${OBJC_PROPERTIES_M} \ ${OBJC_SYNC_M} +OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A} ${RUNTIME_RUNTIME_A} +LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A} ${RUNTIME_RUNTIME_LIB_A} + include ../buildsys.mk CPPFLAGS += -I. -I.. -Iexceptions -Iruntime LD = ${OBJC} LDFLAGS += ${REEXPORT_LIBOBJC} ${MACH_ALIAS_LIST} - -LIB_OBJS := ${LIB_OBJS} ${EXCEPTIONS_EXCEPTIONS_LIB_A} ${RUNTIME_RUNTIME_LIB_A} -OBJS += ${EXCEPTIONS_EXCEPTIONS_A} ${RUNTIME_RUNTIME_A} Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -77,28 +77,20 @@ * \param array An array * \return A new autoreleased OFArray */ + arrayWithArray: (OFArray*)array; -/** - * \brief Creates a new OFArray with the objects from the specified C array. - * - * \param objects A C array of objects, terminated with nil - * \return A new autoreleased OFArray - */ -+ arrayWithCArray: (id*)objects; - /** * \brief Creates a new OFArray with the objects from the specified C array of * the specified length. * * \param objects A C array of objects * \param length The length of the C array * \return A new autoreleased OFArray */ -+ arrayWithCArray: (id*)objects - length: (size_t)length; ++ arrayWithObjects: (id*)objects + count: (size_t)count; /** * \brief Initializes an OFArray with the specified object. * * \param object An object @@ -130,28 +122,20 @@ * \param array An array * \return An initialized OFArray */ - initWithArray: (OFArray*)array; -/** - * \brief Initializes an OFArray with the objects from the specified C array. - * - * \param objects A C array of objects, terminated with nil - * \return An initialized OFArray - */ -- initWithCArray: (id*)objects; - /** * \brief Initializes an OFArray with the objects from the specified C array of * the specified length. * * \param objects A C array of objects * \param length The length of the C array * \return An initialized OFArray */ -- initWithCArray: (id*)objects - length: (size_t)length; +- initWithObjects: (id*)objects + count: (size_t)count; /** * \brief Returns a specified object of the array. * * The returned object is not retained and autoreleased for performance @@ -159,10 +143,11 @@ * * \param index The number of the object to return * \return The specified object of the OFArray */ - (id)objectAtIndex: (size_t)index; +- (id)objectAtIndexedSubscript: (size_t)index; /** * \brief Copies the objects at the specified range to the specified buffer. * * \param buffer The buffer to copy the objects to @@ -174,11 +159,11 @@ /** * \brief Returns the objects of the array as a C array. * * \return The objects of the array as a C array */ -- (id*)cArray; +- (id*)objects; /** * \brief Returns the index of the first object that is equivalent to the * specified object or OF_INVALID_INDEX if it was not found. * @@ -345,5 +330,10 @@ - initWithArray: (OFArray*)data mutationsPtr: (unsigned long*)mutationsPtr; @end #import "OFMutableArray.h" + +#ifndef NSINTEGER_DEFINED +/* Required for array literals to work */ +@compatibility_alias NSArray OFArray; +#endif Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -73,20 +73,15 @@ - initWithArray: (OFArray*)array { return (id)[[OFArray_adjacent alloc] initWithArray: array]; } -- initWithCArray: (id*)objects -{ - return (id)[[OFArray_adjacent alloc] initWithCArray: objects]; -} - -- initWithCArray: (id*)objects - length: (size_t)length -{ - return (id)[[OFArray_adjacent alloc] initWithCArray: objects - length: length]; +- initWithObjects: (id*)objects + count: (size_t)count +{ + return (id)[[OFArray_adjacent alloc] initWithObjects: objects + count: count]; } - initWithSerialization: (OFXMLElement*)element { return (id)[[OFArray_adjacent alloc] initWithSerialization: element]; @@ -155,20 +150,15 @@ + arrayWithArray: (OFArray*)array { return [[[self alloc] initWithArray: array] autorelease]; } -+ arrayWithCArray: (id*)objects -{ - return [[[self alloc] initWithCArray: objects] autorelease]; -} - -+ arrayWithCArray: (id*)objects - length: (size_t)length -{ - return [[[self alloc] initWithCArray: objects - length: length] autorelease]; ++ arrayWithObjects: (id*)objects + count: (size_t)count +{ + return [[[self alloc] initWithObjects: objects + count: count] autorelease]; } - init { if (isa == [OFArray class]) { @@ -214,20 +204,12 @@ [self release]; @throw [OFNotImplementedException exceptionWithClass: c selector: _cmd]; } -- initWithCArray: (id*)objects -{ - Class c = isa; - [self release]; - @throw [OFNotImplementedException exceptionWithClass: c - selector: _cmd]; -} - -- initWithCArray: (id*)objects - length: (size_t)length +- initWithObjects: (id*)objects + count: (size_t)count { Class c = isa; [self release]; @throw [OFNotImplementedException exceptionWithClass: c selector: _cmd]; @@ -254,11 +236,11 @@ for (i = 0; i < range.length; i++) buffer[i] = [self objectAtIndex: range.start + i]; } -- (id*)cArray +- (id*)objects { OFObject *container; size_t count; id *buffer; @@ -286,10 +268,15 @@ - (id)objectAtIndex: (size_t)index { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } + +- (id)objectAtIndexedSubscript: (size_t)index +{ + return [self objectAtIndex: index]; +} - (size_t)indexOfObject: (id)object { size_t i, count = [self count]; @@ -353,12 +340,12 @@ @try { [self getObjects: buffer inRange: range]; - ret = [OFArray arrayWithCArray: buffer - length: range.length]; + ret = [OFArray arrayWithObjects: buffer + count: range.length]; } @finally { [self freeMemory: buffer]; } return ret; @@ -373,11 +360,11 @@ - (OFString*)componentsJoinedByString: (OFString*)separator usingSelector: (SEL)selector { OFAutoreleasePool *pool, *pool2; OFMutableString *ret; - id *cArray; + id *objects; size_t i, count = [self count]; IMP append; if (count == 0) return @""; @@ -386,23 +373,23 @@ ret = [OFMutableString string]; append = [ret methodForSelector: @selector(appendString:)]; pool = [[OFAutoreleasePool alloc] init]; - cArray = [self cArray]; + objects = [self objects]; pool2 = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count - 1; i++) { append(ret, @selector(appendString:), - [cArray[i] performSelector: selector]); + [objects[i] performSelector: selector]); append(ret, @selector(appendString:), separator); [pool2 releaseObjects]; } append(ret, @selector(appendString:), - [cArray[i] performSelector: selector]); + [objects[i] performSelector: selector]); [ret makeImmutable]; [pool release]; @@ -433,18 +420,18 @@ return YES; } - (uint32_t)hash { - id *cArray = [self cArray]; + id *objects = [self objects]; size_t i, count = [self count]; uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < count; i++) { - uint32_t h = [cArray[i] hash]; + uint32_t h = [objects[i] hash]; OF_HASH_ADD(hash, h >> 24); OF_HASH_ADD(hash, (h >> 16) & 0xFF); OF_HASH_ADD(hash, (h >> 8) & 0xFF); OF_HASH_ADD(hash, h & 0xFF); @@ -487,11 +474,11 @@ - (OFXMLElement*)XMLElementBySerializing { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFAutoreleasePool *pool2; OFXMLElement *element; - id *cArray = [self cArray]; + id *objects = [self objects]; size_t i, count = [self count]; if ([self isKindOfClass: [OFMutableArray class]]) element = [OFXMLElement elementWithName: @"OFMutableArray" namespace: OF_SERIALIZATION_NS]; @@ -500,11 +487,11 @@ namespace: OF_SERIALIZATION_NS]; pool2 = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count; i++) { - [element addChild: [cArray[i] XMLElementBySerializing]]; + [element addChild: [objects[i] XMLElementBySerializing]]; [pool2 releaseObjects]; } [element retain]; @@ -533,27 +520,27 @@ return JSON; } - (void)makeObjectsPerformSelector: (SEL)selector { - id *cArray = [self cArray]; + id *objects = [self objects]; size_t i, count = [self count]; for (i = 0; i < count; i++) - ((void(*)(id, SEL))[cArray[i] - methodForSelector: selector])(cArray[i], selector); + ((void(*)(id, SEL))[objects[i] + methodForSelector: selector])(objects[i], selector); } - (void)makeObjectsPerformSelector: (SEL)selector withObject: (id)object { - id *cArray = [self cArray]; + id *objects = [self objects]; size_t i, count = [self count]; for (i = 0; i < count; i++) - ((void(*)(id, SEL, id))[cArray[i] - methodForSelector: selector])(cArray[i], selector, object); + ((void(*)(id, SEL, id))[objects[i] + methodForSelector: selector])(objects[i], selector, object); } - (OFArray*)sortedArray { OFMutableArray *new = [[self mutableCopy] autorelease]; @@ -588,11 +575,11 @@ if (state->state >= count) return 0; state->state = count; - state->itemsPtr = [self cArray]; + state->itemsPtr = [self objects]; state->mutationsPtr = (unsigned long*)self; return (int)count; } @@ -629,12 +616,12 @@ [self enumerateObjectsUsingBlock: ^ (id object, size_t index, BOOL *stop) { tmp[index] = block(object, index); }]; - ret = [OFArray arrayWithCArray: tmp - length: count]; + ret = [OFArray arrayWithObjects: tmp + count: count]; } @finally { [self freeMemory: tmp]; } return ret; @@ -654,12 +641,12 @@ BOOL *stop) { if (block(object, index)) tmp[i++] = object; }]; - ret = [OFArray arrayWithCArray: tmp - length: i]; + ret = [OFArray arrayWithObjects: tmp + count: i]; } @finally { [self freeMemory: tmp]; } return ret; Index: src/OFArray_adjacent.m ================================================================== --- src/OFArray_adjacent.m +++ src/OFArray_adjacent.m @@ -85,32 +85,32 @@ return self; } - initWithArray: (OFArray*)array_ { - id *cArray; + id *objects; size_t i, count; self = [self init]; @try { - cArray = [array_ cArray]; + objects = [array_ objects]; count = [array_ count]; } @catch (id e) { [self release]; @throw e; } @try { for (i = 0; i < count; i++) - [cArray[i] retain]; + [objects[i] retain]; [array addNItems: count - fromCArray: cArray]; + fromCArray: objects]; } @catch (id e) { for (i = 0; i < count; i++) - [cArray[i] release]; + [objects[i] release]; /* Prevent double-release of objects */ [array release]; array = nil; @@ -119,55 +119,27 @@ } return self; } -- initWithCArray: (id*)objects -{ - self = [self init]; - - @try { - id *object; - size_t count = 0; - - for (object = objects; *object != nil; object++) { - [*object retain]; - count++; - } - - [array addNItems: count - fromCArray: objects]; - } @catch (id e) { - id *object; - - for (object = objects; *object != nil; object++) - [*object release]; - - [self release]; - @throw e; - } - - return self; -} - -- initWithCArray: (id*)objects - length: (size_t)length +- initWithObjects: (id*)objects + count: (size_t)count { self = [self init]; @try { size_t i; - for (i = 0; i < length; i++) + for (i = 0; i < count; i++) [objects[i] retain]; - [array addNItems: length + [array addNItems: count fromCArray: objects]; } @catch (id e) { size_t i; - for (i = 0; i < length; i++) + for (i = 0; i < count; i++) [objects[i] release]; [self release]; @throw e; } @@ -217,52 +189,57 @@ - (size_t)count { return [array count]; } -- (id*)cArray +- (id*)objects { return [array cArray]; } - (id)objectAtIndex: (size_t)index { return *((id*)[array itemAtIndex: index]); } + +- (id)objectAtIndexedSubscript: (size_t)index +{ + return *((id*)[array itemAtIndex: index]); +} - (void)getObjects: (id*)buffer inRange: (of_range_t)range { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; if (range.start + range.length > count) @throw [OFOutOfRangeException exceptionWithClass: isa]; for (i = 0; i < range.length; i++) - buffer[i] = cArray[range.start + i]; + buffer[i] = objects[range.start + i]; } - (size_t)indexOfObject: (id)object { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) - if ([cArray[i] isEqual: object]) + if ([objects[i] isEqual: object]) return i; return OF_INVALID_INDEX; } - (size_t)indexOfObjectIdenticalTo: (id)object { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) - if (cArray[i] == object) + if (objects[i] == object) return i; return OF_INVALID_INDEX; } @@ -278,18 +255,18 @@ count = [array count]; if (range.start + range.length > count) @throw [OFOutOfRangeException exceptionWithClass: isa]; - return [OFArray arrayWithCArray: (id*)[array cArray] + range.start - length: range.length]; + return [OFArray arrayWithObjects: (id*)[array cArray] + range.start + count: range.length]; } - (BOOL)isEqual: (id)object { OFArray *otherArray; - id *cArray, *otherCArray; + id *objects, *otherObjects; size_t i, count; if ([object class] != [OFArray_adjacent class] && [object class] != [OFMutableArray_adjacent class] && [object class] != [OFArray_adjacentSubarray class]) @@ -300,30 +277,30 @@ count = [array count]; if (count != [otherArray count]) return NO; - cArray = [array cArray]; - otherCArray = [otherArray cArray]; + objects = [array cArray]; + otherObjects = [otherArray objects]; for (i = 0; i < count; i++) - if (![cArray[i] isEqual: otherCArray[i]]) + if (![objects[i] isEqual: otherObjects[i]]) return NO; return YES; } - (uint32_t)hash { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; uint32_t hash; OF_HASH_INIT(hash); for (i = 0; i < count; i++) { - uint32_t h = [cArray[i] hash]; + uint32_t h = [objects[i] hash]; OF_HASH_ADD(hash, h >> 24); OF_HASH_ADD(hash, (h >> 16) & 0xFF); OF_HASH_ADD(hash, (h >> 8) & 0xFF); OF_HASH_ADD(hash, h & 0xFF); @@ -335,27 +312,27 @@ } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; BOOL stop = NO; for (i = 0; i < count && !stop; i++) - block(cArray[i], i, &stop); + block(objects[i], i, &stop); } #endif - (void)dealloc { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) - [cArray[i] release]; + [objects[i] release]; [array release]; [super dealloc]; } @end Index: src/OFArray_adjacentSubarray.m ================================================================== --- src/OFArray_adjacentSubarray.m +++ src/OFArray_adjacentSubarray.m @@ -19,19 +19,19 @@ #import "OFArray_adjacentSubarray.h" #import "OFArray_adjacent.h" #import "OFMutableArray_adjacent.h" @implementation OFArray_adjacentSubarray -- (id*)cArray +- (id*)objects { - return [array cArray] + range.start; + return [array objects] + range.start; } - (BOOL)isEqual: (id)object { OFArray *otherArray; - id *cArray, *otherCArray; + id *objects, *otherObjects; size_t i; if ([object class] != [OFArray_adjacent class] && [object class] != [OFMutableArray_adjacent class] && [object class] != [OFArray_adjacentSubarray class]) @@ -40,27 +40,27 @@ otherArray = object; if (range.length != [otherArray count]) return NO; - cArray = [self cArray]; - otherCArray = [otherArray cArray]; + objects = [self objects]; + otherObjects = [otherArray objects]; for (i = 0; i < range.length; i++) - if (![cArray[i] isEqual: otherCArray[i]]) + if (![objects[i] isEqual: otherObjects[i]]) return NO; return YES; } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { - id *cArray = [self cArray]; + id *objects = [self objects]; size_t i; BOOL stop = NO; for (i = 0; i < range.length && !stop; i++) - block(cArray[i], i, &stop); + block(objects[i], i, &stop); } #endif @end Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -374,16 +374,10 @@ selector: _cmd]; } - init { - @throw [OFNotImplementedException exceptionWithClass: isa - selector: _cmd]; -} - -- (void)addMemoryToPool: (void*)ptr -{ @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } - (void*)allocMemoryWithSize: (size_t)size Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -53,15 +53,10 @@ { @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; } -- (void)addMemoryToPool: (void*)ptr -{ - @throw [OFNotImplementedException exceptionWithClass: isa - selector: _cmd]; -} - (void*)allocMemoryWithSize: (size_t)size { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; @@ -179,16 +174,10 @@ { @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; } -- (void)addMemoryToPool: (void*)ptr -{ - @throw [OFNotImplementedException exceptionWithClass: isa - selector: _cmd]; -} - - (void*)allocMemoryWithSize: (size_t)size { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } Index: src/OFCountedSet_hashtable.m ================================================================== --- src/OFCountedSet_hashtable.m +++ src/OFCountedSet_hashtable.m @@ -79,15 +79,15 @@ - initWithArray: (OFArray*)array { self = [self init]; @try { - id *cArray = [array cArray]; + id *objects = [array objects]; size_t i, count = [array count]; for (i = 0; i < count; i++) - [self addObject: cArray[i]]; + [self addObject: objects[i]]; } @catch (id e) { [self release]; @throw e; } Index: src/OFDataArray.m ================================================================== --- src/OFDataArray.m +++ src/OFDataArray.m @@ -538,12 +538,11 @@ lastPageByte = of_pagesize - 1; newSize = ((count + nItems) * itemSize + lastPageByte) & ~lastPageByte; if (size != newSize) data = [self resizeMemory: data - toNItems: newSize - ofSize: itemSize]; + toSize: newSize]; memmove(data + (index + nItems) * itemSize, data + index * itemSize, (count - index) * itemSize); memcpy(data + index * itemSize, cArray, nItems * itemSize); Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -81,10 +81,22 @@ * \return A new autoreleased OFDictionary */ + dictionaryWithObjects: (OFArray*)objects forKeys: (OFArray*)keys; +/** + * \brief Creates a new OFDictionary with the specified keys and objects. + * + * \param keys An array of keys + * \param objects An array of objects + * \param count The number of objects in the arrays + * \return A new autoreleased OFDictionary + */ ++ dictionaryWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count; + /** * \brief Creates a new OFDictionary with the specified keys objects. * * \param firstKey The first key * \return A new autoreleased OFDictionary @@ -130,10 +142,23 @@ forKeys: (OFArray*)keys; /** * \brief Initializes an already allocated OFDictionary with the specified keys * and objects. + * + * \param keys An array of keys + * \param objects An array of objects + * \param count The number of objects in the arrays + * \return A new initialized OFDictionary + */ +- initWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count; + +/** + * \brief Initializes an already allocated OFDictionary with the specified keys + * and objects. * * \param firstKey The first key * \return A new initialized OFDictionary */ - initWithKeysAndObjects: (id)firstKey, ...; @@ -157,10 +182,11 @@ * * \param key The key whose object should be returned * \return The object for the given key or nil if the key was not found */ - (id)objectForKey: (id)key; +- (id)objectForKeyedSubscript: (id)key; /** * \brief Checks whether the dictionary contains an object with the specified * address. * @@ -226,5 +252,10 @@ copyKeys: (BOOL)copyKeys; #endif @end #import "OFMutableDictionary.h" + +#ifndef NSINTEGER_DEFINED +/* Required for dictionary literals to work */ +@compatibility_alias NSDictionary OFDictionary; +#endif Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -57,10 +57,19 @@ forKeys: (OFArray*)keys { return (id)[[OFDictionary_hashtable alloc] initWithObjects: objects forKeys: keys]; } + +- initWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count +{ + return (id)[[OFDictionary_hashtable alloc] initWithObjects: objects + forKeys: keys + count: count]; +} - initWithKeysAndObjects: (id )firstKey, ... { id ret; va_list arguments; @@ -144,10 +153,19 @@ forKeys: (OFArray*)keys { return [[[self alloc] initWithObjects: objects forKeys: keys] autorelease]; } + ++ dictionaryWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count +{ + return [[[self alloc] initWithObjects: objects + forKeys: keys + count: count] autorelease]; +} + dictionaryWithKeysAndObjects: (id)firstKey, ... { id ret; va_list arguments; @@ -192,10 +210,20 @@ Class c = isa; [self release]; @throw [OFNotImplementedException exceptionWithClass: c selector: _cmd]; } + +- initWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; +} - initWithKeysAndObjects: (id)firstKey, ... { id ret; va_list arguments; @@ -228,10 +256,15 @@ - (id)objectForKey: (id)key { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } + +- (id)objectForKeyedSubscript: (id)key +{ + return [self objectForKey: key]; +} - (size_t)count { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; @@ -245,24 +278,30 @@ - mutableCopy { return [[OFMutableDictionary alloc] initWithDictionary: self]; } -- (BOOL)isEqual: (id)dictionary +- (BOOL)isEqual: (id)object { + OFDictionary *otherDictionary; OFAutoreleasePool *pool; OFEnumerator *enumerator; id key; - if ([dictionary count] != [self count]) + if (![object isKindOfClass: [OFDictionary class]]) + return NO; + + otherDictionary = object; + + if ([otherDictionary count] != [self count]) return NO; pool = [[OFAutoreleasePool alloc] init]; enumerator = [self keyEnumerator]; while ((key = [enumerator nextObject]) != nil) { - id object = [dictionary objectForKey: key]; + id object = [otherDictionary objectForKey: key]; if (object == nil || ![object isEqual: [self objectForKey: key]]) { [pool release]; return NO; @@ -311,62 +350,62 @@ } - (OFArray*)allKeys { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - id *cArray = [self allocMemoryForNItems: [self count] - ofSize: sizeof(id)]; + id *keys = [self allocMemoryForNItems: [self count] + ofSize: sizeof(id)]; OFArray *ret; OFEnumerator *enumerator; id key; size_t i = 0; pool = [[OFAutoreleasePool alloc] init]; enumerator = [self keyEnumerator]; while ((key = [enumerator nextObject]) != nil) - cArray[i++] = key; + keys[i++] = key; assert(i == [self count]); [pool release]; @try { - ret = [OFArray arrayWithCArray: cArray - length: [self count]]; + ret = [OFArray arrayWithObjects: keys + count: [self count]]; } @finally { - [self freeMemory: cArray]; + [self freeMemory: keys]; } return ret; } - (OFArray*)allObjects { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - id *cArray = [self allocMemoryForNItems: [self count] - ofSize: sizeof(id)]; + id *objects = [self allocMemoryForNItems: [self count] + ofSize: sizeof(id)]; OFArray *ret; OFEnumerator *enumerator; id object; size_t i = 0; pool = [[OFAutoreleasePool alloc] init]; enumerator = [self objectEnumerator]; while ((object = [enumerator nextObject]) != nil) - cArray[i++] = object; + objects[i++] = object; assert(i == [self count]); [pool release]; @try { - ret = [OFArray arrayWithCArray: cArray - length: [self count]]; + ret = [OFArray arrayWithObjects: objects + count: [self count]]; } @finally { - [self freeMemory: cArray]; + [self freeMemory: objects]; } return ret; } Index: src/OFDictionary_hashtable.m ================================================================== --- src/OFDictionary_hashtable.m +++ src/OFDictionary_hashtable.m @@ -233,19 +233,38 @@ } - initWithObjects: (OFArray*)objects forKeys: (OFArray*)keys { + id ret; + + @try { + if ([objects count] != [keys count]) + @throw [OFInvalidArgumentException + exceptionWithClass: isa]; + + ret = [self initWithObjects: [objects objects] + forKeys: [keys objects] + count: [objects count]]; + } @catch (id e) { + [self release]; + @throw e; + } + + return ret; +} + +- initWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count_ +{ self = [super init]; @try { - id *objectsCArray, *keysCArray; uint32_t i, j, newSize; - keysCArray = [keys cArray]; - objectsCArray = [objects cArray]; - count = [keys count]; + count = count_; if (count > UINT32_MAX) @throw [OFOutOfRangeException exceptionWithClass: isa]; for (newSize = 1; newSize < count; newSize <<= 1); @@ -264,31 +283,30 @@ size = newSize; for (i = 0; i < count; i++) { uint32_t hash, last; - hash = [keysCArray[i] hash]; + hash = [keys[i] hash]; last = size; for (j = hash & (size - 1); j < last && data[j] != NULL; j++) - if ([data[j]->key isEqual: keysCArray[i]]) + if ([data[j]->key isEqual: keys[i]]) break; /* In case the last bucket is already used */ if (j >= last) { last = hash & (size - 1); for (j = 0; j < last && data[j] != NULL; j++) - if ([data[j]->key - isEqual: keysCArray[i]]) + if ([data[j]->key isEqual: keys[i]]) break; } /* Key not in dictionary */ if (j >= last || data[j] == NULL || - ![data[j]->key isEqual: keysCArray[i]]) { + ![data[j]->key isEqual: keys[i]]) { struct of_dictionary_hashtable_bucket *bucket; id key; last = size; @@ -307,14 +325,14 @@ @throw [OFOutOfRangeException exceptionWithClass: isa]; bucket = [self allocMemoryWithSize: sizeof(*bucket)]; - key = [keysCArray[i] copy]; + key = [keys[i] copy]; bucket->key = key; - bucket->object = [objectsCArray[i] retain]; + bucket->object = [objects[i] retain]; bucket->hash = hash; data[j] = bucket; continue; @@ -324,13 +342,13 @@ * The key is already in the dictionary. However, we * just replace it so that the programmer gets the same * behavior as if he'd call setObject:forKey: for each * key/object pair. */ - [objectsCArray[i] retain]; + [objects[i] retain]; [data[j]->object release]; - data[j]->object = objectsCArray[i]; + data[j]->object = objects[i]; } } @catch (id e) { [self release]; @throw e; } @@ -628,48 +646,48 @@ } - (OFArray*)allKeys { OFArray *ret; - id *cArray = [self allocMemoryForNItems: count - ofSize: sizeof(id)]; + id *keys = [self allocMemoryForNItems: count + ofSize: sizeof(id)]; size_t i, j; for (i = j = 0; i < size; i++) if (data[i] != NULL && data[i] != DELETED) - cArray[j++] = data[i]->key; + keys[j++] = data[i]->key; assert(j == count); @try { - ret = [OFArray arrayWithCArray: cArray - length: count]; + ret = [OFArray arrayWithObjects: keys + count: count]; } @finally { - [self freeMemory: cArray]; + [self freeMemory: keys]; } return ret; } - (OFArray*)allObjects { OFArray *ret; - id *cArray = [self allocMemoryForNItems: count - ofSize: sizeof(id)]; + id *objects = [self allocMemoryForNItems: count + ofSize: sizeof(id)]; size_t i, j; for (i = j = 0; i < size; i++) if (data[i] != NULL && data[i] != DELETED) - cArray[j++] = data[i]->object; + objects[j++] = data[i]->object; assert(j == count); @try { - ret = [OFArray arrayWithCArray: cArray - length: count]; + ret = [OFArray arrayWithObjects: objects + count: count]; } @finally { - [self freeMemory: cArray]; + [self freeMemory: objects]; } return ret; } Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -93,10 +93,19 @@ * * \param path The path of the directory */ + (void)createDirectoryAtPath: (OFString*)path; +/** + * \brief Creates a directory at the specified path. + * + * \param path The path of the directory + * \param createParents Whether to create the parents of the directory + */ ++ (void)createDirectoryAtPath: (OFString*)path + createParents: (BOOL)createParents; + /** * \brief Returns an array with the files in the specified directory. * * \param path The path of the directory * \return An array of OFStrings with the files at the specified path @@ -108,10 +117,17 @@ * * \param path The new directory to change to */ + (void)changeToDirectory: (OFString*)path; +/** + * \brief Returns the size of the specified file. + * + * \return The size of the specified file + */ ++ (off_t)sizeOfFile: (OFString*)path; + /** * \brief Returns the date of the last modification of the file. * * \return The date of the last modification of the file */ Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -246,10 +246,47 @@ #endif @throw [OFCreateDirectoryFailedException exceptionWithClass: self path: path]; } + ++ (void)createDirectoryAtPath: (OFString*)path + createParents: (BOOL)createParents +{ + OFAutoreleasePool *pool, *pool2; + OFArray *pathComponents; + OFString *currentPath = nil, *component; + OFEnumerator *enumerator; + + if (!createParents) { + [OFFile createDirectoryAtPath: path]; + return; + } + + pool = [[OFAutoreleasePool alloc] init]; + + pathComponents = [path pathComponents]; + enumerator = [pathComponents objectEnumerator]; + pool2 = [[OFAutoreleasePool alloc] init]; + while ((component = [enumerator nextObject]) != nil) { + if (currentPath != nil) + currentPath = [OFString + stringWithPath: currentPath, component, nil]; + else + currentPath = component; + + if (![currentPath isEqual: @""] && + ![OFFile directoryExistsAtPath: currentPath]) + [OFFile createDirectoryAtPath: currentPath]; + + [currentPath retain]; + [pool2 releaseObjects]; + [currentPath autorelease]; + } + + [pool release]; +} + (OFArray*)filesInDirectoryAtPath: (OFString*)path { OFAutoreleasePool *pool; OFMutableArray *files = [OFMutableArray array]; @@ -370,10 +407,24 @@ path: path mode: mode]; # endif } #endif + ++ (off_t)sizeOfFile: (OFString*)path +{ + struct stat s; + + if (stat([path cStringWithEncoding: OF_STRING_ENCODING_NATIVE], + &s) == -1) + /* FIXME: Maybe use another exception? */ + @throw [OFOpenFileFailedException exceptionWithClass: self + path: path + mode: @"r"]; + + return s.st_size; +} + (OFDate*)modificationDateOfFile: (OFString*)path { struct stat s; Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -28,10 +28,12 @@ #import "OFDictionary.h" #import "OFDataArray.h" #import "OFAutoreleasePool.h" #import "OFHTTPRequestFailedException.h" +#import "OFInvalidEncodingException.h" +#import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" @@ -38,11 +40,11 @@ #import "macros.h" Class of_http_request_tls_socket_class = Nil; static OF_INLINE void -normalize_key(OFString *key) +normalizeKey(OFString *key) { uint8_t *str = (uint8_t*)[key UTF8String]; BOOL firstLetter = YES; while (*str != '\0') { @@ -73,14 +75,14 @@ - init { self = [super init]; requestType = OF_HTTP_REQUEST_TYPE_GET; - headers = [[OFDictionary alloc] - initWithObject: @"Something using ObjFW " - @"" - forKey: @"User-Agent"]; + headers = [[OFDictionary alloc] initWithKeysAndObjects: + @"Connection", @"close", + @"User-Agent", @"Something using ObjFW " + @"", nil]; storesData = YES; return self; } @@ -107,11 +109,11 @@ [super dealloc]; } - (void)setURL: (OFURL*)URL_ { - OF_SETTER(URL, URL_, YES, YES) + OF_SETTER(URL, URL_, YES, 1) } - (OFURL*)URL { OF_GETTER(URL, YES) @@ -127,21 +129,21 @@ return requestType; } - (void)setQueryString: (OFString*)queryString_ { - OF_SETTER(queryString, queryString_, YES, YES) + OF_SETTER(queryString, queryString_, YES, 1) } - (OFString*)queryString { OF_GETTER(queryString, YES) } - (void)setHeaders: (OFDictionary*)headers_ { - OF_SETTER(headers, headers_, YES, YES) + OF_SETTER(headers, headers_, YES, 1) } - (OFDictionary*)headers { OF_GETTER(headers, YES) @@ -193,10 +195,12 @@ OFDataArray *data; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object, *contentLengthHeader; int status; const char *type = NULL; + size_t contentLength = 0; + BOOL chunked; char *buffer; size_t bytesReceived; if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"]) @throw [OFUnsupportedProtocolException exceptionWithClass: isa @@ -235,14 +239,14 @@ if ([(path = [URL path]) isEqual: @""]) path = @"/"; if ([URL query] != nil) - [sock writeFormat: @"%s %@?%@ HTTP/1.0\r\n", + [sock writeFormat: @"%s %@?%@ HTTP/1.1\r\n", type, path, [URL query]]; else - [sock writeFormat: @"%s %@ HTTP/1.0\r\n", type, path]; + [sock writeFormat: @"%s %@ HTTP/1.1\r\n", type, path]; if ([URL port] == 80) [sock writeFormat: @"Host: %@\r\n", [URL host]]; else [sock writeFormat: @"Host: %@:%d\r\n", [URL host], @@ -273,45 +277,60 @@ [sock setBuffersWrites: NO]; if (requestType == OF_HTTP_REQUEST_TYPE_POST) [sock writeString: queryString]; - /* - * We also need to check for HTTP/1.1 since Apache always declares the - * reply to be HTTP/1.1. - */ - line = [sock readLine]; + @try { + line = [sock readLine]; + } @catch (OFInvalidEncodingException *e) { + @throw [OFInvalidServerReplyException exceptionWithClass: isa]; + } + if (![line hasPrefix: @"HTTP/1.0 "] && ![line hasPrefix: @"HTTP/1.1 "]) @throw [OFInvalidServerReplyException exceptionWithClass: isa]; status = (int)[[line substringWithRange: of_range(9, 3)] decimalValue]; serverHeaders = [OFMutableDictionary dictionary]; - while ((line = [sock readLine]) != nil) { + for (;;) { OFString *key, *value; - const char *line_c = [line UTF8String], *tmp; + const char *line_c, *tmp; + + @try { + line = [sock readLine]; + } @catch (OFInvalidEncodingException *e) { + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + } + + if (line == nil) + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; if ([line isEqual: @""]) break; + + line_c = [line UTF8String]; if ((tmp = strchr(line_c, ':')) == NULL) @throw [OFInvalidServerReplyException exceptionWithClass: isa]; key = [OFString stringWithUTF8String: line_c length: tmp - line_c]; - normalize_key(key); + normalizeKey(key); do { tmp++; } while (*tmp == ' '); value = [OFString stringWithUTF8String: tmp]; if ((redirects > 0 && (status == 301 || status == 302 || - status == 303) && [key isEqual: @"Location"]) && + status == 303 || status == 307) && + [key isEqual: @"Location"]) && (redirectsFromHTTPSToHTTPAllowed || [scheme isEqual: @"http"] || ![value hasPrefix: @"http://"])) { OFURL *new; BOOL follow; @@ -350,59 +369,147 @@ [delegate request: self didReceiveHeaders: serverHeaders withStatusCode: status]; data = (storesData ? [OFDataArray dataArray] : nil); + chunked = [[serverHeaders objectForKey: @"Transfer-Encoding"] + isEqual: @"chunked"]; + + contentLengthHeader = [serverHeaders objectForKey: @"Content-Length"]; + + if (contentLengthHeader != nil) { + contentLength = (size_t)[contentLengthHeader decimalValue]; + + if (contentLength > SIZE_MAX) + @throw [OFOutOfRangeException exceptionWithClass: isa]; + } buffer = [self allocMemoryWithSize: of_pagesize]; bytesReceived = 0; @try { - size_t len; - - while ((len = [sock readNBytes: of_pagesize - intoBuffer: buffer]) > 0) { - [delegate request: self - didReceiveData: buffer - withLength: len]; - - bytesReceived += len; - [data addNItems: len - fromCArray: buffer]; - } + OFAutoreleasePool *pool2 = [[OFAutoreleasePool alloc] init]; + + if (chunked) { + for (;;) { + size_t pos, toRead; + + @try { + line = [sock readLine]; + } @catch (OFInvalidEncodingException *e) { + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + } + + pos = [line + indexOfFirstOccurrenceOfString: @";"]; + if (pos != OF_INVALID_INDEX) + line = [line substringWithRange: + of_range(0, pos)]; + + @try { + toRead = + (size_t)[line hexadecimalValue]; + } @catch (OFInvalidFormatException *e) { + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + } + + if (toRead == 0 || + (contentLengthHeader != nil && + contentLength >= bytesReceived)) + break; + + while (toRead > 0) { + size_t length = (toRead < of_pagesize + ? toRead : of_pagesize); + + length = [sock readNBytes: length + intoBuffer: buffer]; + + [delegate request: self + didReceiveData: buffer + withLength: length]; + [pool2 releaseObjects]; + + bytesReceived += length; + [data addNItems: length + fromCArray: buffer]; + + toRead -= length; + } + + @try { + line = [sock readLine]; + } @catch (OFInvalidEncodingException *e) { + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + } + + if (![line isEqual: @""]) + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + + [pool2 releaseObjects]; + } + } else { + size_t length; + + while ((length = [sock readNBytes: of_pagesize + intoBuffer: buffer]) > 0) { + [delegate request: self + didReceiveData: buffer + withLength: length]; + [pool2 releaseObjects]; + + bytesReceived += length; + [data addNItems: length + fromCArray: buffer]; + + if (contentLengthHeader != nil && + bytesReceived >= contentLength) + break; + } + } + + [pool2 release]; } @finally { [self freeMemory: buffer]; } - if ((contentLengthHeader = - [serverHeaders objectForKey: @"Content-Length"]) != nil) { - intmax_t cl = [contentLengthHeader decimalValue]; - - if (cl > SIZE_MAX) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - /* - * We only want to throw on these status codes as we will throw - * an OFHTTPRequestFailedException for all other status codes - * later. - */ - if (cl != bytesReceived && (status == 200 || status == 301 || - status == 302 || status == 303)) - @throw [OFTruncatedDataException - exceptionWithClass: isa]; - } + [sock close]; + + /* + * We only want to throw on these status codes as we will throw an + * OFHTTPRequestFailedException for all other status codes later. + */ + if (contentLengthHeader != nil && contentLength != bytesReceived && + (status == 200 || status == 301 || status == 302 || status == 303 || + status == 307)) + @throw [OFTruncatedDataException exceptionWithClass: isa]; [serverHeaders makeImmutable]; result = [[OFHTTPRequestResult alloc] initWithStatusCode: status headers: serverHeaders data: data]; - if (status != 200 && status != 301 && status != 302 && status != 303) + switch (status) { + case 200: + case 301: + case 302: + case 303: + case 307: + break; + default: + [result release]; @throw [OFHTTPRequestFailedException exceptionWithClass: isa HTTPRequest: self result: result]; + } + + [pool release]; return [result autorelease]; } @end Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -57,10 +57,12 @@ * \param index The index of the object to replace * \param object The replacement object */ - (void)replaceObjectAtIndex: (size_t)index withObject: (id)object; +- (void)setObject: (id)object + atIndexedSubscript: (size_t)index; /** * \brief Replaces the first object that has the same address as the specified * object with the other specified object. * Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -106,20 +106,15 @@ - initWithArray: (OFArray*)array { return (id)[[OFMutableArray_adjacent alloc] initWithArray: array]; } -- initWithCArray: (id*)objects -{ - return (id)[[OFMutableArray_adjacent alloc] initWithCArray: objects]; -} - -- initWithCArray: (id*)objects - length: (size_t)length -{ - return (id)[[OFMutableArray_adjacent alloc] initWithCArray: objects - length: length]; +- initWithObjects: (id*)objects + count: (size_t)count +{ + return (id)[[OFMutableArray_adjacent alloc] initWithObjects: objects + count: count]; } - initWithSerialization: (OFXMLElement*)element { return (id)[[OFMutableArray_adjacent alloc] @@ -197,10 +192,17 @@ withObject: (id)object { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } + +- (void)setObject: (id)object + atIndexedSubscript: (size_t)index +{ + [self replaceObjectAtIndex: index + withObject: object]; +} - (void)replaceObject: (id)oldObject withObject: (id)newObject { size_t i, count = [self count]; Index: src/OFMutableArray_adjacent.m ================================================================== --- src/OFMutableArray_adjacent.m +++ src/OFMutableArray_adjacent.m @@ -53,63 +53,63 @@ } - (void)replaceObject: (id)oldObject withObject: (id)newObject { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { - if ([cArray[i] isEqual: oldObject]) { + if ([objects[i] isEqual: oldObject]) { [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; + [objects[i] release]; + objects[i] = newObject; return; } } } - (void)replaceObjectAtIndex: (size_t)index withObject: (id)object { - id *cArray = [array cArray]; + id *objects = [array cArray]; id oldObject; if (index >= [array count]) @throw [OFOutOfRangeException exceptionWithClass: isa]; - oldObject = cArray[index]; - cArray[index] = [object retain]; + oldObject = objects[index]; + objects[index] = [object retain]; [oldObject release]; } - (void)replaceObjectIdenticalTo: (id)oldObject withObject: (id)newObject { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { - if (cArray[i] == oldObject) { + if (objects[i] == oldObject) { [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; + [objects[i] release]; + objects[i] = newObject; return; } } } - (void)removeObject: (id)object { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { - if ([cArray[i] isEqual: object]) { - object = cArray[i]; + if ([objects[i] isEqual: object]) { + object = objects[i]; [array removeItemAtIndex: i]; mutations++; [object release]; @@ -119,15 +119,15 @@ } } - (void)removeObjectIdenticalTo: (id)object { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) { - if (cArray[i] == object) { + if (objects[i] == object) { [array removeItemAtIndex: i]; mutations++; [object release]; @@ -145,19 +145,19 @@ mutations++; } - (void)removeNObjects: (size_t)nObjects { - id *cArray = [array cArray], *copy; + id *objects = [array cArray], *copy; size_t i, count = [array count]; if (nObjects > count) @throw [OFOutOfRangeException exceptionWithClass: isa]; copy = [self allocMemoryForNItems: nObjects ofSize: sizeof(id)]; - memcpy(copy, cArray + (count - nObjects), nObjects * sizeof(id)); + memcpy(copy, objects + (count - nObjects), nObjects * sizeof(id)); @try { [array removeNItems: nObjects]; mutations++; @@ -168,30 +168,30 @@ } } - (void)removeAllObjects { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; for (i = 0; i < count; i++) - [cArray[i] release]; + [objects[i] release]; [array removeAllItems]; } - (void)removeObjectsInRange: (of_range_t)range { - id *cArray = [array cArray], *copy; + id *objects = [array cArray], *copy; size_t i, count = [array count]; if (range.length > count - range.start) @throw [OFOutOfRangeException exceptionWithClass: isa]; copy = [self allocMemoryForNItems: range.length ofSize: sizeof(id)]; - memcpy(copy, cArray + range.start, range.length * sizeof(id)); + memcpy(copy, objects + range.start, range.length * sizeof(id)); @try { [array removeNItems: range.length atIndex: range.start]; mutations++; @@ -213,34 +213,34 @@ } - (void)swapObjectAtIndex: (size_t)index1 withObjectAtIndex: (size_t)index2 { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t count = [array count]; id tmp; if (index1 >= count || index2 >= count) @throw [OFOutOfRangeException exceptionWithClass: isa]; - tmp = cArray[index1]; - cArray[index1] = cArray[index2]; - cArray[index2] = tmp; + tmp = objects[index1]; + objects[index1] = objects[index2]; + objects[index2] = tmp; } - (void)reverse { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, j, count = [array count]; if (count == 0 || count == 1) return; for (i = 0, j = count - 1; i < j; i++, j--) { - id tmp = cArray[i]; - cArray[i] = cArray[j]; - cArray[j] = tmp; + id tmp = objects[i]; + objects[i] = objects[j]; + objects[j] = tmp; } } - (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state objects: (id*)objects @@ -268,11 +268,11 @@ } #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; BOOL stop = NO; unsigned long mutations2 = mutations; for (i = 0; i < count && !stop; i++) { @@ -279,17 +279,17 @@ if (mutations != mutations2) @throw [OFEnumerationMutationException exceptionWithClass: isa object: self]; - block(cArray[i], i, &stop); + block(objects[i], i, &stop); } } - (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block { - id *cArray = [array cArray]; + id *objects = [array cArray]; size_t i, count = [array count]; BOOL stop = NO; unsigned long mutations2 = mutations; for (i = 0; i < count && !stop; i++) { @@ -298,24 +298,24 @@ if (mutations != mutations2) @throw [OFEnumerationMutationException exceptionWithClass: isa object: self]; - newObject = block(cArray[i], i, &stop); + newObject = block(objects[i], i, &stop); if (newObject == nil) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; [newObject retain]; - [cArray[i] release]; - cArray[i] = newObject; + [objects[i] release]; + objects[i] = newObject; } } #endif - (void)makeImmutable { isa = [OFArray_adjacent class]; } @end Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -32,10 +32,12 @@ * \param key The key to set * \param object The object to set the key to */ - (void)setObject: (id)object forKey: (id)key; +- (void)setObject: (id)object + forKeyedSubscript: (id)key; /** * \brief Removes the object for the specified key from the dictionary. * * \param key The key whose object should be removed Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -52,10 +52,20 @@ { return (id)[[OFMutableDictionary_hashtable alloc] initWithObjects: objects forKeys: keys]; } + +- initWithObjects: (id*)objects + forKeys: (id*)keys + count: (size_t)count +{ + return (id)[[OFMutableDictionary_hashtable alloc] + initWithObjects: objects + forKeys: keys + count: count]; +} - initWithKeysAndObjects: (id)firstKey, ... { id ret; va_list arguments; @@ -136,10 +146,17 @@ forKey: (id)key { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; } + +- (void)setObject: (id)object + forKeyedSubscript: (id)key +{ + [self setObject: object + forKey: key]; +} - (void)removeObjectForKey: (id)key { @throw [OFNotImplementedException exceptionWithClass: isa selector: _cmd]; Index: src/OFMutableString_UTF8.h ================================================================== --- src/OFMutableString_UTF8.h +++ src/OFMutableString_UTF8.h @@ -13,12 +13,14 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFMutableString.h" +#import "OFString_UTF8.h" @interface OFMutableString_UTF8: OFMutableString { @public struct of_string_utf8_ivars *restrict s; + struct of_string_utf8_ivars s_store; } @end Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -474,20 +474,10 @@ * * \return A description for the object */ - (OFString*)description; -/** - * \brief Adds a pointer to the object's memory pool. - * - * This is useful to add memory allocated by functions such as asprintf to the - * pool so it gets free'd automatically when the object is deallocated. - * - * \param pointer A pointer to add to the memory pool - */ -- (void)addMemoryToPool: (void*)pointer; - /** * \brief Allocates memory and stores it in the object's memory pool. * * It will be free'd automatically when the object is deallocated. * @@ -606,11 +596,12 @@ #import "OFObject+Serialization.h" #ifdef __cplusplus extern "C" { #endif -extern id objc_getProperty(id, SEL, ptrdiff_t, BOOL); -extern void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL); extern size_t of_pagesize; +extern size_t of_num_cpus; +extern id of_alloc_object(Class class_, size_t extraSize, size_t extraAlignment, + void **extra); #ifdef __cplusplus } #endif Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -57,36 +57,40 @@ #elif defined(OF_THREADS) # import "threading.h" #endif struct pre_ivar { - int32_t retainCount; - void **memoryChunks; - unsigned int memoryChunksSize; + int32_t retainCount; + struct pre_mem *firstMem, *lastMem; #if !defined(OF_ATOMIC_OPS) && defined(OF_THREADS) of_spinlock_t retainCountSpinlock; #endif }; -/* Hopefully no arch needs more than 16 bytes padding */ -#ifndef __BIGGEST_ALIGNMENT__ -# define __BIGGEST_ALIGNMENT__ 16 -#endif +struct pre_mem { + struct pre_mem *prev, *next; + id owner; +}; #define PRE_IVAR_ALIGN ((sizeof(struct pre_ivar) + \ (__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1)) #define PRE_IVAR ((struct pre_ivar*)(void*)((char*)self - PRE_IVAR_ALIGN)) +#define PRE_MEM_ALIGN ((sizeof(struct pre_mem) + \ + (__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1)) +#define PRE_MEM(mem) ((struct pre_mem*)(void*)((char*)mem - PRE_MEM_ALIGN)) + static struct { Class isa; } alloc_failed_exception; static Class autoreleasePool = Nil; static SEL cxx_construct = NULL; static SEL cxx_destruct = NULL; size_t of_pagesize; +size_t of_num_cpus; #ifdef NEED_OBJC_SYNC_INIT extern BOOL objc_sync_init(); #endif @@ -116,10 +120,56 @@ objc_enumerationMutation(id object) { enumeration_mutation_handler(object); } #endif + +id +of_alloc_object(Class class, size_t extraSize, size_t extraAlignment, + void **extra) +{ + OFObject *instance; + size_t instanceSize; + + instanceSize = class_getInstanceSize(class); + + if (OF_UNLIKELY(extraAlignment > 0)) + extraAlignment = ((instanceSize + extraAlignment - 1) & + ~(extraAlignment - 1)) - extraAlignment; + + instance = malloc(PRE_IVAR_ALIGN + instanceSize + + extraAlignment + extraSize); + + if (OF_UNLIKELY(instance == nil)) { + alloc_failed_exception.isa = [OFAllocFailedException class]; + @throw (OFAllocFailedException*)&alloc_failed_exception; + } + + ((struct pre_ivar*)instance)->retainCount = 1; + ((struct pre_ivar*)instance)->firstMem = NULL; + ((struct pre_ivar*)instance)->lastMem = NULL; + +#if !defined(OF_ATOMIC_OPS) && defined(OF_THREADS) + if (OF_UNLIKELY(!of_spinlock_new( + &((struct pre_ivar*)instance)->retainCountSpinlock))) { + free(instance); + @throw [OFInitializationFailedException + exceptionWithClass: class]; + } +#endif + + instance = (OFObject*)((char*)instance + PRE_IVAR_ALIGN); + + instance->isa = class; + memset((char*)instance + sizeof(instance->isa), 0, + instanceSize - sizeof(instance->isa)); + + if (OF_UNLIKELY(extra != NULL)) + *extra = (char*)instance + instanceSize + extraAlignment; + + return instance; +} const char* _NSPrintForDebugger(id object) { return [[object description] @@ -169,49 +219,29 @@ #if defined(_WIN32) SYSTEM_INFO si; GetSystemInfo(&si); of_pagesize = si.dwPageSize; + of_num_cpus = si.dwNumberOfProcessors; #elif defined(_PSP) of_pagesize = 4096; + of_num_cpus = 1; #else if ((of_pagesize = sysconf(_SC_PAGESIZE)) < 1) of_pagesize = 4096; + if ((of_num_cpus = sysconf(_SC_NPROCESSORS_CONF)) < 1) + of_num_cpus = 1; #endif } + (void)initialize { } + alloc { - OFObject *instance; - size_t instanceSize = class_getInstanceSize(self); - - if ((instance = calloc(instanceSize + PRE_IVAR_ALIGN, 1)) == NULL) { - alloc_failed_exception.isa = [OFAllocFailedException class]; - @throw (OFAllocFailedException*)&alloc_failed_exception; - } - - ((struct pre_ivar*)instance)->memoryChunks = NULL; - ((struct pre_ivar*)instance)->memoryChunksSize = 0; - ((struct pre_ivar*)instance)->retainCount = 1; - -#if !defined(OF_ATOMIC_OPS) && defined(OF_THREADS) - if (!of_spinlock_new( - &((struct pre_ivar*)instance)->retainCountSpinlock)) { - free(instance); - @throw [OFInitializationFailedException - exceptionWithClass: self]; - } -#endif - - instance = (OFObject*)((char*)instance + PRE_IVAR_ALIGN); - instance->isa = self; - - return instance; + return of_alloc_object(self, 0, 0, NULL); } + new { return [[self alloc] init]; @@ -566,63 +596,33 @@ { /* Classes containing data should reimplement this! */ return [OFString stringWithFormat: @"<%@: %p>", [self className], self]; } -- (void)addMemoryToPool: (void*)pointer -{ - void **memoryChunks; - unsigned int memoryChunksSize; - - memoryChunksSize = PRE_IVAR->memoryChunksSize + 1; - - if (UINT_MAX - PRE_IVAR->memoryChunksSize < 1 || - memoryChunksSize > UINT_MAX / sizeof(void*)) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - if ((memoryChunks = realloc(PRE_IVAR->memoryChunks, - memoryChunksSize * sizeof(void*))) == NULL) - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: memoryChunksSize]; - - PRE_IVAR->memoryChunks = memoryChunks; - PRE_IVAR->memoryChunks[PRE_IVAR->memoryChunksSize] = pointer; - PRE_IVAR->memoryChunksSize = memoryChunksSize; -} - -- (void*)allocMemoryWithSize: (size_t)size -{ - void *pointer, **memoryChunks; - unsigned int memoryChunksSize; - - if (size == 0) - return NULL; - - memoryChunksSize = PRE_IVAR->memoryChunksSize + 1; - - if (UINT_MAX - PRE_IVAR->memoryChunksSize == 0 || - memoryChunksSize > UINT_MAX / sizeof(void*)) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - if ((pointer = malloc(size)) == NULL) - @throw [OFOutOfMemoryException exceptionWithClass: isa - requestedSize: size]; - - if ((memoryChunks = realloc(PRE_IVAR->memoryChunks, - memoryChunksSize * sizeof(void*))) == NULL) { - free(pointer); - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: memoryChunksSize]; - } - - PRE_IVAR->memoryChunks = memoryChunks; - PRE_IVAR->memoryChunks[PRE_IVAR->memoryChunksSize] = pointer; - PRE_IVAR->memoryChunksSize = memoryChunksSize; - - return pointer; +- (void*)allocMemoryWithSize: (size_t)size +{ + void *pointer; + struct pre_mem *preMem; + + if (size > SIZE_MAX - PRE_IVAR_ALIGN) + @throw [OFOutOfRangeException exceptionWithClass: isa]; + + if ((pointer = malloc(PRE_MEM_ALIGN + size)) == NULL) + @throw [OFOutOfMemoryException exceptionWithClass: isa + requestedSize: size]; + preMem = pointer; + + preMem->owner = self; + preMem->prev = PRE_IVAR->lastMem; + preMem->next = NULL; + + if (PRE_IVAR->lastMem != NULL) + PRE_IVAR->lastMem->next = preMem; + + PRE_IVAR->lastMem = preMem; + + return (char*)pointer + PRE_MEM_ALIGN; } - (void*)allocMemoryForNItems: (size_t)nItems ofSize: (size_t)size { @@ -636,37 +636,44 @@ } - (void*)resizeMemory: (void*)pointer toSize: (size_t)size { - void **iter; + void *new; + struct pre_mem *preMem; if (pointer == NULL) return [self allocMemoryWithSize: size]; if (size == 0) { [self freeMemory: pointer]; return NULL; } - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - - while (iter-- > PRE_IVAR->memoryChunks) { - if (OF_UNLIKELY(*iter == pointer)) { - if (OF_UNLIKELY((pointer = realloc(pointer, - size)) == NULL)) - @throw [OFOutOfMemoryException - exceptionWithClass: isa - requestedSize: size]; - - *iter = pointer; - return pointer; - } - } - - @throw [OFMemoryNotPartOfObjectException exceptionWithClass: isa - pointer: pointer]; + if (PRE_MEM(pointer)->owner != self) + @throw [OFMemoryNotPartOfObjectException + exceptionWithClass: isa + pointer: pointer]; + + if ((new = realloc(PRE_MEM(pointer), PRE_MEM_ALIGN + size)) == NULL) + @throw [OFOutOfMemoryException exceptionWithClass: isa + requestedSize: size]; + preMem = new; + + if (preMem != PRE_MEM(pointer)) { + if (preMem->prev != NULL) + preMem->prev->next = preMem; + if (preMem->next != NULL) + preMem->next->prev = preMem; + + if (PRE_IVAR->firstMem == PRE_MEM(pointer)) + PRE_IVAR->firstMem = preMem; + if (PRE_IVAR->lastMem == PRE_MEM(pointer)) + PRE_IVAR->lastMem = preMem; + } + + return (char*)new + PRE_MEM_ALIGN; } - (void*)resizeMemory: (void*)pointer toNItems: (size_t)nItems ofSize: (size_t)size @@ -687,56 +694,32 @@ toSize: nItems * size]; } - (void)freeMemory: (void*)pointer { - void **iter, *last, **memoryChunks; - unsigned int i, memoryChunksSize; - if (pointer == NULL) return; - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - i = PRE_IVAR->memoryChunksSize; - - while (iter-- > PRE_IVAR->memoryChunks) { - i--; - - if (OF_UNLIKELY(*iter == pointer)) { - memoryChunksSize = PRE_IVAR->memoryChunksSize - 1; - last = PRE_IVAR->memoryChunks[memoryChunksSize]; - - assert(PRE_IVAR->memoryChunksSize != 0 && - memoryChunksSize <= UINT_MAX / sizeof(void*)); - - if (OF_UNLIKELY(memoryChunksSize == 0)) { - free(pointer); - free(PRE_IVAR->memoryChunks); - - PRE_IVAR->memoryChunks = NULL; - PRE_IVAR->memoryChunksSize = 0; - - return; - } - - free(pointer); - PRE_IVAR->memoryChunks[i] = last; - PRE_IVAR->memoryChunksSize = memoryChunksSize; - - if (OF_UNLIKELY((memoryChunks = realloc( - PRE_IVAR->memoryChunks, memoryChunksSize * - sizeof(void*))) == NULL)) - return; - - PRE_IVAR->memoryChunks = memoryChunks; - - return; - } - } - - @throw [OFMemoryNotPartOfObjectException exceptionWithClass: isa - pointer: pointer]; + if (PRE_MEM(pointer)->owner != self) + @throw [OFMemoryNotPartOfObjectException + exceptionWithClass: isa + pointer: pointer]; + + if (PRE_MEM(pointer)->prev != NULL) + PRE_MEM(pointer)->prev->next = PRE_MEM(pointer)->next; + if (PRE_MEM(pointer)->next != NULL) + PRE_MEM(pointer)->next->prev = PRE_MEM(pointer)->prev; + + if (PRE_IVAR->firstMem == PRE_MEM(pointer)) + PRE_IVAR->firstMem = PRE_MEM(pointer)->next; + if (PRE_IVAR->lastMem == PRE_MEM(pointer)) + PRE_IVAR->lastMem = PRE_MEM(pointer)->prev; + + /* To detect double-free */ + PRE_MEM(pointer)->owner = nil; + + free(PRE_MEM(pointer)); } - retain { #if defined(OF_ATOMIC_OPS) @@ -804,11 +787,11 @@ - (void)dealloc { Class class; void (*last)(id, SEL) = NULL; - void **iter; + struct pre_mem *iter; for (class = isa; class != Nil; class = class_getSuperclass(class)) { void (*destruct)(id, SEL); if ([class instancesRespondToSelector: cxx_destruct]) { @@ -819,16 +802,25 @@ last = destruct; } else break; } - iter = PRE_IVAR->memoryChunks + PRE_IVAR->memoryChunksSize; - while (iter-- > PRE_IVAR->memoryChunks) - free(*iter); + iter = PRE_IVAR->firstMem; + while (iter != NULL) { + struct pre_mem *next = iter->next; + + /* + * We can use owner as a sentinel to prevent exploitation in + * case there is a buffer underflow somewhere. + */ + if (iter->owner != self) + abort(); + + free(iter); - if (PRE_IVAR->memoryChunks != NULL) - free(PRE_IVAR->memoryChunks); + iter = next; + } free((char*)self - PRE_IVAR_ALIGN); } /* Required to use properties with the Apple runtime */ @@ -852,16 +844,10 @@ /* * Those are needed as the root class is the superclass of the root class's * metaclass and thus instance methods can be sent to class objects as well. */ -+ (void)addMemoryToPool: (void*)pointer -{ - @throw [OFNotImplementedException exceptionWithClass: self - selector: _cmd]; -} - + (void*)allocMemoryWithSize: (size_t)size { @throw [OFNotImplementedException exceptionWithClass: self selector: _cmd]; } Index: src/OFProcess.m ================================================================== --- src/OFProcess.m +++ src/OFProcess.m @@ -85,11 +85,11 @@ @throw [OFInitializationFailedException exceptionWithClass: isa]; switch ((pid = fork())) { case 0:; - OFString **cArray = [arguments cArray]; + OFString **objects = [arguments objects]; size_t i, count = [arguments count]; char **argv; argv = [self allocMemoryForNItems: count + 2 ofSize: sizeof(char*)]; @@ -96,11 +96,11 @@ argv[0] = (char*)[programName cStringWithEncoding: OF_STRING_ENCODING_NATIVE]; for (i = 0; i < count; i++) - argv[i + 1] = (char*)[cArray[i] + argv[i + 1] = (char*)[objects[i] cStringWithEncoding: OF_STRING_ENCODING_NATIVE]; argv[i + 1] = NULL; Index: src/OFSet_hashtable.m ================================================================== --- src/OFSet_hashtable.m +++ src/OFSet_hashtable.m @@ -78,16 +78,16 @@ self = [self init]; @try { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFNumber *one = [OFNumber numberWithSize: 1]; - id *cArray = [array cArray]; + id *objects = [array objects]; size_t i, count = [array count]; for (i = 0; i < count; i++) [dictionary _setObject: one - forKey: cArray[i] + forKey: objects[i] copyKey: NO]; [pool release]; } @catch (id e) { [self release]; Index: src/OFStreamObserver.m ================================================================== --- src/OFStreamObserver.m +++ src/OFStreamObserver.m @@ -295,17 +295,17 @@ - (void)_processQueue { [mutex lock]; @try { - OFStream **queueCArray = [queue cArray]; + OFStream **queueObjects = [queue objects]; int *queueInfoCArray = [queueInfo cArray]; int *queueFDsCArray = [queueFDs cArray]; size_t i, count = [queue count]; for (i = 0; i < count; i++) { - OFStream *stream = queueCArray[i]; + OFStream *stream = queueObjects[i]; int action = queueInfoCArray[i]; int fd = queueFDsCArray[i]; if ((action & QUEUE_ACTION) == QUEUE_ADD) { if (fd > maxFD) { @@ -374,20 +374,20 @@ } - (BOOL)_processCache { OFAutoreleasePool *pool; - OFStream **cArray = [readStreams cArray]; + OFStream **objects = [readStreams objects]; size_t i, count = [readStreams count]; BOOL foundInCache = NO; pool = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count; i++) { - if ([cArray[i] pendingBytes] > 0 && - ![cArray[i] _isWaitingForDelimiter]) { - [delegate streamIsReadyForReading: cArray[i]]; + if ([objects[i] pendingBytes] > 0 && + ![objects[i] _isWaitingForDelimiter]) { + [delegate streamIsReadyForReading: objects[i]]; foundInCache = YES; [pool releaseObjects]; } } Index: src/OFStreamObserver_select.m ================================================================== --- src/OFStreamObserver_select.m +++ src/OFStreamObserver_select.m @@ -69,11 +69,11 @@ } - (BOOL)observeWithTimeout: (int)timeout { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFStream **cArray; + OFStream **objects; fd_set readFDs_; fd_set writeFDs_; fd_set exceptFDs_; struct timeval time; size_t i, count; @@ -111,23 +111,23 @@ #else assert(recvfrom(cancelFD[0], &buffer, 1, 0, NULL, NULL) > 0); #endif } - cArray = [readStreams cArray]; + objects = [readStreams objects]; count = [readStreams count]; for (i = 0; i < count; i++) { - int fileDescriptor = [cArray[i] fileDescriptor]; + int fileDescriptor = [objects[i] fileDescriptor]; if (FD_ISSET(fileDescriptor, &readFDs_)) { - [delegate streamIsReadyForReading: cArray[i]]; + [delegate streamIsReadyForReading: objects[i]]; [pool releaseObjects]; } if (FD_ISSET(fileDescriptor, &exceptFDs_)) { - [delegate streamDidReceiveException: cArray[i]]; + [delegate streamDidReceiveException: objects[i]]; [pool releaseObjects]; /* * Prevent calling it twice in case the FD is in both * sets. @@ -134,27 +134,27 @@ */ FD_CLR(fileDescriptor, &exceptFDs_); } } - cArray = [writeStreams cArray]; + objects = [writeStreams objects]; count = [writeStreams count]; for (i = 0; i < count; i++) { - int fileDescriptor = [cArray[i] fileDescriptor]; + int fileDescriptor = [objects[i] fileDescriptor]; if (FD_ISSET(fileDescriptor, &writeFDs_)) { - [delegate streamIsReadyForWriting: cArray[i]]; + [delegate streamIsReadyForWriting: objects[i]]; [pool releaseObjects]; } if (FD_ISSET(fileDescriptor, &exceptFDs_)) { - [delegate streamDidReceiveException: cArray[i]]; + [delegate streamDidReceiveException: objects[i]]; [pool releaseObjects]; } } [pool release]; return YES; } @end Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -255,31 +255,74 @@ return (id)[[OFString_UTF8 alloc] init]; } - initWithUTF8String: (const char*)UTF8String { - return (id)[[OFString_UTF8 alloc] initWithUTF8String: UTF8String]; + id string; + size_t length; + void *storage; + + length = strlen(UTF8String); + string = of_alloc_object([OFString_UTF8 class], + length + 1, 1, &storage); + + return (id)[string _initWithUTF8String: UTF8String + length: length + storage: storage]; } - initWithUTF8String: (const char*)UTF8String length: (size_t)UTF8StringLength { - return (id)[[OFString_UTF8 alloc] initWithUTF8String: UTF8String - length: UTF8StringLength]; + id string; + void *storage; + + string = of_alloc_object([OFString_UTF8 class], + UTF8StringLength + 1, 1, &storage); + + return (id)[string _initWithUTF8String: UTF8String + length: UTF8StringLength + storage: storage]; } - initWithCString: (const char*)cString encoding: (of_string_encoding_t)encoding { + if (encoding == OF_STRING_ENCODING_UTF_8) { + id string; + size_t length; + void *storage; + + length = strlen(cString); + string = of_alloc_object([OFString_UTF8 class], + length + 1, 1, &storage); + + return (id)[string _initWithUTF8String: cString + length: length + storage: storage]; + } + return (id)[[OFString_UTF8 alloc] initWithCString: cString encoding: encoding]; } - initWithCString: (const char*)cString encoding: (of_string_encoding_t)encoding length: (size_t)cStringLength { + if (encoding == OF_STRING_ENCODING_UTF_8) { + id string; + void *storage; + + string = of_alloc_object([OFString_UTF8 class], + cStringLength + 1, 1, &storage); + + return (id)[string _initWithUTF8String: cString + length: cStringLength + storage: storage]; + } + return (id)[[OFString_UTF8 alloc] initWithCString: cString encoding: encoding length: cStringLength]; } Index: src/OFString_UTF8.h ================================================================== --- src/OFString_UTF8.h +++ src/OFString_UTF8.h @@ -17,15 +17,27 @@ #import "OFString.h" @interface OFString_UTF8: OFString { @public + /* + * A pointer to the actual data. + * + * Since constant strings don't have s_store, they have to malloc it on + * the first access. Strings created at runtime just set the pointer to + * &s_store. + */ struct of_string_utf8_ivars { char *cString; size_t cStringLength; BOOL UTF8; size_t length; BOOL hashed; uint32_t hash; } *restrict s; + struct of_string_utf8_ivars s_store; } + +- _initWithUTF8String: (const char*)UTF8String + length: (size_t)UTF8StringLength + storage: (char*)storage; @end Index: src/OFString_UTF8.m ================================================================== --- src/OFString_UTF8.m +++ src/OFString_UTF8.m @@ -62,19 +62,56 @@ - init { self = [super init]; @try { - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cString = [self allocMemoryWithSize: 1]; s->cString[0] = '\0'; } @catch (id e) { [self release]; @throw e; } + + return self; +} + +- _initWithUTF8String: (const char*)UTF8String + length: (size_t)UTF8StringLength + storage: (char*)storage +{ + self = [super init]; + + @try { + if (UTF8StringLength >= 3 && + !memcmp(UTF8String, "\xEF\xBB\xBF", 3)) { + UTF8String += 3; + UTF8StringLength -= 3; + } + + s = &s_store; + + s->cString = storage; + s->cStringLength = UTF8StringLength; + + switch (of_string_check_utf8(UTF8String, UTF8StringLength, + &s->length)) { + case 1: + s->UTF8 = YES; + break; + case -1: + @throw [OFInvalidEncodingException + exceptionWithClass: isa]; + } + + memcpy(s->cString, UTF8String, UTF8StringLength); + s->cString[UTF8StringLength] = 0; + } @catch (id e) { + [self release]; + @throw e; + } return self; } - initWithCString: (const char*)cString @@ -91,12 +128,11 @@ cStringLength >= 3 && !memcmp(cString, "\xEF\xBB\xBF", 3)) { cString += 3; cStringLength -= 3; } - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cString = [self allocMemoryWithSize: cStringLength + 1]; s->cStringLength = cStringLength; if (encoding == OF_STRING_ENCODING_UTF_8 || @@ -212,12 +248,11 @@ - initWithString: (OFString*)string { self = [super init]; @try { - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cStringLength = [string UTF8StringLength]; if ([string isKindOfClass: [OFString_UTF8 class]] || [string isKindOfClass: [OFMutableString_UTF8 class]]) @@ -255,12 +290,11 @@ string++; length--; } else if (byteOrder != OF_ENDIANESS_NATIVE) swap = YES; - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cStringLength = length; s->cString = [self allocMemoryWithSize: (length * 4) + 1]; s->length = length; @@ -338,12 +372,11 @@ string++; length--; } else if (byteOrder != OF_ENDIANESS_NATIVE) swap = YES; - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cStringLength = length; s->cString = [self allocMemoryWithSize: (length * 4) + 1]; s->length = length; @@ -433,42 +466,43 @@ arguments: (va_list)arguments { self = [super init]; @try { + char *tmp; int cStringLength; if (format == nil) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; - if ((cStringLength = of_vasprintf(&s->cString, - [format UTF8String], arguments)) == -1) + if ((cStringLength = of_vasprintf(&tmp, [format UTF8String], + arguments)) == -1) @throw [OFInvalidFormatException exceptionWithClass: isa]; s->cStringLength = cStringLength; @try { - switch (of_string_check_utf8(s->cString, - cStringLength, &s->length)) { + switch (of_string_check_utf8(tmp, cStringLength, + &s->length)) { case 1: s->UTF8 = YES; break; case -1: @throw [OFInvalidEncodingException exceptionWithClass: isa]; } - [self addMemoryToPool: s->cString]; - } @catch (id e) { - free(s->cString); - @throw e; + s->cString = [self + allocMemoryWithSize: cStringLength + 1]; + memcpy(s->cString, tmp, cStringLength + 1); + } @finally { + free(tmp); } } @catch (id e) { [self release]; @throw e; } @@ -484,12 +518,11 @@ @try { OFString *component; size_t i, cStringLength; va_list argumentsCopy; - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); + s = &s_store; s->cStringLength = [firstComponent UTF8StringLength]; if ([firstComponent isKindOfClass: [OFString_UTF8 class]] || [firstComponent isKindOfClass: Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -128,11 +128,11 @@ [super dealloc]; } - (void)setSOCKS5Host: (OFString*)host { - OF_SETTER(SOCKS5Host, host, YES, YES) + OF_SETTER(SOCKS5Host, host, YES, 1) } - (OFString*)SOCKS5Host { OF_GETTER(SOCKS5Host, YES) ADDED src/OFThreadPool.h Index: src/OFThreadPool.h ================================================================== --- src/OFThreadPool.h +++ src/OFThreadPool.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" + +#ifdef OF_HAVE_BLOCKS +typedef void (^of_thread_pool_block_t)(id object); +#endif + +@class OFMutableArray; +@class OFList; +@class OFCondition; +@class OFThreadPoolJob; + +/** + * \brief A class providing a pool of reusable threads. + * + * \note When the thread pool is released, all threads will terminate after + * they finish the job they are currently processing. + */ +@interface OFThreadPool: OFObject +{ + size_t size; + OFMutableArray *threads; + volatile int count; +@public + OFList *queue; + OFCondition *queueCondition; + volatile int doneCount; + OFCondition *countCondition; +} + +/** + * \brief Returns a new thread pool with one thread for each core in the system. + * + * \warning If for some reason the number of cores in the system could not be + * determined, the pool will only have one thread! + * + * \return A new thread pool with one thread for each core in the system + */ ++ threadPool; + +/** + * \brief Returns a new thread pool with the specified number of threads. + * + * \warning If for some reason the number of cores in the system could not be + * determined, the pool will only have one thread! + * + * \param size The number of threads for the pool + * \return A new thread pool with the specified number of threads + */ ++ threadPoolWithSize: (size_t)size; + +/** + * \brief Initializes an already allocated OFThreadPool with one thread for + * each core in the system. + * + * \warning If for some reason the number of cores in the system could not be + * determined, the pool will only have one thread! + * + * \return An initialized OFThreadPool with one thread for each core in the + * system + */ +- init; + +/** + * \brief Initializes an already allocated OFThreadPool with the specified + * number of threads. + * + * \warning If for some reason the number of cores in the system could not be + * determined, the pool will only have one thread! + * + * \param size The number of threads for the pool + * \return An initialized OFThreadPool with the specified number of threads + */ +- initWithSize: (size_t)size; + +/** + * \brief Execute the specified selector on the specified target with the + * specified object as soon as a thread is ready. + * + * \param target The target on which to perform the selector + * \param selector The selector to perform on the target + * \param object THe object with which the selector is performed on the target + */ +- (void)dispatchWithTarget: (id)target + selector: (SEL)selector + object: (id)object; + +#ifdef OF_HAVE_BLOCKS +/** + * \brief Executes the specified block as soon as a thread is ready. + * + * \param block The block to execute + */ +- (void)dispatchWithBlock: (of_thread_pool_block_t)block; + +/** + * \brief Executes the specified block as soon as a thread is ready. + * + * \param block The block to execute + * \param object The object to pass to the block + */ +- (void)dispatchWithBlock: (of_thread_pool_block_t)block + object: (id)object; +#endif + +/** + * \brief Waits until all threads have finished. + */ +- (void)waitUntilFinished; +@end ADDED src/OFThreadPool.m Index: src/OFThreadPool.m ================================================================== --- src/OFThreadPool.m +++ src/OFThreadPool.m @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFThreadPool.h" +#import "OFArray.h" +#import "OFList.h" +#import "OFThread.h" +#import "OFAutoreleasePool.h" + +@interface OFThreadPoolJob: OFObject +{ + id target; + SEL selector; + id object; +#ifdef OF_HAVE_BLOCKS + of_thread_pool_block_t block; +#endif +} + ++ jobWithTarget: (id)target + selector: (SEL)selector + object: (id)object; +#ifdef OF_HAVE_BLOCKS ++ jobWithBlock: (of_thread_pool_block_t)block + object: (id)object; +#endif +- initWithTarget: (id)target + selector: (SEL)selector + object: (id)object; +#ifdef OF_HAVE_BLOCKS +- initWithBlock: (of_thread_pool_block_t)block + object: (id)object; +#endif +- (void)perform; +@end + +@implementation OFThreadPoolJob ++ jobWithTarget: (id)target + selector: (SEL)selector + object: (id)object +{ + return [[[self alloc] initWithTarget: target + selector: selector + object: object] autorelease]; +} + +#ifdef OF_HAVE_BLOCKS ++ jobWithBlock: (of_thread_pool_block_t)block + object: (id)object +{ + return [[(OFThreadPoolJob*)[self alloc] + initWithBlock: block + object: object] autorelease]; +} +#endif + +- initWithTarget: (id)target_ + selector: (SEL)selector_ + object: (id)object_ +{ + self = [super init]; + + @try { + target = [target_ retain]; + selector = selector_; + object = [object_ retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +#ifdef OF_HAVE_BLOCKS +- initWithBlock: (of_thread_pool_block_t)block_ + object: (id)object_ +{ + self = [super init]; + + @try { + block = [block_ retain]; + object = [object_ retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} +#endif + +- (void)dealloc +{ + [target release]; + [object release]; +#ifdef OF_HAVE_BLOCKS + [block release]; +#endif + + [super dealloc]; +} + +- (void)perform +{ +#ifdef OF_HAVE_BLOCKS + if (block != nil) + block(object); + else +#endif + [object performSelector: selector + withObject: object]; +} +@end + +@interface OFThreadPoolThread: OFThread +{ + OFList *queue; + OFCondition *queueCondition, *countCondition; +@public + volatile BOOL terminate; + volatile int *doneCount; +} + ++ threadWithThreadPool: (OFThreadPool*)threadPool; +- initWithThreadPool: (OFThreadPool*)threadPool; +@end + +@implementation OFThreadPoolThread ++ threadWithThreadPool: (OFThreadPool*)threadPool +{ + return [[[self alloc] initWithThreadPool: threadPool] autorelease]; +} + +- initWithThreadPool: (OFThreadPool*)threadPool +{ + self = [super init]; + + @try { + queue = [threadPool->queue retain]; + queueCondition = [threadPool->queueCondition retain]; + countCondition = [threadPool->countCondition retain]; + doneCount = &threadPool->doneCount; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [queue release]; + [queueCondition release]; + [countCondition release]; + + [super dealloc]; +} + +- (id)main +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + + if (terminate) { + [pool release]; + return nil; + } + + for (;;) { + OFThreadPoolJob *job; + + [queueCondition lock]; + @try { + of_list_object_t *listObject; + + if (terminate) { + [pool release]; + return nil; + } + + listObject = [queue firstListObject]; + + while (listObject == NULL) { + [queueCondition wait]; + + if (terminate) { + [pool release]; + return nil; + } + + listObject = [queue firstListObject]; + } + + job = [[listObject->object retain] autorelease]; + [queue removeListObject: listObject]; + } @finally { + [queueCondition unlock]; + } + + if (terminate) { + [pool release]; + return nil; + } + + [job perform]; + + if (terminate) { + [pool release]; + return nil; + } + + [pool releaseObjects]; + + [countCondition lock]; + @try { + if (terminate) { + [pool release]; + return nil; + } + + (*doneCount)++; + + [countCondition signal]; + } @finally { + [countCondition unlock]; + } + } +} +@end + +@implementation OFThreadPool ++ threadPool +{ + return [[[self alloc] init] autorelease]; +} + ++ threadPoolWithSize: (size_t)size +{ + return [[[self alloc] initWithSize: size] autorelease]; +} + +- init +{ + return [self initWithSize: of_num_cpus]; +} + +- initWithSize: (size_t)size_ +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + size_t i; + + size = size_; + threads = [[OFMutableArray alloc] init]; + queue = [[OFList alloc] init]; + queueCondition = [[OFCondition alloc] init]; + countCondition = [[OFCondition alloc] init]; + + for (i = 0; i < size; i++) { + OFThreadPoolThread *thread = + [OFThreadPoolThread threadWithThreadPool: self]; + + [threads addObject: thread]; + + [pool releaseObjects]; + } + + /* + * We need to start the threads in a separate loop to make sure + * threads is not modified anymore to prevent a race condition. + */ + for (i = 0; i < size; i++) { + OFThreadPoolThread *thread = [threads objectAtIndex: i]; + + [thread start]; + } + + [pool release]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + [queueCondition lock]; + @try { + [countCondition lock]; + @try { + OFEnumerator *enumerator = [threads objectEnumerator]; + OFThreadPoolThread *thread; + + while ((thread = [enumerator nextObject]) != nil) + thread->terminate = YES; + } @finally { + [countCondition unlock]; + } + + [queueCondition broadcast]; + } @finally { + [queueCondition unlock]; + } + [pool release]; + + [threads release]; + [queue release]; + [queueCondition release]; + [countCondition release]; + + [super dealloc]; +} + +- (void)_dispatchJob: (OFThreadPoolJob*)job +{ + of_atomic_inc_int(&count); + + [queueCondition lock]; + @try { + [queue appendObject: job]; + [queueCondition signal]; + } @finally { + [queueCondition unlock]; + } +} + +- (void)waitUntilFinished +{ + for (;;) { + [countCondition lock]; + @try { + if (doneCount == count) + return; + + [countCondition wait]; + } @finally { + [countCondition unlock]; + } + } +} + +- (void)dispatchWithTarget: (id)target + selector: (SEL)selector + object: (id)object +{ + [self _dispatchJob: [OFThreadPoolJob jobWithTarget: target + selector: selector + object: object]]; +} + +#ifdef OF_HAVE_BLOCKS +- (void)dispatchWithBlock: (of_thread_pool_block_t)block +{ + [self _dispatchJob: [OFThreadPoolJob jobWithBlock: block + object: nil]]; +} + +- (void)dispatchWithBlock: (of_thread_pool_block_t)block + object: (id)object +{ + [self _dispatchJob: [OFThreadPoolJob jobWithBlock: block + object: object]]; +} +#endif +@end Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -42,24 +42,24 @@ array = [[[path componentsSeparatedByString: @"/"] mutableCopy] autorelease]; while (!done) { - id *cArray = [array cArray]; + id *objects = [array objects]; size_t i, length = [array count]; done = YES; for (i = 0; i < length; i++) { - if ([cArray[i] isEqual: @"."]) { + if ([objects[i] isEqual: @"."]) { [array removeObjectAtIndex: i]; done = NO; break; } - if ([cArray[i] isEqual: @".."]) { + if ([objects[i] isEqual: @".."]) { [array removeObjectAtIndex: i]; if (i > 0) [array removeObjectAtIndex: i - 1]; @@ -414,21 +414,21 @@ { if (![scheme_ isEqual: @"http"] && ![scheme_ isEqual: @"https"]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; - OF_SETTER(scheme, scheme_, YES, YES) + OF_SETTER(scheme, scheme_, YES, 1) } - (OFString*)host { OF_GETTER(host, YES) } - (void)setHost: (OFString*)host_ { - OF_SETTER(host, host_, YES, YES) + OF_SETTER(host, host_, YES, 1) } - (uint16_t)port { return port; @@ -444,21 +444,21 @@ OF_GETTER(user, YES) } - (void)setUser: (OFString*)user_ { - OF_SETTER(user, user_, YES, YES) + OF_SETTER(user, user_, YES, 1) } - (OFString*)password { OF_GETTER(password, YES) } - (void)setPassword: (OFString*)password_ { - OF_SETTER(password, password_, YES, YES) + OF_SETTER(password, password_, YES, 1) } - (OFString*)path { OF_GETTER(path, YES) @@ -469,41 +469,41 @@ if (([scheme isEqual: @"http"] || [scheme isEqual: @"https"]) && ![path_ hasPrefix: @"/"]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; - OF_SETTER(path, path_, YES, YES) + OF_SETTER(path, path_, YES, 1) } - (OFString*)parameters { OF_GETTER(parameters, YES) } - (void)setParameters: (OFString*)parameters_ { - OF_SETTER(parameters, parameters_, YES, YES) + OF_SETTER(parameters, parameters_, YES, 1) } - (OFString*)query { OF_GETTER(query, YES) } - (void)setQuery: (OFString*)query_ { - OF_SETTER(query, query_, YES, YES) + OF_SETTER(query, query_, YES, 1) } - (OFString*)fragment { OF_GETTER(fragment, YES) } - (void)setFragment: (OFString*)fragment_ { - OF_SETTER(fragment, fragment_, YES, YES) + OF_SETTER(fragment, fragment_, YES, 1) } - (OFString*)string { OFMutableString *ret = [OFMutableString stringWithFormat: @"%@://", Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -384,21 +384,21 @@ { if (name_ == nil) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; - OF_SETTER(name, name_, YES, YES) + OF_SETTER(name, name_, YES, 1) } - (OFString*)name { OF_GETTER(name, YES) } - (void)setNamespace: (OFString*)ns_ { - OF_SETTER(ns, ns_, YES, YES) + OF_SETTER(ns, ns_, YES, 1) } - (OFString*)namespace { OF_GETTER(ns, YES) @@ -409,11 +409,10 @@ OF_GETTER(attributes, YES) } - (void)setChildren: (OFArray*)children_ { - /* 2 = mutableCopy */ OF_SETTER(children, children_, YES, 2) } - (OFArray*)children { @@ -432,22 +431,22 @@ - (OFString*)stringValue { OFAutoreleasePool *pool; OFMutableString *ret; - OFXMLElement **cArray; + OFXMLElement **objects; size_t i, count = [children count]; if (count == 0) return @""; ret = [OFMutableString string]; - cArray = [children cArray]; + objects = [children objects]; pool = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count; i++) { - [ret appendString: [cArray[i] stringValue]]; + [ret appendString: [objects[i] stringValue]]; [pool releaseObjects]; } [ret makeImmutable]; @@ -463,11 +462,11 @@ { OFAutoreleasePool *pool, *pool2; char *cString; size_t length, i, j, attributesCount; OFString *prefix, *parentPrefix; - OFXMLAttribute **attributesCArray; + OFXMLAttribute **attributesObjects; OFString *ret; OFString *defaultNS; pool = [[OFAutoreleasePool alloc] init]; @@ -549,26 +548,26 @@ i += [ns UTF8StringLength]; cString[i++] = '\''; } /* Attributes */ - attributesCArray = [attributes cArray]; + attributesObjects = [attributes objects]; attributesCount = [attributes count]; pool2 = [[OFAutoreleasePool alloc] init]; for (j = 0; j < attributesCount; j++) { - OFString *attributeName = [attributesCArray[j] name]; + OFString *attributeName = [attributesObjects[j] name]; OFString *attributePrefix = nil; OFString *tmp = - [[attributesCArray[j] stringValue] stringByXMLEscaping]; + [[attributesObjects[j] stringValue] stringByXMLEscaping]; - if ([attributesCArray[j] namespace] != nil && + if ([attributesObjects[j] namespace] != nil && (attributePrefix = [allNamespaces objectForKey: - [attributesCArray[j] namespace]]) == nil) + [attributesObjects[j] namespace]]) == nil) @throw [OFUnboundNamespaceException exceptionWithClass: isa - namespace: [attributesCArray[j] + namespace: [attributesObjects[j] namespace]]; length += [attributeName UTF8StringLength] + (attributePrefix != nil ? [attributePrefix UTF8StringLength] + 1 : 0) + @@ -601,21 +600,22 @@ [pool2 releaseObjects]; } /* Childen */ if (children != nil) { - OFXMLElement **childrenCArray = [children cArray]; + OFXMLElement **childrenObjects = [children objects]; size_t childrenCount = [children count]; OFDataArray *tmp = [OFDataArray dataArray]; BOOL indent; if (indentation > 0) { indent = YES; for (j = 0; j < childrenCount; j++) { - if (childrenCArray[j]->isa == charactersClass || - childrenCArray[j]->isa == CDATAClass) { + if ([childrenObjects[j] isKindOfClass: + charactersClass] || [childrenObjects[j] + isKindOfClass: CDATAClass]) { indent = NO; break; } } } else @@ -626,19 +626,19 @@ unsigned int ind = (indent ? indentation : 0); if (ind) [tmp addItem: "\n"]; - if ([childrenCArray[j] isKindOfClass: + if ([childrenObjects[j] isKindOfClass: [OFXMLElement class]]) - child = [childrenCArray[j] + child = [childrenObjects[j] _XMLStringWithParent: self namespaces: allNamespaces indentation: ind level: level + 1]; else - child = [childrenCArray[j] + child = [childrenObjects[j] XMLStringWithIndentation: ind level: level + 1]; [tmp addNItems: [child UTF8StringLength] fromCArray: [child UTF8String]]; @@ -827,49 +827,49 @@ [pool release]; } - (OFXMLAttribute*)attributeForName: (OFString*)attributeName { - OFXMLAttribute **cArray = [attributes cArray]; + OFXMLAttribute **objects = [attributes objects]; size_t i, count = [attributes count]; for (i = 0; i < count; i++) - if (cArray[i]->ns == nil && - [cArray[i]->name isEqual: attributeName]) - return cArray[i]; + if (objects[i]->ns == nil && + [objects[i]->name isEqual: attributeName]) + return objects[i]; return nil; } - (OFXMLAttribute*)attributeForName: (OFString*)attributeName namespace: (OFString*)attributeNS { - OFXMLAttribute **cArray; + OFXMLAttribute **objects; size_t i, count; if (attributeNS == nil) return [self attributeForName: attributeName]; - cArray = [attributes cArray]; + objects = [attributes objects]; count = [attributes count]; for (i = 0; i < count; i++) - if ([cArray[i]->ns isEqual: attributeNS] && - [cArray[i]->name isEqual: attributeName]) - return cArray[i]; + if ([objects[i]->ns isEqual: attributeNS] && + [objects[i]->name isEqual: attributeName]) + return objects[i]; return nil; } - (void)removeAttributeForName: (OFString*)attributeName { - OFXMLAttribute **cArray = [attributes cArray]; + OFXMLAttribute **objects = [attributes objects]; size_t i, count = [attributes count]; for (i = 0; i < count; i++) { - if (cArray[i]->ns == nil && - [cArray[i]->name isEqual: attributeName]) { + if (objects[i]->ns == nil && + [objects[i]->name isEqual: attributeName]) { [attributes removeObjectAtIndex: i]; return; } } @@ -876,22 +876,22 @@ } - (void)removeAttributeForName: (OFString*)attributeName namespace: (OFString*)attributeNS { - OFXMLAttribute **cArray; + OFXMLAttribute **objects; size_t i, count; if (attributeNS == nil) return [self removeAttributeForName: attributeName]; - cArray = [attributes cArray]; + objects = [attributes objects]; count = [attributes count]; for (i = 0; i < count; i++) { - if ([cArray[i]->ns isEqual: attributeNS] && - [cArray[i]->name isEqual: attributeName]) { + if ([objects[i]->ns isEqual: attributeNS] && + [objects[i]->name isEqual: attributeName]) { [attributes removeObjectAtIndex: i]; return; } } } @@ -924,11 +924,11 @@ OF_GETTER(defaultNamespace, YES) } - (void)setDefaultNamespace: (OFString*)ns_ { - OF_SETTER(defaultNamespace, ns_, YES, YES) + OF_SETTER(defaultNamespace, ns_, YES, 1) } - (void)addChild: (OFXMLNode*)child { if ([child isKindOfClass: [OFXMLAttribute class]]) @@ -963,50 +963,50 @@ } - (OFArray*)elements { OFMutableArray *ret = [OFMutableArray array]; - OFXMLElement **cArray = [children cArray]; + OFXMLElement **objects = [children objects]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if ([cArray[i] isKindOfClass: [OFXMLElement class]]) - [ret addObject: cArray[i]]; + if ([objects[i] isKindOfClass: [OFXMLElement class]]) + [ret addObject: objects[i]]; [ret makeImmutable]; return ret; } - (OFArray*)elementsForName: (OFString*)elementName { OFMutableArray *ret = [OFMutableArray array]; - OFXMLElement **cArray = [children cArray]; + OFXMLElement **objects = [children objects]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if ([cArray[i] isKindOfClass: [OFXMLElement class]] && - cArray[i]->ns == nil && - [cArray[i]->name isEqual: elementName]) - [ret addObject: cArray[i]]; + if ([objects[i] isKindOfClass: [OFXMLElement class]] && + objects[i]->ns == nil && + [objects[i]->name isEqual: elementName]) + [ret addObject: objects[i]]; [ret makeImmutable]; return ret; } - (OFArray*)elementsForNamespace: (OFString*)elementNS { OFMutableArray *ret = [OFMutableArray array]; - OFXMLElement **cArray = [children cArray]; + OFXMLElement **objects = [children objects]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if ([cArray[i] isKindOfClass: [OFXMLElement class]] && - cArray[i]->name != nil && - [cArray[i]->ns isEqual: elementNS]) - [ret addObject: cArray[i]]; + if ([objects[i] isKindOfClass: [OFXMLElement class]] && + objects[i]->name != nil && + [objects[i]->ns isEqual: elementNS]) + [ret addObject: objects[i]]; [ret makeImmutable]; return ret; } @@ -1013,25 +1013,25 @@ - (OFArray*)elementsForName: (OFString*)elementName namespace: (OFString*)elementNS { OFMutableArray *ret; - OFXMLElement **cArray; + OFXMLElement **objects; size_t i, count; if (elementNS == nil) return [self elementsForName: elementName]; ret = [OFMutableArray array]; - cArray = [children cArray]; + objects = [children objects]; count = [children count]; for (i = 0; i < count; i++) - if ([cArray[i] isKindOfClass: [OFXMLElement class]] && - [cArray[i]->ns isEqual: elementNS] && - [cArray[i]->name isEqual: elementName]) - [ret addObject: cArray[i]]; + if ([objects[i] isKindOfClass: [OFXMLElement class]] && + [objects[i]->ns isEqual: elementNS] && + [objects[i]->name isEqual: elementName]) + [ret addObject: objects[i]]; [ret makeImmutable]; return ret; } Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -88,30 +88,30 @@ withPrefix: (OFString*)prefix namespace: (OFString*)ns attributes: (OFArray*)attributes { OFXMLElement *element; - OFXMLAttribute **cArray; + OFXMLAttribute **objects; size_t i, count; element = [OFXMLElement elementWithName: name namespace: ns]; - cArray = [attributes cArray]; + objects = [attributes objects]; count = [attributes count]; for (i = 0; i < count; i++) { - if ([cArray[i] namespace] == nil && - [[cArray[i] name] isEqual: @"xmlns"]) + if ([objects[i] namespace] == nil && + [[objects[i] name] isEqual: @"xmlns"]) continue; - if ([[cArray[i] namespace] + if ([[objects[i] namespace] isEqual: @"http://www.w3.org/2000/xmlns/"]) - [element setPrefix: [cArray[i] name] - forNamespace: [cArray[i] stringValue]]; + [element setPrefix: [objects[i] name] + forNamespace: [objects[i] stringValue]]; - [element addAttribute: cArray[i]]; + [element addAttribute: objects[i]]; } [[stack lastObject] addChild: element]; [stack addObject: element]; } Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -96,20 +96,20 @@ } static OFString* namespace_for_prefix(OFString *prefix, OFArray *namespaces) { - OFDictionary **cArray = [namespaces cArray]; + OFDictionary **objects = [namespaces objects]; ssize_t i; if (prefix == nil) prefix = @""; for (i = [namespaces count] - 1; i >= 0; i--) { OFString *tmp; - if ((tmp = [cArray[i] objectForKey: prefix]) != nil) + if ((tmp = [objects[i] objectForKey: prefix]) != nil) return tmp; } return nil; } @@ -187,10 +187,11 @@ OFMutableDictionary *dict; cache = [[OFBigDataArray alloc] init]; previous = [[OFMutableArray alloc] init]; namespaces = [[OFMutableArray alloc] init]; + attributes = [[OFMutableArray alloc] init]; pool = [[OFAutoreleasePool alloc] init]; dict = [OFMutableDictionary dictionaryWithKeysAndObjects: @"xml", @"http://www.w3.org/XML/1998/namespace", @"xmlns", @"http://www.w3.org/2000/xmlns/", nil]; @@ -668,11 +669,11 @@ i: (size_t*)i last: (size_t*)last { OFAutoreleasePool *pool; OFString *ns; - OFXMLAttribute **attributesCArray; + OFXMLAttribute **attributesObjects; size_t j, attributesCount; if (buffer[*i] != '>' && buffer[*i] != '/') { if (buffer[*i] != ' ' && buffer[*i] != '\t' && buffer[*i] != '\n' && buffer[*i] != '\r') { @@ -682,21 +683,21 @@ } return; } - attributesCArray = [attributes cArray]; + attributesObjects = [attributes objects]; attributesCount = [attributes count]; ns = namespace_for_prefix(prefix, namespaces); if (prefix != nil && ns == nil) @throw [OFUnboundNamespaceException exceptionWithClass: isa prefix: prefix]; for (j = 0; j < attributesCount; j++) - resolve_attribute_namespace(attributesCArray[j], namespaces, + resolve_attribute_namespace(attributesObjects[j], namespaces, isa); pool = [[OFAutoreleasePool alloc] init]; [delegate parser: self @@ -724,13 +725,12 @@ [pool release]; [name release]; [prefix release]; - [attributes release]; + [attributes removeAllObjects]; name = prefix = nil; - attributes = nil; *last = *i + 1; state = (buffer[*i] == '/' ? OF_XMLPARSER_EXPECT_CLOSE : OF_XMLPARSER_OUTSIDE_TAG); @@ -825,13 +825,10 @@ forKey: @""]; if ([attributePrefix isEqual: @"xmlns"]) [[namespaces lastObject] setObject: attributeValue forKey: attributeName]; - if (attributes == nil) - attributes = [[OFMutableArray alloc] init]; - [attributes addObject: [OFXMLAttribute attributeWithName: attributeName namespace: attributePrefix stringValue: attributeValue]]; Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -132,12 +132,13 @@ # import "atomic.h" #endif #ifdef OF_THREADS # import "OFThread.h" +# import "OFThreadPool.h" # import "threading.h" #endif #import "asprintf.h" #import "base64.h" #import "of_asprintf.h" #import "of_strptime.h" Index: src/atomic.h ================================================================== --- src/atomic.h +++ src/atomic.h @@ -31,17 +31,30 @@ of_atomic_add_int(volatile int *p, int i) { #if !defined(OF_THREADS) return (*p += i); #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - __asm__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); + if (sizeof(int) == 4) + __asm__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +# ifdef OF_AMD64_ASM + else if (sizeof(int) == 8) + __asm__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_add_and_fetch(p, i); #elif defined(OF_HAVE_OSATOMIC) @@ -81,15 +94,25 @@ static OF_INLINE void* of_atomic_add_ptr(void* volatile *p, intptr_t i) { #if !defined(OF_THREADS) return (*(char* volatile*)p += i); -#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) +#elif defined(OF_X86_ASM) __asm__ ( "lock\n\t" "xaddl %0, %2\n\t" "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void*)i; +#elif defined(OF_AMD64_ASM) + __asm__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" : "+&r"(i) : "r"(i), "m"(*p) ); return (void*)i; @@ -111,18 +134,32 @@ of_atomic_sub_int(volatile int *p, int i) { #if !defined(OF_THREADS) return (*p -= i); #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - __asm__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); + if (sizeof(int) == 4) + __asm__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +# ifdef OF_AMD64_ASM + else if (sizeof(int) == 8) + __asm__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_sub_and_fetch(p, i); #elif defined(OF_HAVE_OSATOMIC) @@ -163,16 +200,27 @@ static OF_INLINE void* of_atomic_sub_ptr(void* volatile *p, intptr_t i) { #if !defined(OF_THREADS) return (*(char* volatile*)p -= i); -#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) +#elif defined(OF_X86_ASM) __asm__ ( "negl %0\n\t" "lock\n\t" "xaddl %0, %2\n\t" "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void*)i; +#elif defined(OF_AMD64_ASM) + __asm__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" : "+&r"(i) : "r"(i), "m"(*p) ); return (void*)i; @@ -196,19 +244,34 @@ #if !defined(OF_THREADS) return ++*p; #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) uint32_t i; - __asm__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); + if (sizeof(int) == 4) + __asm__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); +# ifdef OF_AMD64_ASM + else if (sizeof(int) == 8) + __asm__ ( + "xorq %0, %0\n\t" + "incq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "incq %0" + : "=&r"(i) + : "m"(*p) + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_add_and_fetch(p, 1); #elif defined(OF_HAVE_OSATOMIC) @@ -254,19 +317,34 @@ #if !defined(OF_THREADS) return --*p; #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) uint32_t i; - __asm__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); + if (sizeof(int) == 4) + __asm__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); +# ifdef OF_AMD64_ASM + else if (sizeof(int) == 8) + __asm__ ( + "xorq %0, %0\n\t" + "decq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "decq %0" + : "=&r"(i) + : "m"(*p) + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_sub_and_fetch(p, 1); #elif defined(OF_HAVE_OSATOMIC) @@ -311,22 +389,40 @@ of_atomic_or_int(volatile unsigned int *p, unsigned int i) { #if !defined(OF_THREADS) return (*p |= i); #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - __asm__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %2, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0\n\t" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax" - ); + if (sizeof(int) == 4) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); +# ifdef OF_AMD64_ASM + if (sizeof(int) == 8) + __asm__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %2, %%rax\n\t" + "orq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax" + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_or_and_fetch(p, i); #elif defined(OF_HAVE_OSATOMIC) @@ -372,22 +468,40 @@ of_atomic_and_int(volatile unsigned int *p, unsigned int i) { #if !defined(OF_THREADS) return (*p &= i); #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - __asm__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %2, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0\n\t" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax" - ); + if (sizeof(int) == 4) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); +# ifdef OF_AMD64_ASM + if (sizeof(int) == 8) + __asm__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %2, %%rax\n\t" + "andq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax" + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_and_and_fetch(p, i); #elif defined(OF_HAVE_OSATOMIC) @@ -433,22 +547,40 @@ of_atomic_xor_int(volatile unsigned int *p, unsigned int i) { #if !defined(OF_THREADS) return (*p ^= i); #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - __asm__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %2, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchgl %0, %2\n\t" - "jne 0\n\t" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax" - ); + if (sizeof(int) == 4) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); +# ifdef OF_AMD64_ASM + if (sizeof(int) == 8) + __asm__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %2, %%rax\n\t" + "xorq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax" + ); +# endif + else + abort(); return i; #elif defined(OF_HAVE_GCC_ATOMIC_OPS) return __sync_xor_and_fetch(p, i); #elif defined(OF_HAVE_OSATOMIC) @@ -499,11 +631,11 @@ return YES; } return NO; #elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) - int r; + int32_t r; __asm__ ( "xorl %0, %0\n\t" "lock\n\t" "cmpxchg %2, %3\n\t" Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -59,10 +59,15 @@ #ifdef OF_BIG_ENDIAN # define OF_ENDIANESS_NATIVE OF_ENDIANESS_BIG_ENDIAN #else # define OF_ENDIANESS_NATIVE OF_ENDIANESS_LITTLE_ENDIAN #endif + +/* Hopefully no arch needs more than 16 bytes padding */ +#ifndef __BIGGEST_ALIGNMENT__ +# define __BIGGEST_ALIGNMENT__ 16 +#endif #ifdef __GNUC__ # if defined(__amd64__) || defined(__x86_64__) # define OF_AMD64_ASM # elif defined(__i386__) @@ -82,10 +87,13 @@ # define OF_PATH_DELIMITER '/' #else # define OF_PATH_DELIMITER '\\' #endif +extern id objc_getProperty(id, SEL, ptrdiff_t, BOOL); +extern void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, signed char); + #define OF_IVAR_OFFSET(ivar) ((intptr_t)&ivar - (intptr_t)self) #define OF_GETTER(ivar, atomic) \ return objc_getProperty(self, _cmd, OF_IVAR_OFFSET(ivar), atomic); #define OF_SETTER(ivar, value, atomic, copy) \ objc_setProperty(self, _cmd, OF_IVAR_OFFSET(ivar), value, atomic, copy); Index: src/objc_properties.m ================================================================== --- src/objc_properties.m +++ src/objc_properties.m @@ -64,11 +64,11 @@ return *(id*)(void*)((char*)self + offset); } void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, BOOL atomic, - BOOL copy) + signed char copy) { if (atomic) { id *ptr = (id*)(void*)((char*)self + offset); #ifdef OF_THREADS unsigned hash = SPINLOCK_HASH(ptr); @@ -82,15 +82,10 @@ switch (copy) { case 0: *ptr = [value retain]; break; case 2: - /* - * Apple uses this to indicate that the copy - * should be mutable. Please hit them for - * abusing a poor BOOL! - */ *ptr = [value mutableCopy]; break; default: *ptr = [value copy]; } Index: src/unicode.m ================================================================== --- src/unicode.m +++ src/unicode.m @@ -101,11 +101,11 @@ 0, 0, 0, 0, 571, 0, 0, 11390, 11391, 0, 577, 0, 0, 0, 0, 582, 0, 584, 0, 586, 0, 588, 0, 590, 11375, 11373, 11376, 385, 390, 0, 393, 394, 0, 399, 0, 400, 0, 0, 0, 0, - 403, 0, 0, 404, 0, 42893, 0, 0, + 403, 0, 0, 404, 0, 42893, 42922, 0, 407, 406, 0, 11362, 0, 0, 0, 412, 0, 11374, 413, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 11364, 0, 0, 422, 0, 0, 425, 0, 0, 0, 0, 430, 580, 433, 434, 581, 0, 0, 0, @@ -434,21 +434,21 @@ 0, 11464, 0, 11466, 0, 11468, 0, 11470, 0, 11472, 0, 11474, 0, 11476, 0, 11478, 0, 11480, 0, 11482, 0, 11484, 0, 11486, 0, 11488, 0, 11490, 0, 0, 0, 0, 0, 0, 0, 0, 11499, 0, 11501, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 11506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const of_unichar_t upper_page_45[0x100] = { 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, - 4288, 4289, 4290, 4291, 4292, 4293, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 4288, 4289, 4290, 4291, 4292, 4293, 0, 4295, + 0, 0, 0, 0, 0, 4301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -527,11 +527,11 @@ 0, 42856, 0, 42858, 0, 42860, 0, 42862, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42873, 0, 42875, 0, 0, 42878, 0, 42880, 0, 42882, 0, 42884, 0, 42886, 0, 0, 0, 0, 42891, 0, 0, 0, - 0, 42896, 0, 0, 0, 0, 0, 0, + 0, 42896, 0, 42898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42912, 0, 42914, 0, 42916, 0, 42918, 0, 42920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -848,12 +848,12 @@ 0, 0, 0, 0, 0, 0, 0, 0, 11520, 11521, 11522, 11523, 11524, 11525, 11526, 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, 11535, 11536, 11537, 11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, 11551, - 11552, 11553, 11554, 11555, 11556, 11557, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 11552, 11553, 11554, 11555, 11556, 11557, 0, 11559, + 0, 0, 0, 0, 0, 11565, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1029,11 +1029,11 @@ 11465, 0, 11467, 0, 11469, 0, 11471, 0, 11473, 0, 11475, 0, 11477, 0, 11479, 0, 11481, 0, 11483, 0, 11485, 0, 11487, 0, 11489, 0, 11491, 0, 0, 0, 0, 0, 0, 0, 0, 11500, 0, 11502, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const of_unichar_t lower_page_166[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, @@ -1087,14 +1087,14 @@ 42857, 0, 42859, 0, 42861, 0, 42863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42874, 0, 42876, 0, 7545, 42879, 0, 42881, 0, 42883, 0, 42885, 0, 42887, 0, 0, 0, 0, 42892, 0, 613, 0, 0, - 42897, 0, 0, 0, 0, 0, 0, 0, + 42897, 0, 42899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42913, 0, 42915, 0, 42917, 0, 42919, 0, - 42921, 0, 0, 0, 0, 0, 0, 0, + 42921, 0, 614, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -71,11 +71,12 @@ echo "Uploading files to iOS device ${IOS_HOST} at ${IOS_TMP}..." ssh ${IOS_USER}@${IOS_HOST} \ 'rm -fr ${IOS_TMP} && mkdir -p ${IOS_TMP}/plugin' scp -q ../src/libobjfw.dylib tests testfile.bin testfile.txt \ serialization.xml ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/ - scp -q plugin/TestPlugin.impl ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/plugin/ + scp -q plugin/TestPlugin.bundle \ + ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/plugin/ echo "Running tests binary on iOS device ${IOS_HOST}..." ssh ${IOS_USER}@${IOS_HOST} \ 'cd ${IOS_TMP} && ${TEST_LAUNCHER} ./tests' EBOOT.PBP: ${PROG_NOINST} Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -27,12 +27,11 @@ static OFString *module = @"OFArray"; static OFString *c_ary[] = { @"Foo", @"Bar", - @"Baz", - nil + @"Baz" }; @implementation TestsAppDelegate (OFArrayTests) - (void)arrayTests { @@ -47,16 +46,14 @@ TEST(@"+[array]", (m[0] = [OFMutableArray array])) TEST(@"+[arrayWithObjects:]", (a[0] = [OFArray arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) - TEST(@"+[arrayWithCArray:]", (a[1] = [OFArray arrayWithCArray: c_ary])) - - TEST(@"+[arrayWithCArray:length:]", - (a[2] = [OFArray arrayWithCArray: c_ary - length: 3]) && - [a[2] isEqual: a[1]]) + TEST(@"+[arrayWithObjects:count:]", + (a[1] = [OFArray arrayWithObjects: c_ary + count: 3]) && + [a[1] isEqual: a[0]]) TEST(@"-[description]", [[a[0] description ]isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) TEST(@"-[addObject:]", R([m[0] addObject: c_ary[0]]) && Index: tests/OFHTTPRequestTests.m ================================================================== --- tests/OFHTTPRequestTests.m +++ tests/OFHTTPRequestTests.m @@ -57,24 +57,27 @@ [cond signal]; [cond unlock]; client = [listener accept]; - if (![[client readLine] isEqual: @"GET /foo HTTP/1.0"]) + if (![[client readLine] isEqual: @"GET /foo HTTP/1.1"]) assert(0); if (![[client readLine] isEqual: [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, port]]) assert(0); + + if (![[client readLine] isEqual: @"Connection: close"]) + assert(0); if (![[client readLine] hasPrefix: @"User-Agent:"]) assert(0); if (![[client readLine] isEqual: @""]) assert(0); - [client writeString: @"HTTP/1.0 200 OK\r\n" + [client writeString: @"HTTP/1.1 200 OK\r\n" @"cONTeNT-lENgTH: 7\r\n" @"\r\n" @"foo\n" @"bar"]; [client close]; Index: tests/OFObjectTests.m ================================================================== --- tests/OFObjectTests.m +++ tests/OFObjectTests.m @@ -38,49 +38,49 @@ OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFObject *obj = [[[OFObject alloc] init] autorelease]; void *p, *q, *r; OFObject *o; MyObj *m; - - EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object", - OFMemoryNotPartOfObjectException, [obj freeMemory: (void*)1]) + char *tmp; TEST(@"Allocating 4096 bytes", (p = [obj allocMemoryWithSize: 4096]) != NULL) TEST(@"Freeing memory", R([obj freeMemory: p])) - EXPECT_EXCEPTION(@"Detect freeing of memory twice", - OFMemoryNotPartOfObjectException, [obj freeMemory: p]) - TEST(@"Allocating and freeing 4096 bytes 3 times", (p = [obj allocMemoryWithSize: 4096]) != NULL && (q = [obj allocMemoryWithSize: 4096]) != NULL && (r = [obj allocMemoryWithSize: 4096]) != NULL && R([obj freeMemory: p]) && R([obj freeMemory: q]) && R([obj freeMemory: r])) + tmp = [self allocMemoryWithSize: 1024]; + EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object", + OFMemoryNotPartOfObjectException, [obj freeMemory: tmp]) + EXPECT_EXCEPTION(@"Detect out of memory on alloc", - OFOutOfMemoryException, [obj allocMemoryWithSize: SIZE_MAX]) + OFOutOfMemoryException, [obj allocMemoryWithSize: SIZE_MAX - 128]) EXPECT_EXCEPTION(@"Detect out of memory on resize", OFOutOfMemoryException, { p = [obj allocMemoryWithSize: 1]; [obj resizeMemory: p - toSize: SIZE_MAX]; + toSize: SIZE_MAX - 128]; }) [obj freeMemory: p]; TEST(@"Allocate when trying to resize NULL", (p = [obj resizeMemory: NULL toSize: 1024]) != NULL) [obj freeMemory: p]; EXPECT_EXCEPTION(@"Detect resizing of memory not allocated by object", - OFMemoryNotPartOfObjectException, [obj resizeMemory: (void*)1 - toSize: 1024]) + OFMemoryNotPartOfObjectException, [obj resizeMemory: tmp + toSize: 2048]) + [self freeMemory: tmp]; TEST(@"+[description]", [[OFObject description] isEqual: @"OFObject"] && [[MyObj description] isEqual: @"MyObj"]) Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -24,11 +24,11 @@ OBJC="@OBJC@" OBJCFLAGS="@GNU_RUNTIME@ -fexceptions -fobjc-exceptions" OBJCFLAGS="$OBJCFLAGS -fconstant-string-class=OFConstantString" OBJCFLAGS="$OBJCFLAGS @NO_CONST_CFSTRINGS@ @BLOCKS_FLAGS@ @NO_WARN_UNUSED@" LIB_CFLAGS="@LIB_CFLAGS@" -LIB_LDFLAGS="@LIB_LDFLAGS@" +LIB_LDFLAGS='@LIB_LDFLAGS@' LIB_PREFIX="@LIB_PREFIX@" LIB_SUFFIX="@LIB_SUFFIX@" LDFLAGS="" LDFLAGS_REEXPORT="@LDFLAGS_REEXPORT@" LDFLAGS_RPATH="@LDFLAGS_RPATH@" @@ -35,11 +35,11 @@ LIBS="-L${libdir} -lobjfw @LIBS@" PLUGIN_CFLAGS="@PLUGIN_CFLAGS@" PLUGIN_LDFLAGS="@PLUGIN_LDFLAGS@" PLUGIN_SUFFIX="@PLUGIN_SUFFIX@" PROG_SUFFIX="@EXEEXT@" -VERSION="0.7-dev" +VERSION="@PACKAGE_VERSION@" show_help() { cat <<__EOF__ objfw-config: Available arguments are: @@ -106,11 +106,12 @@ printf "SHARED_LIB, LIB_MAJOR and " 2>&1 echo "and LIB_MINOR to be set!" 1>&2 exit 1 fi - printf "%s" "$LIB_LDFLAGS" + eval "printf '%s' \"$(echo $LIB_LDFLAGS | \ + sed 's/\$\$/$/g')\"" ;; --lib-prefix) if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then echo "LIB_MAJOR and LIB_MINOR need to be set!" \ 1>&2