Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -30,21 +30,27 @@ src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/objc_sync/objc_sync tests/plugin/Info.plist +tests/serialization_xml.m tests/terminal/terminal_tests +tests/testfile_bin.m +tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro +tests/tests.rpx utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -32,24 +32,30 @@ src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync tests/plugin/Info.plist +tests/serialization_xml.m tests/terminal/terminal_tests +tests/testfile_bin.m +tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro +tests/tests.rpx utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp ADDED .github/workflows/amiga-gcc.yml Index: .github/workflows/amiga-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/amiga-gcc.yml @@ -0,0 +1,37 @@ +name: amiga-gcc +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-amiga-lib + steps: + - name: Install dependencies + run: docker pull amigadev/crosstools:m68k-amigaos + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e PATH="/opt/m68k-amigaos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:m68k-amigaos \ + sh -c 'cd /objfw && ./configure --host=m68k-amigaos ${{ matrix.configure_flags }}' + - name: make + run: | + docker run \ + -e PATH="/opt/m68k-amigaos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:m68k-amigaos \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e PATH="/opt/m68k-amigaos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:m68k-amigaos \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/ios.yml Index: .github/workflows/ios.yml ================================================================== --- /dev/null +++ .github/workflows/ios.yml @@ -0,0 +1,35 @@ +name: ios +on: [push, pull_request] +jobs: + build: + runs-on: macos-latest + strategy: + matrix: + arch: + - arm64 + - x86_64 + configure_flags: + - + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + export IPHONEOS_DEPLOYMENT_TARGET="9.0" + if [ "${{ matrix.arch}}" = "x86_64" ]; then + sdk="iphonesimulator" + else + sdk="iphoneos" + fi + export OBJC="clang -isysroot $(xcrun --sdk $sdk --show-sdk-path)" + export OBJC="$OBJC -arch ${{ matrix.arch }}" + ./configure --host=${{ matrix.arch }}-apple-darwin \ + ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make install + run: sudo make install ADDED .github/workflows/macos-10.15.yml Index: .github/workflows/macos-10.15.yml ================================================================== --- /dev/null +++ .github/workflows/macos-10.15.yml @@ -0,0 +1,31 @@ +name: macos-10.15 +on: [push, pull_request] +jobs: + tests: + runs-on: macos-10.15 + strategy: + matrix: + configure_flags: + - + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/macos-11.yml Index: .github/workflows/macos-11.yml ================================================================== --- /dev/null +++ .github/workflows/macos-11.yml @@ -0,0 +1,31 @@ +name: macos-11 +on: [push, pull_request] +jobs: + tests: + runs-on: macos-11 + strategy: + matrix: + configure_flags: + - + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/morphos.yml Index: .github/workflows/morphos.yml ================================================================== --- /dev/null +++ .github/workflows/morphos.yml @@ -0,0 +1,37 @@ +name: morphos +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-amiga-lib + steps: + - name: Install dependencies + run: docker pull amigadev/crosstools:ppc-morphos + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e PATH="/opt/ppc-morphos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:ppc-morphos \ + sh -c 'cd /objfw && ./configure --host=ppc-morphos ${{ matrix.configure_flags }}' + - name: make + run: | + docker run \ + -e PATH="/opt/ppc-morphos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:ppc-morphos \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e PATH="/opt/ppc-morphos/bin:$PATH" \ + -v "$PWD:/objfw" \ + amigadev/crosstools:ppc-morphos \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/nintendo-3ds.yml Index: .github/workflows/nintendo-3ds.yml ================================================================== --- /dev/null +++ .github/workflows/nintendo-3ds.yml @@ -0,0 +1,35 @@ +name: nintendo-3ds +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitarm + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c 'cd /objfw && ./configure --host=arm-none-eabi --with-3ds' + - name: make + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/nintendo-ds.yml Index: .github/workflows/nintendo-ds.yml ================================================================== --- /dev/null +++ .github/workflows/nintendo-ds.yml @@ -0,0 +1,35 @@ +name: nintendo-ds +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitarm + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c 'cd /objfw && ./configure --host=arm-none-eabi --with-nds' + - name: make + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/nintendo-switch.yml Index: .github/workflows/nintendo-switch.yml ================================================================== --- /dev/null +++ .github/workflows/nintendo-switch.yml @@ -0,0 +1,35 @@ +name: nintendo-switch +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkita64 + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitA64/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkita64 \ + sh -c 'cd /objfw && ./configure --host=aarch64-none-elf --with-nintendo-switch' + - name: make + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitA64/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkita64 \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitA64/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkita64 \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/ubuntu-18.04-32bit.yml Index: .github/workflows/ubuntu-18.04-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-18.04, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="clang -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04-gcc-32bit.yml Index: .github/workflows/ubuntu-18.04-gcc-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-gcc-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-18.04, GCC, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib gobjc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04-gcc.yml Index: .github/workflows/ubuntu-18.04-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-gcc.yml @@ -0,0 +1,39 @@ +name: ubuntu-18.04, GCC +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gobjc libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04.yml Index: .github/workflows/ubuntu-18.04.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04.yml @@ -0,0 +1,39 @@ +name: ubuntu-18.04 +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-32bit.yml Index: .github/workflows/ubuntu-20.04-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-20.04, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="clang -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-gcc-32bit.yml Index: .github/workflows/ubuntu-20.04-gcc-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-gcc-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-20.04, GCC, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib gobjc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-gcc.yml Index: .github/workflows/ubuntu-20.04-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-gcc.yml @@ -0,0 +1,39 @@ +name: ubuntu-20.04, GCC +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gobjc libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04.yml Index: .github/workflows/ubuntu-20.04.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04.yml @@ -0,0 +1,39 @@ +name: ubuntu-20.04 +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/wii-u.yml Index: .github/workflows/wii-u.yml ================================================================== --- /dev/null +++ .github/workflows/wii-u.yml @@ -0,0 +1,35 @@ +name: wii-u +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitppc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c 'cd /objfw && ./configure --host=powerpc-eabi --with-wii-u' + - name: make + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c "cd /objfw && make -j$(nproc)" ADDED .github/workflows/wii.yml Index: .github/workflows/wii.yml ================================================================== --- /dev/null +++ .github/workflows/wii.yml @@ -0,0 +1,35 @@ +name: wii +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitppc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c 'cd /objfw && ./configure --host=powerpc-eabi --with-wii' + - name: make + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c "cd /objfw && make -j$(nproc)" + - name: make install + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c "cd /objfw && make -j$(nproc)" Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -32,24 +32,30 @@ src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync tests/plugin/Info.plist +tests/serialization_xml.m tests/terminal/terminal_tests +tests/testfile_bin.m +tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds +tests/tests.nro +tests/tests.rpx utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp Index: Doxyfile ================================================================== --- Doxyfile +++ Doxyfile @@ -1,15 +1,18 @@ PROJECT_NAME = "ObjFW" OUTPUT_DIRECTORY = docs/ INPUT = src src/exceptions src/runtime FILE_PATTERNS = *.h *.m HTML_OUTPUT = . +HAVE_DOT = NO GENERATE_LATEX = NO HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_MEMBERS = YES TYPEDEF_HIDES_STRUCT = YES PREDEFINED = __OBJC__ \ + _Nonnull \ + _Nullable \ DOXYGEN \ OF_BOXABLE \ OF_CONSUMED \ OF_DESIGNATED_INITIALIZER \ OF_GENERIC(...)= \ Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -14,10 +14,13 @@ .PHONY: docs release utils tests: src +check: tests + cd tests && ${MAKE} -s run + docs: rm -fr docs doxygen >/dev/null release: docs Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -103,10 +103,20 @@ * OS Versions: 10.5, 10.7-10.15, Darling * Architectures: PowerPC, PowerPC64, x86, x86_64 * Compilers: Clang 3.1-10.0, Apple GCC 4.0.1 & 4.2.1 * Runtimes: Apple, ObjFW + +MiNT +---- + + * OS Versions: FreeMiNT 1.19 + * Architectures: m68k + * Runtimes: ObjFW + * Compilers: GCC 4.6.4 (MiNT 20130415) + * Limitations: No shared libraries, no threads + MorphOS ------- * OS Versions: 3.14 @@ -142,10 +152,20 @@ * Compilers: GCC 4.8.2 (devkitARM release 42) * Runtimes: ObjFW * Limitations: No threads, no sockets * Notes: File support requires an argv-compatible launcher (such as HBMenu) + +Nintendo Switch +--------------- + + * OS Versions: yuzu 1093 + * Architectures: AArch64 + * Compilers: GCC 12.1.0 (devkitA64 release 19) + * Runtimes: ObjFW + * Limitations: No sockets, no shared libraries, not tested on real hardware + OpenBSD ------- * OS Versions: 5.2-6.7 @@ -189,20 +209,32 @@ * Architectures: PowerPC * Compilers: GCC 4.6.3 (devkitPPC release 26) * Runtimes: ObjFW * Limitations: No threads + +Wii U +----- + + * OS Versions: Cemu 12.26.2f + * Architectures: PowerPC + * Compilers: gcc version 12.1.0 (devkitPPC release 41) + * Runtimes: ObjFW + * Limitations: No files, no threads, no sockets, no shared libraries, not + tested on real hardware + Windows ------- - * OS Versions: 98 SE, NT 4.0, XP (x86), 7 (x64), 8 (x64), 8.1 (x64), 10, + * OS Versions: 98 SE, NT 4.0, XP (x86), 7 (x64), 8 (x64), 8.1 (x64), 10, 11, Wine (x86 & x64) - * Architectures: x86, x86_64 + * Architectures: x86, x86_64, AArch64 * Compilers: GCC 5.3.0 & 6.2.0 from msys2 (x86 & x64), Clang 3.9.0 from msys2 (x86), - Clang 10.0 from msys2 (x86 & x86_64) + Clang 10.0 from msys2 (x86 & x86_64), + Clang 14.0.4 from msys2 (AArch64) * Runtimes: ObjFW Others ------ Index: README.md ================================================================== --- README.md +++ README.md @@ -1,10 +1,10 @@ There are three ways you are probably reading this right now: - * On [ObjFW](https://objfw.nil.im/)'s homepage, via Fossil + * On [ObjFW](https://objfw.nil.im/)'s homepage, via Fossil's web interface * On [GitHub](https://github.com/ObjFW/ObjFW) - * Via an editor or pager, by opening `README.md` from a checkout or tarball + * Via an editor or pager, by opening `README.md` from a clone or tarball ObjFW is developed using Fossil, so if you are reading this on GitHub or any other place, you are most likely using a mirror. @@ -19,12 +19,11 @@ * [Building as a framework](#building-framework) * [Using the macOS or iOS framework in Xcode](#framework-in-xcode) * [Broken Xcode versions](#broken-xcode-versions) * [Windows](#windows) * [Getting MSYS2](#getting-msys2) - * [Updating MSYS2](#updating-msys2) - * [Installing MinGW-w64 using MSYS2](#installing-mingw-w64) + * [Setting up MSYS2](#setting-up-msys2) * [Getting, building and installing ObjFW](#steps-windows) * [Nintendo DS, Nintendo 3DS and Wii](#nintendo) * [Nintendo DS](#nintendo-ds) * [Nintendo 3DS](#nintendo-3ds) * [Wii](#wii) @@ -31,10 +30,12 @@ * [Amiga](#amiga) * [Writing your first application with ObjFW](#first-app) * [Documentation](#documentation) * [Bugs and feature requests](#bugs) * [Support and community](#support) + * [Donating](#donating) + * [Thanks](#thanks) * [Commercial use](#commercial-use)

What is ObjFW?

@@ -106,17 +107,16 @@

Fossil

Clone the Fossil repository like this: - $ fossil clone https://objfw.nil.im objfw.fossil - $ mkdir objfw && cd objfw - $ fossil open ../objfw.fossil + $ fossil clone https://objfw.nil.im You can then use Fossil's web interface to browse the timeline, tickets, wiki pages, etc.: + $ cd objfw $ fossil ui It's also possible to open the same local repository multiple times, so that you have multiple working directories all backed by the same local repository. @@ -123,10 +123,16 @@ In order to verify the signature of the currently checked out checkin, you can use: $ fossil artifact current | gpg --verify + + Please note that not all checkins are signed, as the signing key only resides + on trusted systems. This means that checkins I perform on e.g. Windows are + unsigned. However, usually it should not take long until there is another + signed checkin. Alternatively, you can go back until the last signed checkin + and review changes from there on.

Git

To clone the Git repository, use the following: @@ -139,11 +145,12 @@ To install ObjFW, just run the following commands: $ ./configure $ make - $ make install + $ make check + $ sudo make install In case you checked out ObjFW from the Fossil or Git repository, you need to run the following command first: $ ./autogen.sh @@ -151,27 +158,33 @@

macOS and iOS

Building as a framework

When building for macOS or iOS, everything is built as a `.framework` by - default if `--disable-shared` has not been specified to `configure`. + default if `--disable-shared` has not been specified to `./configure`. The + frameworks will end up in `$PREFIX/Library/Frameworks`. - To build for iOS, use something like this: + To build for macOS, just follow the + regular instructions above. + + To build for iOS, follow the regular instructions, but instead of + `./configure` do something like this: $ clang="clang -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" $ export OBJC="$clang -arch armv7 -arch arm64" $ export OBJCPP="$clang -arch armv7 -E" $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" $ ./configure --prefix=/usr/local/ios --host=arm64-apple-darwin - To build for the iOS simulator, use something like this: + To build for the iOS simulator, follow the regular instructions, but instead + of `./configure` use something like this: $ clang="clang -isysroot $(xcrun --sdk iphonesimulator --show-sdk-path)" - $ export OBJC="$clang -arch i386 -arch x86_64" - $ export OBJCPP="$clang -arch i386 -E" + $ export OBJC="$clang -arch arm64 -arch x86_64" + $ export OBJCPP="$clang -arch arm64 -E" $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" - $ ./configure --prefix=/usr/local/iossim --host=x86_64-apple-darwin + $ ./configure --prefix=/usr/local/iossim --host=arm64-apple-darwin

Using the macOS or iOS framework in Xcode

To use the macOS framework in Xcode, you need to add the `.framework`s to your project and add the following flags to `Other C Flags`: @@ -209,73 +222,61 @@

Getting MSYS2

The first thing to install is [MSYS2](https://www.msys2.org) to provide a basic UNIX-like environment for Windows. Unfortunately, the binaries are not - signed and there is no way to verify their integrity, so only download this - from a trusted connection. Everything else you will download using MSYS2 - later will be cryptographically signed. - -

Updating MSYS2

- - The first thing to do is updating MSYS2. It is important to update things in - a certain order, as `pacman` (the package manager MSYS2 uses, which comes - from Arch Linux) does not know about a few things that are special on - Windows. - - First, update the mirror list: - - $ pacman -Sy pacman-mirrors - - Then proceed to update the `msys2-runtime` itself, `bash` and `pacman`: - - $ pacman -S msys2-runtime bash pacman mintty - - Now close the current window and restart MSYS2, as the current window is now - defunct. In a new MSYS2 window, update the rest of MSYS2: - - $ pacman -Su - - Now you have a fully updated MSYS2. Whenever you want to update MSYS2, - proceed in this order. Notice that the first `pacman` invocation includes - `-y` to actually fetch a new list of packages. - -

Installing MinGW-w64 using MSYS2

- - Now it's time to install MinGW-w64. If you want to build 32 bit binaries: - - $ pacman -S mingw-w64-i686-clang mingw-w64-i686-gcc-objc - - For 64 bit binaries: - - $ pacman -S mingw-w64-x86_64-clang mingw-w64-x86_64-gcc-objc - - There is nothing wrong with installing them both, as MSYS2 has created two - entries in your start menu: `MinGW-w64 Win32 Shell` and - `MinGW-w64 Win64 Shell`. So if you want to build for 32 or 64 bit, you just - start the correct shell. - - Finally, install a few more things needed to build ObjFW: - - $ pacman -S autoconf automake fossil make + signed, so make sure you download it via HTTPS. However, packages you + download and install via MSYS2 are cryptographically signed. + +

Setting up MSYS2

+ + MSYS2 currently supports 5 different + [environments](https://www.msys2.org/docs/environments/). All of them except + for the one called just "MSYS" are supported, but which packages you need to + install depends on the environment(s) you want to use. + + For MINGW64, use: + + $ pacman -Syu mingw-w64-x86_64-clang mingw-w64-x86_64-fossil + + For UCRT64, use: + + $ pacman -Syu mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-fossil + + For CLANG64, use: + + $ pacman -Syu mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-fossil + + For MINGW32, use: + + $ pacman -Syu mingw-w64-i686-clang mingw-w64-i686-fossil + + When using `pacman` to install the packages, `pacman` might tell you to close + the window. If it does so, close the window, restart MSYS2 and execute the + `pacman` command again. + + There is nothing wrong with installing multiple environments, as MSYS2 has + created shortcuts for each of them in your start menu. Just make sure to use + the correct shortcut for the environment you want to use. + + Finally, install a few more things that are common between all environments: + + $ pacman -S autoconf automake make

Getting, building and installing ObjFW

- Start the MinGW-w64 Win32 or Win64 Shell (depening on what version you want - to build - do *not* use the MSYS2 Shell shortcut, but use the MinGW-w64 Win32 - or Win64 Shell shortcut instead!) and check out ObjFW: - - $ fossil clone https://objfw.nil.im objfw.fossil - $ mkdir objfw && cd objfw - $ fossil open ../objfw.fossil - - You can also download a release tarball if you want. Now go to the newly + Start the MSYS2 using the shortcut for the environment you want to use and + check out ObjFW: + + $ fossil clone https://objfw.nil.im + + You can also download a release tarball if you want. Now `cd` to the newly checked out repository and build and install it: $ ./autogen.sh && ./configure && make -j16 install - If everything was successfully, you can now build projects using ObjFW for + If everything was successful, you can now build projects using ObjFW for Windows using the normal `objfw-compile` and friends.

Nintendo DS, Nintendo 3DS and Wii

Download and install [devkitPro](https://devkitpro.org/wiki/Getting_Started). @@ -368,12 +369,27 @@ * A [Gitter room](https://gitter.im/ObjFW/ObjFW), bridged to the Matrix room above Please don't hesitate to join any or all of those! + +

Donating

+ + If you want to donate to ObjFW, you can read about possible ways to do so + [here](https://objfw.nil.im/wiki?name=Donating). + + +

Thanks

+ + * Thank you to [Jonathan Neuschäfer](https://github.com/neuschaefer) for + reviewing the *entirety* (all 84k LoC at the time) of ObjFW's codebase in + 2017! + * Thank you to [Hill Ma](https://github.com/mahiuchun) for donating an M1 Mac + Mini to the project! +

Commercial use

If for whatever reason neither the terms of the QPL nor those of the GPL work for you, a proprietary license for ObjFW including support is available upon request. Just write a mail to js@nil.im and we can find a reasonable solution for both parties. Index: build-aux/m4/buildsys.m4 ================================================================== --- build-aux/m4/buildsys.m4 +++ build-aux/m4/buildsys.m4 @@ -24,10 +24,13 @@ AC_DEFUN([BUILDSYS_INIT], [ AC_REQUIRE([AC_CANONICAL_BUILD]) AC_REQUIRE([AC_CANONICAL_HOST]) + AC_ARG_ENABLE(rpath, + AS_HELP_STRING([--disable-rpath], [do not use rpath])) + case "$build_os" in darwin*) case "$host_os" in darwin*) AC_SUBST(BUILD_AND_HOST_ARE_DARWIN, yes) @@ -180,11 +183,13 @@ LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}' LIB_LDFLAGS_INSTALL_NAME='-Wl,-install_name,${libdir}/$${out%.dylib}.${LIB_MAJOR}.dylib' LIB_PREFIX='lib' LIB_SUFFIX='.dylib' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-bundle ${PLUGIN_LDFLAGS_BUNDLE_LOADER}' PLUGIN_SUFFIX='.bundle' AS_IF([test x"$host_is_ios" = x"yes"], [ LINK_PLUGIN='rm -fr $$out && ${MKDIR_P} $$out && if test -f Info.plist; then ${INSTALL} -m 644 Info.plist $$out/Info.plist; fi && ${LD} -o $$out/$${out%${PLUGIN_SUFFIX}} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS} && ${CODESIGN} -fs ${CODESIGN_IDENTITY} --timestamp=none $$out' @@ -198,21 +203,21 @@ CLEAN_LIB='' ;; *-*-mingw* | *-*-cygwin*) AC_MSG_RESULT(MinGW / Cygwin) LIB_CFLAGS='' - LIB_LDFLAGS='-shared -Wl,--export-all-symbols,--out-implib,lib$$out.a' + LIB_LDFLAGS='-shared -Wl,--export-all-symbols' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='' - LIB_SUFFIX='.dll' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + LIB_SUFFIX='${LIB_MAJOR}.dll' + LINK_LIB='&& ${LN_S} $$out lib$${out%${LIB_SUFFIX}}.dll.a' PLUGIN_CFLAGS='' - PLUGIN_LDFLAGS='-shared' + PLUGIN_LDFLAGS='-shared -Wl,--export-all-symbols' PLUGIN_SUFFIX='.dll' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' - INSTALL_LIB='&& ${MKDIR_P} ${DESTDIR}${bindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/$$i && ${INSTALL} -m 755 lib$$i.a ${DESTDIR}${libdir}/lib$$i.a' - UNINSTALL_LIB='&& rm -f ${DESTDIR}${bindir}/$$i ${DESTDIR}${libdir}/lib$$i.a' + INSTALL_LIB='&& ${MKDIR_P} ${DESTDIR}${bindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/$$i && ${INSTALL} -m 755 lib$${i%${LIB_SUFFIX}}.dll.a ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a' + UNINSTALL_LIB='&& rm -f ${DESTDIR}${bindir}/$$i ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a' INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='${SHARED_LIB}.a ${SHARED_LIB_NOINST}.a' ;; *-*-openbsd* | *-*-mirbsd*) @@ -220,11 +225,13 @@ LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-shared' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.so.${LIB_MAJOR}.${LIB_MINOR}' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.so' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i' @@ -238,11 +245,13 @@ LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}.${LIB_MINOR}' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.so' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.so' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR} && rm -f ${DESTDIR}${libdir}/$$i && ${LN_S} $$i.${LIB_MAJOR}.${LIB_MINOR} ${DESTDIR}${libdir}/$$i' @@ -256,11 +265,10 @@ LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.so' - LDFLAGS_RPATH='' PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.so' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0 && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i' @@ -275,11 +283,13 @@ LIB_LDFLAGS='-shared -Wl,+h,$$out' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.${LIB_MAJOR}' LINK_LIB='&& rm -f $${out%%.*}.sl && ${LN_S} $$out $${out%%.*}.sl' - LDFLAGS_RPATH='-Wl,+b,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,+b,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.sl' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.sl' @@ -294,11 +304,13 @@ LIB_LDFLAGS='-shared -Wl,+h,$$out' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.${LIB_MAJOR}' LINK_LIB='&& rm -f $${out%%.*}.so && ${LN_S} $$out $${out%%.*}.so' - LDFLAGS_RPATH='-Wl,+b,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,+b,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.so' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.so' @@ -312,11 +324,13 @@ LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.so' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + AS_IF([test x"$enable_rpath" != x"no"], [ + LDFLAGS_RPATH='-Wl,-rpath,${libdir}' + ]) PLUGIN_CFLAGS='-fPIC -DPIC' PLUGIN_LDFLAGS='-shared' PLUGIN_SUFFIX='.so' LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0 && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i' ADDED build-aux/m4/pkg.m4 Index: build-aux/m4/pkg.m4 ================================================================== --- /dev/null +++ build-aux/m4/pkg.m4 @@ -0,0 +1,343 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 11 (pkg-config-0.29.1) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------ +dnl +dnl Prepare a "--with-" configure option using the lowercase +dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +dnl PKG_CHECK_MODULES in a single macro. +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +])dnl PKG_WITH_MODULES + +dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ----------------------------------------------- +dnl +dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +dnl check._[VARIABLE-PREFIX] is exported as make variable. +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +])dnl PKG_HAVE_WITH_MODULES + +dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------------------ +dnl +dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +dnl and preprocessor variable. +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +])dnl PKG_HAVE_DEFINE_WITH_MODULES Index: buildsys.mk.in ================================================================== --- buildsys.mk.in +++ buildsys.mk.in @@ -210,11 +210,11 @@ done if test x"${includesubdir}" = x"${COPY_HEADERS_IF_SUBDIR}"; then \ for i in "" ${INCLUDES}; do \ test x"$$i" = x"" && continue; \ - ${MKDIR_P} ${COPY_HEADERS_DESTINATION} || exit $$?; \ + ${MKDIR_P} $$(dirname ${COPY_HEADERS_DESTINATION}/$$i) || exit $$?; \ ${INSTALL} -m 644 $$i ${COPY_HEADERS_DESTINATION}/$$i || exit $$?; \ done \ fi ${AMIGA_LIB} ${AMIGA_LIB_NOINST}: ${EXT_DEPS} ${AMIGA_LIB_OBJS_START} ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA} @@ -731,11 +731,11 @@ if test x"${INSTALL_INCLUDES}" = x"yes"; then \ for i in "" ${INCLUDES}; do \ test x"$$i" = x"" && continue; \ ${INSTALL_STATUS}; \ - if ${MKDIR_P} ${DESTDIR}${includedir}/${includesubdir} && ${INSTALL} -m 644 $$i ${DESTDIR}${includedir}/${includesubdir}/$$i; then \ + if ${MKDIR_P} $$(dirname ${DESTDIR}${includedir}/${includesubdir}/$$i) && ${INSTALL} -m 644 $$i ${DESTDIR}${includedir}/${includesubdir}/$$i; then \ ${INSTALL_OK}; \ else \ ${INSTALL_FAILED}; \ fi \ done \ Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1,6 +1,6 @@ -AC_INIT(ObjFW, 1.1-dev, js@nil.im) +AC_INIT(ObjFW, 1.1dev, js@nil.im) AC_CONFIG_SRCDIR(src) AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_MACRO_DIR(build-aux/m4) AC_DEFINE(OBJFW_VERSION_MAJOR, 1, [The major version of ObjFW]) @@ -44,14 +44,16 @@ LDFLAGS="$LDFLAGS -noixemul" LIBS="$LIBS -ldebug" enable_files="yes" # Required for reading ENV: enable_shared="no" + with_tls="no" supports_amiga_lib="yes" AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFWRT_AMIGA_LIB, objfwrt68k.library) + AC_SUBST(OBJFWRT_AMIGA_LIB, + ['objfwrt${OBJFWRT_LIB_MAJOR}.library']) dnl For 68000, GCC emits calls to helper functions that dnl do not work properly in a library. t="-mcpu=68020 -fbaserel -noixemul -ffreestanding" AC_SUBST(AMIGA_LIB_CFLAGS, $t) t="$t -resident -nostartfiles -nodefaultlibs -ldebug -lc" @@ -63,10 +65,11 @@ powerpc-*-amigaos*) CPPFLAGS="$CPPFLAGS -D__USE_INLINE__" enable_files="yes" # Required for reading ENV: enable_shared="no" + with_tls="no" AC_SUBST(LIBBASES_M, libbases.m) ;; *-morphos*) AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O2 -g"]) @@ -78,11 +81,12 @@ enable_files="yes" # Required for reading ENV: enable_shared="no" supports_amiga_lib="yes" AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFWRT_AMIGA_LIB, objfwrt.library) + AC_SUBST(OBJFWRT_AMIGA_LIB, + ['objfwrt${OBJFW_LIB_MAJOR}ppc.library']) t="-mresident32 -ffreestanding -noixemul" AC_SUBST(AMIGA_LIB_CFLAGS, $t) t="-mresident32 -nostartfiles -nodefaultlibs -noixemul -ldebug" AC_SUBST(AMIGA_LIB_LDFLAGS, "$t -lc") ]) @@ -133,10 +137,15 @@ dnl also used for .S files. OBJCFLAGS="$OBJCFLAGS -include inttypes.h" dnl We need -latomic for GCC's atomics to work. LIBS="$LIBS -latomic" ;; +*-*-mint*) + enable_shared="no" + enable_threads="no" # TODO + with_tls="no" + ;; esac AS_IF([test x"$host_os" = x"msdosdjgpp" -a x"$build_os" = x"msdosdjgpp"], [ dnl Hack to make configure find these on DOS. : ${AR:=ar.exe} @@ -171,18 +180,43 @@ flags="-mrvl -mcpu=750 -meabi -mhard-float" OBJCFLAGS="$OBJCFLAGS $flags" OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" CPPFLAGS="$CPPFLAGS -DGEKKO -I$DEVKITPRO/libogc/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DGEKKO -I\$DEVKITPRO/libogc/include" LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -meabi -mhard-float" LIBS="$LIBS -L$DEVKITPRO/libogc/lib/wii -lfat -logc" TESTS_LIBS="$TESTS_LIBS -lwiiuse -lbte" enable_shared="no" enable_threads="no" # TODO + with_tls="no" AC_DEFINE(OF_WII, 1, [Whether we are compiling for Wii]) - OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DGEKKO -I\$DEVKITPRO/libogc/include" + AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) +]) + +AC_ARG_WITH(wii-u, + AS_HELP_STRING([--with-wii-u], [build for Wii U])) +AS_IF([test x"$with_wii_u" = x"yes"], [ + AS_IF([test x"$DEVKITPRO" = x""], [ + AC_MSG_ERROR([DEVKITPRO is not set! Please set DEVKITPRO.]) + ]) + + flags="-mcpu=750 -meabi -mhard-float" + OBJCFLAGS="$OBJCFLAGS $flags" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" + CPPFLAGS="-isystem $DEVKITPRO/wut/include -D__WIIU__ -D__WUT__" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -isystem \$DEVKITPRO/wut/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -D__WIIU__ -D__WUT__" + LDFLAGS="-specs=$DEVKITPRO/wut/share/wut.specs" + LIBS="-L$DEVKITPRO/wut/lib -L$DEVKITPRO/wut/lib/stubs -lwut" + enable_files="no" # TODO + enable_shared="no" # TODO + enable_threads="no" # TODO + enable_sockets="no" # TODO + + AC_DEFINE(OF_WII_U, 1, [Whether we are compiling for Wii U]) AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) AC_ARG_WITH(nds, AS_HELP_STRING([--with-nds], [build for Nintendo DS])) @@ -193,20 +227,20 @@ flags="-march=armv5te -mtune=arm946e-s -mthumb -mthumb-interwork" OBJCFLAGS="$OBJCFLAGS $flags" OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" CPPFLAGS="$CPPFLAGS -DARM9 -I$DEVKITPRO/libnds/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DARM9 -I\$DEVKITPRO/libnds/include" ASFLAGS="$ASFLAGS -march=armv5te" LDFLAGS="$LDFLAGS -specs=ds_arm9.specs" LIBS="$LIBS -L$DEVKITPRO/libnds/lib -lfilesystem -lfat -lnds9" enable_shared="no" enable_threads="no" # TODO enable_sockets="no" # TODO check_pedantic="no" AC_DEFINE(OF_NINTENDO_DS, 1, [Whether we are compiling for Nintendo DS]) - OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DARM9 -I\$DEVKITPRO/libnds/include" AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) AC_ARG_WITH(3ds, AS_HELP_STRING([--with-3ds], [build for Nintendo 3DS])) @@ -218,23 +252,48 @@ flags="-march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft" flags="$flags -mword-relocations" OBJCFLAGS="$OBJCFLAGS $flags" OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" CPPFLAGS="$CPPFLAGS -DARM11 -I$DEVKITPRO/libctru/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DARM11 -I\$DEVKITPRO/libctru/include" ASFLAGS="$ASFLAGS -march=armv6k" LDFLAGS="$LDFLAGS -specs=3dsx.specs -march=armv6k -mtune=mpcore" LDFLAGS="$LDFLAGS -mfloat-abi=hard -mtp=soft -mword-relocations" LIBS="$LIBS -L$DEVKITPRO/libctru/lib -lctru" enable_shared="no" enable_threads="no" # TODO + with_tls="no" check_pedantic="no" AC_DEFINE(OF_NINTENDO_3DS, 1, [Whether we are compiling for Nintendo 3DS]) - OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -DARM11 -I\$DEVKITPRO/libctru/include" AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) + +AC_ARG_WITH(nintendo-switch, + AS_HELP_STRING([--with-nintendo-switch], [build for Nintendo Switch])) +AS_IF([test x"$with_nintendo_switch" = x"yes"], [ + AS_IF([test x"$DEVKITPRO" = x""], [ + AC_MSG_ERROR([DEVKITPRO is not set! Please set DEVKITPRO.]) + ]) + + flags="-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE" + OBJCFLAGS="$OBJCFLAGS $flags" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" + CPPFLAGS="$CPPFLAGS -D__SWITCH__ -I$DEVKITPRO/libnx/include" + OBJFW_CPPFLAGS="$OBJFW_CPPFLAGS -D__SWITCH__ -I$DEVKITPRO/libnx/include" + ASFLAGS="$ASFLAGS $flags" + LDFLAGS="$LDFLAGS -specs=$DEVKITPRO/libnx/switch.specs $flags" + LIBS="$LIBS -L$DEVKITPRO/libnx/lib -lnx" + enable_shared="no" + enable_threads="yes" + enable_sockets="no" # TODO + check_pedantic="no" + + AC_DEFINE(OF_NINTENDO_SWITCH, 1, + [Whether we are compiling for Nintendo Switch]) +]) CPP="$OBJCPP" CPPFLAGS="$CPPFLAGS $OBJCPPFLAGS -DOF_COMPILING_OBJFW" flags="-fexceptions -fobjc-exceptions -funwind-tables" flags="$flags -fconstant-string-class=OFConstantString" @@ -258,19 +317,10 @@ ;; i?86-*-darwin* | x86_64-*-darwin*) dnl Don't use -no-integrated-as on Darwin. It breaks building dnl for the iOS simulator. ;; - i?86-*-* | x86_64-*-*) - dnl Many older Clang versions don't support jmp short. - ASFLAGS="$ASFLAGS -no-integrated-as" - ;; - *-*-mingw*) - dnl Clang's assembler on Windows is not complete yet and cannot - dnl compile all .S files. - ASFLAGS="$ASFLAGS -no-integrated-as" - ;; sparc64-*-*openbsd*) dnl Clang generates assembly output on SPARC64 that OpenBSD's dnl assembler does not accept. flag="-integrated-as" OBJCFLAGS="$OBJCFLAGS $flag" @@ -425,11 +475,11 @@ AC_MSG_CHECKING(whether we need -D_GNU_SOURCE) AC_EGREP_CPP(egrep_cpp_yes, [ #include #if defined(__GLIBC__) || defined(__MINGW32__) || \ - defined(__NEWLIB__) || defined(__MORPHOS__) + defined(__NEWLIB__) || defined(__MORPHOS__) || defined(__MINT__) egrep_cpp_yes #endif ], [ AC_MSG_RESULT(yes) CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS" @@ -640,10 +690,13 @@ OBJCFLAGS="$old_OBJCFLAGS" ;; esac case "$host_os" in +mint*) + dnl _Unwind_Backtrace crashes on MiNT + ;; hpux*) dnl _Unwind_Backtrace() returns complete garbage on HP-UX. ;; *) AC_CHECK_FUNCS(_Unwind_Backtrace) @@ -829,10 +882,14 @@ AC_CHECK_FUNCS(strtof truncf) AC_CHECK_FUNC(asprintf, [ case "$host" in + *-*-mint*) + dnl asprintf is not in headers + have_asprintf="no" + ;; *-*-mingw*) dnl asprintf from MinGW is broken on older Windows versions have_asprintf="no" ;; *-psp-*) @@ -980,10 +1037,11 @@ ;; esac AC_DEFINE(OF_HAVE_THREADS, 1, [Whether we have threads]) AC_SUBST(USE_SRCS_THREADS, '${SRCS_THREADS}') + AC_SUBST(OBJC_SYNC, objc_sync) AC_ARG_ENABLE(compiler-tls, AS_HELP_STRING([--disable-compiler-tls], [disable compiler thread local storage])) @@ -1336,10 +1394,13 @@ AC_CHECK_HEADER(netinet/tcp.h, [ AC_DEFINE(OF_HAVE_NETINET_TCP_H, 1, [Whether we have netinet/tcp.h]) ]) AC_CHECK_HEADERS([arpa/inet.h netdb.h]) + AC_CHECK_HEADER(sys/un.h, [ + AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h]) + ]) AC_CHECK_HEADER(netipx/ipx.h, [ AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1, [Whether we have netipx/ipx.h]) ]) @@ -1369,10 +1430,13 @@ #endif ], [ AC_DEFINE(OF_HAVE_IPV6, 1, [Whether we have IPv6]) ]) ], [ + dnl Work around a bug in autoconf 2.61 that creates a broken + dnl configure if this branch is empty. + : ], [ #ifdef _WIN32 typedef int BOOL; #endif @@ -1389,10 +1453,44 @@ # endif # include # include #endif ]) + + AC_CHECK_HEADERS(afunix.h, [ + AC_DEFINE(OF_HAVE_AFUNIX_H, 1, [Whether we have afunix.h]) + ], [], [ + #ifdef _WIN32 + # include + #endif + ]) + AC_CHECK_MEMBER(struct sockaddr_un.sun_path, [ + AC_DEFINE(OF_HAVE_UNIX_SOCKETS, 1, + [Whether we have UNIX sockets]) + AC_SUBST(USE_SRCS_UNIX_SOCKETS, '${SRCS_UNIX_SOCKETS}') + ], [], [ + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #ifdef OF_HAVE_SYS_UN_H + # include + #endif + #ifdef _WIN32 + # include + #endif + #ifdef HAVE_AFUNIX_H + # include + #endif + + #ifdef __morphos__ + # error MorphOS has the struct but does not support it + #endif + + #ifdef __MINT__ + # error Gives invalid argument at runtime + #endif + ]) AC_CHECK_MEMBER(struct sockaddr_ipx.sipx_network, [], [ AC_CHECK_MEMBER(struct sockaddr_ipx.sa_netnum, [], [], [ #ifdef _WIN32 typedef int BOOL; @@ -1506,18 +1604,124 @@ AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M, "OFSelectKernelEventObserver.m") ]) ;; esac + + AC_ARG_WITH(tls, + AS_HELP_STRING([--with-tls], [ + enable TLS support using the specified library + (yes, openssl, gnutls, securetransport or no)])) + AS_IF([test x"$with_tls" = x""], [with_tls="yes"]) + tls_support="no" + + AS_IF([test x"$with_tls" = x"securetransport" \ + -o x"$with_tls" = x"yes"], [ + AC_CHECK_HEADERS(Security/SecureTransport.h, [ + old_LIBS="$LIBS" + LIBS="-framework Security -framework Foundation $LIBS" + + AC_CHECK_FUNC(SSLHandshake, [ + AC_DEFINE(HAVE_SECURE_TRANSPORT, 1, + [Whether we have Secure Transport]) + + tls_support="Secure Transport" + TLS_LIBS="-framework Foundation $TLS_LIBS" + TLS_LIBS="-framework Security $TLS_LIBS" + + AC_SUBST(OF_SECURE_TRANSPORT_TLS_STREAM_M, + "OFSecureTransportTLSStream.m") + + AC_CHECK_FUNCS(SSLCreateContext) + ], []) + + LIBS="$old_LIBS" + ]) + ]) + + AS_IF([test x"$with_tls" = x"openssl" \ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + case "$host_os" in + morphos*) + ssl="ssl_shared" + crypto="crypto_shared" + ;; + *) + ssl="ssl" + crypto="crypto" + ;; + esac + + AC_CHECK_LIB($ssl, SSL_set1_host, [ + AC_CHECK_HEADER(openssl/ssl.h, [ + AC_DEFINE(HAVE_OPENSSL, 1, + [Whether we have OpenSSL]) + + tls_support="OpenSSL" + TLS_LIBS="-l$ssl -l$crypto $TLS_LIBS" + + AC_SUBST(OF_OPENSSL_TLS_STREAM_M, + "OFOpenSSLTLSStream.m") + ]) + ], [], [-l$crypto]) + ]) + + AS_IF([test x"$with_tls" = x"gnutls" \ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + PKG_CHECK_MODULES(gnutls, [gnutls >= 3.5.0], [ + AC_DEFINE(HAVE_GNUTLS, 1, [Whether we have GnuTLS]) + + tls_support="GnuTLS" + TLS_CPPFLAGS="$gnutls_CFLAGS $TLS_CPPFLAGS" + TLS_LIBS="$gnutls_LIBS $TLS_LIBS" + + AC_SUBST(OF_GNUTLS_TLS_STREAM_M, "OFGnuTLSTLSStream.m") + ], [ + dnl Disable default action-if-not-found, which exits + dnl configure with an error. + : + ]) + ]) + + AS_IF([test x"$tls_support" != x"no"], [ + AC_SUBST(TLS, "tls") + AC_SUBST(TLS_CPPFLAGS) + AC_SUBST(TLS_LIBS) + AC_DEFINE(HAVE_TLS_SUPPORT, 1, + [Whether we have an implementation for TLS]) + AC_CONFIG_FILES(src/tls/Info.plist) + + OFHTTP_LIBS="-lobjfwtls $TLS_LIBS $OFHTTP_LIBS" + + AS_IF([test x"$enable_shared" != x"no"], [ + AC_SUBST(OBJFWTLS_SHARED_LIB, + "${LIB_PREFIX}objfwtls${LIB_SUFFIX}") + ]) + AS_IF([test x"$enable_static" = x"yes" \ + -o x"$enable_shared" = x"no"], [ + AC_SUBST(OBJFWTLS_STATIC_LIB, "libobjfwtls.a") + ]) + AS_IF([test x"$build_framework" = x"yes"], [ + AC_SUBST(OBJFWTLS_FRAMEWORK, "ObjFWTLS.framework") + ]) + ]) + + AS_IF([test x"$with_tls" != x"no" -a x"$tls_support" = x"no"], [ + AC_MSG_ERROR(m4_normalize([ + No TLS implementation was found. Please install OpenSSL, + GnuTLS or use --without-tls. + ])) + ]) AS_IF([test x"$enable_threads" != x"no"], [ AC_SUBST(OF_HTTP_CLIENT_TESTS_M, "OFHTTPClientTests.m") ]) AC_SUBST(OFDNS, "ofdns") AS_IF([test x"$enable_files" != x"no"], [ AC_SUBST(OFHTTP, "ofhttp") + AC_SUBST(OFHTTP_LIBS) ]) ]) AC_DEFUN([CHECK_BUILTIN_BSWAP], [ AC_MSG_CHECKING(for __builtin_bswap$1) @@ -1553,10 +1757,13 @@ egrep_cpp_yes #endif ], [ AC_MSG_RESULT(yes) have_subprocesses="yes" + + AC_CHECK_FUNCS(posix_spawnp) + AC_CHECK_HEADERS(spawn.h) ], [ AC_MSG_RESULT(no) have_subprocesses="no" ]) ;; @@ -1830,10 +2037,15 @@ __attribute__((__objc_root_class__)) # endif #endif @interface Test @end + + /** + * @struct Foo conftest.m conftest.m + */ + typedef struct {} Foo; ]) ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) @@ -1913,11 +2125,10 @@ AC_CHECK_PROG(WINE, wine64, wine64) ;; esac AS_IF([test x"$WINE" != x""], [ - AC_SUBST(RUN_TESTS, "run") AC_SUBST(WRAPPER, "$WINE") ]) AS_IF([test x"$with_wii" = x"yes"], [ dnl Keep this lowercase, as WIILOAD is a variable used by @@ -1927,12 +2138,10 @@ AS_IF([test x"$wiiload" != x""], [ AC_SUBST(WRAPPER, "$wiiload") ]) ]) -], [ - AC_SUBST(RUN_TESTS, "run") ]) AC_ARG_WITH(fish_completions, AS_HELP_STRING([--with-fish-completions], [install completions for the fish shell])) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,23 +1,27 @@ OBJFW_SHARED_LIB = @OBJFW_SHARED_LIB@ OBJFW_STATIC_LIB = @OBJFW_STATIC_LIB@ OBJFW_FRAMEWORK = @OBJFW_FRAMEWORK@ -OBJFW_LIB_MAJOR = 9 -OBJFW_LIB_MINOR = 1 +OBJFW_LIB_MAJOR = 0 +OBJFW_LIB_MINOR = 0 OBJFW_LIB_MAJOR_MINOR = ${OBJFW_LIB_MAJOR}.${OBJFW_LIB_MINOR} OBJFWRT_SHARED_LIB = @OBJFWRT_SHARED_LIB@ OBJFWRT_STATIC_LIB = @OBJFWRT_STATIC_LIB@ OBJFWRT_FRAMEWORK = @OBJFWRT_FRAMEWORK@ OBJFWRT_AMIGA_LIB = @OBJFWRT_AMIGA_LIB@ -OBJFWRT_LIB_MAJOR = 1 +OBJFWRT_LIB_MAJOR = 0 OBJFWRT_LIB_MINOR = 0 OBJFWRT_LIB_MAJOR_MINOR = ${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR} OBJFWBRIDGE_SHARED_LIB = @OBJFWBRIDGE_SHARED_LIB@ OBJFWBRIDGE_STATIC_LIB = @OBJFWBRIDGE_STATIC_LIB@ OBJFWBRIDGE_FRAMEWORK = @OBJFWBRIDGE_FRAMEWORK@ + +OBJFWTLS_SHARED_LIB = @OBJFWTLS_SHARED_LIB@ +OBJFWTLS_STATIC_LIB = @OBJFWTLS_STATIC_LIB@ +OBJFWTLS_FRAMEWORK = @OBJFWTLS_FRAMEWORK@ BIN_PREFIX = @BIN_PREFIX@ BRIDGE = @BRIDGE@ CVINCLUDE_INLINE_H = @CVINCLUDE_INLINE_H@ ENCODINGS_A = @ENCODINGS_A@ @@ -38,19 +42,24 @@ LINKLIB = @LINKLIB@ LOOKUP_ASM_A = @LOOKUP_ASM_A@ LOOKUP_ASM_AMIGALIB_A = @LOOKUP_ASM_AMIGALIB_A@ LOOKUP_ASM_LIB_A = @LOOKUP_ASM_LIB_A@ MAP_LDFLAGS = @MAP_LDFLAGS@ +OBJC_SYNC = @OBJC_SYNC@ OFARC = @OFARC@ OFDNS = @OFDNS@ OFHASH = @OFHASH@ OFHTTP = @OFHTTP@ +OFHTTP_LIBS = @OFHTTP_LIBS@ OF_BLOCK_TESTS_M = @OF_BLOCK_TESTS_M@ OF_EPOLL_KERNEL_EVENT_OBSERVER_M = @OF_EPOLL_KERNEL_EVENT_OBSERVER_M@ +OF_GNUTLS_TLS_STREAM_M = @OF_GNUTLS_TLS_STREAM_M@ OF_HTTP_CLIENT_TESTS_M = @OF_HTTP_CLIENT_TESTS_M@ OF_KQUEUE_KERNEL_EVENT_OBSERVER_M = @OF_KQUEUE_KERNEL_EVENT_OBSERVER_M@ +OF_OPENSSL_TLS_STREAM_M = @OF_OPENSSL_TLS_STREAM_M@ OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@ +OF_SECURE_TRANSPORT_TLS_STREAM_M = @OF_SECURE_TRANSPORT_TLS_STREAM_M@ OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@ OF_SUBPROCESS_M = @OF_SUBPROCESS_M@ REEXPORT_RUNTIME = @REEXPORT_RUNTIME@ REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@ RUNTIME = @RUNTIME@ @@ -57,22 +66,25 @@ RUNTIME_ARC_TESTS_M = @RUNTIME_ARC_TESTS_M@ RUNTIME_AUTORELEASE_M = @RUNTIME_AUTORELEASE_M@ RUNTIME_FRAMEWORK_LIBS = @RUNTIME_FRAMEWORK_LIBS@ RUNTIME_INSTANCE_M = @RUNTIME_INSTANCE_M@ RUNTIME_LIBS = @RUNTIME_LIBS@ -RUN_TESTS = @RUN_TESTS@ SFDC_INLINE_H = @SFDC_INLINE_H@ SFDC_TARGET = @SFDC_TARGET@ SFD_FILE = @SFD_FILE@ TESTPLUGIN = @TESTPLUGIN@ TESTPLUGIN_LIBS = @TESTPLUGIN_LIBS@ TESTS_LIBS = @TESTS_LIBS@ TESTS_STATIC_LIB = @TESTS_STATIC_LIB@ +TLS = @TLS@ +TLS_CPPFLAGS = @TLS_CPPFLAGS@ +TLS_LIBS = @TLS_LIBS@ UNICODE_M = @UNICODE_M@ USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_IPX = @USE_SRCS_IPX@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@ USE_SRCS_THREADS = @USE_SRCS_THREADS@ +USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@ USE_SRCS_WINDOWS = @USE_SRCS_WINDOWS@ WRAPPER = @WRAPPER@ Index: generators/library/FuncArrayGenerator.h ================================================================== --- generators/library/FuncArrayGenerator.h +++ generators/library/FuncArrayGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: generators/library/FuncArrayGenerator.m ================================================================== --- generators/library/FuncArrayGenerator.m +++ generators/library/FuncArrayGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -65,14 +65,14 @@ - (void)generate { [_include writeString: COPYRIGHT]; [_include writeString: - @"/* This file is automatically generated from library.xml */\n" - @"\n"]; + @"/* This file is automatically generated from amiga-library.xml */" + @"\n\n"]; for (OFXMLElement *function in [_library elementsForName: @"function"]) [_include writeFormat: @"(CONST_APTR)glue_%@,\n", [function attributeForName: @"name"].stringValue]; } @end Index: generators/library/GlueGenerator.h ================================================================== --- generators/library/GlueGenerator.h +++ generators/library/GlueGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: generators/library/GlueGenerator.m ================================================================== --- generators/library/GlueGenerator.m +++ generators/library/GlueGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -70,16 +70,16 @@ { [_header writeString: COPYRIGHT]; [_impl writeString: COPYRIGHT]; [_header writeString: - @"/* This file is automatically generated from library.xml */\n" - @"\n"]; + @"/* This file is automatically generated from amiga-library.xml */" + @"\n\n"]; [_impl writeString: - @"/* This file is automatically generated from library.xml */\n" - @"\n" + @"/* This file is automatically generated from amiga-library.xml */" + @"\n\n" @"#include \"config.h\"\n" @"\n" @"#import \"amiga-glue.h\"\n" @"\n"]; Index: generators/library/LibraryGenerator.m ================================================================== --- generators/library/LibraryGenerator.m +++ generators/library/LibraryGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -34,30 +34,34 @@ - (void)applicationDidFinishLaunching { OFURL *sourcesURL = [[OFFileManager defaultManager].currentDirectoryURL URLByAppendingPathComponent: @"../../src"]; OFURL *runtimeLibraryURL = [sourcesURL - URLByAppendingPathComponent: @"runtime/library.xml"]; + URLByAppendingPathComponent: @"runtime/amiga-library.xml"]; OFURL *runtimeLinkLibURL = [sourcesURL URLByAppendingPathComponent: @"runtime/linklib/linklib.m"]; OFURL *runtimeGlueHeaderURL = [sourcesURL URLByAppendingPathComponent: @"runtime/amiga-glue.h"]; OFURL *runtimeGlueURL = [sourcesURL URLByAppendingPathComponent: @"runtime/amiga-glue.m"]; OFURL *runtimeFuncArrayURL = [sourcesURL URLByAppendingPathComponent: @"runtime/amiga-funcarray.inc"]; OFXMLElement *runtimeLibrary = [OFXMLElement elementWithStream: - [OFFile fileWithURL: runtimeLibraryURL - mode: @"r"]]; - OFFile *runtimeLinkLib = [OFFile fileWithURL: runtimeLinkLibURL - mode: @"w"]; - OFFile *runtimeGlueHeader = [OFFile fileWithURL: runtimeGlueHeaderURL - mode: @"w"]; - OFFile *runtimeGlue = [OFFile fileWithURL: runtimeGlueURL - mode: @"w"]; - OFFile *runtimeFuncArray = [OFFile fileWithURL: runtimeFuncArrayURL - mode: @"w"]; + [OFFile fileWithPath: runtimeLibraryURL.fileSystemRepresentation + mode: @"r"]]; + OFFile *runtimeLinkLib = + [OFFile fileWithPath: runtimeLinkLibURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeGlueHeader = + [OFFile fileWithPath: runtimeGlueHeaderURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeGlue = + [OFFile fileWithPath: runtimeGlueURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeFuncArray = + [OFFile fileWithPath: runtimeFuncArrayURL.fileSystemRepresentation + mode: @"w"]; LinkLibGenerator *runtimeLinkLibGenerator = [[[LinkLibGenerator alloc] initWithLibrary: runtimeLibrary implementation: runtimeLinkLib] autorelease]; GlueGenerator *runtimeGlueGenerator = [[[GlueGenerator alloc] initWithLibrary: runtimeLibrary Index: generators/library/LinkLibGenerator.h ================================================================== --- generators/library/LinkLibGenerator.h +++ generators/library/LinkLibGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: generators/library/LinkLibGenerator.m ================================================================== --- generators/library/LinkLibGenerator.m +++ generators/library/LinkLibGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -69,12 +69,12 @@ OFArray OF_GENERIC(OFXMLElement *) *functions; size_t funcIndex = 0; [_impl writeString: COPYRIGHT]; [_impl writeString: - @"/* This file is automatically generated from library.xml */\n" - @"\n" + @"/* This file is automatically generated from amiga-library.xml */" + @"\n\n" @"#include \"config.h\"\n" @"\n"]; for (OFXMLElement *include in [_library elementsForName: @"include"]) [_impl writeFormat: @"#import \"%@\"\n", Index: generators/library/Makefile ================================================================== --- generators/library/Makefile +++ generators/library/Makefile @@ -4,29 +4,33 @@ SRCS = FuncArrayGenerator.m \ GlueGenerator.m \ LibraryGenerator.m \ LinkLibGenerator.m +include ../../buildsys.mk + .PHONY: run run: all rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/objfw.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../../src/libobjfw.dylib; then \ ${LN_S} ../../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -36,12 +40,13 @@ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/runtime/objfwrt.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi @@ -54,17 +59,17 @@ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT -include ../../buildsys.mk - CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} LD = ${OBJC} Index: generators/library/copyright.h ================================================================== --- generators/library/copyright.h +++ generators/library/copyright.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #import "OFString.h" #define COPYRIGHT \ @"/*\n" \ - @" * Copyright (c) 2008-2021 Jonathan Schleifer \n" \ + @" * Copyright (c) 2008-2022 Jonathan Schleifer \n" \ @" *\n" \ @" * All rights reserved.\n" \ @" *\n" \ @" * This file is part of ObjFW. It may be distributed under the terms " \ @"of the\n" \ Index: generators/unicode/Makefile ================================================================== --- generators/unicode/Makefile +++ generators/unicode/Makefile @@ -1,29 +1,33 @@ include ../../extra.mk PROG_NOINST = gen_tables${PROG_SUFFIX} SRCS = TableGenerator.m +include ../../buildsys.mk + .PHONY: run run: all rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/objfw.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../../src/libobjfw.dylib; then \ ${LN_S} ../../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -33,12 +37,13 @@ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/runtime/objfwrt.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi @@ -51,17 +56,17 @@ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT -include ../../buildsys.mk - CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} LD = ${OBJC} Index: generators/unicode/TableGenerator.h ================================================================== --- generators/unicode/TableGenerator.h +++ generators/unicode/TableGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: generators/unicode/TableGenerator.m ================================================================== --- generators/unicode/TableGenerator.m +++ generators/unicode/TableGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -53,12 +53,12 @@ _titlecaseTableSize = SIZE_MAX; _caseFoldingTableSize = SIZE_MAX; _decompositionTableSize = SIZE_MAX; _decompositionCompatTableSize = SIZE_MAX; } @catch (id e) { - @throw e; [self release]; + @throw e; } return self; } Index: generators/unicode/copyright.h ================================================================== --- generators/unicode/copyright.h +++ generators/unicode/copyright.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #import "OFString.h" #define COPYRIGHT \ @"/*\n" \ - @" * Copyright (c) 2008-2021 Jonathan Schleifer \n" \ + @" * Copyright (c) 2008-2022 Jonathan Schleifer \n" \ @" *\n" \ @" * All rights reserved.\n" \ @" *\n" \ @" * This file is part of ObjFW. It may be distributed under the terms " \ @"of the\n" \ ADDED objfw.spec Index: objfw.spec ================================================================== --- /dev/null +++ objfw.spec @@ -0,0 +1,248 @@ +%global libobjfw_major 0 +%global libobjfw_minor 0 +%global libobjfwrt_major 0 +%global libobjfwrt_minor 0 +%global libobjfwtls_major 0 +%global libobjfwtls_minor 0 +%if 0%{?suse_version} +%global libobjfw_pkgname libobjfw%{libobjfw_major} +%global libobjfwrt_pkgname libobjfwrt%{libobjfwrt_major} +%global libobjfwtls_pkgname libobjfwtls%{libobjfwtls_major} +%else +%global libobjfw_pkgname libobjfw +%global libobjfwrt_pkgname libobjfwrt +%global libobjfwtls_pkgname libobjfwtls +%endif + +Name: objfw +Version: 1.1dev +Release: 1%{?dist} +Summary: Portable, lightweight framework for the Objective-C language + +%if 0%{?suse_version} +License: QPL-1.0 or GPL-3.0 or GPL-2.0 +Group: Development/Languages/C and C++ +%else +License: QPL or GPLv3 or GPLv2 +%endif +URL: https://objfw.nil.im +Source0: objfw-%{version}.tar.gz + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: clang +BuildRequires: make +BuildRequires: pkgconfig(openssl) +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfw_pkgname}-devel = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}-devel = %{version}-%{release} +Requires: ofarc%{_isa} = %{version}-%{release} +Requires: ofdns%{_isa} = %{version}-%{release} +Requires: ofhash%{_isa} = %{version}-%{release} +Requires: ofhttp%{_isa} = %{version}-%{release} + +%description +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 you would otherwise need if you want to +be portable. + +It supports all modern Objective-C features when using Clang, but is also +compatible with GCC ≥ 4.6 to allow maximum portability. + +ObjFW also comes with its own lightweight and extremely fast Objective-C +runtime, which in real world use cases was found to be significantly faster +than both GNU's and Apple's runtime. + +%package -n %{libobjfw_pkgname} +Summary: ObjFW library +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfw_pkgname} +The %{libobjfw_pkgname} package contains the library needed by programs using +ObjFW. + +%package -n %{libobjfw_pkgname}-devel +Summary: Header files, libraries and tools for %{libobjfw_pkgname} +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}-devel = %{version}-%{release} + +%description -n %{libobjfw_pkgname}-devel +The %{libobjfw_pkgname}-devel package contains the header files, libraries and +tools to develop programs using ObjFW. + +%package -n %{libobjfwrt_pkgname} +Summary: ObjFW Objective-C runtime library + +%description -n %{libobjfwrt_pkgname} +The %{libobjfwrt_pkgname} package contains ObjFW's Objective-C runtime library. + +%package -n %{libobjfwrt_pkgname}-devel +Summary: Header files and libraries for %{libobjfwrt_pkgname} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfwrt_pkgname}-devel +The %{libobjfwrt_pkgname}-devel package contains header files and libraries for +ObjFW's Objective-C runtime library. + +%package -n %{libobjfwtls_pkgname} +Summary: TLS support for ObjFW +Requires: openssl%{_isa} >= 1.1.1 + +%description -n %{libobjfwtls_pkgname} +The %{libobjfwtls_pkgname} package contains TLS support for ObjFW + +%package -n %{libobjfwtls_pkgname}-devel +Summary: Header files and libraries for %{libobjfwtls_pkgname} +Requires: %{libobjfwtls_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfwtls_pkgname}-devel +The %{libobjfwtls_pkgname}-devel package contains header files and libraries +for TLS support for ObjFW. + +%package -n ofarc +Summary: Utility for handling ZIP, Tar and LHA archives +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofarc +ofarc is a multi-format archive utility that allows creating, listing, +extracting and modifying ZIP, Tar and LHA archives using ObjFW's classes for +various archive types. + +%package -n ofdns +Summary: Utility for performing DNS requests on the command line +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofdns +ofdns is an utility for performing DNS requests on the command line using +ObjFW's DNS resolver. + +%package -n ofhash +Summary: Utility to hash files with various cryptographic hash functions +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofhash +ofhash is an utility to hash files with various cryptographic hash functions +(even using different algorithms at once) using ObjFW's classes for various +cryptographic hashes. + +%package -n ofhttp +Summary: Command line downloader for HTTP(S) +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwtls_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofhttp +ofhttp is a command line downloader for HTTP and HTTPS (via ObjOpenSSL) using +ObjFW's OFHTTPClient class. It supports all features one would expect from a +modern command line downloader such as resuming of downloads, using a SOCKS5 +proxy, a modern terminal-based UI, etc. + +%prep +%autosetup +./autogen.sh + +%build +%configure OBJC=clang --disable-rpath +%make_build + +%install +%make_install + +%check +make -C tests run + +%if 0%{?suse_version} +%post -n %{libobjfw_pkgname} -p /sbin/ldconfig +%postun -n %{libobjfw_pkgname} -p /sbin/ldconfig +%post -n %{libobjfwrt_pkgname} -p /sbin/ldconfig +%postun -n %{libobjfwrt_pkgname} -p /sbin/ldconfig +%endif + +%files +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfw_pkgname} +%{_libdir}/libobjfw.so.%{libobjfw_major} +%{_libdir}/libobjfw.so.%{libobjfw_major}.%{libobjfw_minor}.0 +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfw_pkgname}-devel +%{_libdir}/libobjfw.so +%dir %{_includedir}/ObjFW +%{_includedir}/ObjFW +%{_bindir}/objfw-compile +%{_bindir}/objfw-config +%{_bindir}/objfw-new +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwrt_pkgname} +%{_libdir}/libobjfwrt.so.%{libobjfwrt_major} +%{_libdir}/libobjfwrt.so.%{libobjfwrt_major}.%{libobjfwrt_minor}.0 +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwrt_pkgname}-devel +%{_libdir}/libobjfwrt.so +%{_includedir}/ObjFWRT/ObjFWRT.h +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwtls_pkgname} +%{_libdir}/libobjfwtls.so.%{libobjfwtls_major} +%{_libdir}/libobjfwtls.so.%{libobjfwtls_major}.%{libobjfwtls_minor}.0 +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwtls_pkgname}-devel +%{_libdir}/libobjfwtls.so +%{_includedir}/ObjFWTLS/ObjFWTLS.h +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofarc +%{_bindir}/ofarc +%{_datadir}/ofarc/lang/de.json +%{_datadir}/ofarc/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofdns +%{_bindir}/ofdns +%{_datadir}/ofdns/lang/de.json +%{_datadir}/ofdns/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofhash +%{_bindir}/ofhash +%{_datadir}/ofhash/lang/de.json +%{_datadir}/ofhash/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofhttp +%{_bindir}/ofhttp +%{_datadir}/ofhttp/lang/de.json +%{_datadir}/ofhttp/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -1,47 +1,47 @@ include ../extra.mk SUBDIRS = ${RUNTIME} exceptions encodings forwarding invocation -SUBDIRS_AFTER = ${BRIDGE} +SUBDIRS_AFTER = ${BRIDGE} ${TLS} DISTCLEAN = Info.plist objfw-defs.h SHARED_LIB = ${OBJFW_SHARED_LIB} STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} LIB_MAJOR = ${OBJFW_LIB_MAJOR} LIB_MINOR = ${OBJFW_LIB_MINOR} -SRCS = OFASPrintF.m \ - OFApplication.m \ +SRCS = OFApplication.m \ OFArray.m \ - OFBase64.m \ OFBlock.m \ - OFCRC16.m \ - OFCRC32.m \ OFCharacterSet.m \ OFColor.m \ OFConstantString.m \ OFCountedSet.m \ OFData.m \ OFData+CryptographicHashing.m \ OFData+MessagePackParsing.m \ OFDate.m \ OFDictionary.m \ + OFEmbeddedFileURLHandler.m \ OFEnumerator.m \ OFFileManager.m \ OFGZIPStream.m \ OFHMAC.m \ - OFHuffmanTree.m \ + OFINICategory.m \ + OFINIFile.m \ + OFINIFileSettings.m \ OFInflate64Stream.m \ OFInflateStream.m \ OFInvocation.m \ OFLHAArchive.m \ OFLHAArchiveEntry.m \ OFList.m \ OFLocale.m \ OFMD5Hash.m \ OFMapTable.m \ + OFMemoryStream.m \ OFMessagePackExtension.m \ OFMethodSignature.m \ OFMutableArray.m \ OFMutableData.m \ OFMutableDictionary.m \ @@ -51,10 +51,12 @@ OFMutableString.m \ OFMutableTarArchiveEntry.m \ OFMutableTriple.m \ OFMutableURL.m \ OFMutableZIPArchiveEntry.m \ + OFNotification.m \ + OFNotificationCenter.m \ OFNull.m \ OFNumber.m \ OFObject.m \ OFObject+KeyValueCoding.m \ OFObject+Serialization.m \ @@ -76,29 +78,30 @@ OFSeekableStream.m \ OFSerialization.m \ OFSet.m \ OFSortedList.m \ OFStdIOStream.m \ - OFStrPTime.m \ OFStream.m \ OFString.m \ OFString+CryptographicHashing.m \ OFString+JSONParsing.m \ OFString+PropertyListParsing.m \ OFString+Serialization.m \ OFString+URLEncoding.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ - ${OF_SUBUPROCESS_M} \ + ${OF_SUBPROCESS_M} \ + OFSettings.m \ OFSystemInfo.m \ OFTarArchive.m \ OFTarArchiveEntry.m \ OFThread.m \ OFTimer.m \ OFTriple.m \ OFURL.m \ OFURLHandler.m \ + OFUUID.m \ OFValue.m \ OFXMLAttribute.m \ OFXMLCDATA.m \ OFXMLCharacters.m \ OFXMLComment.m \ @@ -114,17 +117,11 @@ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ ${USE_SRCS_WINDOWS} SRCS_FILES = OFFile.m \ - OFINICategory.m \ - OFINIFile.m \ - OFSettings.m \ OFString+PathAdditions.m -SRCS_IPX = OFIPXSocket.m \ - OFSPXSocket.m \ - OFSPXStreamSocket.m SRCS_PLUGINS = OFPlugin.m SRCS_SOCKETS = OFDNSQuery.m \ OFDNSResolver.m \ OFDNSResourceRecord.m \ OFDNSResponse.m \ @@ -137,50 +134,59 @@ OFHTTPServer.m \ OFSequencedPacketSocket.m \ OFSocket.m \ OFStreamSocket.m \ OFTCPSocket.m \ + OFTLSStream.m \ OFUDPSocket.m \ - ${USE_SRCS_IPX} + ${USE_SRCS_IPX} \ + ${USE_SRCS_UNIX_SOCKETS} +SRCS_IPX = OFIPXSocket.m \ + OFSPXSocket.m \ + OFSPXStreamSocket.m +SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ + OFUNIXStreamSocket.m SRCS_THREADS = OFCondition.m \ OFMutex.m \ OFPlainCondition.m \ OFPlainMutex.m \ OFPlainThread.m \ OFRecursiveMutex.m \ - OFTLSKey.m \ - OFThreadPool.m + OFTLSKey.m SRCS_WINDOWS = OFWin32ConsoleStdIOStream.m \ OFWindowsRegistryKey.m INCLUDES_ATOMIC = OFAtomic.h \ - OFAtomic_builtins.h \ - OFAtomic_no_threads.h \ - OFAtomic_osatomic.h \ - OFAtomic_powerpc.h \ - OFAtomic_sync_builtins.h \ - OFAtomic_x86.h + platform/GCC4/OFAtomic.h \ + platform/GCC4.7/OFAtomic.h \ + platform/PowerPC/OFAtomic.h \ + platform/macOS/OFAtomic.h \ + platform/x86/OFAtomic.h INCLUDES := ${SRCS:.m=.h} \ OFCollection.h \ OFCryptographicHash.h \ OFJSONRepresentation.h \ OFKernelEventObserver.h \ OFKeyValueCoding.h \ OFLocking.h \ OFMessagePackRepresentation.h \ - OFTLSSocket.h \ ObjFW.h \ macros.h \ objfw-defs.h \ platform.h \ ${USE_INCLUDES_ATOMIC} -SRCS += OFAdjacentArray.m \ +SRCS += OFASPrintF.m \ + OFAdjacentArray.m \ OFAdjacentSubarray.m \ + OFBase64.m \ OFBitSetCharacterSet.m \ OFBytesValue.m \ + OFCRC16.m \ + OFCRC32.m \ OFCountedMapTableSet.m \ + OFHuffmanTree.m \ OFInvertedCharacterSet.m \ OFLHADecompressingStream.m \ OFMapTableDictionary.m \ OFMapTableSet.m \ OFMutableAdjacentArray.m \ @@ -193,24 +199,24 @@ OFRangeCharacterSet.m \ OFRangeValue.m \ OFRectValue.m \ OFSandbox.m \ OFSizeValue.m \ + OFStrPTime.m \ OFSubarray.m \ OFUTF8String.m \ ${LIBBASES_M} \ ${RUNTIME_AUTORELEASE_M} \ ${RUNTIME_INSTANCE_M} \ ${UNICODE_M} -SRCS_FILES += OFFileURLHandler.m \ - OFINIFileSettings.m +SRCS_FILES += OFFileURLHandler.m SRCS_SOCKETS += OFDNSResolverSettings.m \ + ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ OFHTTPURLHandler.m \ OFHostAddressResolver.m \ OFIPSocketAsyncConnector.m \ OFKernelEventObserver.m \ - ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M} \ ${OF_POLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_SELECT_KERNEL_EVENT_OBSERVER_M} \ OFTCPSocketSOCKS5Connector.m Index: src/OFASPrintF.h ================================================================== --- src/OFASPrintF.h +++ src/OFASPrintF.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFASPrintF.m ================================================================== --- src/OFASPrintF.m +++ src/OFASPrintF.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -51,11 +51,11 @@ */ # define asprintf asprintf_ # define vasprintf vasprintf_ #endif -struct context { +struct Context { const char *format; size_t formatLen; char subformat[maxSubformatLen + 1]; size_t subformatLen; va_list arguments; @@ -146,11 +146,11 @@ return ret; } #endif static bool -appendString(struct context *ctx, const char *append, size_t appendLen) +appendString(struct Context *ctx, const char *append, size_t appendLen) { char *newBuf; if (appendLen == 0) return true; @@ -166,11 +166,11 @@ return true; } static bool -appendSubformat(struct context *ctx, const char *subformat, +appendSubformat(struct Context *ctx, const char *subformat, size_t subformatLen) { if (ctx->subformatLen + subformatLen > maxSubformatLen) return false; @@ -180,11 +180,11 @@ return true; } static bool -stringState(struct context *ctx) +stringState(struct Context *ctx) { if (ctx->format[ctx->i] == '%') { if (ctx->i > 0) if (!appendString(ctx, ctx->format + ctx->last, ctx->i - ctx->last)) @@ -199,11 +199,11 @@ return true; } static bool -formatFlagsState(struct context *ctx) +formatFlagsState(struct Context *ctx) { switch (ctx->format[ctx->i]) { case '-': case '+': case ' ': @@ -226,11 +226,11 @@ return true; } static bool -formatFieldWidthState(struct context *ctx) +formatFieldWidthState(struct Context *ctx) { if ((ctx->format[ctx->i] >= '0' && ctx->format[ctx->i] <= '9') || ctx->format[ctx->i] == '*' || ctx->format[ctx->i] == '.') { if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) return false; @@ -241,11 +241,11 @@ return true; } static bool -formatLengthModifierState(struct context *ctx) +formatLengthModifierState(struct Context *ctx) { /* Only one allowed */ switch (ctx->format[ctx->i]) { case 'h': /* and also hh */ if (ctx->formatLen > ctx->i + 1 && @@ -371,11 +371,11 @@ ctx->state = stateFormatConversionSpecifier; return true; } static bool -formatConversionSpecifierState(struct context *ctx) +formatConversionSpecifierState(struct Context *ctx) { char *tmp = NULL; int tmpLen = 0; #ifndef HAVE_ASPRINTF_L OFString *point; @@ -729,11 +729,11 @@ ctx->state = stateString; return true; } -static bool (*states[])(struct context *) = { +static bool (*states[])(struct Context *) = { stringState, formatFlagsState, formatFieldWidthState, formatLengthModifierState, formatConversionSpecifierState @@ -740,11 +740,11 @@ }; int OFVASPrintF(char **string, const char *format, va_list arguments) { - struct context ctx; + struct Context ctx; ctx.format = format; ctx.formatLen = strlen(format); memset(ctx.subformat, 0, maxSubformatLen + 1); ctx.subformatLen = 0; Index: src/OFAdjacentArray.h ================================================================== --- src/OFAdjacentArray.h +++ src/OFAdjacentArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFAdjacentArray.m ================================================================== --- src/OFAdjacentArray.m +++ src/OFAdjacentArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFAdjacentSubarray.h ================================================================== --- src/OFAdjacentSubarray.h +++ src/OFAdjacentSubarray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFAdjacentSubarray.m ================================================================== --- src/OFAdjacentSubarray.m +++ src/OFAdjacentSubarray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFApplication.h ================================================================== --- src/OFApplication.h +++ src/OFApplication.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -14,10 +14,11 @@ */ #include #import "OFObject.h" +#import "OFNotification.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -26,10 +27,15 @@ @class OFMutableArray OF_GENERIC(ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFSandbox; @class OFString; +/** + * @brief A notification that will be sent when the application will terminate. + */ +extern const OFNotificationName OFApplicationWillTerminateNotification; + /** * @brief Specify the class to be used as the application delegate. * * An instance of this class will be created and act as the application * delegate. @@ -143,10 +149,14 @@ * @brief A class which represents the application as an object. * * In order to create a new OFApplication, you should create a class conforming * to the optional @ref OFApplicationDelegate protocol and put * `OF_APPLICATION_DELEGATE(NameOfYourClass)` in the .m file of that class. + * + * When the application is about to be terminated, + * @ref OFApplicationDelegate#applicationWillTerminate will be called on the + * delegate and an @ref OFApplicationWillTerminateNotification will be sent. */ OF_SUBCLASSING_RESTRICTED @interface OFApplication: OFObject { OFString *_programName; Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,10 +30,11 @@ #ifdef OF_AMIGAOS # import "OFFile.h" # import "OFFileManager.h" #endif #import "OFLocale.h" +#import "OFNotificationCenter.h" #import "OFPair.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" #import "OFSandbox.h" #import "OFString.h" @@ -73,21 +74,30 @@ OF_DIRECT_MEMBERS @interface OFApplication () - (instancetype)of_init OF_METHOD_FAMILY(init); - (void)of_setArgumentCount: (int *)argc andArgumentValues: (char **[])argv; #ifdef OF_WINDOWS -- (void)of_setArgumentCount: (int)argc andWideArgumentValues: (wchar_t *[])argv; +- (void)of_setArgumentCount: (int *)argc + andArgumentValues: (char **[])argv + andWideArgumentCount: (int)wargc + andWideArgumentValues: (wchar_t *[])wargv; #endif - (void)of_run; @end +const OFNotificationName OFApplicationWillTerminateNotification = + @"OFApplicationWillTerminateNotification"; static OFApplication *app = nil; static void atexitHandler(void) { id delegate = app.delegate; + + [[OFNotificationCenter defaultCenter] + postNotificationName: OFApplicationWillTerminateNotification + object: app]; if ([delegate respondsToSelector: @selector(applicationWillTerminate)]) [delegate applicationWillTerminate]; [delegate release]; @@ -111,11 +121,14 @@ app = [[OFApplication alloc] of_init]; #ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) { __wgetmainargs(&wargc, &wargv, &wenvp, _CRT_glob, &si); - [app of_setArgumentCount: wargc andWideArgumentValues: wargv]; + [app of_setArgumentCount: argc + andArgumentValues: argv + andWideArgumentCount: wargc + andWideArgumentValues: wargv]; } else #endif [app of_setArgumentCount: argc andArgumentValues: argv]; app.delegate = delegate; @@ -460,11 +473,11 @@ [_environment release]; [super dealloc]; } -- (void)of_setArgumentCount: (int *)argc andArgumentValues: (char ***)argv +- (void)of_setArgumentCount: (int *)argc andArgumentValues: (char **[])argv { void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; OFStringEncoding encoding; @@ -493,22 +506,28 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_WINDOWS -- (void)of_setArgumentCount: (int)argc andWideArgumentValues: (wchar_t **)argv +- (void)of_setArgumentCount: (int *)argc + andArgumentValues: (char **[])argv + andWideArgumentCount: (int)wargc + andWideArgumentValues: (wchar_t *[])wargv { void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; - if (argc > 0) { - _programName = [[OFString alloc] initWithUTF16String: argv[0]]; + _argc = argc; + _argv = argv; + + if (wargc > 0) { + _programName = [[OFString alloc] initWithUTF16String: wargv[0]]; arguments = [[OFMutableArray alloc] init]; - for (int i = 1; i < argc; i++) + for (int i = 1; i < wargc; i++) [arguments addObject: - [OFString stringWithUTF16String: argv[i]]]; + [OFString stringWithUTF16String: wargv[i]]]; [arguments makeImmutable]; _arguments = arguments; } Index: src/OFArray+Private.h ================================================================== --- src/OFArray+Private.h +++ src/OFArray+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -180,13 +180,12 @@ * * @param objects A C array of objects * @param count The length of the C array * @return A new autoreleased OFArray */ -+ (instancetype) - arrayWithObjects: (ObjectType const _Nonnull *_Nonnull)objects - count: (size_t)count; ++ (instancetype)arrayWithObjects: (ObjectType const _Nonnull *_Nonnull)objects + count: (size_t)count; /** * @brief Initializes an OFArray with the specified object. * * @param object An object @@ -435,18 +434,10 @@ * @return A new array with the objects from the specified array added */ - (OFArray OF_GENERIC(ObjectType) *)arrayByAddingObjectsFromArray: (OFArray OF_GENERIC(ObjectType) *)array; -/** - * @brief Creates a new array with the specified object removed. - * - * @param object The object to remove - * @return A new array with the specified object removed - */ -- (OFArray OF_GENERIC(ObjectType) *)arrayByRemovingObject: (ObjectType)object; - #ifdef OF_HAVE_BLOCKS /** * @brief Executes a block for each object. * * @param block The block to execute for each object Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -237,22 +237,25 @@ - (id const *)objects { size_t count = self.count; id *buffer = OFAllocMemory(count, sizeof(id)); + id const *ret; @try { [self getObjects: buffer inRange: OFRangeMake(0, count)]; - return [[OFData dataWithItemsNoCopy: buffer - count: count - itemSize: sizeof(id) - freeWhenDone: true] items]; + ret = [[OFData dataWithItemsNoCopy: buffer + count: count + itemSize: sizeof(id) + freeWhenDone: true] items]; } @catch (id e) { OFFreeMemory(buffer); @throw e; } + + return ret; } - (id)copy { return [self retain]; @@ -810,18 +813,10 @@ [ret makeImmutable]; return ret; } -- (OFArray *)arrayByRemovingObject: (id)object -{ - OFMutableArray *ret = [[self mutableCopy] autorelease]; - [ret removeObject: object]; - [ret makeImmutable]; - return ret; -} - #ifdef OF_HAVE_BLOCKS - (OFArray *)mappedArrayUsingBlock: (OFArrayMapBlock)block { OFArray *ret; size_t count = self.count; Index: src/OFAtomic.h ================================================================== --- src/OFAtomic.h +++ src/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,20 +20,166 @@ #ifndef OF_HAVE_ATOMIC_OPS # error No atomic operations available! #endif #if !defined(OF_HAVE_THREADS) -# import "OFAtomic_no_threads.h" +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return (*p += i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p += i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p += i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return (*p -= i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p -= i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p -= i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p |= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p |= i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p &= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p &= i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p ^= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p ^= i); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + /* nop */ +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + /* nop */ +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + /* nop */ +} #elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) -# import "OFAtomic_x86.h" +# import "platform/x86/OFAtomic.h" #elif defined(OF_POWERPC) && defined(__GNUC__) && !defined(__APPLE_CC__) && \ !defined(OF_AIX) -# import "OFAtomic_powerpc.h" +# import "platform/PowerPC/OFAtomic.h" #elif defined(OF_HAVE_ATOMIC_BUILTINS) -# import "OFAtomic_builtins.h" +# import "platform/GCC4.7/OFAtomic.h" #elif defined(OF_HAVE_SYNC_BUILTINS) -# import "OFAtomic_sync_builtins.h" +# import "platform/GCC4/OFAtomic.h" #elif defined(OF_HAVE_OSATOMIC) -# import "OFAtomic_osatomic.h" +# import "platform/macOS/OFAtomic.h" #else # error No atomic operations available! #endif DELETED src/OFAtomic_builtins.h Index: src/OFAtomic_builtins.h ================================================================== --- src/OFAtomic_builtins.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - __atomic_thread_fence(__ATOMIC_SEQ_CST); -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - __atomic_thread_fence(__ATOMIC_ACQUIRE); -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - __atomic_thread_fence(__ATOMIC_RELEASE); -} DELETED src/OFAtomic_no_threads.h Index: src/OFAtomic_no_threads.h ================================================================== --- src/OFAtomic_no_threads.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return (*p += i); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p += i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p += i); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return (*p -= i); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p -= i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p -= i); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p |= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p |= i); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p &= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p &= i); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p ^= i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p ^= i); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - /* nop */ -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - /* nop */ -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - /* nop */ -} DELETED src/OFAtomic_osatomic.h Index: src/OFAtomic_osatomic.h ================================================================== --- src/OFAtomic_osatomic.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(i, (int32_t *)p); -#endif -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(-i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(-i, (int32_t *)p); -#endif -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return OSAtomicCompareAndSwapInt(o, n, p); -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return OSAtomicCompareAndSwap32(o, n, p); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return OSAtomicCompareAndSwapPtr(o, n, p); -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - OSMemoryBarrier(); -} DELETED src/OFAtomic_powerpc.h Index: src/OFAtomic_powerpc.h ================================================================== --- src/OFAtomic_powerpc.h +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE bool -OFAtomicIntCompAndSwap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} DELETED src/OFAtomic_sync_builtins.h Index: src/OFAtomic_sync_builtins.h ================================================================== --- src/OFAtomic_sync_builtins.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_add_and_fetch(p, (void *)i); -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_sub_and_fetch(p, (void *)i); -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -OFAtomicInt32CompAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - __sync_synchronize(); -} DELETED src/OFAtomic_x86.h Index: src/OFAtomic_x86.h ================================================================== --- src/OFAtomic_x86.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -OF_ASSUME_NONNULL_BEGIN - -static OF_INLINE int -OFAtomicIntAdd(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -OFAtomicIntSubtract(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "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; -} - -static OF_INLINE int32_t -OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64) - __asm__ __volatile__ ( - "negq %0\n\t" - "lock\n\t" - "xaddq %0, %2\n\t" - "subq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -OFAtomicIntIncrease(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "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_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "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; -} - -static OF_INLINE int32_t -OFAtomicInt32Increase(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE int -OFAtomicIntDecrease(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "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_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "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; -} - -static OF_INLINE int32_t -OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "orq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "andq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64 - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "xorq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchgl %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE bool -OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE void -OFMemoryBarrier(void) -{ - __asm__ __volatile__ ( - "mfence" ::: "memory" - ); -} - -static OF_INLINE void -OFAcquireMemoryBarrier(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -static OF_INLINE void -OFReleaseMemoryBarrier(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -OF_ASSUME_NONNULL_END Index: src/OFBase64.h ================================================================== --- src/OFBase64.h +++ src/OFBase64.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBase64.m ================================================================== --- src/OFBase64.m +++ src/OFBase64.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBitSetCharacterSet.h ================================================================== --- src/OFBitSetCharacterSet.h +++ src/OFBitSetCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBitSetCharacterSet.m ================================================================== --- src/OFBitSetCharacterSet.m +++ src/OFBitSetCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBlock.h ================================================================== --- src/OFBlock.h +++ src/OFBlock.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,12 +40,12 @@ @end #ifdef __cplusplus extern "C" { #endif -extern void *_Block_copy(const void *); -extern void _Block_release(const void *); +extern void *_Nullable _Block_copy(const void *_Nullable); +extern void _Block_release(const void *_Nullable); # if defined(OF_WINDOWS) && \ (defined(OF_NO_SHARED) || defined(OF_COMPILING_OBJFW)) /* * Clang has implicit declarations for these, but they are dllimport. When Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBytesValue.h ================================================================== --- src/OFBytesValue.h +++ src/OFBytesValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFBytesValue.m ================================================================== --- src/OFBytesValue.m +++ src/OFBytesValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCRC16.h ================================================================== --- src/OFCRC16.h +++ src/OFCRC16.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCRC16.m ================================================================== --- src/OFCRC16.m +++ src/OFCRC16.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCRC32.h ================================================================== --- src/OFCRC32.h +++ src/OFCRC32.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCRC32.m ================================================================== --- src/OFCRC32.m +++ src/OFCRC32.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCharacterSet.h ================================================================== --- src/OFCharacterSet.h +++ src/OFCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCharacterSet.m ================================================================== --- src/OFCharacterSet.m +++ src/OFCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCollection.h ================================================================== --- src/OFCollection.h +++ src/OFCollection.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFColor.h ================================================================== --- src/OFColor.h +++ src/OFColor.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCondition.h ================================================================== --- src/OFCondition.h +++ src/OFCondition.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCondition.m ================================================================== --- src/OFCondition.m +++ src/OFCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -104,11 +104,11 @@ #ifdef OF_AMIGAOS - (bool)waitForTimeInterval: (OFTimeInterval)timeInterval orExecSignal: (ULONG *)signalMask { - int error = OFPlainConditionTimedWaitExecOrSignal(&_condition, &_mutex, + int error = OFPlainConditionTimedWaitOrExecSignal(&_condition, &_mutex, timeInterval, signalMask); if (error == ETIMEDOUT) return false; Index: src/OFConstantString.h ================================================================== --- src/OFConstantString.h +++ src/OFConstantString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -347,10 +347,16 @@ - (OFString *)stringByAppendingPathComponent: (OFString *)component { [self finishInitialization]; return [self stringByAppendingPathComponent: component]; } + +- (OFString *)stringByAppendingPathExtension: (OFString *)extension +{ + [self finishInitialization]; + return [self stringByAppendingPathExtension: extension]; +} - (OFString *)stringByPrependingString: (OFString *)string { [self finishInitialization]; return [self stringByPrependingString: string]; Index: src/OFCountedMapTableSet.h ================================================================== --- src/OFCountedMapTableSet.h +++ src/OFCountedMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCountedMapTableSet.m ================================================================== --- src/OFCountedMapTableSet.m +++ src/OFCountedMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -41,11 +41,11 @@ @try { void *pool = objc_autoreleasePoolPush(); if ([set isKindOfClass: [OFCountedSet class]]) { - OFCountedSet *countedSet = (OFCountedSet *)countedSet; + OFCountedSet *countedSet = (OFCountedSet *)set; for (id object in countedSet) { size_t count = [countedSet countForObject: object]; Index: src/OFCountedSet.h ================================================================== --- src/OFCountedSet.h +++ src/OFCountedSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCountedSet.m ================================================================== --- src/OFCountedSet.m +++ src/OFCountedSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFCryptographicHash.h ================================================================== --- src/OFCryptographicHash.h +++ src/OFCryptographicHash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -98,10 +98,15 @@ * @param buffer The buffer which should be included into the calculation * @param length The length of the buffer */ - (void)updateWithBuffer: (const void *)buffer length: (size_t)length; +/** + * @brief Performs the final calculation of the cryptographic hash. + */ +- (void)calculate; + /** * @brief Resets all state so that a new hash can be calculated. * * @warning This invalidates any pointer previously returned by @ref digest. If * you are still interested in the previous digest, you need to memcpy Index: src/OFDNSQuery.h ================================================================== --- src/OFDNSQuery.h +++ src/OFDNSQuery.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSQuery.m ================================================================== --- src/OFDNSQuery.m +++ src/OFDNSQuery.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,10 +37,11 @@ #import "OFDNSQueryFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" +#import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #ifndef SOCK_DNS # define SOCK_DNS 0 @@ -745,11 +746,15 @@ OFSocketAddressParseIPv6(@"::", 0); _IPv6Socket = [[OFUDPSocket alloc] init]; [_IPv6Socket of_bindToAddress: &address extraType: SOCK_DNS]; - _IPv6Socket.canBlock = false; + @try { + _IPv6Socket.canBlock = false; + } @catch (OFNotImplementedException *e) { + /* Can't do anything about it... */ + } _IPv6Socket.delegate = self; } sock = _IPv6Socket; break; @@ -760,11 +765,15 @@ OFSocketAddressParseIPv4(@"0.0.0.0", 0); _IPv4Socket = [[OFUDPSocket alloc] init]; [_IPv4Socket of_bindToAddress: &address extraType: SOCK_DNS]; - _IPv4Socket.canBlock = false; + @try { + _IPv4Socket.canBlock = false; + } @catch (OFNotImplementedException *e) { + /* Can't do anything about it... */ + } _IPv4Socket.delegate = self; } sock = _IPv4Socket; break; Index: src/OFDNSResolverSettings.h ================================================================== --- src/OFDNSResolverSettings.h +++ src/OFDNSResolverSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -64,15 +64,21 @@ # define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" #else # define HOSTS_PATH @"/etc/hosts" # define RESOLV_CONF_PATH @"/etc/resolv.conf" #endif + +#ifndef HOST_NAME_MAX +# define HOST_NAME_MAX 255 +#endif #ifndef OF_WII static OFString * domainFromHostname(OFString *hostname) { + OFString *ret; + if (hostname == nil) return nil; @try { OFSocketAddressParseIP(hostname, 0); @@ -79,30 +85,32 @@ /* * If we are still here, the host name is a valid IP address. * We can't use that as local domain. */ - return nil; + ret = nil; } @catch (OFInvalidFormatException *e) { /* Not an IP address -> we can use it if it contains a dot. */ size_t pos = [hostname rangeOfString: @"."].location; - if (pos == OFNotFound) - return nil; - - return [hostname substringFromIndex: pos + 1]; + if (pos != OFNotFound) + ret = [hostname substringFromIndex: pos + 1]; + else + ret = nil; } + + return ret; } #endif #if !defined(OF_WII) && !defined(OF_MORPHOS) static OFString * obtainHostname(void) { - char hostname[256]; + char hostname[HOST_NAME_MAX + 1]; - if (gethostname(hostname, 256) != 0) + if (gethostname(hostname, HOST_NAME_MAX + 1) != 0) return nil; return [OFString stringWithCString: hostname encoding: [OFLocale encoding]]; } Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -618,14 +618,41 @@ @end #ifdef __cplusplus extern "C" { #endif +/** + * @brief Returns the name for the specified OFDNSClass. + * + * @param DNSClass The OFDNSClass to return the name for + * @return The name for the specified OFDNSClass + */ extern OFString *_Nonnull OFDNSClassName(OFDNSClass DNSClass); + +/** + * @brief Returns the name for the specified OFDNSRecordType. + * + * @param recordType The OFDNSRecordType to return the name for + * @return The name for the specified OFDNSRecordType + */ extern OFString *_Nonnull OFDNSRecordTypeName(OFDNSRecordType recordType); + +/** + * @brief Parses the specified string as an @ref OFDNSClass. + * + * @param string The string to parse as an @ref OFDNSClass + * @return The parsed OFDNSClass + */ extern OFDNSClass OFDNSClassParseName(OFString *_Nonnull string); + +/** + * @brief Parses the specified string as an @ref OFDNSRecordType. + * + * @param string The string to parse as an @ref OFDNSRecordType + * @return The parsed OFDNSRecordType + */ extern OFDNSRecordType OFDNSRecordTypeParseName(OFString *_Nonnull string); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSResponse.h ================================================================== --- src/OFDNSResponse.h +++ src/OFDNSResponse.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDNSResponse.m ================================================================== --- src/OFDNSResponse.m +++ src/OFDNSResponse.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -54,11 +54,11 @@ } return self; } -- (instancetype)init OF_UNAVAILABLE +- (instancetype)init { OF_INVALID_INIT_METHOD } - (void)dealloc Index: src/OFData+CryptographicHashing.h ================================================================== --- src/OFData+CryptographicHashing.h +++ src/OFData+CryptographicHashing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFData+CryptographicHashing.m ================================================================== --- src/OFData+CryptographicHashing.m +++ src/OFData+CryptographicHashing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,10 +39,11 @@ const unsigned char *digest; char cString[digestSize * 2]; [hash updateWithBuffer: self->_items length: self->_count * self->_itemSize]; + [hash calculate]; digest = hash.digest; for (size_t i = 0; i < digestSize; i++) { uint8_t high, low; Index: src/OFData+MessagePackParsing.h ================================================================== --- src/OFData+MessagePackParsing.h +++ src/OFData+MessagePackParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFData+MessagePackParsing.m ================================================================== --- src/OFData+MessagePackParsing.m +++ src/OFData+MessagePackParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -43,15 +43,15 @@ * for OFData with item size 1. */ @interface OFData: OFObject { - unsigned char *_items; + unsigned char *_Nullable _items; size_t _count, _itemSize; bool _freeWhenDone; @private - OFData *_parentData; + OFData *_Nullable _parentData; OF_RESERVE_IVARS(OFData, 4) } /** * @brief The size of a single item in the OFData in bytes. @@ -66,11 +66,12 @@ /** * @brief All elements of the OFData as a C array. * * @warning The pointer is only valid until the OFData is changed! */ -@property (readonly, nonatomic) const void *items OF_RETURNS_INNER_POINTER; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) const void *items + OF_RETURNS_INNER_POINTER; /** * @brief The first item of the OFData or `NULL`. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) const void *firstItem @@ -118,10 +119,13 @@ itemSize: (size_t)itemSize; /** * @brief Creates a new OFData with the specified `count` items of size 1 by * taking over ownership of the specified items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -132,10 +136,13 @@ freeWhenDone: (bool)freeWhenDone; /** * @brief Creates a new OFData with the specified `count` items of the * specified size by taking ownership of the specified items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed @@ -167,13 +174,13 @@ */ + (instancetype)dataWithContentsOfURL: (OFURL *)URL; /** * @brief Creates a new OFData with an item size of 1, containing the data of - * the string representation. + * the hex string representation. * - * @param string The string representation of the data + * @param string The hex string representation of the data * @return A new autoreleased OFData */ + (instancetype)dataWithStringRepresentation: (OFString *)string; /** @@ -184,21 +191,21 @@ * @return A new autoreleased OFData */ + (instancetype)dataWithBase64EncodedString: (OFString *)string; /** - * @brief Initialized an already allocated OFData with the specified `count` + * @brief Initializes an already allocated OFData with the specified `count` * items of size 1. * * @param items The items to store in the OFData * @param count The number of items * @return An initialized OFData */ - (instancetype)initWithItems: (const void *)items count: (size_t)count; /** - * @brief Initialized an already allocated OFData with the specified `count` + * @brief Initializes an already allocated OFData with the specified `count` * items of the specified size. * * @param items The items to store in the OFData * @param count The number of items * @param itemSize The item size of a single item in bytes @@ -210,10 +217,13 @@ /** * @brief Initializes an already allocated OFData with the specified `count` * items of size 1 by taking over ownership of the specified items * pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -225,10 +235,13 @@ /** * @brief Initializes an already allocated OFData with the specified `count` * items of the specified size by taking ownership of the specified * items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed @@ -260,13 +273,13 @@ */ - (instancetype)initWithContentsOfURL: (OFURL *)URL; /** * @brief Initializes an already allocated OFData with an item size of 1, - * containing the data of the string representation. + * containing the data of the hex string representation. * - * @param string The string representation of the data + * @param string The hex string representation of the data * @return A new autoreleased OFData */ - (instancetype)initWithStringRepresentation: (OFString *)string; /** Index: src/OFData.m ================================================================== --- src/OFData.m +++ src/OFData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDatagramSocket.h ================================================================== --- src/OFDatagramSocket.h +++ src/OFDatagramSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,18 +39,15 @@ const OFSocketAddress *_Nonnull sender, id _Nullable exception); /** * @brief A block which is called when a packet has been sent. * - * @param data The data which was sent - * @param receiver The receiver for the packet * @param exception An exception which occurred while reading or `nil` on * success * @return The data to repeat the send with or nil if it should not repeat */ typedef OFData *_Nullable (^OFDatagramSocketAsyncSendDataBlock)( - OFData *_Nonnull data, const OFSocketAddress *_Nonnull receiver, id _Nullable exception); #endif /** * @protocol OFDatagramSocketDelegate OFDatagramSocket.h \ Index: src/OFDatagramSocket.m ================================================================== --- src/OFDatagramSocket.m +++ src/OFDatagramSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -116,11 +116,11 @@ @throw [OFSetOptionFailedException exceptionWithObject: self errNo: errno]; _canBlock = canBlock; #elif defined(OF_WINDOWS) - u_long v = canBlock; + u_long v = !canBlock; if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self errNo: OFSocketErrNo()]; @@ -175,35 +175,40 @@ sender->length = (socklen_t)sizeof(sender->sockaddr); #ifndef OF_WINDOWS if ((ret = recvfrom(_socket, buffer, length, 0, - &sender->sockaddr.sockaddr, &sender->length)) < 0) + (struct sockaddr *)&sender->sockaddr, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: OFSocketErrNo()]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recvfrom(_socket, buffer, (int)length, 0, - &sender->sockaddr.sockaddr, &sender->length)) < 0) + (struct sockaddr *)&sender->sockaddr, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: OFSocketErrNo()]; #endif - switch (sender->sockaddr.sockaddr.sa_family) { + switch (((struct sockaddr *)&sender->sockaddr)->sa_family) { case AF_INET: sender->family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: sender->family = OFSocketAddressFamilyIPv6; break; +#endif +#ifdef OF_HAVE_UNIX_SOCKETS + case AF_UNIX: + sender->family = OFSocketAddressFamilyUNIX; + break; #endif #ifdef OF_HAVE_IPX case AF_IPX: sender->family = OFSocketAddressFamilyIPX; break; @@ -274,12 +279,11 @@ if (length > SSIZE_MAX) @throw [OFOutOfRangeException exception]; if ((bytesWritten = sendto(_socket, (void *)buffer, length, 0, - (struct sockaddr *)&receiver->sockaddr.sockaddr, - receiver->length)) < 0) + (struct sockaddr *)&receiver->sockaddr, receiver->length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: OFSocketErrNo()]; @@ -288,11 +292,11 @@ if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((bytesWritten = sendto(_socket, buffer, (int)length, 0, - &receiver->sockaddr.sockaddr, receiver->length)) < 0) + (struct sockaddr *)&receiver->sockaddr, receiver->length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: OFSocketErrNo()]; Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,12 +39,12 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#ifdef OF_AMIGAOS_M68K -/* amiga-gcc does not have trunc() */ +#if defined(OF_AMIGAOS_M68K) || defined(OF_MINT) +/* amiga-gcc and freemint-gcc do not have trunc() */ # define trunc(x) ((int64_t)(x)) #endif @interface OFDate () + (instancetype)of_alloc; Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -32,12 +32,36 @@ OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); #ifdef OF_HAVE_BLOCKS +/** + * @brief A block for enumerating an OFDictionary. + * + * @param key The current key + * @param object The object for the current key + * @param stop A pointer to a variable that can be set to true to stop the + * enumeration. + */ typedef void (^OFDictionaryEnumerationBlock)(id key, id object, bool *stop); + +/** + * @brief A block for filtering an OFDictionary. + * + * @param key The key to inspect + * @param object The object for the key to inspect + * @return Whether the object should be in the filtered dictionary. + */ typedef bool (^OFDictionaryFilterBlock)(id key, id object); + +/** + * @brief A block for mapping keys to objects in an OFDictionary. + * + * @param key The key to map + * @param object The current object for the key + * @return The object to map the key to + */ typedef id _Nonnull (^OFDictionaryMapBlock)(id key, id object); #endif /** * @class OFDictionary OFDictionary.h ObjFW/OFDictionary.h @@ -104,13 +128,12 @@ * * @param keys An array of keys * @param objects An array of objects * @return A new autoreleased OFDictionary */ -+ (instancetype) - dictionaryWithObjects: (OFArray OF_GENERIC(ObjectType) *)objects - forKeys: (OFArray OF_GENERIC(KeyType) *)keys; ++ (instancetype)dictionaryWithObjects: (OFArray OF_GENERIC(ObjectType) *)objects + forKeys: (OFArray OF_GENERIC(KeyType) *)keys; /** * @brief Creates a new OFDictionary with the specified keys and objects. * * @param keys An array of keys Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 ADDED src/OFEmbeddedFileURLHandler.h Index: src/OFEmbeddedFileURLHandler.h ================================================================== --- /dev/null +++ src/OFEmbeddedFileURLHandler.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2022 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 "OFURLHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFEmbeddedFileURLHandler: OFURLHandler +@end + +OF_ASSUME_NONNULL_END ADDED src/OFEmbeddedFileURLHandler.m Index: src/OFEmbeddedFileURLHandler.m ================================================================== --- /dev/null +++ src/OFEmbeddedFileURLHandler.m @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008-2022 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" + +#include +#include +#include + +#import "OFEmbeddedFileURLHandler.h" +#import "OFMemoryStream.h" +#import "OFURL.h" + +#import "OFInvalidArgumentException.h" +#import "OFOpenItemFailedException.h" + +#ifdef OF_HAVE_THREADS +# import "OFOnce.h" +# import "OFPlainMutex.h" +#endif + +struct EmbeddedFile { + const char *name; + const uint8_t *bytes; + size_t size; +} *embeddedFiles = NULL; +size_t numEmbeddedFiles = 0; +#ifdef OF_HAVE_THREADS +static OFPlainMutex mutex; + +static void +init(void) +{ + OFEnsure(OFPlainMutexNew(&mutex) == 0); +} +#endif + +void +OFRegisterEmbeddedFile(const char *name, const uint8_t *bytes, size_t size) +{ +#ifdef OF_HAVE_THREADS + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, init); + + OFEnsure(OFPlainMutexLock(&mutex) == 0); +#endif + + embeddedFiles = realloc(embeddedFiles, + sizeof(*embeddedFiles) * (numEmbeddedFiles + 1)); + OFEnsure(embeddedFiles != NULL); + + embeddedFiles[numEmbeddedFiles].name = name; + embeddedFiles[numEmbeddedFiles].bytes = bytes; + embeddedFiles[numEmbeddedFiles].size = size; + numEmbeddedFiles++; + +#ifdef OF_HAVE_THREADS + OFEnsure(OFPlainMutexUnlock(&mutex) == 0); +#endif +} + +@implementation OFEmbeddedFileURLHandler +- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode +{ + const char *path; + + if (![URL.scheme isEqual: @"objfw-embedded"] || URL.host != nil || + URL.port != nil || URL.user != nil || URL.password != nil || + URL.query != nil || URL.fragment != nil) + @throw [OFInvalidArgumentException exception]; + + if (![mode isEqual: @"r"]) + @throw [OFOpenItemFailedException exceptionWithURL: URL + mode: mode + errNo: EROFS]; + + if ((path = URL.path.UTF8String) == NULL) { + @throw [OFInvalidArgumentException exception]; + } + +#ifdef OF_HAVE_THREADS + OFEnsure(OFPlainMutexLock(&mutex) == 0); + @try { +#endif + for (size_t i = 0; i < numEmbeddedFiles; i++) { + if (strcmp(embeddedFiles[i].name, path) != 0) + continue; + + return [OFMemoryStream + streamWithMemoryAddress: (void *) + embeddedFiles[i].bytes + size: embeddedFiles[i].size + writable: false]; + } +#ifdef OF_HAVE_THREADS + } @finally { + OFEnsure(OFPlainMutexUnlock(&mutex) == 0); + } +#endif + + @throw [OFOpenItemFailedException exceptionWithURL: URL + mode: mode + errNo: ENOENT]; +} +@end Index: src/OFEnumerator.h ================================================================== --- src/OFEnumerator.h +++ src/OFEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -48,12 +48,10 @@ /** * @struct OFFastEnumerationState OFEnumerator.h ObjFW/OFEnumerator.h * * @brief State information for fast enumerations. */ -#define OFFastEnumerationState NSFastEnumerationState -#ifndef NSINTEGER_DEFINED typedef struct { /** Arbitrary state information for the enumeration */ unsigned long state; /** Pointer to a C array of objects to return */ id __unsafe_unretained _Nullable *_Nullable itemsPtr; @@ -60,10 +58,12 @@ /** Arbitrary state information to detect mutations */ unsigned long *_Nullable mutationsPtr; /** Additional arbitrary state information */ unsigned long extra[5]; } OFFastEnumerationState; +#ifndef NSINTEGER_DEFINED +typedef OFFastEnumerationState NSFastEnumerationState; #endif /** * @protocol OFFastEnumeration OFEnumerator.h ObjFW/OFEnumerator.h * Index: src/OFEnumerator.m ================================================================== --- src/OFEnumerator.m +++ src/OFEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFEpollKernelEventObserver.h ================================================================== --- src/OFEpollKernelEventObserver.h +++ src/OFEpollKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFEpollKernelEventObserver.m ================================================================== --- src/OFEpollKernelEventObserver.m +++ src/OFEpollKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -63,30 +63,10 @@ * `a+` | Read-write, create or append * @return A new autoreleased OFFile */ + (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode; -/** - * @brief Creates a new OFFile with the specified URL and mode. - * - * @param URL The URL to the file to open - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * Mode | Description - * ---------------|------------------------------------- - * `r` | Read-only - * `r+` | Read-write - * `w` | Write-only, create or truncate - * `wx` | Write-only, create or fail, exclusive - * `w+` | Read-write, create or truncate - * `w+x` | Read-write, create or fail, exclusive - * `a` | Write-only, create or append - * `a+` | Read-write, create or append - * @return A new autoreleased OFFile - */ -+ (instancetype)fileWithURL: (OFURL *)URL mode: (OFString *)mode; - /** * @brief Creates a new OFFile with the specified native file handle. * * @param handle A native file handle. If OF_FILE_HANDLE_IS_FD is defined, this * is a file descriptor. The handle is closed when the OFFile @@ -93,12 +73,10 @@ * object is deallocated! * @return A new autoreleased OFFile */ + (instancetype)fileWithHandle: (OFFileHandle)handle; -- (instancetype)init OF_UNAVAILABLE; - /** * @brief Initializes an already allocated OFFile. * * @param path The path to the file to open as a string * @param mode The mode in which the file should be opened.@n @@ -122,38 +100,16 @@ - (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode; /** * @brief Initializes an already allocated OFFile. * - * @param URL The URL to the file to open - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * Mode | Description - * ---------------|------------------------------------- - * `r` | read-only - * `rb` | read-only, binary - * `r+` | read-write - * `rb+` or `r+b` | read-write, binary - * `w` | write-only, create, truncate - * `wb` | write-only, create, truncate, binary - * `w` | read-write, create, truncate - * `wb+` or `w+b` | read-write, create, truncate, binary - * `a` | write-only, create, append - * `ab` | write-only, create, append, binary - * `a+` | read-write, create, append - * `ab+` or `a+b` | read-write, create, append, binary - * @return An initialized OFFile - */ -- (instancetype)initWithURL: (OFURL *)URL mode: (OFString *)mode; - -/** - * @brief Initializes an already allocated OFFile. - * * @param handle A native file handle. If OF_FILE_HANDLE_IS_FD is defined, this * is a file descriptor. The handle is closed when the OFFile * object is deallocated! * @return An initialized OFFile */ - (instancetype)initWithHandle: (OFFileHandle)handle OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -46,10 +46,15 @@ #import "OFWriteFailedException.h" #ifdef OF_WINDOWS # include #endif + +#ifdef OF_AMIGAOS +# include +# include +#endif #ifdef OF_WII # include #endif @@ -56,13 +61,14 @@ #ifdef OF_NINTENDO_DS # include # include #endif -#ifdef OF_AMIGAOS -# include -# include +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id #endif #ifndef O_BINARY # define O_BINARY 0 #endif @@ -77,28 +83,32 @@ #endif #ifndef OF_AMIGAOS # define closeHandle(h) close(h) #else -static struct _OFFileHandle +static struct _OFFileHandle { struct _OFFileHandle *previous, *next; BPTR handle; bool append; } *firstHandle = NULL; static void closeHandle(OFFileHandle handle) { Close(handle->handle); + + Forbid(); if (handle->previous != NULL) handle->previous->next = handle->next; if (handle->next != NULL) handle->next->previous = handle->previous; if (firstHandle == handle) firstHandle = handle->next; + + Permit(); OFFreeMemory(handle); } OF_DESTRUCTOR() @@ -178,32 +188,31 @@ #ifdef OF_NINTENDO_DS if (!nitroFSInit(NULL)) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif + +#ifdef OF_NINTENDO_SWITCH + if (R_SUCCEEDED(romfsInit())) + /* + * Errors are intentionally ignored, as it's possible we just + * have no romfs. + */ + atexit((void (*)(void))romfsExit); +#endif } + (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode { return [[[self alloc] initWithPath: path mode: mode] autorelease]; } -+ (instancetype)fileWithURL: (OFURL *)URL mode: (OFString *)mode -{ - return [[[self alloc] initWithURL: URL mode: mode] autorelease]; -} - + (instancetype)fileWithHandle: (OFFileHandle)handle { return [[[self alloc] initWithHandle: handle] autorelease]; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { OFFileHandle handle; @try { @@ -289,18 +298,22 @@ exceptionWithPath: path mode: mode errNo: EIO]; } } + + Forbid(); handle->previous = NULL; handle->next = firstHandle; if (firstHandle != NULL) firstHandle->previous = handle; firstHandle = handle; + + Permit(); } @catch (id e) { OFFreeMemory(handle); @throw e; } #endif @@ -319,37 +332,23 @@ } return self; } -- (instancetype)initWithURL: (OFURL *)URL mode: (OFString *)mode -{ - void *pool = objc_autoreleasePoolPush(); - OFString *fileSystemRepresentation; - - @try { - fileSystemRepresentation = URL.fileSystemRepresentation; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithPath: fileSystemRepresentation mode: mode]; - - objc_autoreleasePoolPop(pool); - - return self; -} - - (instancetype)initWithHandle: (OFFileHandle)handle { self = [super init]; _handle = handle; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (bool)lowlevelIsAtEndOfStream { if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; Index: src/OFFileManager.h ================================================================== --- src/OFFileManager.h +++ src/OFFileManager.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -407,10 +407,21 @@ * @return An array with the URLs of the items in the specified directory */ - (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL; #ifdef OF_HAVE_FILES +/** + * @brief Returns an array with all subpaths of the specified directory. + * + * @note `.` and `..` (of the directory itself or any subdirectory) are not + * part of the returned array. + * + * @param path The path to the directory whose subpaths should be returned + * @return An array of OFString with the subpaths of the specified directory + */ +- (OFArray OF_GENERIC(OFString *) *)subpathsOfDirectoryAtPath: (OFString *)path; + /** * @brief Changes the current working directory. * * @param path The new directory to change to */ Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -65,43 +65,23 @@ #ifdef OF_AMIGAOS # include # include #endif + +#ifdef OF_MINT +# include +#endif @interface OFDefaultFileManager: OFFileManager @end -const OFFileAttributeKey OFFileSize = @"OFFileSize"; -const OFFileAttributeKey OFFileType = @"OFFileType"; -const OFFileAttributeKey OFFilePOSIXPermissions = @"OFFilePOSIXPermissions"; -const OFFileAttributeKey OFFileOwnerAccountID = @"OFFileOwnerAccountID"; -const OFFileAttributeKey OFFileGroupOwnerAccountID = - @"OFFileGroupOwnerAccountID"; -const OFFileAttributeKey OFFileOwnerAccountName = @"OFFileOwnerAccountName"; -const OFFileAttributeKey OFFileGroupOwnerAccountName = - @"OFFileGroupOwnerAccountName"; -const OFFileAttributeKey OFFileLastAccessDate = @"OFFileLastAccessDate"; -const OFFileAttributeKey OFFileModificationDate = @"OFFileModificationDate"; -const OFFileAttributeKey OFFileStatusChangeDate = @"OFFileStatusChangeDate"; -const OFFileAttributeKey OFFileCreationDate = @"OFFileCreationDate"; -const OFFileAttributeKey OFFileSymbolicLinkDestination = - @"OFFileSymbolicLinkDestination"; - -const OFFileAttributeType OFFileTypeRegular = @"OFFileTypeRegular"; -const OFFileAttributeType OFFileTypeDirectory = @"OFFileTypeDirectory"; -const OFFileAttributeType OFFileTypeSymbolicLink = @"OFFileTypeSymbolicLink"; -const OFFileAttributeType OFFileTypeFIFO = @"OFFileTypeFIFO"; -const OFFileAttributeType OFFileTypeCharacterSpecial = - @"OFFileTypeCharacterSpecial"; -const OFFileAttributeType OFFileTypeBlockSpecial = @"OFFileTypeBlockSpecial"; -const OFFileAttributeType OFFileTypeSocket = @"OFFileTypeSocket"; -const OFFileAttributeType OFFileTypeUnknown = @"OFFileTypeUnknown"; - #ifdef OF_AMIGAOS4 # define CurrentDir(lock) SetCurrentDir(lock) #endif + +#include "OFFileManagerConstants.inc" static OFFileManager *defaultManager; #ifdef OF_AMIGAOS static bool dirChanged = false; @@ -470,10 +450,41 @@ ret = [OFMutableArray arrayWithCapacity: URLs.count]; for (OFURL *URL in URLs) [ret addObject: URL.lastPathComponent]; + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFArray OF_GENERIC(OFString *) *)subpathsOfDirectoryAtPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableArray OF_GENERIC(OFString *) *ret = + [OFMutableArray arrayWithObject: path]; + + for (OFString *subpath in [self contentsOfDirectoryAtPath: path]) { + void *pool2 = objc_autoreleasePoolPush(); + OFString *fullSubpath = + [path stringByAppendingPathComponent: subpath]; + OFFileAttributes attributes = + [self attributesOfItemAtPath: fullSubpath]; + + if ([attributes.fileType isEqual: OFFileTypeDirectory]) + [ret addObjectsFromArray: + [self subpathsOfDirectoryAtPath: fullSubpath]]; + else + [ret addObject: fullSubpath]; + + objc_autoreleasePoolPop(pool2); + } + + [ret makeImmutable]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; ADDED src/OFFileManagerConstants.inc Index: src/OFFileManagerConstants.inc ================================================================== --- /dev/null +++ src/OFFileManagerConstants.inc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +const OFFileAttributeKey OFFileSize = @"OFFileSize"; +const OFFileAttributeKey OFFileType = @"OFFileType"; +const OFFileAttributeKey OFFilePOSIXPermissions = @"OFFilePOSIXPermissions"; +const OFFileAttributeKey OFFileOwnerAccountID = @"OFFileOwnerAccountID"; +const OFFileAttributeKey OFFileGroupOwnerAccountID = + @"OFFileGroupOwnerAccountID"; +const OFFileAttributeKey OFFileOwnerAccountName = @"OFFileOwnerAccountName"; +const OFFileAttributeKey OFFileGroupOwnerAccountName = + @"OFFileGroupOwnerAccountName"; +const OFFileAttributeKey OFFileLastAccessDate = @"OFFileLastAccessDate"; +const OFFileAttributeKey OFFileModificationDate = @"OFFileModificationDate"; +const OFFileAttributeKey OFFileStatusChangeDate = @"OFFileStatusChangeDate"; +const OFFileAttributeKey OFFileCreationDate = @"OFFileCreationDate"; +const OFFileAttributeKey OFFileSymbolicLinkDestination = + @"OFFileSymbolicLinkDestination"; + +const OFFileAttributeType OFFileTypeRegular = @"OFFileTypeRegular"; +const OFFileAttributeType OFFileTypeDirectory = @"OFFileTypeDirectory"; +const OFFileAttributeType OFFileTypeSymbolicLink = @"OFFileTypeSymbolicLink"; +const OFFileAttributeType OFFileTypeFIFO = @"OFFileTypeFIFO"; +const OFFileAttributeType OFFileTypeCharacterSpecial = + @"OFFileTypeCharacterSpecial"; +const OFFileAttributeType OFFileTypeBlockSpecial = @"OFFileTypeBlockSpecial"; +const OFFileAttributeType OFFileTypeSocket = @"OFFileTypeSocket"; +const OFFileAttributeType OFFileTypeUnknown = @"OFFileTypeUnknown"; Index: src/OFFileURLHandler.h ================================================================== --- src/OFFileURLHandler.h +++ src/OFFileURLHandler.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFGZIPStream.h ================================================================== --- src/OFGZIPStream.h +++ src/OFGZIPStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHMAC.h ================================================================== --- src/OFHMAC.h +++ src/OFHMAC.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -101,10 +101,15 @@ * @param buffer The buffer which should be included into the calculation * @param length The length of the buffer */ - (void)updateWithBuffer: (const void *)buffer length: (size_t)length; +/** + * @brief Performs the final calculation of the HMAC. + */ +- (void)calculate; + /** * @brief Resets the HMAC so that it can be calculated for a new message. * * @note This does not reset the key so that a new HMAC with the same key can * be calculated efficiently. If you want to reset both, use Index: src/OFHMAC.m ================================================================== --- src/OFHMAC.m +++ src/OFHMAC.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,10 +17,11 @@ #import "OFHMAC.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFInvalidArgumentException.h" @implementation OFHMAC @synthesize hashClass = _hashClass; @synthesize allowsSwappableMemory = _allowsSwappableMemory; @@ -82,10 +83,11 @@ if (length > blockSize) { id hash = [_hashClass hashWithAllowsSwappableMemory: _allowsSwappableMemory]; [hash updateWithBuffer: key length: length]; + [hash calculate]; length = hash.digestSize; if OF_UNLIKELY (length > blockSize) length = blockSize; @@ -138,21 +140,30 @@ exceptionWithObject: self]; [_innerHash updateWithBuffer: buffer length: length]; } -- (const unsigned char *)digest +- (void)calculate { + if (_calculated) + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; + if (_outerHash == nil || _innerHash == nil) @throw [OFInvalidArgumentException exception]; - if (_calculated) - return _outerHash.digest; - + [_innerHash calculate]; [_outerHash updateWithBuffer: _innerHash.digest length: _innerHash.digestSize]; + [_outerHash calculate]; _calculated = true; +} + +- (const unsigned char *)digest +{ + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; return _outerHash.digest; } - (size_t)digestSize Index: src/OFHTTPClient.h ================================================================== --- src/OFHTTPClient.h +++ src/OFHTTPClient.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -25,10 +25,11 @@ @class OFHTTPClient; @class OFHTTPRequest; @class OFHTTPResponse; @class OFStream; @class OFTCPSocket; +@class OFTLSStream; @class OFURL; /** * @protocol OFHTTPClientDelegate OFHTTPClient.h ObjFW/OFHTTPClient.h * @@ -48,24 +49,36 @@ response: (nullable OFHTTPResponse *)response exception: (nullable id)exception; @optional /** - * @brief A callback which is called when an OFHTTPClient creates a socket. - * - * This is useful if the connection is using HTTPS and the server requires a - * client certificate. This callback can then be used to tell the TLS socket - * about the certificate. Another use case is to tell the socket about a SOCKS5 - * proxy it should use for this connection. - * - * @param client The OFHTTPClient that created a socket - * @param socket The socket created by the OFHTTPClient - * @param request The request for which the socket was created - */ -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)socket - request: (OFHTTPRequest *)request; + * @brief A callback which is called when an OFHTTPClient creates a TCP socket. + * + * This can be used to tell the socket about a SOCKS5 proxy it should use for + * this connection. + * + * @param client The OFHTTPClient that created a TCP socket + * @param TCPSocket The socket created by the OFHTTPClient + * @param request The request for which the TCP socket was created + */ +- (void)client: (OFHTTPClient *)client + didCreateTCPSocket: (OFTCPSocket *)TCPSocket + request: (OFHTTPRequest *)request; + +/** + * @brief A callback which is called when an OFHTTPClient creates a TLS stream. + * + * This can be used to tell the TLS stream about a client certificate it should + * use before performing the TLS handshake. + * + * @param client The OFHTTPClient that created a TLS stream + * @param TLSStream The TLS stream created by the OFHTTPClient + * @param request The request for which the TLS stream was created + */ +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)TLSStream + request: (OFHTTPRequest *)request; /** * @brief A callback which is called when an OFHTTPClient wants to send the * body for a request. * @@ -134,11 +147,11 @@ #ifdef OF_HTTPCLIENT_M @public #endif OFObject *_Nullable _delegate; bool _allowsInsecureRedirects, _inProgress; - OFTCPSocket *_Nullable _socket; + OFStream *_Nullable _stream; OFURL *_Nullable _lastURL; bool _lastWasHEAD; OFHTTPResponse *_Nullable _lastResponse; } Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,13 +26,13 @@ #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFKernelEventObserver.h" #import "OFNumber.h" #import "OFRunLoop.h" -#import "OFSocket+Private.h" #import "OFString.h" #import "OFTCPSocket.h" +#import "OFTLSStream.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" @@ -49,11 +49,12 @@ #import "OFWriteFailedException.h" static const unsigned int defaultRedirects = 10; OF_DIRECT_MEMBERS -@interface OFHTTPClientRequestHandler: OFObject +@interface OFHTTPClientRequestHandler: OFObject { @public OFHTTPClient *_client; OFHTTPRequest *_request; unsigned int _redirects; @@ -72,32 +73,32 @@ OF_DIRECT_MEMBERS @interface OFHTTPClientRequestBodyStream: OFStream { OFHTTPClientRequestHandler *_handler; - OFTCPSocket *_socket; + OFStream *_stream; bool _chunked; unsigned long long _toWrite; bool _atEndOfStream; } - (instancetype)initWithHandler: (OFHTTPClientRequestHandler *)handler - socket: (OFTCPSocket *)sock; + stream: (OFStream *)stream; @end OF_DIRECT_MEMBERS @interface OFHTTPClientResponse: OFHTTPResponse { - OFTCPSocket *_socket; + OFStream *_stream; bool _hasContentLength, _chunked, _keepAlive; bool _atEndOfStream, _setAtEndOfStream; long long _toRead; } @property (nonatomic, setter=of_setKeepAlive:) bool of_keepAlive; -- (instancetype)initWithSocket: (OFTCPSocket *)sock; +- (instancetype)initWithStream: (OFStream *)stream; @end OF_DIRECT_MEMBERS @interface OFHTTPClientSyncPerformer: OFObject { @@ -293,20 +294,20 @@ didPerformRequest: _request response: nil exception: exception]; } -- (void)createResponseWithSocketOrThrow: (OFTCPSocket *)sock +- (void)createResponseWithStreamOrThrow: (OFStream *)stream { OFURL *URL = _request.URL; OFHTTPClientResponse *response; OFString *connectionHeader; bool keepAlive; OFString *location; id exception; - response = [[[OFHTTPClientResponse alloc] initWithSocket: sock] + response = [[[OFHTTPClientResponse alloc] initWithStream: stream] autorelease]; response.protocolVersionString = _version; response.statusCode = _status; response.headers = _serverHeaders; @@ -325,11 +326,11 @@ } if (keepAlive) { response.of_keepAlive = true; - _client->_socket = [sock retain]; + _client->_stream = [stream retain]; _client->_lastURL = [URL copy]; _client->_lastWasHEAD = (_request.method == OFHTTPRequestMethodHead); _client->_lastResponse = [response retain]; } @@ -429,14 +430,14 @@ withObject: response withObject: exception afterDelay: 0]; } -- (void)createResponseWithSocket: (OFTCPSocket *)sock +- (void)createResponseWithStream: (OFStream *)stream { @try { - [self createResponseWithSocketOrThrow: sock]; + [self createResponseWithStreamOrThrow: stream]; } @catch (id e) { [self raiseException: e]; } } @@ -471,11 +472,11 @@ _status = (short)status; return true; } -- (bool)handleServerHeader: (OFString *)line socket: (OFTCPSocket *)sock +- (bool)handleServerHeader: (OFString *)line stream: (OFStream *)stream { OFString *key, *value, *old; const char *lineC, *tmp; char *keyC; @@ -490,14 +491,14 @@ [_client->_delegate client: _client didReceiveHeaders: _serverHeaders statusCode: _status request: _request]; - sock.delegate = nil; + stream.delegate = nil; - [self performSelector: @selector(createResponseWithSocket:) - withObject: sock + [self performSelector: @selector(createResponseWithStream:) + withObject: stream afterDelay: 0]; return false; } @@ -532,11 +533,11 @@ [_serverHeaders setObject: value forKey: key]; return true; } -- (bool)stream: (OFStream *)sock +- (bool)stream: (OFStream *)stream didReadLine: (OFString *)line exception: (id)exception { bool ret; @@ -552,12 +553,11 @@ @try { if (_firstLine) { _firstLine = false; ret = [self handleFirstLine: line]; } else - ret = [self handleServerHeader: line - socket: (OFTCPSocket *)sock]; + ret = [self handleServerHeader: line stream: stream]; } @catch (id e) { [self raiseException: e]; ret = false; } @@ -594,12 +594,11 @@ if (chunked || [headers objectForKey: @"Content-Length"] != nil) { stream.delegate = nil; OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc] - initWithHandler: self - socket: (OFTCPSocket *)stream] autorelease]; + initWithHandler: self stream: stream] autorelease]; if ([_client->_delegate respondsToSelector: @selector(client:wantsRequestBody:request:)]) [_client->_delegate client: _client wantsRequestBody: requestBody @@ -608,23 +607,23 @@ [stream asyncReadLine]; return nil; } -- (void)handleSocket: (OFTCPSocket *)sock +- (void)handleStream: (OFStream *)stream { /* * As a work around for a bug with split packets in lighttpd when using * HTTPS, we construct the complete request in a buffer string and then * send it all at once. * - * We do not use the socket's write buffer in case we need to resend + * We do not use the streams's write buffer in case we need to resend * the entire request (e.g. in case a keep-alive connection timed out). */ @try { - [sock asyncWriteString: constructRequestString(_request)]; + [stream asyncWriteString: constructRequestString(_request)]; } @catch (id e) { [self raiseException: e]; return; } } @@ -632,58 +631,95 @@ - (void)socket: (OFTCPSocket *)sock didConnectToHost: (OFString *)host port: (uint16_t)port exception: (id)exception { - sock.delegate = self; + if (exception != nil) { + [self raiseException: exception]; + return; + } + sock.canBlock = false; + + if ([_client->_delegate respondsToSelector: + @selector(client:didCreateTCPSocket:request:)]) + [_client->_delegate client: _client + didCreateTCPSocket: sock + request: _request]; + + if ([_request.URL.scheme caseInsensitiveCompare: @"https"] == + OFOrderedSame) { + OFTLSStream *stream; + @try { + stream = [OFTLSStream streamWithStream: sock]; + } @catch (OFNotImplementedException *e) { + [self raiseException: + [OFUnsupportedProtocolException + exceptionWithURL: _request.URL]]; + return; + } + + if ([_client->_delegate respondsToSelector: + @selector(client:didCreateTLSStream:request:)]) + [_client->_delegate client: _client + didCreateTLSStream: stream + request: _request]; + + stream.delegate = self; + [stream asyncPerformClientHandshakeWithHost: _request.URL.host]; + } else { + sock.delegate = self; + [self performSelector: @selector(handleStream:) + withObject: sock + afterDelay: 0]; + } +} + +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (id)exception +{ if (exception != nil) { [self raiseException: exception]; return; } - if ([_client->_delegate respondsToSelector: - @selector(client:didCreateSocket:request:)]) - [_client->_delegate client: _client - didCreateSocket: sock - request: _request]; - - [self performSelector: @selector(handleSocket:) - withObject: sock + [self performSelector: @selector(handleStream:) + withObject: stream afterDelay: 0]; } - (void)start { OFURL *URL = _request.URL; - OFTCPSocket *sock; + OFStream *stream; /* Can we reuse the last socket? */ - if (_client->_socket != nil && !_client->_socket.atEndOfStream && + if (_client->_stream != nil && !_client->_stream.atEndOfStream && [_client->_lastURL.scheme isEqual: URL.scheme] && [_client->_lastURL.host isEqual: URL.host] && (_client->_lastURL.port == URL.port || [_client->_lastURL.port isEqual: URL.port]) && (_client->_lastWasHEAD || _client->_lastResponse.atEndOfStream)) { /* - * Set _socket to nil, so that in case of an error it won't be - * reused. If everything is successful, we set _socket again + * Set _stream to nil, so that in case of an error it won't be + * reused. If everything is successful, we set _stream again * at the end. */ - sock = [_client->_socket autorelease]; - _client->_socket = nil; + stream = [_client->_stream autorelease]; + _client->_stream = nil; [_client->_lastURL release]; _client->_lastURL = nil; [_client->_lastResponse release]; _client->_lastResponse = nil; - sock.delegate = self; + stream.delegate = self; - [self performSelector: @selector(handleSocket:) - withObject: sock + [self performSelector: @selector(handleStream:) + withObject: stream afterDelay: 0]; } else [self closeAndReconnect]; } @@ -694,23 +730,18 @@ OFTCPSocket *sock; uint16_t port; OFNumber *URLPort; [_client close]; + + sock = [OFTCPSocket socket]; if ([URL.scheme caseInsensitiveCompare: @"https"] == - OFOrderedSame) { - if (OFTLSSocketClass == Nil) - @throw [OFUnsupportedProtocolException - exceptionWithURL: URL]; - - sock = [[[OFTLSSocketClass alloc] init] autorelease]; + OFOrderedSame) port = 443; - } else { - sock = [OFTCPSocket socket]; + else port = 80; - } URLPort = URL.port; if (URLPort != nil) port = URLPort.unsignedShortValue; @@ -722,20 +753,20 @@ } @end @implementation OFHTTPClientRequestBodyStream - (instancetype)initWithHandler: (OFHTTPClientRequestHandler *)handler - socket: (OFTCPSocket *)sock + stream: (OFStream *)stream { self = [super init]; @try { OFDictionary OF_GENERIC(OFString *, OFString *) *headers; OFString *transferEncoding, *contentLengthString; _handler = [handler retain]; - _socket = [sock retain]; + _stream = [stream retain]; headers = _handler->_request.headers; transferEncoding = [headers objectForKey: @"Transfer-Encoding"]; _chunked = [transferEncoding isEqual: @"chunked"]; @@ -757,25 +788,23 @@ return self; } - (void)dealloc { - if (_socket != nil) + if (_stream != nil) [self close]; [_handler release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t requestedLength = length; - size_t ret; + /* TODO: Use non-blocking writes */ - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; /* * We must not send a chunk of size 0, as that would end the body. We * always ignore writing 0 bytes to still allow writing 0 bytes after @@ -783,90 +812,80 @@ */ if (length == 0) return 0; if (_atEndOfStream) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: requestedLength - bytesWritten: 0 - errNo: 0]; + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: ENOTCONN]; if (_chunked) - [_socket writeFormat: @"%zX\r\n", length]; + [_stream writeFormat: @"%zX\r\n", length]; else if (length > _toWrite) - length = (size_t)_toWrite; + @throw [OFOutOfRangeException exception]; - ret = [_socket writeBuffer: buffer length: length]; + [_stream writeBuffer: buffer length: length]; if (_chunked) - [_socket writeString: @"\r\n"]; - - if (ret > length) - @throw [OFOutOfRangeException exception]; + [_stream writeString: @"\r\n"]; if (!_chunked) { - _toWrite -= ret; + _toWrite -= length; if (_toWrite == 0) _atEndOfStream = true; } - if (requestedLength > length) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: requestedLength - bytesWritten: ret - errNo: 0]; - - return ret; + return length; } - (bool)lowlevelIsAtEndOfStream { return _atEndOfStream; } - (void)close { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_chunked) - [_socket writeString: @"0\r\n\r\n"]; + [_stream writeString: @"0\r\n\r\n"]; else if (_toWrite > 0) @throw [OFTruncatedDataException exception]; - _socket.delegate = _handler; - [_socket asyncReadLine]; + _stream.delegate = _handler; + [_stream asyncReadLine]; - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [super close]; } - (int)fileDescriptorForWriting { - return _socket.fileDescriptorForWriting; + return ((OFStream *)_stream) + .fileDescriptorForWriting; } @end @implementation OFHTTPClientResponse @synthesize of_keepAlive = _keepAlive; -- (instancetype)initWithSocket: (OFTCPSocket *)sock +- (instancetype)initWithStream: (OFStream *)stream { self = [super init]; - _socket = [sock retain]; + _stream = [stream retain]; return self; } - (void)dealloc { - if (_socket != nil) + if (_stream != nil) [self close]; [super dealloc]; } @@ -900,30 +919,30 @@ } } - (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_atEndOfStream) return 0; if (!_hasContentLength && !_chunked) - return [_socket readIntoBuffer: buffer length: length]; + return [_stream readIntoBuffer: buffer length: length]; - if (_socket.atEndOfStream) + if (_stream.atEndOfStream) @throw [OFTruncatedDataException exception]; /* Content-Length */ if (!_chunked) { size_t ret; if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - ret = [_socket readIntoBuffer: buffer length: length]; + ret = [_stream readIntoBuffer: buffer length: length]; if (ret > length) @throw [OFOutOfRangeException exception]; _toRead -= ret; @@ -935,11 +954,11 @@ /* Chunked */ if (_toRead == -2) { char tmp[2]; - switch ([_socket readIntoBuffer: tmp length: 2]) { + switch ([_stream readIntoBuffer: tmp length: 2]) { case 2: _toRead++; if (tmp[1] != '\n') @throw [OFInvalidServerReplyException exception]; @@ -955,11 +974,11 @@ return 0; } else if (_toRead == -1) { char tmp; - if ([_socket readIntoBuffer: &tmp length: 1] == 1) { + if ([_stream readIntoBuffer: &tmp length: 1] == 1) { _toRead++; if (tmp != '\n') @throw [OFInvalidServerReplyException exception]; } @@ -970,11 +989,11 @@ return 0; } else if (_toRead > 0) { if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - length = [_socket readIntoBuffer: buffer length: length]; + length = [_stream readIntoBuffer: buffer length: length]; _toRead -= length; if (_toRead == 0) _toRead = -2; @@ -983,11 +1002,11 @@ void *pool = objc_autoreleasePoolPush(); OFString *line; size_t pos; @try { - line = [_socket tryReadLine]; + line = [_stream tryReadLine]; } @catch (OFInvalidEncodingException *e) { @throw [OFInvalidServerReplyException exception]; } if (line == nil) @@ -997,14 +1016,14 @@ if (pos != OFNotFound) line = [line substringToIndex: pos]; if (line.length < 1) { /* - * We have read the empty string because the socket is + * We have read the empty string because the stream is * at end of stream. */ - if (_socket.atEndOfStream && pos == OFNotFound) + if (_stream.atEndOfStream && pos == OFNotFound) @throw [OFTruncatedDataException exception]; else @throw [OFInvalidServerReplyException exception]; } @@ -1035,41 +1054,42 @@ - (bool)lowlevelIsAtEndOfStream { if (_atEndOfStream) return true; - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (!_hasContentLength && !_chunked) - return _socket.atEndOfStream; + return _stream.atEndOfStream; return _atEndOfStream; } - (int)fileDescriptorForReading { - if (_socket == nil) + if (_stream == nil) return -1; - return _socket.fileDescriptorForReading; + return ((OFStream *)_stream) + .fileDescriptorForReading; } - (bool)hasDataInReadBuffer { - return (super.hasDataInReadBuffer || _socket.hasDataInReadBuffer); + return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer); } - (void)close { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; _atEndOfStream = false; - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [super close]; } @end @@ -1132,19 +1152,30 @@ didPerformRequest: request response: response exception: nil]; } -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)sock - request: (OFHTTPRequest *)request +- (void)client: (OFHTTPClient *)client + didCreateTCPSocket: (OFTCPSocket *)TCPSocket + request: (OFHTTPRequest *)request +{ + if ([_delegate respondsToSelector: + @selector(client:didCreateTCPSocket:request:)]) + [_delegate client: client + didCreateTCPSocket: TCPSocket + request: request]; +} + +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)TLSStream + request: (OFHTTPRequest *)request { if ([_delegate respondsToSelector: - @selector(client:didCreateSocket:request:)]) - [_delegate client: client - didCreateSocket: sock - request: request]; + @selector(client:didCreateTLSStream:request:)]) + [_delegate client: client + didCreateTLSStream: TLSStream + request: request]; } - (void)client: (OFHTTPClient *)client wantsRequestBody: (OFStream *)body request: (OFHTTPRequest *)request @@ -1255,15 +1286,15 @@ objc_autoreleasePoolPop(pool); } - (void)close { - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [_lastURL release]; _lastURL = nil; [_lastResponse release]; _lastResponse = nil; } @end Index: src/OFHTTPCookie.h ================================================================== --- src/OFHTTPCookie.h +++ src/OFHTTPCookie.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHTTPCookie.m ================================================================== --- src/OFHTTPCookie.m +++ src/OFHTTPCookie.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHTTPCookieManager.h ================================================================== --- src/OFHTTPCookieManager.h +++ src/OFHTTPCookieManager.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHTTPCookieManager.m ================================================================== --- src/OFHTTPCookieManager.m +++ src/OFHTTPCookieManager.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHTTPRequest.h ================================================================== --- src/OFHTTPRequest.h +++ src/OFHTTPRequest.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -107,17 +107,10 @@ * * @note The setter creates a copy of the remote address. */ @property OF_NULLABLE_PROPERTY (nonatomic) const OFSocketAddress *remoteAddress; -/** - * @brief Creates a new OFHTTPRequest. - * - * @return A new, autoreleased OFHTTPRequest - */ -+ (instancetype)request; - /** * @brief Creates a new OFHTTPRequest with the specified URL. * * @param URL The URL for the request * @return A new, autoreleased OFHTTPRequest @@ -129,10 +122,12 @@ * * @param URL The URL for the request * @return An initialized OFHTTPRequest */ - (instancetype)initWithURL: (OFURL *)URL; + +- (instancetype)init OF_UNAVAILABLE; @end #ifdef __cplusplus extern "C" { #endif Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -78,44 +78,36 @@ } @implementation OFHTTPRequest @synthesize URL = _URL, method = _method, headers = _headers; -+ (instancetype)request -{ - return [[[self alloc] init] autorelease]; -} - + (instancetype)requestWithURL: (OFURL *)URL { return [[[self alloc] initWithURL: URL] autorelease]; } -- (instancetype)init +- (instancetype)initWithURL: (OFURL *)URL { self = [super init]; - _method = OFHTTPRequestMethodGet; - _protocolVersion.major = 1; - _protocolVersion.minor = 1; - - return self; -} - -- (instancetype)initWithURL: (OFURL *)URL -{ - self = [self init]; - @try { _URL = [URL copy]; + _method = OFHTTPRequestMethodGet; + _protocolVersion.major = 1; + _protocolVersion.minor = 1; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_URL release]; [_headers release]; @@ -139,16 +131,15 @@ return NULL; } - (id)copy { - OFHTTPRequest *copy = [[OFHTTPRequest alloc] init]; + OFHTTPRequest *copy = [[OFHTTPRequest alloc] initWithURL: _URL]; @try { copy->_method = _method; copy->_protocolVersion = _protocolVersion; - copy.URL = _URL; copy.headers = _headers; copy.remoteAddress = self.remoteAddress; } @catch (id e) { [copy release]; @throw e; Index: src/OFHTTPResponse.h ================================================================== --- src/OFHTTPResponse.h +++ src/OFHTTPResponse.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -22,11 +22,11 @@ @class OFArray OF_GENERIC(ObjectType); /** * @class OFHTTPResponse OFHTTPResponse.h ObjFW/OFHTTPResponse.h * - * @brief A class for representing an HTTP request reply as a stream. + * @brief A class for representing an HTTP request response as a stream. */ @interface OFHTTPResponse: OFStream { OFHTTPRequestProtocolVersion _protocolVersion; short _statusCode; @@ -33,42 +33,45 @@ OFDictionary OF_GENERIC(OFString *, OFString *) *_headers; OF_RESERVE_IVARS(OFHTTPResponse, 4) } /** - * @brief The protocol version of the HTTP request reply. + * @brief The protocol version of the HTTP request response. */ @property (nonatomic) OFHTTPRequestProtocolVersion protocolVersion; /** - * @brief The protocol version of the HTTP request reply as a string. + * @brief The protocol version of the HTTP request response as a string. */ @property (copy, nonatomic) OFString *protocolVersionString; /** - * @brief The status code of the reply to the HTTP request. + * @brief The status code of the response to the HTTP request. */ @property (nonatomic) short statusCode; /** - * @brief The headers of the reply to the HTTP request. + * @brief The headers of the response to the HTTP request. */ @property (copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *headers; /** - * @brief The reply as a string, trying to detect the encoding. + * @brief Read the response as a string, trying to detect the encoding and + * falling back to the specified encoding if not detectable. + * + * @return The response as a string */ -@property (readonly, nonatomic) OFString *string; +- (OFString *)readString; /** - * @brief Returns the reply as a string, trying to detect the encoding and + * @brief Rread the response as a string, trying to detect the encoding and * falling back to the specified encoding if not detectable. * - * @return The reply as a string + * @return The response as a string */ -- (OFString *)stringWithEncoding: (OFStringEncoding)encoding; +- (OFString *)readStringWithEncoding: (OFStringEncoding)encoding; @end #ifdef __cplusplus extern "C" { #endif Index: src/OFHTTPResponse.m ================================================================== --- src/OFHTTPResponse.m +++ src/OFHTTPResponse.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -294,16 +294,16 @@ return [OFString stringWithFormat: @"%hhu.%hhu", _protocolVersion.major, _protocolVersion.minor]; } -- (OFString *)string +- (OFString *)readString { - return [self stringWithEncoding: OFStringEncodingAutodetect]; + return [self readStringWithEncoding: OFStringEncodingAutodetect]; } -- (OFString *)stringWithEncoding: (OFStringEncoding)encoding +- (OFString *)readStringWithEncoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFString *contentType, *contentLengthString, *ret; OFData *data; Index: src/OFHTTPServer.h ================================================================== --- src/OFHTTPServer.h +++ src/OFHTTPServer.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -62,11 +62,12 @@ */ - (bool)server: (OFHTTPServer *)server didReceiveExceptionOnListeningSocket: (id)exception; /** - * @brief This method is called when a client socket encountered an exception. + * @brief This method is called when a socket for a client encountered an + * exception. * * This can happen when the OFHTTPServer tries to properly close the * connection. If no headers have been sent yet, it will send headers, and if * chunked transfer encoding was used, it will send a chunk of size 0. However, * if the other end already closed the connection before that, this will raise @@ -91,13 +92,10 @@ OF_SUBCLASSING_RESTRICTED @interface OFHTTPServer: OFObject { OFString *_Nullable _host; uint16_t _port; - bool _usesTLS; - OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile; - const char *_Nullable _privateKeyPassphrase; id _Nullable _delegate; OFString *_Nullable _name; OFTCPSocket *_Nullable _listeningSocket; #ifdef OF_HAVE_THREADS size_t _numberOfThreads, _nextThreadIndex; @@ -119,46 +117,10 @@ * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property (nonatomic) uint16_t port; -/** - * @brief Whether the HTTP server uses TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property (nonatomic) bool usesTLS; - -/** - * @brief The path to the X.509 certificate file to use for TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; - -/** - * @brief The path to the PKCS#8 private key file to use for TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; - -/** - * @brief The passphrase to decrypt the PKCS#8 private key file for TLS. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - const char *privateKeyPassphrase; - /** * @brief The delegate for the HTTP server. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id delegate; Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -13,10 +13,11 @@ * file. */ #include "config.h" +#include #include #include #import "OFHTTPServer.h" #import "OFArray.h" @@ -26,11 +27,10 @@ #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" #import "OFSocket+Private.h" #import "OFTCPSocket.h" -#import "OFTLSSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" @@ -114,16 +114,17 @@ @interface OFHTTPServerThread: OFThread - (void)stop; @end #endif -static OF_INLINE OFString * +static OFString * normalizedKey(OFString *key) { char *cString = OFStrDup(key.UTF8String); unsigned char *tmp = (unsigned char *)cString; bool firstLetter = true; + OFString *ret; while (*tmp != '\0') { if (!OFASCIIIsAlpha(*tmp)) { firstLetter = true; tmp++; @@ -136,16 +137,18 @@ firstLetter = false; tmp++; } @try { - return [OFString stringWithUTF8StringNoCopy: cString - freeWhenDone: true]; + ret = [OFString stringWithUTF8StringNoCopy: cString + freeWhenDone: true]; } @catch (id e) { OFFreeMemory(cString); @throw e; } + + return ret; } @implementation OFHTTPServerResponse - (instancetype)initWithSocket: (OFStreamSocket *)sock server: (OFHTTPServer *)server @@ -223,12 +226,22 @@ @throw [OFNotOpenException exceptionWithObject: self]; if (!_headersSent) [self of_sendHeaders]; - if (!_chunked) - return [_socket writeBuffer: buffer length: length]; + if (!_chunked) { + @try { + [_socket writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + @throw e; + } + + return length; + } pool = objc_autoreleasePoolPush(); [_socket writeString: [OFString stringWithFormat: @"%zX\r\n", length]]; objc_autoreleasePoolPop(pool); @@ -523,20 +536,27 @@ URL.scheme = @"http"; URL.host = _host; if (_port != 80) URL.port = [OFNumber numberWithUnsignedShort: _port]; - if ((pos = [_path rangeOfString: @"?"].location) != OFNotFound) { - OFString *path, *query; - - path = [_path substringToIndex: pos]; - query = [_path substringFromIndex: pos + 1]; - - URL.URLEncodedPath = path; - URL.URLEncodedQuery = query; - } else - URL.URLEncodedPath = _path; + @try { + if ((pos = [_path rangeOfString: @"?"].location) != + OFNotFound) { + OFString *path, *query; + + path = [_path substringToIndex: pos]; + query = [_path substringFromIndex: pos + 1]; + + URL.URLEncodedPath = path; + URL.URLEncodedQuery = query; + } else + URL.URLEncodedPath = _path; + } @catch (OFInvalidFormatException *e) { + objc_autoreleasePoolPop(pool); + [self sendErrorAndClose: 400]; + return; + } [URL makeImmutable]; request = [OFHTTPRequest requestWithURL: URL]; request.method = _method; @@ -806,70 +826,10 @@ - (uint16_t)port { return _port; } -- (void)setUsesTLS: (bool)usesTLS -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _usesTLS = usesTLS; -} - -- (bool)usesTLS -{ - return _usesTLS; -} - -- (void)setCertificateFile: (OFString *)certificateFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _certificateFile; - _certificateFile = [certificateFile copy]; - [old release]; -} - -- (OFString *)certificateFile -{ - return _certificateFile; -} - -- (void)setPrivateKeyFile: (OFString *)privateKeyFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _privateKeyFile; - _privateKeyFile = [privateKeyFile copy]; - [old release]; -} - -- (OFString *)privateKeyFile -{ - return _privateKeyFile; -} - -- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _privateKeyPassphrase = privateKeyPassphrase; -} - -- (const char *)privateKeyPassphrase -{ - return _privateKeyPassphrase; -} - #ifdef OF_HAVE_THREADS - (void)setNumberOfThreads: (size_t)numberOfThreads { if (numberOfThreads == 0) @throw [OFInvalidArgumentException exception]; @@ -894,25 +854,11 @@ @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; - if (_usesTLS) { - OFTCPSocket *TLSSocket; - - if (OFTLSSocketClass == Nil) - @throw [OFUnsupportedProtocolException exception]; - - TLSSocket = [[OFTLSSocketClass alloc] init]; - _listeningSocket = TLSSocket; - - TLSSocket.certificateFile = _certificateFile; - TLSSocket.privateKeyFile = _privateKeyFile; - TLSSocket.privateKeyPassphrase = _privateKeyPassphrase; - } else - _listeningSocket = [[OFTCPSocket alloc] init]; - + _listeningSocket = [[OFTCPSocket alloc] init]; _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { Index: src/OFHTTPURLHandler.h ================================================================== --- src/OFHTTPURLHandler.h +++ src/OFHTTPURLHandler.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHTTPURLHandler.m ================================================================== --- src/OFHTTPURLHandler.m +++ src/OFHTTPURLHandler.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHostAddressResolver.h ================================================================== --- src/OFHostAddressResolver.h +++ src/OFHostAddressResolver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHostAddressResolver.m ================================================================== --- src/OFHostAddressResolver.m +++ src/OFHostAddressResolver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHuffmanTree.h ================================================================== --- src/OFHuffmanTree.h +++ src/OFHuffmanTree.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFHuffmanTree.m ================================================================== --- src/OFHuffmanTree.m +++ src/OFHuffmanTree.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFINICategory+Private.h ================================================================== --- src/OFINICategory+Private.h +++ src/OFINICategory+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFINICategory.h ================================================================== --- src/OFINICategory.h +++ src/OFINICategory.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFINICategory.m ================================================================== --- src/OFINICategory.m +++ src/OFINICategory.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFINIFile.h ================================================================== --- src/OFINIFile.h +++ src/OFINIFile.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -18,10 +18,11 @@ #import "OFINICategory.h" OF_ASSUME_NONNULL_BEGIN @class OFMutableArray OF_GENERIC(ObjectType); +@class OFURL; /** * @class OFINIFile OFINIFile.h ObjFW/OFINIFile.h * * @brief A class for reading, creating and modifying INI files. @@ -38,51 +39,50 @@ @property (readonly, nonatomic) OFArray OF_GENERIC(OFINICategory *) *categories; /** * @brief Creates a new OFINIFile with the contents of the specified file. * - * @param path The path to the file whose contents the OFINIFile should contain + * @param URL The URL to the file whose contents the OFINIFile should contain * * @return A new, autoreleased OFINIFile with the contents of the specified file */ -+ (instancetype)fileWithPath: (OFString *)path; ++ (instancetype)fileWithURL: (OFURL *)URL; /** * @brief Creates a new OFINIFile with the contents of the specified file in * the specified encoding. * - * @param path The path to the file whose contents the OFINIFile should contain + * @param URL The URL to the file whose contents the OFINIFile should contain * @param encoding The encoding of the specified file * * @return A new, autoreleased OFINIFile with the contents of the specified file */ -+ (instancetype)fileWithPath: (OFString *)path - encoding: (OFStringEncoding)encoding; ++ (instancetype)fileWithURL: (OFURL *)URL encoding: (OFStringEncoding)encoding; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFINIFile with the contents of the * specified file. * - * @param path The path to the file whose contents the OFINIFile should contain + * @param URL The URL to the file whose contents the OFINIFile should contain * * @return An initialized OFINIFile with the contents of the specified file */ -- (instancetype)initWithPath: (OFString *)path; +- (instancetype)initWithURL: (OFURL *)URL; /** * @brief Initializes an already allocated OFINIFile with the contents of the * specified file in the specified encoding. * - * @param path The path to the file whose contents the OFINIFile should contain + * @param URL The URL to the file whose contents the OFINIFile should contain * @param encoding The encoding of the specified file * * @return An initialized OFINIFile with the contents of the specified file */ -- (instancetype)initWithPath: (OFString *)path - encoding: (OFStringEncoding)encoding +- (instancetype)initWithURL: (OFURL *)URL + encoding: (OFStringEncoding)encoding OF_DESIGNATED_INITIALIZER; /** * @brief Returns an @ref OFINICategory for the category with the specified * name. @@ -95,20 +95,20 @@ - (OFINICategory *)categoryForName: (OFString *)name; /** * @brief Writes the contents of the OFINIFile to a file. * - * @param path The path of the file to write to + * @param URL The URL of the file to write to */ -- (void)writeToFile: (OFString *)path; +- (void)writeToURL: (OFURL *)URL; /** * @brief Writes the contents of the OFINIFile to a file in the specified * encoding. * - * @param path The path of the file to write to + * @param URL The URL of the file to write to * @param encoding The encoding to use */ -- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding; +- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFINIFile.m ================================================================== --- src/OFINIFile.m +++ src/OFINIFile.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,21 +17,23 @@ #include #import "OFINIFile.h" #import "OFArray.h" -#import "OFString.h" -#import "OFFile.h" +#import "OFINICategory+Private.h" #import "OFINICategory.h" -#import "OFINICategory+Private.h" +#import "OFStream.h" +#import "OFString.h" +#import "OFURL.h" +#import "OFURLHandler.h" #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" OF_DIRECT_MEMBERS @interface OFINIFile () -- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding; +- (void)of_parseURL: (OFURL *)URL encoding: (OFStringEncoding)encoding; @end static bool isWhitespaceLine(OFString *line) { @@ -46,41 +48,38 @@ } @implementation OFINIFile @synthesize categories = _categories; -+ (instancetype)fileWithPath: (OFString *)path ++ (instancetype)fileWithURL: (OFURL *)URL { - return [[[self alloc] initWithPath: path] autorelease]; + return [[[self alloc] initWithURL: URL] autorelease]; } -+ (instancetype)fileWithPath: (OFString *)path - encoding: (OFStringEncoding)encoding ++ (instancetype)fileWithURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { - return [[[self alloc] initWithPath: path - encoding: encoding] autorelease]; + return [[[self alloc] initWithURL: URL encoding: encoding] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithPath: (OFString *)path +- (instancetype)initWithURL: (OFURL *)URL { - return [self initWithPath: path encoding: OFStringEncodingUTF8]; + return [self initWithURL: URL encoding: OFStringEncodingAutodetect]; } -- (instancetype)initWithPath: (OFString *)path - encoding: (OFStringEncoding)encoding +- (instancetype)initWithURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { self = [super init]; @try { _categories = [[OFMutableArray alloc] init]; - [self of_parseFile: path encoding: encoding]; + [self of_parseURL: URL encoding: encoding]; } @catch (id e) { [self release]; @throw e; } @@ -109,19 +108,20 @@ objc_autoreleasePoolPop(pool); return category; } -- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding +- (void)of_parseURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - OFFile *file; + OFStream *file; OFINICategory *category = nil; OFString *line; @try { - file = [OFFile fileWithPath: path mode: @"r"]; + file = [[OFURLHandler handlerForURL: URL] openItemAtURL: URL + mode: @"r"]; } @catch (OFOpenItemFailedException *e) { /* Handle missing file like an empty file */ if (e.errNo == ENOENT) return; @@ -152,19 +152,21 @@ } objc_autoreleasePoolPop(pool); } -- (void)writeToFile: (OFString *)path +- (void)writeToURL: (OFURL *)URL { - [self writeToFile: path encoding: OFStringEncodingUTF8]; + [self writeToURL: URL encoding: OFStringEncodingUTF8]; } -- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding +- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - OFFile *file = [OFFile fileWithPath: path mode: @"w"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL + mode: @"w"]; bool first = true; for (OFINICategory *category in _categories) if ([category of_writeToStream: file encoding: encoding Index: src/OFINIFileSettings.h ================================================================== --- src/OFINIFileSettings.h +++ src/OFINIFileSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,16 +15,17 @@ #import "OFSettings.h" OF_ASSUME_NONNULL_BEGIN -@class OFString; @class OFINIFile; +@class OFString; +@class OFURL; @interface OFINIFileSettings: OFSettings { - OFString *_filePath; + OFURL *_fileURL; OFINIFile *_INIFile; } @end OF_ASSUME_NONNULL_END Index: src/OFINIFileSettings.m ================================================================== --- src/OFINIFileSettings.m +++ src/OFINIFileSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -14,14 +14,15 @@ */ #include "config.h" #import "OFINIFileSettings.h" -#import "OFString.h" #import "OFArray.h" #import "OFINIFile.h" +#import "OFString.h" #import "OFSystemInfo.h" +#import "OFURL.h" @implementation OFINIFileSettings - (instancetype)initWithApplicationName: (OFString *)applicationName { self = [super initWithApplicationName: applicationName]; @@ -29,13 +30,13 @@ @try { void *pool = objc_autoreleasePoolPush(); OFString *fileName; fileName = [applicationName stringByAppendingString: @".ini"]; - _filePath = [[[OFSystemInfo userConfigPath] - stringByAppendingPathComponent: fileName] copy]; - _INIFile = [[OFINIFile alloc] initWithPath: _filePath]; + _fileURL = [[[OFSystemInfo userConfigURL] + URLByAppendingPathComponent: fileName] copy]; + _INIFile = [[OFINIFile alloc] initWithURL: _fileURL]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -44,11 +45,11 @@ return self; } - (void)dealloc { - [_filePath release]; + [_fileURL release]; [_INIFile release]; [super dealloc]; } @@ -240,8 +241,8 @@ objc_autoreleasePoolPop(pool); } - (void)save { - [_INIFile writeToFile: _filePath]; + [_INIFile writeToURL: _fileURL]; } @end Index: src/OFIPSocketAsyncConnector.h ================================================================== --- src/OFIPSocketAsyncConnector.h +++ src/OFIPSocketAsyncConnector.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFIPSocketAsyncConnector.m ================================================================== --- src/OFIPSocketAsyncConnector.m +++ src/OFIPSocketAsyncConnector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -74,11 +74,11 @@ OFEnsure(0); } else { #endif if ([_delegate respondsToSelector: @selector(socket:didConnectToHost:port:exception:)]) - [_delegate socket: _socket + [_delegate socket: _socket didConnectToHost: _host port: _port exception: _exception]; #ifdef OF_HAVE_BLOCKS } @@ -171,11 +171,15 @@ [_socket setCanBlock: false]; #endif if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { #if !defined(OF_NINTENDO_3DS) && !defined(OF_WII) +# ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +# else if (errNo == EINPROGRESS) { +# endif [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } else { Index: src/OFIPXSocket.h ================================================================== --- src/OFIPXSocket.h +++ src/OFIPXSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFIPXSocket.m ================================================================== --- src/OFIPXSocket.m +++ src/OFIPXSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -41,19 +41,19 @@ #endif if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = OFSocketAddressMakeIPX(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(0, zeroNode, port); #ifdef OF_WINDOWS protocol = NSPROTO_IPX + packetType; #else _packetType = address.sockaddr.ipx.sipx_type = packetType; #endif - if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_DGRAM | SOCK_CLOEXEC, protocol)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port packetType: packetType socket: self @@ -64,11 +64,12 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif - if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -80,11 +81,11 @@ memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (OFGetSockName(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, &address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -93,11 +94,11 @@ packetType: packetType socket: self errNo: errNo]; } - if (address.sockaddr.sockaddr.sa_family != AF_IPX) { + if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: packetType Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -12,11 +12,10 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" -#import "OFHuffmanTree.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN #define OFInflate64StreamBufferSize 4096 @@ -49,23 +48,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - OFHuffmanTree _Nullable litLenTree; - OFHuffmanTree _Nullable distTree; - OFHuffmanTree _Nullable codeLenTree; - OFHuffmanTree _Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable codeLenTree; + struct _OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - OFHuffmanTree _Nullable litLenTree; - OFHuffmanTree _Nullable distTree; - OFHuffmanTree _Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflate64Stream.m ================================================================== --- src/OFInflate64Stream.m +++ src/OFInflate64Stream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -12,11 +12,10 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" -#import "OFHuffmanTree.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN #define OFInflateStreamBufferSize 4096 @@ -49,23 +48,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - OFHuffmanTree _Nullable litLenTree; - OFHuffmanTree _Nullable distTree; - OFHuffmanTree _Nullable codeLenTree; - OFHuffmanTree _Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable codeLenTree; + struct _OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - OFHuffmanTree _Nullable litLenTree; - OFHuffmanTree _Nullable distTree; - OFHuffmanTree _Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFInvertedCharacterSet.h ================================================================== --- src/OFInvertedCharacterSet.h +++ src/OFInvertedCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFInvertedCharacterSet.m ================================================================== --- src/OFInvertedCharacterSet.m +++ src/OFInvertedCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFInvocation.h ================================================================== --- src/OFInvocation.h +++ src/OFInvocation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFInvocation.m ================================================================== --- src/OFInvocation.m +++ src/OFInvocation.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFJSONRepresentation.h ================================================================== --- src/OFJSONRepresentation.h +++ src/OFJSONRepresentation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFKeyValueCoding.h ================================================================== --- src/OFKeyValueCoding.h +++ src/OFKeyValueCoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFKqueueKernelEventObserver.h ================================================================== --- src/OFKqueueKernelEventObserver.h +++ src/OFKqueueKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFKqueueKernelEventObserver.m ================================================================== --- src/OFKqueueKernelEventObserver.m +++ src/OFKqueueKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHAArchive.h ================================================================== --- src/OFLHAArchive.h +++ src/OFLHAArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -12,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFLHAArchive.h" #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" #import "OFCRC16.h" @@ -471,32 +473,34 @@ [super dealloc]; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - uint32_t bytesWritten; - if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (UINT32_MAX - _bytesWritten < length) @throw [OFOutOfRangeException exception]; @try { - bytesWritten = (uint32_t)[_stream writeBuffer: buffer - length: length]; + [_stream writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { - _bytesWritten += e.bytesWritten; + OFEnsure(e.bytesWritten <= length); + + _bytesWritten += (uint32_t)e.bytesWritten; _CRC16 = OFCRC16(_CRC16, buffer, e.bytesWritten); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; @throw e; } - _bytesWritten += (uint32_t)bytesWritten; - _CRC16 = OFCRC16(_CRC16, buffer, bytesWritten); + _bytesWritten += (uint32_t)length; + _CRC16 = OFCRC16(_CRC16, buffer, length); - return bytesWritten; + return length; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) Index: src/OFLHAArchiveEntry+Private.h ================================================================== --- src/OFLHAArchiveEntry+Private.h +++ src/OFLHAArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHAArchiveEntry.h ================================================================== --- src/OFLHAArchiveEntry.h +++ src/OFLHAArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLHADecompressingStream.m ================================================================== --- src/OFLHADecompressingStream.m +++ src/OFLHADecompressingStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -49,20 +49,20 @@ * @brief Returns the next list item of the list item. * * @param listItem The list item for which the next list item should be returned * @return The next list item of the list item */ -OFListItem OFListItemNext(OFListItem _Nonnull listItem); +extern OFListItem _Nullable OFListItemNext(OFListItem _Nonnull listItem); /*! * @brief Returns the previous list item of the list item. * * @param listItem The list item for which the previous list item should be * returned * @return The previous list item of the list item */ -OFListItem OFListItemPrevious(OFListItem _Nonnull listItem); +extern OFListItem _Nullable OFListItemPrevious(OFListItem _Nonnull listItem); /*! * @brief Returns the object of the list item. * * @warning The returned object is not retained and autoreleased - this is the @@ -69,11 +69,11 @@ * caller's responsibility! * * @param listItem The list item for which the object should be returned * @return The object of the list item */ -id OFListItemObject(OFListItem _Nonnull listItem); +extern id _Nonnull OFListItemObject(OFListItem _Nonnull listItem); #ifdef __cplusplus } #endif /** Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFLocale.h ================================================================== --- src/OFLocale.h +++ src/OFLocale.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -150,11 +150,11 @@ * * @warning This sets the locale via `setlocale()`! * * @warning You should never call this yourself, except if you do not use * @ref OFApplication. In this case, you need to allocate exactly one - * instance of OFLocale, which will be come the current locale, and + * instance of OFLocale, which will become the current locale, and * call this method. */ - (instancetype)init; #ifdef OF_HAVE_FILES Index: src/OFLocale.m ================================================================== --- src/OFLocale.m +++ src/OFLocale.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -424,11 +424,11 @@ if (0) { # endif OFStringEncoding ASCII = OFStringEncodingASCII; @try { - _encoding = OFStringEncodingForName( + _encoding = OFStringEncodingParseName( [OFString stringWithCString: buffer encoding: ASCII]); } @catch (OFInvalidArgumentException *e) { _encoding = OFStringEncodingISO8859_1; } Index: src/OFLocking.h ================================================================== --- src/OFLocking.h +++ src/OFLocking.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMD5Hash.h ================================================================== --- src/OFMD5Hash.h +++ src/OFMD5Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMD5Hash.m ================================================================== --- src/OFMD5Hash.m +++ src/OFMD5Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,10 +19,11 @@ #import "OFMD5Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" static const size_t digestSize = 16; static const size_t blockSize = 64; @@ -242,12 +243,21 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); @@ -263,12 +273,10 @@ processBlock(_iVars->state, _iVars->buffer.words); OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfBE(_iVars->state, 4); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; Index: src/OFMapTable+Private.h ================================================================== --- src/OFMapTable+Private.h +++ src/OFMapTable+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMapTable.h ================================================================== --- src/OFMapTable.h +++ src/OFMapTable.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -71,11 +71,11 @@ OF_SUBCLASSING_RESTRICTED @interface OFMapTable: OFObject { OFMapTableFunctions _keyFunctions, _objectFunctions; struct OFMapTableBucket *_Nonnull *_Nullable _buckets; - unsigned long _count, _capacity; + uint32_t _count, _capacity; unsigned char _rotate; unsigned long _mutations; } /** @@ -233,12 +233,12 @@ */ @interface OFMapTableEnumerator: OFObject { OFMapTable *_mapTable; struct OFMapTableBucket *_Nonnull *_Nullable _buckets; - unsigned long _capacity, _mutations, *_Nullable _mutationsPtr; - unsigned long _position; + uint32_t _capacity; + unsigned long _mutations, *_Nullable _mutationsPtr, _position; } - (instancetype)init OF_UNAVAILABLE; /** Index: src/OFMapTable.m ================================================================== --- src/OFMapTable.m +++ src/OFMapTable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,17 +26,17 @@ #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" -extern unsigned long OFHashSeed; +extern uint32_t OFHashSeed; -static const unsigned long minCapacity = 16; +static const uint32_t minCapacity = 16; struct OFMapTableBucket { void *key, *object; - unsigned long hash; + uint32_t hash; }; static struct OFMapTableBucket deletedBucket = { 0 }; static void * defaultRetain(void *object) @@ -63,11 +63,11 @@ OF_DIRECT_MEMBERS @interface OFMapTableEnumerator () - (instancetype)of_initWithMapTable: (OFMapTable *)mapTable buckets: (struct OFMapTableBucket **)buckets - capacity: (unsigned long)capacity + capacity: (uint32_t)capacity mutationsPointer: (unsigned long *)mutationsPtr OF_METHOD_FAMILY(init); @end @interface OFMapTableKeyEnumerator: OFMapTableEnumerator @@ -134,23 +134,23 @@ SET_DEFAULT(_objectFunctions.hash, defaultHash); SET_DEFAULT(_objectFunctions.equal, defaultEqual); #undef SET_DEFAULT - if (capacity > ULONG_MAX / sizeof(*_buckets) || - capacity > ULONG_MAX / 8) + if (capacity > UINT32_MAX / sizeof(*_buckets) || + capacity > UINT32_MAX / 8) @throw [OFOutOfRangeException exception]; for (_capacity = 1; _capacity < capacity;) { - if (_capacity > ULONG_MAX / 2) + if (_capacity > UINT32_MAX / 2) @throw [OFOutOfRangeException exception]; _capacity *= 2; } if (capacity * 8 / _capacity >= 6) - if (_capacity <= ULONG_MAX / 2) + if (_capacity <= UINT32_MAX / 2) _capacity *= 2; if (_capacity < minCapacity) _capacity = minCapacity; @@ -166,11 +166,11 @@ return self; } - (void)dealloc { - for (unsigned long i = 0; i < _capacity; i++) { + for (uint32_t i = 0; i < _capacity; i++) { if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { _keyFunctions.release(_buckets[i]->key); _objectFunctions.release(_buckets[i]->object); OFFreeMemory(_buckets[i]); @@ -181,23 +181,23 @@ [super dealloc]; } static void -resizeForCount(OFMapTable *self, unsigned long count) +resizeForCount(OFMapTable *self, uint32_t count) { - unsigned long fullness, capacity; + uint32_t fullness, capacity; struct OFMapTableBucket **buckets; - if (count > ULONG_MAX / sizeof(*self->_buckets) || - count > ULONG_MAX / 8) + if (count > UINT32_MAX / sizeof(*self->_buckets) || + count > UINT32_MAX / 8) @throw [OFOutOfRangeException exception]; fullness = count * 8 / self->_capacity; if (fullness >= 6) { - if (self->_capacity > ULONG_MAX / 2) + if (self->_capacity > UINT32_MAX / 2) return; capacity = self->_capacity * 2; } else if (fullness <= 1) capacity = self->_capacity / 2; @@ -212,14 +212,14 @@ capacity < minCapacity) return; buckets = OFAllocZeroedMemory(capacity, sizeof(*buckets)); - for (unsigned long i = 0; i < self->_capacity; i++) { + for (uint32_t i = 0; i < self->_capacity; i++) { if (self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket) { - unsigned long j, last; + uint32_t j, last; last = capacity; for (j = self->_buckets[i]->hash & (capacity - 1); j < last && buckets[j] != NULL; j++); @@ -243,14 +243,13 @@ self->_buckets = buckets; self->_capacity = capacity; } static void -setObject(OFMapTable *restrict self, void *key, void *object, - unsigned long hash) +setObject(OFMapTable *restrict self, void *key, void *object, uint32_t hash) { - unsigned long i, last; + uint32_t i, last; void *old; if (key == NULL || object == NULL) @throw [OFInvalidArgumentException exception]; @@ -351,11 +350,11 @@ if (mapTable->_count != _count || mapTable->_keyFunctions.equal != _keyFunctions.equal || mapTable->_objectFunctions.equal != _objectFunctions.equal) return false; - for (unsigned long i = 0; i < _capacity; i++) { + for (uint32_t i = 0; i < _capacity; i++) { if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { void *objectIter = [mapTable objectForKey: _buckets[i]->key]; if (!_objectFunctions.equal(objectIter, @@ -387,11 +386,11 @@ initWithKeyFunctions: _keyFunctions objectFunctions: _objectFunctions capacity: _capacity]; @try { - for (unsigned long i = 0; i < _capacity; i++) + for (uint32_t i = 0; i < _capacity; i++) if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) setObject(copy, _buckets[i]->key, _buckets[i]->object, OFRotateRight(_buckets[i]->hash, _rotate)); @@ -408,16 +407,16 @@ return _count; } - (void *)objectForKey: (void *)key { - unsigned long i, hash, last; + uint32_t i, hash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft(_keyFunctions.hash(key), _rotate); + hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); last = _capacity; for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -443,21 +442,21 @@ return NULL; } - (void)setObject: (void *)object forKey: (void *)key { - setObject(self, key, object,_keyFunctions.hash(key)); + setObject(self, key, object, (uint32_t)_keyFunctions.hash(key)); } - (void)removeObjectForKey: (void *)key { - unsigned long i, hash, last; + uint32_t i, hash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft(_keyFunctions.hash(key), _rotate); + hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); last = _capacity; for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -504,11 +503,11 @@ } } - (void)removeAllObjects { - for (unsigned long i = 0; i < _capacity; i++) { + for (uint32_t i = 0; i < _capacity; i++) { if (_buckets[i] != NULL) { if (_buckets[i] == &deletedBucket) { _buckets[i] = NULL; continue; } @@ -536,11 +535,11 @@ - (bool)containsObject: (void *)object { if (object == NULL || _count == 0) return false; - for (unsigned long i = 0; i < _capacity; i++) + for (uint32_t i = 0; i < _capacity; i++) if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) if (_objectFunctions.equal(_buckets[i]->object, object)) return true; return false; @@ -549,11 +548,11 @@ - (bool)containsObjectIdenticalTo: (void *)object { if (object == NULL || _count == 0) return false; - for (unsigned long i = 0; i < _capacity; i++) + for (uint32_t i = 0; i < _capacity; i++) if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) if (_buckets[i]->object == object) return true; return false; @@ -651,11 +650,11 @@ OF_INVALID_INIT_METHOD } - (instancetype)of_initWithMapTable: (OFMapTable *)mapTable buckets: (struct OFMapTableBucket **)buckets - capacity: (unsigned long)capacity + capacity: (uint32_t)capacity mutationsPointer: (unsigned long *)mutationsPtr { self = [super init]; _mapTable = [mapTable retain]; Index: src/OFMapTableDictionary.h ================================================================== --- src/OFMapTableDictionary.h +++ src/OFMapTableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMapTableDictionary.m ================================================================== --- src/OFMapTableDictionary.m +++ src/OFMapTableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMapTableSet.h ================================================================== --- src/OFMapTableSet.h +++ src/OFMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMapTableSet.m ================================================================== --- src/OFMapTableSet.m +++ src/OFMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 ADDED src/OFMemoryStream.h Index: src/OFMemoryStream.h ================================================================== --- /dev/null +++ src/OFMemoryStream.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2022 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 "OFSeekableStream.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFMemoryStream OFMemoryStream.h ObjFW/OFMemoryStream.h + * + * @brief A seekable stream for reading from and writing to memory. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFMemoryStream: OFSeekableStream +{ + char *_address; + size_t _size, _position; + bool _writable; +} + +/** + * @brief Creates a new OFMemoryStream with the specified memory. + * + * @warning The memory is not copied, so it is your responsibility that the + * specified memory stays alive for as long as the OFMemoryStream does! + * + * @param address The memory address for the stream + * @param size The size of the memory at the specified address + * @param writable Whether writes to memory should be allowed + * @return A new autoreleased OFMemoryStream + */ ++ (instancetype)streamWithMemoryAddress: (void *)address + size: (size_t)size + writable: (bool)writable; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFMemoryStream with the specified + * memory. + * + * @warning The memory is not copied, so it is your responsibility that the + * specified memory stays alive for as long as the OFMemoryStream does! + * + * @param address The memory address for the stream + * @param size The size of the memory at the specified address + * @param writable Whether writes to memory should be allowed + * @return An initialized OFMemoryStream + */ +- (instancetype)initWithMemoryAddress: (void *)address + size: (size_t)size + writable: (bool)writable; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFMemoryStream.m Index: src/OFMemoryStream.m ================================================================== --- /dev/null +++ src/OFMemoryStream.m @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFMemoryStream.h" + +#import "OFInvalidArgumentException.h" +#import "OFOutOfRangeException.h" +#import "OFWriteFailedException.h" +#import "OFSeekFailedException.h" + +@implementation OFMemoryStream ++ (instancetype)streamWithMemoryAddress: (void *)address + size: (size_t)size + writable: (bool)writable +{ + return [[[self alloc] initWithMemoryAddress: address + size: size + writable: writable] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithMemoryAddress: (void *)address + size: (size_t)size + writable: (bool)writable +{ + self = [super init]; + + @try { + if (size > SSIZE_MAX || (ssize_t)size != (OFFileOffset)size) + @throw [OFOutOfRangeException exception]; + + _address = address; + _size = size; + _writable = writable; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + if (SIZE_MAX - _position < length || _position + length > _size) + length = _size - _position; + + memcpy(buffer, _address + _position, length); + _position += length; + + return length; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + size_t bytesWritten = length; + + if (!_writable) + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: EBADF]; + + if (SIZE_MAX - _position < length || _position + length > _size) + bytesWritten = _size - _position; + + memcpy(_address + _position, buffer, bytesWritten); + _position += bytesWritten; + + if (bytesWritten != length) + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: EFBIG]; + + return bytesWritten; +} + +- (bool)lowlevelIsAtEndOfStream +{ + return (_position == _size); +} + +- (OFFileOffset)lowlevelSeekToOffset: (OFFileOffset)offset whence: (int)whence +{ + OFFileOffset new; + + switch (whence) { + case SEEK_SET: + new = offset; + break; + case SEEK_CUR: + new = (OFFileOffset)_position + offset; + break; + case SEEK_END: + new = (OFFileOffset)_size + offset; + break; + default: + @throw [OFInvalidArgumentException exception]; + } + + if (new < 0 || new > (OFFileOffset)_size) + @throw [OFSeekFailedException exceptionWithStream: self + offset: offset + whence: whence + errNo: EINVAL]; + + return (_position = (size_t)new); +} +@end Index: src/OFMessagePackExtension.h ================================================================== --- src/OFMessagePackExtension.h +++ src/OFMessagePackExtension.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMessagePackExtension.m ================================================================== --- src/OFMessagePackExtension.m +++ src/OFMessagePackExtension.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMessagePackRepresentation.h ================================================================== --- src/OFMessagePackRepresentation.h +++ src/OFMessagePackRepresentation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMethodSignature.h ================================================================== --- src/OFMethodSignature.h +++ src/OFMethodSignature.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMethodSignature.m ================================================================== --- src/OFMethodSignature.m +++ src/OFMethodSignature.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableAdjacentArray.h ================================================================== --- src/OFMutableAdjacentArray.h +++ src/OFMutableAdjacentArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableAdjacentArray.m ================================================================== --- src/OFMutableAdjacentArray.m +++ src/OFMutableAdjacentArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -105,12 +105,10 @@ for (size_t i = 0; i < count; i++) { if ([objects[i] isEqual: oldObject]) { [newObject retain]; [objects[i] release]; objects[i] = newObject; - - return; } } } - (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object @@ -164,18 +162,21 @@ objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) { if ([objects[i] isEqual: object]) { - object = objects[i]; + id tmp = objects[i]; [_array removeItemAtIndex: i]; _mutations++; - [object release]; + [tmp release]; - return; + objects = _array.items; + i--; + count--; + continue; } } } - (void)removeObjectIdenticalTo: (id)object @@ -194,11 +195,14 @@ [_array removeItemAtIndex: i]; _mutations++; [object release]; - return; + objects = _array.items; + i--; + count--; + continue; } } } - (void)removeObjectAtIndex: (size_t)idx Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -92,11 +92,11 @@ */ - (void)insertObjectsFromArray: (OFArray OF_GENERIC(ObjectType) *)array atIndex: (size_t)index; /** - * @brief Replaces the first object equivalent to the specified object with the + * @brief Replaces all objects equivalent to the specified object with the * other specified object. * * @param oldObject The object to replace * @param newObject The replacement object */ @@ -131,18 +131,18 @@ */ - (void)replaceObjectIdenticalTo: (ObjectType)oldObject withObject: (ObjectType)newObject; /** - * @brief Removes the first object equivalent to the specified object. + * @brief Removes all objects equivalent to the specified object. * * @param object The object to remove */ - (void)removeObject: (ObjectType)object; /** - * @brief Removes the first object that has the same address as the specified + * @brief Removes all objects that have the same address as the specified * object. * * @param object The object to remove */ - (void)removeObjectIdenticalTo: (ObjectType)object; @@ -153,11 +153,11 @@ * @param index The index of the object to remove */ - (void)removeObjectAtIndex: (size_t)index; /** - * @brief Removes the object in the specified range. + * @brief Removes the objects in the specified range. * * @param range The range of the objects to remove */ - (void)removeObjectsInRange: (OFRange)range; Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -293,16 +293,13 @@ if (oldObject == nil || newObject == nil) @throw [OFInvalidArgumentException exception]; count = self.count; - for (size_t i = 0; i < count; i++) { - if ([[self objectAtIndex: i] isEqual: oldObject]) { + for (size_t i = 0; i < count; i++) + if ([[self objectAtIndex: i] isEqual: oldObject]) [self replaceObjectAtIndex: i withObject: newObject]; - return; - } - } } - (void)replaceObjectIdenticalTo: (id)oldObject withObject: (id)newObject { size_t count; @@ -337,11 +334,13 @@ for (size_t i = 0; i < count; i++) { if ([[self objectAtIndex: i] isEqual: object]) { [self removeObjectAtIndex: i]; - return; + i--; + count--; + continue; } } } - (void)removeObjectIdenticalTo: (id)object @@ -355,11 +354,13 @@ for (size_t i = 0; i < count; i++) { if ([self objectAtIndex: i] == object) { [self removeObjectAtIndex: i]; - return; + i--; + count--; + continue; } } } - (void)removeObjectsInRange: (OFRange)range Index: src/OFMutableData.h ================================================================== --- src/OFMutableData.h +++ src/OFMutableData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,11 +37,12 @@ * @warning The pointer is only valid until the OFMutableData is changed! * * Modifying the returned array directly is allowed and will change the contents * of the data. */ -@property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *mutableItems + OF_RETURNS_INNER_POINTER; /** * @brief The first item of the OFMutableData or `NULL`. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *mutableFirstItem Index: src/OFMutableData.m ================================================================== --- src/OFMutableData.m +++ src/OFMutableData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableLHAArchiveEntry.h ================================================================== --- src/OFMutableLHAArchiveEntry.h +++ src/OFMutableLHAArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableLHAArchiveEntry.m ================================================================== --- src/OFMutableLHAArchiveEntry.m +++ src/OFMutableLHAArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableMapTableDictionary.h ================================================================== --- src/OFMutableMapTableDictionary.h +++ src/OFMutableMapTableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableMapTableDictionary.m ================================================================== --- src/OFMutableMapTableDictionary.m +++ src/OFMutableMapTableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableMapTableSet.h ================================================================== --- src/OFMutableMapTableSet.h +++ src/OFMutableMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableMapTableSet.m ================================================================== --- src/OFMutableMapTableSet.m +++ src/OFMutableMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutablePair.h ================================================================== --- src/OFMutablePair.h +++ src/OFMutablePair.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutablePair.m ================================================================== --- src/OFMutablePair.m +++ src/OFMutablePair.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableSet.h ================================================================== --- src/OFMutableSet.h +++ src/OFMutableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableSet.m ================================================================== --- src/OFMutableSet.m +++ src/OFMutableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableTriple.h ================================================================== --- src/OFMutableTriple.h +++ src/OFMutableTriple.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableTriple.m ================================================================== --- src/OFMutableTriple.m +++ src/OFMutableTriple.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableURL.h ================================================================== --- src/OFMutableURL.h +++ src/OFMutableURL.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -129,12 +129,12 @@ * * For example, a query like `key1=value1&key2=value2` would correspond to the * following dictionary: * * @{ - * @"key1": "value1", - * @"key2": "value2" + * @"key1": @"value1", + * @"key2": @"value2" * } */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary; @@ -175,11 +175,11 @@ */ - (void)appendPathComponent: (OFString *)component isDirectory: (bool)isDirectory; /** - * @brief Resolves relative sub paths. + * @brief Resolves relative subpaths. */ - (void)standardizePath; /** * @brief Converts the mutable URL to an immutable URL. Index: src/OFMutableURL.m ================================================================== --- src/OFMutableURL.m +++ src/OFMutableURL.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableUTF8String.h ================================================================== --- src/OFMutableUTF8String.h +++ src/OFMutableUTF8String.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableZIPArchiveEntry.h ================================================================== --- src/OFMutableZIPArchiveEntry.h +++ src/OFMutableZIPArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutableZIPArchiveEntry.m ================================================================== --- src/OFMutableZIPArchiveEntry.m +++ src/OFMutableZIPArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutex.h ================================================================== --- src/OFMutex.h +++ src/OFMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFMutex.m ================================================================== --- src/OFMutex.m +++ src/OFMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFNonretainedObjectValue.h ================================================================== --- src/OFNonretainedObjectValue.h +++ src/OFNonretainedObjectValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFNonretainedObjectValue.m ================================================================== --- src/OFNonretainedObjectValue.m +++ src/OFNonretainedObjectValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 ADDED src/OFNotification.h Index: src/OFNotification.h ================================================================== --- /dev/null +++ src/OFNotification.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008-2022 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" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFConstantString; +@class OFDictionary OF_GENERIC(KeyType, ObjectType); + +/** + * @brief A name for a notification. + */ +typedef OFConstantString *OFNotificationName; + +/** + * @class OFNotification OFNotification.h ObjFW/OFNotification.h + * + * @brief A class to represent a notification for or from + * @ref OFNotificationCenter. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFNotification: OFObject +{ + OFNotificationName _name; + id _Nullable _object; + OFDictionary *_Nullable _userInfo; +} + +/** + * @brief The name of the notification. + */ +@property (readonly, nonatomic) OFNotificationName name; + +/** + * @brief The object of the notification. This is commonly the sender of the + * notification. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; + +/** + * @brief Additional information about the notification. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFDictionary *userInfo; + +/** + * @brief Creates a new notification with the specified name and object. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @return A new, autoreleased OFNotification + */ ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Creates a new notification with the specified name, object and + * additional information. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @param userInfo Additional information for the notification + * @return A new, autoreleased OFNotification + */ ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo; + +/** + * @brief Initializes an already allocated notification with the specified + * name and object. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @return An initialized OFNotification + */ +- (instancetype)initWithName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Initializes an already allocated notification with the specified + * name, object and additional information. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @param userInfo Additional information for the notification + * @return An initialized OFNotification + */ +- (instancetype)initWithName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFNotification.m Index: src/OFNotification.m ================================================================== --- /dev/null +++ src/OFNotification.m @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2022 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 "OFNotification.h" +#import "OFDictionary.h" +#import "OFString.h" + +@implementation OFNotification +@synthesize name = _name, object = _object, userInfo = _userInfo; + ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (id)object +{ + return [[[self alloc] initWithName: name object: object] autorelease]; +} + ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (id)object + userInfo: (OFDictionary *)userInfo +{ + return [[[self alloc] initWithName: name + object: object + userInfo: userInfo] autorelease]; +} + +- (instancetype)initWithName: (OFNotificationName)name object: (id)object +{ + return [self initWithName: name object: object userInfo: nil]; +} + +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + userInfo: (OFDictionary *)userInfo +{ + self = [super init]; + + @try { + _name = [name copy]; + _object = [object retain]; + _userInfo = [userInfo copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_name release]; + [_object release]; + [_userInfo release]; + + [super dealloc]; +} + +- (id)copy +{ + return [self retain]; +} +@end ADDED src/OFNotificationCenter.h Index: src/OFNotificationCenter.h ================================================================== --- /dev/null +++ src/OFNotificationCenter.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008-2022 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" +#import "OFNotification.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); +#ifdef OF_HAVE_THREADS +@class OFMutex; +#endif +@class OFNotificationCenterHandle; + +#ifdef OF_HAVE_BLOCKS +/** + * @brief A block which is called when a notification has been posted. + * + * @param notification The notification that has been posted + */ +typedef void (^OFNotificationCenterBlock)(OFNotification *notification); +#endif + +/** + * @class OFNotificationCenter OFNotificationCenter.h \ + * ObjFW/OFNotificationCenter.h + * + * @brief A class to send and register for notifications. + */ +@interface OFNotificationCenter: OFObject +{ +#ifdef OF_HAVE_THREADS + OFMutex *_mutex; +#endif + OFMutableDictionary *_handles; + OF_RESERVE_IVARS(OFNotificationCenter, 4) +} + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nonatomic) OFNotificationCenter *defaultCenter; +#endif + +/** + * @brief Returns the default notification center. + */ ++ (OFNotificationCenter *)defaultCenter; + +/** + * @brief Adds an observer for the specified notification and object. + * + * @param observer The object that should receive notifications + * @param selector The selector to call on the observer on notifications. The + * method must take exactly one object of type @ref + * OFNotification. + * @param name The name of the notification to observe + * @param object The object that should be sending the notification, or `nil` + * if the object should be ignored to determine what + * notifications to deliver + */ +- (void)addObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Removes an observer. All parameters must match those used with + * @ref addObserver:selector:name:object:. + * + * @param observer The observer that was specified when adding the observer + * @param selector The selector that was specified when adding the observer + * @param name The name that was specified when adding the observer + * @param object The object that was specified when adding the observer + */ +- (void)removeObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (nullable id)object; + +#ifdef OF_HAVE_BLOCKS +/** + * @brief Adds an observer for the specified notification and object. + * + * To remove the observer again, use @ref removeObserver:. + * + * @param name The name of the notification to observe + * @param object The object that should be sending the notification, or `nil` + * if the object should be ignored to determine what + * notifications to deliver + * @param block The block to handle notifications + * @return An opaque object to remove the observer again + */ +- (OFNotificationCenterHandle *) + addObserverForName: (OFNotificationName)name + object: (nullable id)object + usingBlock: (OFNotificationCenterBlock)block; + +/** + * @brief Removes an observer. The specified observer must be one returned by + * @ref addObserver:selector:name:object:. + * + * @param observer The object that was returned when adding the observer + */ +- (void)removeObserver: (OFNotificationCenterHandle *)observer; +#endif + +/** + * @brief Posts the specified notification. + * + * @param notification The notification to post + */ +- (void)postNotification: (OFNotification *)notification; + +/** + * @brief Posts a notification with the specified name and object. + * + * @param name The name for the notification + * @param object The object for the notification + */ +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Posts a notification with the specified name, object and additional + * information. + * + * @param name The name for the notification + * @param object The object for the notification + * @param userInfo Additional information for the notification + */ +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFNotificationCenter.m Index: src/OFNotificationCenter.m ================================================================== --- /dev/null +++ src/OFNotificationCenter.m @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2008-2022 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 "OFNotificationCenter.h" +#import "OFArray.h" +#import "OFDictionary.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif +#import "OFSet.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" + +@interface OFDefaultNotificationCenter: OFNotificationCenter +@end + +@interface OFNotificationCenterHandle: OFObject +{ +@public + OFNotificationName _name; + id _observer; + SEL _selector; + unsigned long _selectorHash; +#ifdef OF_HAVE_BLOCKS + OFNotificationCenterBlock _block; +#endif + id _object; +} + +- (instancetype)initWithName: (OFNotificationName)name + observer: (id)observer + selector: (SEL)selector + object: (id)object; +#ifdef OF_HAVE_BLOCKS +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + block: (OFNotificationCenterBlock)block; +#endif +@end + +static OFNotificationCenter *defaultCenter; + +@implementation OFNotificationCenterHandle +- (instancetype)initWithName: (OFNotificationName)name + observer: (id)observer + selector: (SEL)selector + object: (id)object +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + + _name = [name copy]; + _observer = [observer retain]; + _selector = selector; + _object = [object retain]; + + _selectorHash = [[OFString stringWithUTF8String: + sel_getName(_selector)] hash]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +#ifdef OF_HAVE_BLOCKS +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + block: (OFNotificationCenterBlock)block +{ + self = [super init]; + + @try { + _name = [name copy]; + _object = [object retain]; + _block = [block copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} +#endif + +- (void)dealloc +{ + [_name release]; + [_observer release]; + [_object release]; +#ifdef OF_HAVE_BLOCKS + [_block release]; +#endif + + [super dealloc]; +} + +- (bool)isEqual: (OFNotificationCenterHandle *)handle +{ + if (![handle isKindOfClass: [OFNotificationCenterHandle class]]) + return false; + + if (![handle->_name isEqual: _name]) + return false; + + if (handle->_observer != _observer && + ![handle->_observer isEqual: _observer]) + return false; + + if (handle->_selector != _selector && + !sel_isEqual(handle->_selector, _selector)) + return false; + +#ifdef OF_HAVE_BLOCKS + if (handle->_block != _block) + return false; +#endif + + if (handle->_object != _object && ![handle->_object isEqual: _object]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddHash(&hash, [_observer hash]); + OFHashAddHash(&hash, _selectorHash); +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) + OFHashAddHash(&hash, (unsigned long)(uintptr_t)_block); +#endif + OFHashAddHash(&hash, [_object hash]); + + OFHashFinalize(&hash); + + return hash; +} +@end + +@implementation OFNotificationCenter ++ (void)initialize +{ + if (self != [OFNotificationCenter class]) + return; + + defaultCenter = [[OFDefaultNotificationCenter alloc] init]; +} + ++ (OFNotificationCenter *)defaultCenter +{ + return defaultCenter; +} + +- (instancetype)init +{ + self = [super init]; + + @try { +#ifdef OF_HAVE_THREADS + _mutex = [[OFMutex alloc] init]; +#endif + _handles = [[OFMutableDictionary alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ +#ifdef OF_HAVE_THREADS + [_mutex release]; +#endif + [_handles release]; + + [super dealloc]; +} + +- (void)of_addObserver: (OFNotificationCenterHandle *)handle +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + OFMutableSet *handlesForName = + [_handles objectForKey: handle->_name]; + + if (handlesForName == nil) { + handlesForName = [OFMutableSet set]; + [_handles setObject: handlesForName + forKey: handle->_name]; + } + + [handlesForName addObject: handle]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif +} + +- (void)addObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (id)object +{ + void *pool = objc_autoreleasePoolPush(); + + [self of_addObserver: + [[[OFNotificationCenterHandle alloc] initWithName: name + observer: observer + selector: selector + object: object] + autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +#ifdef OF_HAVE_BLOCKS +- (OFNotificationCenterHandle *) + addObserverForName: (OFNotificationName)name + object: (id)object + usingBlock: (OFNotificationCenterBlock)block +{ + void *pool = objc_autoreleasePoolPush(); + OFNotificationCenterHandle *handle = + [[[OFNotificationCenterHandle alloc] initWithName: name + object: object + block: block] + autorelease]; + + [self of_addObserver: handle]; + + [handle retain]; + + objc_autoreleasePoolPop(pool); + + return [handle autorelease]; +} +#endif + +- (void)removeObserver: (OFNotificationCenterHandle *)handle +{ + void *pool = objc_autoreleasePoolPush(); + + /* {} required to avoid -Wmisleading-indentation false positive. */ + if (![handle isKindOfClass: [OFNotificationCenterHandle class]]) { + @throw [OFInvalidArgumentException exception]; + } + +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + OFNotificationName name = [[handle->_name copy] autorelease]; + OFMutableSet *handlesForName = [_handles objectForKey: name]; + + [handlesForName removeObject: handle]; + + if (handlesForName.count == 0) + [_handles removeObjectForKey: name]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif + + objc_autoreleasePoolPop(pool); +} + +- (void)removeObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (id)object +{ + void *pool = objc_autoreleasePoolPush(); + + [self removeObserver: + [[[OFNotificationCenterHandle alloc] initWithName: name + observer: observer + selector: selector + object: object] + autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)postNotification: (OFNotification *)notification +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *matchedHandles = [OFMutableArray array]; + +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + for (OFNotificationCenterHandle *handle in + [_handles objectForKey: notification.name]) + if (handle->_object == nil || + handle->_object == notification.object) + [matchedHandles addObject: handle]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif + + for (OFNotificationCenterHandle *handle in matchedHandles) { +#ifdef OF_HAVE_BLOCKS + if (handle->_block != NULL) + handle->_block(notification); + else { +#endif + void (*callback)(id, SEL, OFNotification *) = + (void (*)(id, SEL, OFNotification *)) + [handle->_observer methodForSelector: + handle->_selector]; + + callback(handle->_observer, handle->_selector, + notification); +#ifdef OF_HAVE_BLOCKS + } +#endif + } + + objc_autoreleasePoolPop(pool); +} + +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object +{ + [self postNotificationName: name object: object userInfo: nil]; +} + +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo +{ + void *pool = objc_autoreleasePoolPush(); + + [self postNotification: + [OFNotification notificationWithName: name + object: object + userInfo: userInfo]]; + + objc_autoreleasePoolPop(pool); +} +@end + +@implementation OFDefaultNotificationCenter +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OFMaxRetainCount; +} +@end Index: src/OFNull.h ================================================================== --- src/OFNull.h +++ src/OFNull.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFNull.m ================================================================== --- src/OFNull.m +++ src/OFNull.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -122,20 +122,18 @@ /** * @brief The OFNumber as a string. */ @property (readonly, nonatomic) OFString *stringValue; -#ifdef OF_HAVE_UNAVAILABLE + (instancetype)valueWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; + (instancetype)valueWithPointer: (const void *)pointer OF_UNAVAILABLE; + (instancetype)valueWithNonretainedObject: (id)object OF_UNAVAILABLE; + (instancetype)valueWithRange: (OFRange)range OF_UNAVAILABLE; + (instancetype)valueWithPoint: (OFPoint)point OF_UNAVAILABLE; + (instancetype)valueWithSize: (OFSize)size OF_UNAVAILABLE; + (instancetype)valueWithRect: (OFRect)rect OF_UNAVAILABLE; -#endif /** * @brief Creates a new OFNumber with the specified `bool`. * * @param value The `bool` value which the OFNumber should contain @@ -238,14 +236,12 @@ * @return A new autoreleased OFNumber */ + (instancetype)numberWithDouble: (double)value; - (instancetype)init OF_UNAVAILABLE; -#ifdef OF_HAVE_UNAVAILABLE - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; -#endif /** * @brief Initializes an already allocated OFNumber with the specified `bool`. * * @param value The `bool` value which the OFNumber should contain Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -509,10 +509,46 @@ if (self == [OFNumber class]) return (id)&placeholder; return [super alloc]; } + ++ (instancetype)valueWithBytes: (const void *)bytes + objCType: (const char *)objCType +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithPointer: (const void *)pointer +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithNonretainedObject: (id)object +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithRange: (OFRange)range +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithPoint: (OFPoint)point +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithSize: (OFSize)size +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithRect: (OFRect)rect +{ + OF_UNRECOGNIZED_SELECTOR +} + (instancetype)numberWithBool: (bool)value { return [[[self alloc] initWithBool: value] autorelease]; } @@ -577,10 +613,16 @@ return [[[self alloc] initWithDouble: value] autorelease]; } - (instancetype)init { + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithBytes: (const void *)bytes + objCType: (const char *)objCType +{ OF_INVALID_INIT_METHOD } - (instancetype)initWithBool: (bool)value { Index: src/OFObject+KeyValueCoding.h ================================================================== --- src/OFObject+KeyValueCoding.h +++ src/OFObject+KeyValueCoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFObject+KeyValueCoding.m ================================================================== --- src/OFObject+KeyValueCoding.m +++ src/OFObject+KeyValueCoding.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFObject+Serialization.h ================================================================== --- src/OFObject+Serialization.h +++ src/OFObject+Serialization.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFObject+Serialization.m ================================================================== --- src/OFObject+Serialization.m +++ src/OFObject+Serialization.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -627,14 +627,13 @@ * * Derived classes can override this to execute their own code when the class * is unloaded. * * @warning This is not supported by the Apple runtime and currently only - * called by the ObjFW runtime when objc_unregister_class() or - * objc_exit() has been called! + * called by the ObjFW runtime when @ref objc_deinit has been called! * In the future, this might also be called by the ObjFW runtime when - * the class is part of a plugin that has been unloaded. + * the class is part of a plugin that is being unloaded. */ + (void)unload; /** * @brief A method which is called the moment before the first call to the class Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,10 +16,11 @@ #include "config.h" #include #include #include +#include "unistd_wrapper.h" #include #ifdef OF_APPLE_RUNTIME # include @@ -46,11 +47,10 @@ #import "OFAllocFailedException.h" #import "OFEnumerationMutationException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" -#import "OFMemoryNotPartOfObjectException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #if defined(OF_APPLE_RUNTIME) && __OBJC2__ @@ -70,11 +70,11 @@ #ifdef OF_APPLE_RUNTIME extern id _Nullable _objc_rootAutorelease(id _Nullable object); #endif #if defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR) extern id OFForward(id, SEL, ...); -extern struct stret OFForward_stret(id, SEL, ...); +extern struct Stret OFForward_stret(id, SEL, ...); #else # define OFForward OFMethodNotFound # define OFForward_stret OFMethodNotFound_stret #endif @@ -133,12 +133,14 @@ } void * OFResizeMemory(void *pointer, size_t count, size_t size) { - if OF_UNLIKELY (count == 0 || size == 0) + if OF_UNLIKELY (count == 0 || size == 0) { + free(pointer); return NULL; + } if OF_UNLIKELY (count > SIZE_MAX / size) @throw [OFOutOfRangeException exception]; if OF_UNLIKELY ((pointer = realloc(pointer, count * size)) == NULL) Index: src/OFOnce.h ================================================================== --- src/OFOnce.h +++ src/OFOnce.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,9 +30,17 @@ #endif #ifdef __cplusplus extern "C" { #endif -extern void OFOnce(OFOnceControl *control, void (*func)(void)); +/** + * @brief Executes the specified function exactly once in the application's + * lifetime, even in a multi-threaded environment. + * + * @param control An OFOnceControl. This should be a static variable + * preinitialized to `OFOnceControlInitValue`. + * @param function The function to execute once + */ +extern void OFOnce(OFOnceControl *control, void (*function)(void)); #ifdef __cplusplus } #endif Index: src/OFOnce.m ================================================================== --- src/OFOnce.m +++ src/OFOnce.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,26 +26,26 @@ #ifdef OF_AMIGAOS # include #endif void -OFOnce(OFOnceControl *control, void (*func)(void)) +OFOnce(OFOnceControl *control, void (*function)(void)) { #if !defined(OF_HAVE_THREADS) if (*control == 0) { - func(); + function(); *control = 1; } #elif defined(OF_HAVE_PTHREADS) - pthread_once(control, func); + pthread_once(control, function); #elif defined(OF_HAVE_ATOMIC_OPS) /* Avoid atomic operations in case it's already done. */ if (*control == 2) return; if (OFAtomicIntCompareAndSwap(control, 0, 1)) { - func(); + function(); OFMemoryBarrier(); OFAtomicIntIncrease(control); } else @@ -73,12 +73,12 @@ } Permit(); if (run) { - func(); + function(); *control = 2; } #else # error No OFOnce available #endif } Index: src/OFOptionsParser.h ================================================================== --- src/OFOptionsParser.h +++ src/OFOptionsParser.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFOptionsParser.m ================================================================== --- src/OFOptionsParser.m +++ src/OFOptionsParser.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPBKDF2.h ================================================================== --- src/OFPBKDF2.h +++ src/OFPBKDF2.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPBKDF2.m ================================================================== --- src/OFPBKDF2.m +++ src/OFPBKDF2.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -71,17 +71,19 @@ memcpy(extendedSaltItems + param.saltLength, &i, 4); [param.HMAC reset]; [param.HMAC updateWithBuffer: extendedSaltItems length: param.saltLength + 4]; + [param.HMAC calculate]; memcpy(bufferItems, param.HMAC.digest, digestSize); memcpy(digestItems, param.HMAC.digest, digestSize); for (size_t j = 1; j < param.iterations; j++) { [param.HMAC reset]; [param.HMAC updateWithBuffer: digestItems length: digestSize]; + [param.HMAC calculate]; memcpy(digestItems, param.HMAC.digest, digestSize); for (size_t k = 0; k < digestSize; k++) bufferItems[k] ^= digestItems[k]; Index: src/OFPair.h ================================================================== --- src/OFPair.h +++ src/OFPair.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPair.m ================================================================== --- src/OFPair.m +++ src/OFPair.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPlainCondition.h ================================================================== --- src/OFPlainCondition.h +++ src/OFPlainCondition.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPlainCondition.m ================================================================== --- src/OFPlainCondition.m +++ src/OFPlainCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,11 +16,11 @@ #include "config.h" #include "platform.h" #if defined(OF_HAVE_PTHREADS) -# include "platform/posix/OFPlainCondition.m" +# include "platform/POSIX/OFPlainCondition.m" #elif defined(OF_WINDOWS) -# include "platform/windows/OFPlainCondition.m" +# include "platform/Windows/OFPlainCondition.m" #elif defined(OF_AMIGAOS) -# include "platform/amiga/OFPlainCondition.m" +# include "platform/AmigaOS/OFPlainCondition.m" #endif Index: src/OFPlainMutex.h ================================================================== --- src/OFPlainMutex.h +++ src/OFPlainMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPlainMutex.m ================================================================== --- src/OFPlainMutex.m +++ src/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,11 +16,11 @@ #include "config.h" #include "platform.h" #if defined(OF_HAVE_PTHREADS) -# include "platform/posix/OFPlainMutex.m" +# include "platform/POSIX/OFPlainMutex.m" #elif defined(OF_WINDOWS) -# include "platform/windows/OFPlainMutex.m" +# include "platform/Windows/OFPlainMutex.m" #elif defined(OF_AMIGAOS) -# include "platform/amiga/OFPlainMutex.m" +# include "platform/AmigaOS/OFPlainMutex.m" #endif Index: src/OFPlainThread.h ================================================================== --- src/OFPlainThread.h +++ src/OFPlainThread.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -73,16 +73,11 @@ { return (thread == GetCurrentThread()); } #elif defined(OF_AMIGAOS) extern OFPlainThread OFCurrentPlainThread(void); - -static OF_INLINE bool -OFPlainThreadIsCurrent(OFPlainThread thread) -{ - return (thread->thread == FindTask(NULL)); -} +extern bool OFPlainThreadIsCurrent(OFPlainThread); #endif #ifdef __cplusplus extern "C" { #endif Index: src/OFPlainThread.m ================================================================== --- src/OFPlainThread.m +++ src/OFPlainThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,11 +16,11 @@ #include "config.h" #include "platform.h" #if defined(OF_HAVE_PTHREADS) -# include "platform/posix/OFPlainThread.m" +# include "platform/POSIX/OFPlainThread.m" #elif defined(OF_WINDOWS) -# include "platform/windows/OFPlainThread.m" +# include "platform/Windows/OFPlainThread.m" #elif defined(OF_AMIGAOS) -# include "platform/amiga/OFPlainThread.m" +# include "platform/AmigaOS/OFPlainThread.m" #endif Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -18,58 +18,64 @@ @class OFString; #ifndef OF_WINDOWS # include typedef void *OFPluginHandle; - -typedef enum { - OFDLOpenFlagLazy = RTLD_LAZY, - OFDLOpenFlagNow = RTLD_NOW -} OFDLOpenFlags; #else # include typedef HMODULE OFPluginHandle; - -typedef enum { - OFDLOpenFlagLazy = 0, - OFDLOpenFlagNow = 0 -} OFDLOpenFlags; #endif OF_ASSUME_NONNULL_BEGIN /** * @class OFPlugin OFPlugin.h ObjFW/OFPlugin.h * - * @brief Provides a system for loading plugins at runtime. + * @brief A class representing a loaded plugin (shared library). * - * A plugin must subclass @ref OFPlugin and have a global function called - * `OFPluginInit`, which returns an instance of the @ref OFPlugin subclass and - * takes no parameters. */ +OF_SUBCLASSING_RESTRICTED @interface OFPlugin: OFObject { - OFPluginHandle _pluginHandle; - OF_RESERVE_IVARS(OFPlugin, 4) + OFPluginHandle _handle; } /** - * @brief Loads a plugin from a file. - * - * @param path Path to the plugin file. The suffix is appended automatically. - * @return The loaded plugin - */ -+ (OF_KINDOF(OFPlugin *))pluginWithPath: (OFString *)path; -@end - -#ifdef __cplusplus -extern "C" { -#endif -extern OFPluginHandle OFDLOpen(OFString *path, OFDLOpenFlags flags); -extern void *OFDLSym(OFPluginHandle handle, const char *symbol); -extern OFString *_Nullable OFDLError(void); -extern void OFDLClose(OFPluginHandle handle); -#ifdef __cplusplus -} -#endif + * @brief Returns the plugin path for a plugin with the specified name. + * + * E.g. on ELF systems, it appends .so, while on macOS and iOS, it creates the + * appropriate plugin path. This can also be prefixed by a directory. + * + * @param name The name to return the plugin path for + * @return The plugin path + */ ++ (OFString *)pathForName: (OFString *)name; + +/** + * @brief Creates a new OFPlugin by loading the plugin with the specified path. + * + * @param path The path to the plugin file. The suffix is appended + * automatically. + * @return An new, autoreleased OFPlugin + */ ++ (instancetype)pluginWithPath: (OFString *)path; + +/** + * @brief Initializes an already allocated OFPlugin by loading the plugin with + * the specified path. + * + * @param path The path to the plugin file. The suffix is appended + * automatically. + * @return An initialized OFPlugin + */ +- (instancetype)initWithPath: (OFString *)path; + +/** + * @brief Returns the address for the specified symbol, or `nil` if not found. + * + * @param symbol The symbol to return the address for + * @return The address for the speccified symbol, or `nil` if not found + */ +- (nullable void *)addressForSymbol: (OFString *)symbol; +@end OF_ASSUME_NONNULL_END Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,116 +28,90 @@ #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLoadPluginFailedException.h" -typedef OFPlugin *(*PluginInit)(void); - -OFPluginHandle -OFDLOpen(OFString *path, OFDLOpenFlags flags) -{ -#ifndef OF_WINDOWS - return dlopen([path cStringWithEncoding: [OFLocale encoding]], flags); -#else - if (path == nil) - return GetModuleHandle(NULL); - - if ([OFSystemInfo isWindowsNT]) - return LoadLibraryW(path.UTF16String); - else - return LoadLibraryA( - [path cStringWithEncoding: [OFLocale encoding]]); -#endif -} - -void * -OFDLSym(OFPluginHandle handle, const char *symbol) -{ -#ifndef OF_WINDOWS - return dlsym(handle, symbol); -#else - return (void *)(uintptr_t)GetProcAddress(handle, symbol); -#endif -} - -void -OFDLClose(OFPluginHandle handle) -{ -#ifndef OF_WINDOWS - dlclose(handle); -#else - FreeLibrary(handle); -#endif -} - -OFString * -OFDLError(void) -{ -#ifndef OF_WINDOWS - return [OFString stringWithCString: dlerror() - encoding: [OFLocale encoding]]; -#else - return nil; -#endif -} - -@implementation OFPlugin -+ (id)pluginWithPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFPluginHandle handle; - PluginInit initPlugin; - OFPlugin *plugin; - -#if defined(OF_MACOS) - path = [path stringByAppendingFormat: @".bundle/Contents/MacOS/%@", - path.lastPathComponent]; -#elif defined(OF_IOS) - path = [path stringByAppendingFormat: @".bundle/%@", - path.lastPathComponent]; -#else - path = [path stringByAppendingString: @PLUGIN_SUFFIX]; -#endif - - if ((handle = OFDLOpen(path, OFDLOpenFlagLazy)) == NULL) - @throw [OFLoadPluginFailedException - exceptionWithPath: path - error: OFDLError()]; - - objc_autoreleasePoolPop(pool); - - initPlugin = (PluginInit)(uintptr_t)OFDLSym(handle, "OFPluginInit"); - if (initPlugin == (PluginInit)0 || (plugin = initPlugin()) == nil) { - OFDLClose(handle); - @throw [OFInitializationFailedException - exceptionWithClass: self]; - } - - plugin->_pluginHandle = handle; - return plugin; -} - -- (instancetype)init -{ - if ([self isMemberOfClass: [OFPlugin class]]) { - @try { - [self doesNotRecognizeSelector: _cmd]; - } @catch (id e) { - [self release]; - @throw e; - } - - abort(); - } - - return [super init]; +#ifndef RTLD_LAZY +# define RTLD_LAZY 0 +#endif + +@implementation OFPlugin ++ (instancetype)pluginWithPath: (OFString *)path +{ + return [[[self alloc] initWithPath: path] autorelease]; +} + ++ (OFString *)pathForName: (OFString *)name +{ +#if defined(OF_MACOS) + return [name stringByAppendingFormat: @".bundle/Contents/MacOS/%@", + name.lastPathComponent]; +#elif defined(OF_IOS) + return [name stringByAppendingFormat: @".bundle/%@", + name.lastPathComponent]; +#else + return [name stringByAppendingString: @PLUGIN_SUFFIX]; +#endif +} + +- (instancetype)initWithPath: (OFString *)path +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + +#ifndef OF_WINDOWS + _handle = dlopen( + [path cStringWithEncoding: [OFLocale encoding]], RTLD_LAZY); +#else + if ([OFSystemInfo isWindowsNT]) + _handle = LoadLibraryW(path.UTF16String); + else + _handle = LoadLibraryA( + [path cStringWithEncoding: [OFLocale encoding]]); +#endif + + if (_handle == NULL) { +#ifndef OF_WINDOWS + OFString *error = [OFString + stringWithCString: dlerror() + encoding: [OFLocale encoding]]; +#else + OFString *error = nil; +#endif + @throw [OFLoadPluginFailedException + exceptionWithPath: path + error: error]; + } + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void *)addressForSymbol: (OFString *)symbol +{ +#ifndef OF_WINDOWS + return dlsym(_handle, + [symbol cStringWithEncoding: [OFLocale encoding]]); +#else + return (void *)(uintptr_t)GetProcAddress(_handle, + [symbol cStringWithEncoding: [OFLocale encoding]]); +#endif } - (void)dealloc { - OFPluginHandle h = _pluginHandle; +#ifndef OF_WINDOWS + dlclose(_handle); +#else + FreeLibrary(_handle); +#endif [super dealloc]; - - OFDLClose(h); } @end Index: src/OFPointValue.h ================================================================== --- src/OFPointValue.h +++ src/OFPointValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPointValue.m ================================================================== --- src/OFPointValue.m +++ src/OFPointValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPointerValue.h ================================================================== --- src/OFPointerValue.h +++ src/OFPointerValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPointerValue.m ================================================================== --- src/OFPointerValue.m +++ src/OFPointerValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPollKernelEventObserver.h ================================================================== --- src/OFPollKernelEventObserver.h +++ src/OFPollKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFPollKernelEventObserver.m ================================================================== --- src/OFPollKernelEventObserver.m +++ src/OFPollKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRIPEMD160Hash.h ================================================================== --- src/OFRIPEMD160Hash.h +++ src/OFRIPEMD160Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRIPEMD160Hash.m ================================================================== --- src/OFRIPEMD160Hash.m +++ src/OFRIPEMD160Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,10 +19,11 @@ #import "OFRIPEMD160Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" static const size_t digestSize = 20; static const size_t blockSize = 64; @@ -256,12 +257,21 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); @@ -277,12 +287,10 @@ processBlock(_iVars->state, _iVars->buffer.words); OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfBE(_iVars->state, 5); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; Index: src/OFRangeCharacterSet.h ================================================================== --- src/OFRangeCharacterSet.h +++ src/OFRangeCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRangeCharacterSet.m ================================================================== --- src/OFRangeCharacterSet.m +++ src/OFRangeCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRangeValue.h ================================================================== --- src/OFRangeValue.h +++ src/OFRangeValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRangeValue.m ================================================================== --- src/OFRangeValue.m +++ src/OFRangeValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRectValue.h ================================================================== --- src/OFRectValue.h +++ src/OFRectValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRectValue.m ================================================================== --- src/OFRectValue.m +++ src/OFRectValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRecursiveMutex.h ================================================================== --- src/OFRecursiveMutex.h +++ src/OFRecursiveMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRecursiveMutex.m ================================================================== --- src/OFRecursiveMutex.m +++ src/OFRecursiveMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRunLoop.h ================================================================== --- src/OFRunLoop.h +++ src/OFRunLoop.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,12 +40,14 @@ #import "OFTimer.h" #import "OFTimer+Private.h" #import "OFDate.h" #import "OFObserveFailedException.h" +#import "OFWriteFailedException.h" -const OFRunLoopMode OFDefaultRunLoopMode = @"OFDefaultRunLoopMode"; +#include "OFRunLoopConstants.inc" + static OFRunLoop *mainRunLoop = nil; @interface OFRunLoopState: OFObject #ifdef OF_HAVE_SOCKETS @@ -566,26 +568,31 @@ size_t dataLength = _data.count * _data.itemSize; OFData *newData, *oldData; @try { const char *dataItems = _data.items; + length = dataLength - _writtenLength; + [object writeBuffer: dataItems + _writtenLength length: length]; + } @catch (OFWriteFailedException *e) { + length = e.bytesWritten; - length = [object writeBuffer: dataItems + _writtenLength - length: dataLength - _writtenLength]; + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + exception = e; } @catch (id e) { length = 0; exception = e; } _writtenLength += length; + OFEnsure(_writtenLength <= dataLength); if (_writtenLength != dataLength && exception == nil) return true; # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, _writtenLength, exception); + newData = _block(_writtenLength, exception); if (newData == nil) return false; oldData = _data; @@ -638,26 +645,31 @@ size_t cStringLength = [_string cStringLengthWithEncoding: _encoding]; OFString *newString, *oldString; @try { const char *cString = [_string cStringWithEncoding: _encoding]; + length = cStringLength - _writtenLength; + [object writeBuffer: cString + _writtenLength length: length]; + } @catch (OFWriteFailedException *e) { + length = e.bytesWritten; - length = [object writeBuffer: cString + _writtenLength - length: cStringLength - _writtenLength]; + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + exception = e; } @catch (id e) { length = 0; exception = e; } _writtenLength += length; + OFEnsure(_writtenLength <= cStringLength); if (_writtenLength != cStringLength && exception == nil) return true; # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newString = _block(_string, _writtenLength, exception); + newString = _block(_writtenLength, exception); if (newString == nil) return false; oldString = _string; @@ -847,11 +859,11 @@ exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, &_receiver, exception); + newData = _block(exception); if (newData == nil) return false; oldData = _data; @@ -948,11 +960,11 @@ exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, exception); + newData = _block(exception); if (newData == nil) return false; oldData = _data; @@ -1413,12 +1425,14 @@ - (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode { OFRunLoopState *state = stateForMode(self, mode, false); - if (state == nil) + /* {} required to avoid -Wmisleading-indentation false positive. */ + if (state == nil) { return; + } #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif ADDED src/OFRunLoopConstants.inc Index: src/OFRunLoopConstants.inc ================================================================== --- /dev/null +++ src/OFRunLoopConstants.inc @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +const OFRunLoopMode OFDefaultRunLoopMode = @"OFDefaultRunLoopMode"; Index: src/OFSHA1Hash.h ================================================================== --- src/OFSHA1Hash.h +++ src/OFSHA1Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,10 +19,11 @@ #import "OFSHA1Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" static const size_t digestSize = 20; static const size_t blockSize = 64; @@ -216,12 +217,21 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); @@ -237,12 +247,10 @@ processBlock(_iVars->state, _iVars->buffer.words); OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 5); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; Index: src/OFSHA224Hash.h ================================================================== --- src/OFSHA224Hash.h +++ src/OFSHA224Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA224Hash.m ================================================================== --- src/OFSHA224Hash.m +++ src/OFSHA224Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA224Or256Hash.h ================================================================== --- src/OFSHA224Or256Hash.h +++ src/OFSHA224Or256Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA224Or256Hash.m ================================================================== --- src/OFSHA224Or256Hash.m +++ src/OFSHA224Or256Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,10 +20,11 @@ #import "OFSHA224Or256Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" static const size_t blockSize = 64; @interface OFSHA224Or256Hash () @@ -232,12 +233,21 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); @@ -253,12 +263,10 @@ processBlock(_iVars->state, _iVars->buffer.words); OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 8); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; Index: src/OFSHA256Hash.h ================================================================== --- src/OFSHA256Hash.h +++ src/OFSHA256Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA256Hash.m ================================================================== --- src/OFSHA256Hash.m +++ src/OFSHA256Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA384Hash.h ================================================================== --- src/OFSHA384Hash.h +++ src/OFSHA384Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA384Hash.m ================================================================== --- src/OFSHA384Hash.m +++ src/OFSHA384Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA384Or512Hash.h ================================================================== --- src/OFSHA384Or512Hash.h +++ src/OFSHA384Or512Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA384Or512Hash.m ================================================================== --- src/OFSHA384Or512Hash.m +++ src/OFSHA384Or512Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,10 +20,11 @@ #import "OFSHA384Or512Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" static const size_t blockSize = 128; @interface OFSHA384Or512Hash () @@ -245,12 +246,21 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 128 - _iVars->bufferLength - 1); @@ -264,12 +274,10 @@ processBlock(_iVars->state, _iVars->buffer.words); OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 8); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; Index: src/OFSHA512Hash.h ================================================================== --- src/OFSHA512Hash.h +++ src/OFSHA512Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSHA512Hash.m ================================================================== --- src/OFSHA512Hash.m +++ src/OFSHA512Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSPXSocket.h ================================================================== --- src/OFSPXSocket.h +++ src/OFSPXSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -42,21 +42,21 @@ @optional /** * @brief A method which is called when a socket connected. * * @param socket The socket which connected - * @param node The node the socket connected to * @param network The network of the node the socket connected to + * @param node The node the socket connected to * @param port The port of the node to which the socket connected * @param exception An exception that occurred while connecting, or nil on * success */ -- (void)socket: (OFSPXSocket *)socket - didConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - exception: (nullable id)exception; +- (void)socket: (OFSPXSocket *)socket + didConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + exception: (nullable id)exception; @end /** * @class OFSPXSocket OFSPXSocket.h ObjFW/OFSPXSocket.h * @@ -83,44 +83,44 @@ id delegate; /** * @brief Connect the OFSPXSocket to the specified destination. * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - */ -- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSPXSocket to the specified destination. - * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSPXSocket to the specified destination. - * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - * @param runLoopMode The run loop mode in which to perform the async connect - */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode; + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + */ +- (void)connectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSPXSocket to the specified destination. + * + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + */ +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSPXSocket to the specified destination. + * + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + * @param runLoopMode The run loop mode in which to perform the async connect + */ +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * @@ -128,14 +128,14 @@ * @param network The network on which the node to connect to is * @param port The port (sometimes also called socket number) on the node to * connect to * @param block The block to execute once the connection has been established */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - block: (OFSPXSocketAsyncConnectBlock)block; +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + block: (OFSPXSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * * @param node The node to connect to @@ -143,15 +143,15 @@ * @param port The port (sometimes also called socket number) on the node to * connect to * @param runLoopMode The run loop mode in which to perform the async connect * @param block The block to execute once the connection has been established */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode - block: (OFSPXSocketAsyncConnectBlock)block; +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * Index: src/OFSPXSocket.m ================================================================== --- src/OFSPXSocket.m +++ src/OFSPXSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -44,21 +44,21 @@ OF_DIRECT_MEMBERS @interface OFSPXSocketAsyncConnectDelegate: OFObject { OFSPXSocket *_socket; - unsigned char _node[IPX_NODE_LEN]; uint32_t _network; + unsigned char _node[IPX_NODE_LEN]; uint16_t _port; #ifdef OF_HAVE_BLOCKS OFSPXSocketAsyncConnectBlock _block; #endif } - (instancetype)initWithSocket: (OFSPXSocket *)socket - node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXSocketAsyncConnectBlock)block #endif ; @@ -65,23 +65,23 @@ - (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; @end @implementation OFSPXSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXSocket *)sock - node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXSocketAsyncConnectBlock)block #endif { self = [super init]; @try { _socket = [sock retain]; - memcpy(_node, node, IPX_NODE_LEN); _network = network; + memcpy(_node, node, IPX_NODE_LEN); _port = port; #ifdef OF_HAVE_BLOCKS _block = [block copy]; #endif } @catch (id e) { @@ -103,11 +103,11 @@ } - (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode { OFSocketAddress address = - OFSocketAddressMakeIPX(_node, _network, _port); + OFSocketAddressMakeIPX(_network, _node, _port); id exception = nil; int errNo; if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { exception = [self of_connectionFailedExceptionForErrNo: errNo]; @@ -115,11 +115,15 @@ } _socket.canBlock = false; if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { +#ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +#else if (errNo == EINPROGRESS) { +#endif [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } @@ -147,28 +151,28 @@ if (_block != NULL) _block(exception); else { #endif if ([delegate respondsToSelector: - @selector(socket:didConnectToNode:network:port:exception:)]) - [delegate socket: _socket - didConnectToNode: _node - network: _network - port: _port - exception: exception]; + @selector(socket:didConnectToNetwork:node:port:exception:)]) + [delegate socket: _socket + didConnectToNetwork: _network + node: _node + port: _port + exception: exception]; #ifdef OF_HAVE_BLOCKS } #endif } - (id)of_connectionFailedExceptionForErrNo: (int)errNo { - return [OFConnectionFailedException exceptionWithNode: _node - network: _network - port: _port - socket: _socket - errNo: errNo]; + return [OFConnectionFailedException exceptionWithNetwork: _network + node: _node + port: _port + socket: _socket + errNo: errNo]; } @end @implementation OFSPXSocket @dynamic delegate; @@ -202,11 +206,11 @@ errNo: (int *)errNo { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; - if (connect(_socket, &address->sockaddr.sockaddr, + if (connect(_socket, (struct sockaddr *)&address->sockaddr, address->length) != 0) { *errNo = OFSocketErrNo(); return false; } @@ -217,58 +221,58 @@ { closesocket(_socket); _socket = OFInvalidSocketHandle; } -- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port +- (void)connectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port { - OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port); + OFSocketAddress address = OFSocketAddressMakeIPX(network, node, port); int errNo; if (![self of_createSocketForAddress: &address errNo: &errNo]) @throw [OFConnectionFailedException - exceptionWithNode: node - network: network - port: port - socket: self - errNo: errNo]; + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; @throw [OFConnectionFailedException - exceptionWithNode: node - network: network - port: port - socket: self - errNo: errNo]; - } -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port -{ - [self asyncConnectToNode: node - network: network - port: port - runLoopMode: OFDefaultRunLoopMode]; -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; + } +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port +{ + [self asyncConnectToNetwork: network + node: node + port: port + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXSocketAsyncConnectDelegate alloc] initWithSocket: self - node: node network: network + node: node port: port #ifdef OF_HAVE_BLOCKS block: NULL #endif ] autorelease] startWithRunLoopMode: runLoopMode]; @@ -275,34 +279,34 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - block: (OFSPXSocketAsyncConnectBlock)block -{ - [self asyncConnectToNode: node - network: network - port: port - runLoopMode: OFDefaultRunLoopMode - block: block]; -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode - block: (OFSPXSocketAsyncConnectBlock)block +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + block: (OFSPXSocketAsyncConnectBlock)block +{ + [self asyncConnectToNetwork: network + node: node + port: port + runLoopMode: OFDefaultRunLoopMode + block: block]; +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXSocketAsyncConnectDelegate alloc] initWithSocket: self - node: node network: network + node: node port: port block: block ] autorelease] startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); @@ -318,13 +322,13 @@ #endif if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = OFSocketAddressMakeIPX(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(0, zeroNode, port); - if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port packetType: SPXPacketType @@ -336,11 +340,12 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif - if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -352,11 +357,11 @@ memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (OFGetSockName(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, &address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -365,11 +370,11 @@ packetType: SPXPacketType socket: self errNo: errNo]; } - if (address.sockaddr.sockaddr.sa_family != AF_IPX) { + if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: SPXPacketType Index: src/OFSPXStreamSocket.h ================================================================== --- src/OFSPXStreamSocket.h +++ src/OFSPXStreamSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -43,21 +43,21 @@ @optional /** * @brief A method which is called when a socket connected. * * @param socket The socket which connected - * @param node The node the socket connected to * @param network The network of the node the socket connected to + * @param node The node the socket connected to * @param port The port of the node to which the socket connected * @param exception An exception that occurred while connecting, or nil on * success */ -- (void)socket: (OFSPXStreamSocket *)socket - didConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - exception: (nullable id)exception; +- (void)socket: (OFSPXStreamSocket *)socket + didConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + exception: (nullable id)exception; @end /** * @class OFSPXStreamSocket OFSPXStreamSocket.h ObjFW/OFSPXStreamSocket.h * @@ -84,79 +84,79 @@ id delegate; /** * @brief Connect the OFSPXStreamSocket to the specified destination. * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - */ -- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSPXStreamSocket to the specified - * destination. - * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSPXStreamSocket to the specified - * destination. - * - * @param node The node to connect to - * @param network The network on which the node to connect to is - * @param port The port (sometimes also called socket number) on the node to - * connect to - * @param runLoopMode The run loop mode in which to perform the async connect - */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode; + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + */ +- (void)connectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSPXStreamSocket to the specified + * destination. + * + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + */ +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSPXStreamSocket to the specified + * destination. + * + * @param network The network on which the node to connect to is + * @param node The node to connect to + * @param port The port (sometimes also called socket number) on the node to + * connect to + * @param runLoopMode The run loop mode in which to perform the async connect + */ +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. * - * @param node The node to connect to * @param network The network on which the node to connect to is + * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to * @param block The block to execute once the connection has been established */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - block: (OFSPXStreamSocketAsyncConnectBlock)block; +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + block: (OFSPXStreamSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. * - * @param node The node to connect to * @param network The network on which the node to connect to is + * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to * @param runLoopMode The run loop mode in which to perform the async connect * @param block The block to execute once the connection has been established */ -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode - block: (OFSPXStreamSocketAsyncConnectBlock)block; +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXStreamSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * Index: src/OFSPXStreamSocket.m ================================================================== --- src/OFSPXStreamSocket.m +++ src/OFSPXStreamSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -45,21 +45,21 @@ OF_DIRECT_MEMBERS @interface OFSPXStreamSocketAsyncConnectDelegate: OFObject { OFSPXStreamSocket *_socket; - unsigned char _node[IPX_NODE_LEN]; uint32_t _network; + unsigned char _node[IPX_NODE_LEN]; uint16_t _port; #ifdef OF_HAVE_BLOCKS OFSPXStreamSocketAsyncConnectBlock _block; #endif } - (instancetype)initWithSocket: (OFSPXStreamSocket *)socket - node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXStreamSocketAsyncConnectBlock)block #endif ; @@ -66,23 +66,23 @@ - (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; @end @implementation OFSPXStreamSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXStreamSocket *)sock - node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXStreamSocketAsyncConnectBlock)block #endif { self = [super init]; @try { _socket = [sock retain]; - memcpy(_node, node, IPX_NODE_LEN); _network = network; + memcpy(_node, node, IPX_NODE_LEN); _port = port; #ifdef OF_HAVE_BLOCKS _block = [block copy]; #endif } @catch (id e) { @@ -104,11 +104,11 @@ } - (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode { OFSocketAddress address = - OFSocketAddressMakeIPX(_node, _network, _port); + OFSocketAddressMakeIPX(_network, _node, _port); id exception = nil; int errNo; if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { exception = [self of_connectionFailedExceptionForErrNo: errNo]; @@ -116,11 +116,15 @@ } _socket.canBlock = false; if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { +#ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +#else if (errNo == EINPROGRESS) { +#endif [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } @@ -149,28 +153,28 @@ if (_block != NULL) _block(exception); else { #endif if ([delegate respondsToSelector: - @selector(socket:didConnectToNode:network:port:exception:)]) - [delegate socket: _socket - didConnectToNode: _node - network: _network - port: _port - exception: exception]; + @selector(socket:didConnectToNetwork:node:port:exception:)]) + [delegate socket: _socket + didConnectToNetwork: _network + node: _node + port: _port + exception: exception]; #ifdef OF_HAVE_BLOCKS } #endif } - (id)of_connectionFailedExceptionForErrNo: (int)errNo { - return [OFConnectionFailedException exceptionWithNode: _node - network: _network - port: _port - socket: _socket - errNo: errNo]; + return [OFConnectionFailedException exceptionWithNetwork: _network + node: _node + port: _port + socket: _socket + errNo: errNo]; } @end @implementation OFSPXStreamSocket @dynamic delegate; @@ -204,11 +208,11 @@ errNo: (int *)errNo { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; - if (connect(_socket, &address->sockaddr.sockaddr, + if (connect(_socket, (struct sockaddr *)&address->sockaddr, address->length) != 0) { *errNo = OFSocketErrNo(); return false; } @@ -219,58 +223,58 @@ { closesocket(_socket); _socket = OFInvalidSocketHandle; } -- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port +- (void)connectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port { - OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port); + OFSocketAddress address = OFSocketAddressMakeIPX(network, node, port); int errNo; if (![self of_createSocketForAddress: &address errNo: &errNo]) @throw [OFConnectionFailedException - exceptionWithNode: node - network: network - port: port - socket: self - errNo: errNo]; + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; @throw [OFConnectionFailedException - exceptionWithNode: node - network: network - port: port - socket: self - errNo: errNo]; - } -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port -{ - [self asyncConnectToNode: node - network: network - port: port - runLoopMode: OFDefaultRunLoopMode]; -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; + } +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port +{ + [self asyncConnectToNetwork: network + node: node + port: port + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXStreamSocketAsyncConnectDelegate alloc] initWithSocket: self - node: node network: network + node: node port: port #ifdef OF_HAVE_BLOCKS block: NULL #endif ] autorelease] startWithRunLoopMode: runLoopMode]; @@ -277,34 +281,34 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - block: (OFSPXStreamSocketAsyncConnectBlock)block -{ - [self asyncConnectToNode: node - network: network - port: port - runLoopMode: OFDefaultRunLoopMode - block: block]; -} - -- (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - runLoopMode: (OFRunLoopMode)runLoopMode - block: (OFSPXStreamSocketAsyncConnectBlock)block +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + block: (OFSPXStreamSocketAsyncConnectBlock)block +{ + [self asyncConnectToNetwork: network + node: node + port: port + runLoopMode: OFDefaultRunLoopMode + block: block]; +} + +- (void)asyncConnectToNetwork: (uint32_t)network + node: (unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXStreamSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXStreamSocketAsyncConnectDelegate alloc] initWithSocket: self - node: node network: network + node: node port: port block: block ] autorelease] startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); @@ -320,13 +324,13 @@ #endif if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = OFSocketAddressMakeIPX(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(0, zeroNode, port); - if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port packetType: SPXPacketType socket: self @@ -337,11 +341,12 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif - if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -353,11 +358,11 @@ memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (OFGetSockName(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, &address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -366,11 +371,11 @@ packetType: SPXPacketType socket: self errNo: errNo]; } - if (address.sockaddr.sockaddr.sa_family != AF_IPX) { + if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: SPXPacketType Index: src/OFSandbox.h ================================================================== --- src/OFSandbox.h +++ src/OFSandbox.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSandbox.m ================================================================== --- src/OFSandbox.m +++ src/OFSandbox.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFScrypt.h ================================================================== --- src/OFScrypt.h +++ src/OFScrypt.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFScrypt.m ================================================================== --- src/OFScrypt.m +++ src/OFScrypt.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSecureData.h ================================================================== --- src/OFSecureData.h +++ src/OFSecureData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,11 +30,11 @@ * memory. */ OF_SUBCLASSING_RESTRICTED @interface OFSecureData: OFData { - struct page *_page; + void *_page; bool _allowsSwappableMemory; } /** * @brief Whether the data may be stored in swappable memory. Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,28 +36,28 @@ #import "OFOutOfRangeException.h" #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) static const size_t chunkSize = 16; -struct page { - struct page *next, *previous; +struct Page { + struct Page *next, *previous; void *map; unsigned char *page; }; # if defined(OF_HAVE_COMPILER_TLS) -static thread_local struct page *firstPage = NULL; -static thread_local struct page *lastPage = NULL; -static thread_local struct page **preallocatedPages = NULL; +static thread_local struct Page *firstPage = NULL; +static thread_local struct Page *lastPage = NULL; +static thread_local struct Page **preallocatedPages = NULL; static thread_local size_t numPreallocatedPages = 0; # elif defined(OF_HAVE_THREADS) static OFTLSKey firstPageKey, lastPageKey; static OFTLSKey preallocatedPagesKey, numPreallocatedPagesKey; # else -static struct page *firstPage = NULL; -static struct page *lastPage = NULL; -static struct page **preallocatedPages = NULL; +static struct Page *firstPage = NULL; +static struct Page *lastPage = NULL; +static struct Page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; # endif static void * mapPages(size_t numPages) @@ -92,19 +92,19 @@ munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); } -static struct page * +static struct Page * addPage(bool allowPreallocated) { size_t pageSize = [OFSystemInfo pageSize]; size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) / CHAR_BIT; - struct page *page; + struct Page *page; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page *lastPage; + struct Page *lastPage; # endif if (allowPreallocated) { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) uintptr_t numPreallocatedPages = @@ -111,11 +111,11 @@ (uintptr_t)OFTLSKeyGet(numPreallocatedPagesKey); # endif if (numPreallocatedPages > 0) { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page **preallocatedPages = + struct Page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey); # endif numPreallocatedPages--; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) @@ -178,11 +178,11 @@ return page; } static void -removePageIfEmpty(struct page *page) +removePageIfEmpty(struct Page *page) { unsigned char *map = page->map; size_t pageSize = [OFSystemInfo pageSize]; size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) / CHAR_BIT; @@ -213,11 +213,11 @@ OFFreeMemory(page); } static void * -allocateMemory(struct page *page, size_t bytes) +allocateMemory(struct Page *page, size_t bytes) { size_t chunks, chunksLeft, pageSize, i, firstChunk; bytes = OFRoundUpToPowerOf2(chunkSize, bytes); chunks = chunksLeft = bytes / chunkSize; @@ -244,11 +244,11 @@ return NULL; } static void -freeMemory(struct page *page, void *pointer, size_t bytes) +freeMemory(struct Page *page, void *pointer, size_t bytes) { size_t chunks, chunkIndex; bytes = OFRoundUpToPowerOf2(chunkSize, bytes); chunks = bytes / chunkSize; @@ -283,19 +283,19 @@ { #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) size_t pageSize = [OFSystemInfo pageSize]; size_t numPages = OFRoundUpToPowerOf2(pageSize, size) / pageSize; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey); + struct Page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey); size_t numPreallocatedPages; # endif size_t i; if (preallocatedPages != NULL) @throw [OFInvalidArgumentException exception]; - preallocatedPages = OFAllocZeroedMemory(numPages, sizeof(struct page)); + preallocatedPages = OFAllocZeroedMemory(numPages, sizeof(struct Page)); # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) OFEnsure(OFTLSKeySet(preallocatedPagesKey, preallocatedPages) == 0); # endif @try { @@ -421,14 +421,14 @@ } else if (count * itemSize >= pageSize) _items = mapPages(OFRoundUpToPowerOf2(pageSize, count * itemSize) / pageSize); else { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page *lastPage = OFTLSKeyGet(lastPageKey); + struct Page *lastPage = OFTLSKeyGet(lastPageKey); # endif - for (struct page *page = lastPage; page != NULL; + for (struct Page *page = lastPage; page != NULL; page = page->previous) { _items = allocateMemory(page, count * itemSize); if (_items != NULL) { _page = page; Index: src/OFSeekableStream.h ================================================================== --- src/OFSeekableStream.h +++ src/OFSeekableStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSeekableStream.m ================================================================== --- src/OFSeekableStream.m +++ src/OFSeekableStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSelectKernelEventObserver.h ================================================================== --- src/OFSelectKernelEventObserver.h +++ src/OFSelectKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSelectKernelEventObserver.m ================================================================== --- src/OFSelectKernelEventObserver.m +++ src/OFSelectKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSequencedPacketSocket+Private.h ================================================================== --- src/OFSequencedPacketSocket+Private.h +++ src/OFSequencedPacketSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -38,17 +38,16 @@ id _Nullable exception); /** * @brief A block which is called when a packet has been sent. * - * @param data The data which was sent * @param exception An exception which occurred while reading or `nil` on * success * @return The data to repeat the send with or nil if it should not repeat */ typedef OFData *_Nullable (^OFSequencedPacketSocketAsyncSendDataBlock)( - OFData *_Nonnull data, id _Nullable exception); + id _Nullable exception); /** * @brief A block which is called when the socket accepted a connection. * * @param acceptedSocket The socket which has been accepted Index: src/OFSequencedPacketSocket.m ================================================================== --- src/OFSequencedPacketSocket.m +++ src/OFSequencedPacketSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -133,11 +133,11 @@ @throw [OFSetOptionFailedException exceptionWithObject: self errNo: errno]; _canBlock = canBlock; #elif defined(OF_WINDOWS) - u_long v = canBlock; + u_long v = !canBlock; if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self errNo: OFSocketErrNo()]; @@ -329,27 +329,27 @@ client->_remoteAddress.length = (socklen_t)sizeof(client->_remoteAddress.sockaddr); #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, SOCK_CLOEXEC)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; @@ -360,11 +360,12 @@ #endif assert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); - switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) { + switch (((struct sockaddr *)&client->_remoteAddress.sockaddr) + ->sa_family) { case AF_INET: client->_remoteAddress.family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: Index: src/OFSerialization.h ================================================================== --- src/OFSerialization.h +++ src/OFSerialization.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,10 +15,11 @@ #import "OFObject.h" OF_ASSUME_NONNULL_BEGIN +@class OFConstantString; @class OFXMLElement; /** * @protocol OFSerialization OFSerialization.h ObjFW/OFSerialization.h * @@ -40,11 +41,11 @@ @end #ifdef __cplusplus extern "C" { #endif -extern OFString *const OFSerializationNS; +extern OFConstantString *const OFSerializationNS; #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFSerialization.m ================================================================== --- src/OFSerialization.m +++ src/OFSerialization.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -14,6 +14,7 @@ */ #import "OFSerialization.h" #import "OFString.h" -OFString *const OFSerializationNS = @"https://objfw.nil.im/serialization"; +OFConstantString *const OFSerializationNS = + @"https://objfw.nil.im/serialization"; Index: src/OFSet.h ================================================================== --- src/OFSet.h +++ src/OFSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -140,20 +140,10 @@ * @param firstObject The first object for the set * @return An initialized set with the specified objects */ - (instancetype)initWithObjects: (ObjectType)firstObject, ... OF_SENTINEL; -/** - * @brief Initializes an already allocated set with the specified objects. - * - * @param objects An array of objects for the set - * @param count The number of objects in the specified array - * @return An initialized set with the specified objects - */ -- (instancetype)initWithObjects: (ObjectType const _Nonnull *_Nonnull)objects - count: (size_t)count; - /** * @brief Initializes an already allocated set with the specified object and * va_list. * * @param firstObject The first object for the set @@ -161,10 +151,20 @@ * @return An initialized set with the specified object and va_list */ - (instancetype)initWithObject: (ObjectType)firstObject arguments: (va_list)arguments; +/** + * @brief Initializes an already allocated set with the specified objects. + * + * @param objects An array of objects for the set + * @param count The number of objects in the specified array + * @return An initialized set with the specified objects + */ +- (instancetype)initWithObjects: (ObjectType const _Nonnull *_Nonnull)objects + count: (size_t)count; + /** * @brief Returns an OFEnumerator to enumerate through all objects of the set. * * @return An OFEnumerator to enumerate through all objects of the set */ @@ -184,35 +184,17 @@ * @return Whether the receiver and the specified set have at least one object * in common */ - (bool)intersectsSet: (OFSet OF_GENERIC(ObjectType) *)set; -/** - * @brief Creates a new set which contains the objects which are in the - * receiver, but not in the specified set. - * - * @param set The set whose objects will not be in the new set - */ -- (OFSet OF_GENERIC(ObjectType) *)setBySubtractingSet: - (OFSet OF_GENERIC(ObjectType) *)set; - -/** - * @brief Creates a new set by creating the intersection of the receiver and - * the specified set. - * - * @param set The set to intersect with - */ -- (OFSet OF_GENERIC(ObjectType) *)setByIntersectingWithSet: - (OFSet OF_GENERIC(ObjectType) *)set; - /** * @brief Creates a new set by creating the union of the receiver and the * specified set. * * @param set The set to create the union with */ -- (OFSet OF_GENERIC(ObjectType) *)setByAddingSet: +- (OFSet OF_GENERIC(ObjectType) *)setByAddingObjectsFromSet: (OFSet OF_GENERIC(ObjectType) *)set; /** * @brief Checks whether the set contains an object equal to the specified * object. Index: src/OFSet.m ================================================================== --- src/OFSet.m +++ src/OFSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -385,27 +385,11 @@ objc_autoreleasePoolPop(pool); return [element autorelease]; } -- (OFSet *)setBySubtractingSet: (OFSet *)set -{ - OFMutableSet *new = [[self mutableCopy] autorelease]; - [new minusSet: set]; - [new makeImmutable]; - return new; -} - -- (OFSet *)setByIntersectingWithSet: (OFSet *)set -{ - OFMutableSet *new = [[self mutableCopy] autorelease]; - [new intersectSet: set]; - [new makeImmutable]; - return new; -} - -- (OFSet *)setByAddingSet: (OFSet *)set +- (OFSet *)setByAddingObjectsFromSet: (OFSet *)set { OFMutableSet *new = [[self mutableCopy] autorelease]; [new unionSet: set]; [new makeImmutable]; return new; Index: src/OFSettings.h ================================================================== --- src/OFSettings.h +++ src/OFSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSettings.m ================================================================== --- src/OFSettings.m +++ src/OFSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -46,12 +46,12 @@ self = [super init]; @try { _applicationName = [applicationName copy]; } @catch (id e) { - @throw e; [self release]; + @throw e; } return self; } Index: src/OFSizeValue.h ================================================================== --- src/OFSizeValue.h +++ src/OFSizeValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSizeValue.m ================================================================== --- src/OFSizeValue.m +++ src/OFSizeValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSocket+Private.h ================================================================== --- src/OFSocket+Private.h +++ src/OFSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,10 +36,16 @@ # include #endif #ifdef OF_HAVE_NETIPX_IPX_H # include #endif +#ifdef OF_HAVE_SYS_UN_H +# include +#endif +#ifdef OF_HAVE_AFUNIX_H +# include +#endif #ifdef OF_WINDOWS # include # include # ifdef OF_HAVE_IPX @@ -66,10 +72,14 @@ static const OFSocketHandle OFInvalidSocketHandle = -1; #else typedef SOCKET OFSocketHandle; static const OFSocketHandle OFInvalidSocketHandle = INVALID_SOCKET; #endif + +#ifdef OF_WINDOWS +typedef short sa_family_t; +#endif #ifdef OF_WII typedef u8 sa_family_t; #endif @@ -87,10 +97,12 @@ OFSocketAddressFamilyUnknown, /** IPv4 */ OFSocketAddressFamilyIPv4, /** IPv6 */ OFSocketAddressFamilyIPv6, + /** UNIX */ + OFSocketAddressFamilyUNIX, /** IPX */ OFSocketAddressFamilyIPX, /** Any address family */ OFSocketAddressFamilyAny = 255 } OFSocketAddressFamily; @@ -104,10 +116,17 @@ uint8_t s6_addr[16]; } sin6_addr; uint32_t sin6_scope_id; }; #endif + +#if !defined(OF_HAVE_UNIX_SOCKETS) && !defined(OF_MORPHOS) && !defined(OF_MINT) +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; +#endif #ifndef OF_HAVE_IPX # define IPX_NODE_LEN 6 struct sockaddr_ipx { sa_family_t sipx_family; @@ -129,22 +148,19 @@ * @struct OFSocketAddress OFSocket.h ObjFW/OFSocket.h * * @brief A struct which represents a host / port pair for a socket. */ typedef struct OF_BOXABLE { + OFSocketAddressFamily family; /* - * Even though struct sockaddr contains the family, we need to use our - * own family, as we need to support storing an IPv6 address on systems - * that don't support IPv6. These may not have AF_INET6 defined and we - * can't just define it, as the value is system-dependent and might - * clash with an existing value. + * We can't use struct sockaddr as it can contain variable length + * arrays. */ - OFSocketAddressFamily family; union { - struct sockaddr sockaddr; struct sockaddr_in in; struct sockaddr_in6 in6; + struct sockaddr_un un; struct sockaddr_ipx ipx; } sockaddr; socklen_t length; } OFSocketAddress; @@ -178,19 +194,27 @@ * @return The parsed IPv6 and port as an OFSocketAddress */ extern OFSocketAddress OFSocketAddressParseIPv6(OFString *IP, uint16_t port); /** - * @brief Creates an IPX address for the specified network, node and port. + * @brief Creates a UNIX socket address from the specified path. * - * @param node The node in the IPX network + * @param path The path of the UNIX socket + * @return A UNIX socket address with the specified path + */ +extern OFSocketAddress OFSocketAddressMakeUNIX(OFString *path); + +/** + * @brief Creates an IPX address for the specified node, network and port. + * * @param network The IPX network + * @param node The node in the IPX network * @param port The IPX port (sometimes called socket number) on the node + * @return An IPX socket address with the specified node, network and port. */ -extern OFSocketAddress OFSocketAddressMakeIPX( - const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, - uint16_t port); +extern OFSocketAddress OFSocketAddressMakeIPX(uint32_t network, + const unsigned char node[_Nonnull IPX_NODE_LEN], uint16_t port); /** * @brief Compares two OFSocketAddress for equality. * * @param address1 The address to compare with the second address @@ -235,10 +259,19 @@ * @param address The address on which to get the port * @return The port of the address */ extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address); +/** + * @brief Gets the UNIX socket path of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the UNIX socket path + * @return The UNIX socket path + */ +extern OFString *_Nullable OFSocketAddressUNIXPath( + const OFSocketAddress *_Nonnull address); + /** * @brief Sets the IPX network of the specified @ref OFSocketAddress. * * @param address The address on which to set the IPX network * @param network The IPX network to set on the address Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -43,10 +43,11 @@ #import "OFException.h" /* For some E* -> WSAE* defines */ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFLockFailedException.h" +#import "OFOutOfRangeException.h" #import "OFUnlockFailedException.h" #ifdef OF_AMIGAOS # include #endif @@ -53,10 +54,16 @@ #ifdef OF_NINTENDO_3DS # include <3ds/types.h> # include <3ds/services/soc.h> #endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id +#endif #if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) static OFMutex *mutex; static void @@ -127,20 +134,20 @@ if (socInit(ctx, 0x100000) != 0) return; atexit((void (*)(void))socExit); +# elif defined(OF_NINTENDO_SWITCH) + if (R_FAILED(socketInitializeDefault())) + return; + + atexit(socketExit); # endif # if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) mutex = [[OFMutex alloc] init]; atexit(releaseMutex); - -# ifdef OF_WII - if (OFSpinlockNew(&spinlock) != 0) - return; -# endif # endif initSuccessful = true; } @@ -512,11 +519,40 @@ return ret; } OFSocketAddress -OFSocketAddressMakeIPX(const unsigned char node[IPX_NODE_LEN], uint32_t network, +OFSocketAddressMakeUNIX(OFString *path) +{ + void *pool = objc_autoreleasePoolPush(); + OFStringEncoding encoding = [OFLocale encoding]; + size_t length = [path cStringLengthWithEncoding: encoding]; + OFSocketAddress ret; + + if (length > sizeof(ret.sockaddr.un.sun_path)) + @throw [OFOutOfRangeException exception]; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyUNIX; + ret.length = (socklen_t) + (offsetof(struct sockaddr_un, sun_path) + length); + +#ifdef AF_UNIX + ret.sockaddr.un.sun_family = AF_UNIX; +#else + ret.sockaddr.un.sun_family = AF_UNSPEC; +#endif + memcpy(ret.sockaddr.un.sun_path, + [path cStringWithEncoding: encoding], length); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +OFSocketAddress +OFSocketAddressMakeIPX(uint32_t network, const unsigned char node[IPX_NODE_LEN], uint16_t port) { OFSocketAddress ret; memset(&ret, '\0', sizeof(ret)); @@ -526,14 +562,14 @@ #ifdef AF_IPX ret.sockaddr.ipx.sipx_family = AF_IPX; #else ret.sockaddr.ipx.sipx_family = AF_UNSPEC; #endif - memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); network = OFToBigEndian32(network); memcpy(&ret.sockaddr.ipx.sipx_network, &network, sizeof(ret.sockaddr.ipx.sipx_network)); + memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); return ret; } @@ -542,10 +578,13 @@ const OFSocketAddress *address2) { const struct sockaddr_in *addrIn1, *addrIn2; const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; const struct sockaddr_ipx *addrIPX1, *addrIPX2; + void *pool; + OFString *path1, *path2; + bool ret; if (address1->family != address2->family) return false; switch (address1->family) { @@ -565,11 +604,11 @@ if (addrIn1->sin_port != addrIn2->sin_port) return false; if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr) return false; - break; + return true; case OFSocketAddressFamilyIPv6: if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) || address2->length < (socklen_t)sizeof(struct sockaddr_in6)) @throw [OFInvalidArgumentException exception]; @@ -581,11 +620,28 @@ if (memcmp(addrIn6_1->sin6_addr.s6_addr, addrIn6_2->sin6_addr.s6_addr, sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0) return false; - break; + return true; + case OFSocketAddressFamilyUNIX: + pool = objc_autoreleasePoolPush(); + + path1 = OFSocketAddressUNIXPath(address1); + path2 = OFSocketAddressUNIXPath(address2); + + if (path1 == nil || path2 == nil) { + objc_autoreleasePoolPop(pool); + + return false; + } + + ret = [path1 isEqual: path2]; + + objc_autoreleasePoolPop(pool); + + return ret; case OFSocketAddressFamilyIPX: if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) || address2->length < (socklen_t)sizeof(struct sockaddr_ipx)) @throw [OFInvalidArgumentException exception]; @@ -599,16 +655,14 @@ return false; if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, IPX_NODE_LEN) != 0) return false; - break; + return true; default: @throw [OFInvalidArgumentException exception]; } - - return true; } unsigned long OFSocketAddressHash(const OFSocketAddress *address) { @@ -646,10 +700,19 @@ i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) OFHashAdd(&hash, address->sockaddr.in6.sin6_addr.s6_addr[i]); break; + case OFSocketAddressFamilyUNIX:; + void *pool = objc_autoreleasePoolPush(); + OFString *path = OFSocketAddressUNIXPath(address); + + hash = path.hash; + + objc_autoreleasePoolPop(pool); + + return hash; case OFSocketAddressFamilyIPX:; unsigned char network[ sizeof(address->sockaddr.ipx.sipx_network)]; if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) @@ -801,10 +864,32 @@ return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); default: @throw [OFInvalidArgumentException exception]; } } + +OFString * +OFSocketAddressUNIXPath(const OFSocketAddress *_Nonnull address) +{ + socklen_t length; + + if (address->family != OFSocketAddressFamilyUNIX) + @throw [OFInvalidArgumentException exception]; + + length = address->length - offsetof(struct sockaddr_un, sun_path); + + for (socklen_t i = 0; i < length; i++) + if (address->sockaddr.un.sun_path[i] == 0) + length = i; + + if (length <= 0) + return nil; + + return [OFString stringWithCString: address->sockaddr.un.sun_path + encoding: [OFLocale encoding] + length: length]; +} void OFSocketAddressSetIPXNetwork(OFSocketAddress *address, uint32_t network) { if (address->family != OFSocketAddressFamilyIPX) Index: src/OFSortedList.h ================================================================== --- src/OFSortedList.h +++ src/OFSortedList.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSortedList.m ================================================================== --- src/OFSortedList.m +++ src/OFSortedList.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFStdIOStream+Private.h ================================================================== --- src/OFStdIOStream+Private.h +++ src/OFStdIOStream+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,14 +17,16 @@ OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface OFStdIOStream () -#ifndef OF_AMIGAOS -- (instancetype)of_initWithFileDescriptor: (int)fd OF_METHOD_FAMILY(init); -#else +#if defined(OF_AMIGAOS) - (instancetype)of_initWithHandle: (BPTR)handle closable: (bool)closable OF_METHOD_FAMILY(init); +#elif defined(OF_WII_U) +- (instancetype)of_init OF_METHOD_FAMILY(init); +#else +- (instancetype)of_initWithFileDescriptor: (int)fd OF_METHOD_FAMILY(init); #endif @end OF_ASSUME_NONNULL_END Index: src/OFStdIOStream.h ================================================================== --- src/OFStdIOStream.h +++ src/OFStdIOStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,19 +36,19 @@ */ #ifdef OF_STDIO_STREAM_WIN32_CONSOLE_H OF_SUBCLASSING_RESTRICTED #endif @interface OFStdIOStream: OFStream -#if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) +#if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && !defined(OF_WII_U) #endif { -#ifndef OF_AMIGAOS - int _fd; -#else +#if defined(OF_AMIGAOS) BPTR _handle; bool _closable; +#elif !defined(OF_WII_U) + int _fd; #endif bool _atEndOfStream; } /** @@ -148,16 +148,27 @@ * @brief The standard error as an OFStream. */ extern OFStdIOStream *_Nullable OFStdErr; /** - * @brief Log the specified printf-style format to @ref OFStdErr. + * @brief Logs the specified printf-style format to @ref OFStdErr. + * + * This prefixes the output with the date, timestamp, process name and PID. * - * This prefixes the output with the date, timestamp, process name and PID and - * allows `%@` as a printf-style formatted to print objects. + * @param format The format for the line to log. See @ref OFStream#writeFormat:. */ extern void OFLog(OFConstantString *format, ...); + +/** + * @brief Logs the specified printf-style format to @ref OFStdErr. + * + * This prefixes the output with the date, timestamp, process name and PID. + * + * @param format The format for the line to log. See @ref OFStream#writeFormat:. + * @param arguments The arguments for the format + */ +extern void OFLogV(OFConstantString *format, va_list arguments); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFStdIOStream.m ================================================================== --- src/OFStdIOStream.m +++ src/OFStdIOStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -49,10 +49,16 @@ #ifdef OF_AMIGAOS # include # include # undef HAVE_ISATTY #endif + +#ifdef OF_WII_U +# define BOOL WUT_BOOL +# include +# undef BOOL +#endif /* References for static linking */ #ifdef OF_WINDOWS void _reference_to_OFWin32ConsoleStdIOStream(void) @@ -75,35 +81,42 @@ #endif void OFLog(OFConstantString *format, ...) { + va_list arguments; + + va_start(arguments, format); + OFLogV(format, arguments); + va_end(arguments); +} + +void +OFLogV(OFConstantString *format, va_list arguments) +{ void *pool = objc_autoreleasePoolPush(); OFDate *date; OFString *dateString, *me, *msg; - va_list arguments; date = [OFDate date]; dateString = [date localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; #ifdef OF_HAVE_FILES me = [OFApplication programName].lastPathComponent; #else me = [OFApplication programName]; #endif - va_start(arguments, format); msg = [[[OFString alloc] initWithFormat: format arguments: arguments] autorelease]; - va_end(arguments); [OFStdErr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString, date.microsecond / 1000, me, getpid(), msg]; objc_autoreleasePoolPop(pool); } -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) static int colorToANSI(OFColor *color) { if ([color isEqual: [OFColor black]]) return 30; @@ -147,22 +160,11 @@ + (void)load { if (self != [OFStdIOStream class]) return; -# ifndef OF_AMIGAOS - int fd; - - if ((fd = fileno(stdin)) >= 0) - OFStdIn = [[OFStdIOStream alloc] of_initWithFileDescriptor: fd]; - if ((fd = fileno(stdout)) >= 0) - OFStdOut = [[OFStdIOStream alloc] - of_initWithFileDescriptor: fd]; - if ((fd = fileno(stderr)) >= 0) - OFStdErr = [[OFStdIOStream alloc] - of_initWithFileDescriptor: fd]; -# else +# if defined(OF_AMIGAOS) BPTR input, output, error; bool inputClosable = false, outputClosable = false, errorClosable = false; input = Input(); @@ -188,69 +190,112 @@ closable: inputClosable]; OFStdOut = [[OFStdIOStream alloc] of_initWithHandle: output closable: outputClosable]; OFStdErr = [[OFStdIOStream alloc] of_initWithHandle: error closable: errorClosable]; +# elif defined(OF_WII_U) + OFStdOut = [[OFStdIOStream alloc] of_init]; + OFStdErr = [[OFStdIOStream alloc] of_init]; +# else + int fd; + + if ((fd = fileno(stdin)) >= 0) + OFStdIn = [[OFStdIOStream alloc] of_initWithFileDescriptor: fd]; + if ((fd = fileno(stdout)) >= 0) + OFStdOut = [[OFStdIOStream alloc] + of_initWithFileDescriptor: fd]; + if ((fd = fileno(stderr)) >= 0) + OFStdErr = [[OFStdIOStream alloc] + of_initWithFileDescriptor: fd]; # endif } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } -#ifndef OF_AMIGAOS -- (instancetype)of_initWithFileDescriptor: (int)fd -{ - self = [super init]; - - _fd = fd; - - return self; -} -#else +#if defined(OF_AMIGAOS) - (instancetype)of_initWithHandle: (BPTR)handle closable: (bool)closable { self = [super init]; _handle = handle; _closable = closable; return self; } +#elif defined(OF_WII_U) +- (instancetype)of_init +{ + return [super init]; +} +#else +- (instancetype)of_initWithFileDescriptor: (int)fd +{ + self = [super init]; + + _fd = fd; + + return self; +} #endif - (void)dealloc { -#ifndef OF_AMIGAOS - if (_fd != -1) -#else +#if defined(OF_AMIGAOS) if (_handle != 0) -#endif + [self close]; +#elif !defined(OF_WII_U) + if (_fd != -1) [self close]; +#endif [super dealloc]; } - (bool)lowlevelIsAtEndOfStream { -#ifndef OF_AMIGAOS - if (_fd == -1) -#else +#if defined(OF_AMIGAOS) if (_handle == 0) -#endif + @throw [OFNotOpenException exceptionWithObject: self]; +#elif !defined(OF_WII_U) + if (_fd == -1) @throw [OFNotOpenException exceptionWithObject: self]; +#endif return _atEndOfStream; } - (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { +#if defined(OF_AMIGAOS) + ssize_t ret; + + if (_handle == 0) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (length > LONG_MAX) + @throw [OFOutOfRangeException exception]; + + if ((ret = Read(_handle, buffer, length)) < 0) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: EIO]; + + if (ret == 0) + _atEndOfStream = true; + + return ret; +#elif defined(OF_WII_U) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: EOPNOTSUPP]; +#else ssize_t ret; -#ifndef OF_AMIGAOS if (_fd == -1) @throw [OFNotOpenException exceptionWithObject: self]; # ifndef OF_WINDOWS if ((ret = read(_fd, buffer, length)) < 0) @@ -264,32 +309,41 @@ if ((ret = read(_fd, buffer, (unsigned int)length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: errno]; # endif -#else - if (_handle == 0) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (length > LONG_MAX) - @throw [OFOutOfRangeException exception]; - - if ((ret = Read(_handle, buffer, length)) < 0) - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: EIO]; -#endif if (ret == 0) _atEndOfStream = true; return ret; +#endif } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { -#ifndef OF_AMIGAOS +#if defined(OF_AMIGAOS) + LONG bytesWritten; + + if (_handle == 0) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (length > SSIZE_MAX) + @throw [OFOutOfRangeException exception]; + + if ((bytesWritten = Write(_handle, (void *)buffer, length)) < 0) + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: EIO]; + + return (size_t)bytesWritten; +#elif defined(OF_WII_U) + OSConsoleWrite(buffer, length); + + return length; +#else if (_fd == -1) @throw [OFNotOpenException exceptionWithObject: self]; # ifndef OF_WINDOWS ssize_t bytesWritten; @@ -312,30 +366,16 @@ @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: errno]; # endif -#else - LONG bytesWritten; - - if (_handle == 0) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (length > SSIZE_MAX) - @throw [OFOutOfRangeException exception]; - - if ((bytesWritten = Write(_handle, (void *)buffer, length)) < 0) - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: EIO]; -#endif return (size_t)bytesWritten; +#endif } -#if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) +#if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && !defined(OF_WII_U) - (int)fileDescriptorForReading { return _fd; } @@ -345,24 +385,24 @@ } #endif - (void)close { -#ifndef OF_AMIGAOS - if (_fd == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - close(_fd); - _fd = -1; -#else +#if defined(OF_AMIGAOS) if (_handle == 0) @throw [OFNotOpenException exceptionWithObject: self]; if (_closable) Close(_handle); _handle = 0; +#elif !defined(OF_WII_U) + if (_fd == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + close(_fd); + _fd = -1; #endif [super close]; } @@ -385,20 +425,21 @@ return OFMaxRetainCount; } - (bool)hasTerminal { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) return isatty(_fd); #else return false; #endif } - (int)columns { -#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && !defined(OF_AMIGAOS) +#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && \ + !defined(OF_AMIGAOS) && !defined(OF_WII_U) struct winsize ws; if (ioctl(_fd, TIOCGWINSZ, &ws) != 0) return -1; @@ -408,11 +449,12 @@ #endif } - (int)rows { -#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && !defined(OF_AMIGAOS) +#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && \ + !defined(OF_AMIGAOS) && !defined(OF_WII_U) struct winsize ws; if (ioctl(_fd, TIOCGWINSZ, &ws) != 0) return -1; @@ -422,11 +464,11 @@ #endif } - (void)setForegroundColor: (OFColor *)color { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) int code; if (!isatty(_fd)) return; @@ -437,11 +479,11 @@ #endif } - (void)setBackgroundColor: (OFColor *)color { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) int code; if (!isatty(_fd)) return; @@ -452,41 +494,41 @@ #endif } - (void)reset { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; [self writeString: @"\033[0m"]; #endif } - (void)clear { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; [self writeString: @"\033[2J"]; #endif } - (void)eraseLine { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; [self writeString: @"\033[2K"]; #endif } - (void)setCursorColumn: (unsigned int)column { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; [self writeFormat: @"\033[%uG", column + 1]; #endif @@ -495,11 +537,11 @@ - (void)setCursorPosition: (OFPoint)position { if (position.x < 0 || position.y < 0) @throw [OFInvalidArgumentException exception]; -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; [self writeFormat: @"\033[%u;%uH", (unsigned)position.y + 1, (unsigned)position.x + 1]; @@ -506,11 +548,11 @@ #endif } - (void)setRelativeCursorPosition: (OFPoint)position { -#ifdef HAVE_ISATTY +#if defined(HAVE_ISATTY) && !defined(OF_WII_U) if (!isatty(_fd)) return; if (position.x > 0) [self writeFormat: @"\033[%uC", (unsigned)position.x]; Index: src/OFStrPTime.h ================================================================== --- src/OFStrPTime.h +++ src/OFStrPTime.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -27,12 +27,12 @@ OF_ASSUME_NONNULL_BEGIN #ifdef __cplusplus extern "C" { #endif -extern const char *OFStrPTime(const char *buf, const char *fmt, struct tm *tm, - short *tz); +extern const char *_Nullable OFStrPTime(const char *buffer, const char *format, + struct tm *tm, short *_Nullable tz); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFStrPTime.m ================================================================== --- src/OFStrPTime.m +++ src/OFStrPTime.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFStream+Private.h ================================================================== --- src/OFStream+Private.h +++ src/OFStream+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -63,35 +63,33 @@ /** * @brief A block which is called when data was written asynchronously to a * stream. * - * @param data The data which was written to the stream * @param bytesWritten The number of bytes which have been written. This * matches the length of the specified data on the * asynchronous write if no exception was encountered. * @param exception An exception which occurred while writing or `nil` on * success * @return The data to repeat the write with or nil if it should not repeat */ -typedef OFData *_Nullable (^OFStreamAsyncWriteDataBlock)(OFData *_Nonnull data, - size_t bytesWritten, id _Nullable exception); +typedef OFData *_Nullable (^OFStreamAsyncWriteDataBlock)(size_t bytesWritten, + id _Nullable exception); /** * @brief A block which is called when a string was written asynchronously to a * stream. * - * @param string The string which was written to the stream * @param bytesWritten The number of bytes which have been written. This * matches the length of the specified data on the * asynchronous write if no exception was encountered. * @param exception An exception which occurred while writing or `nil` on * success * @return The string to repeat the write with or nil if it should not repeat */ typedef OFString *_Nullable (^OFStreamAsyncWriteStringBlock)( - OFString *_Nonnull string, size_t bytesWritten, id _Nullable exception); + size_t bytesWritten, id _Nullable exception); #endif /** * @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h * @@ -205,11 +203,11 @@ @property (readonly, nonatomic, getter=isAtEndOfStream) bool atEndOfStream; /** * @brief Whether writes are buffered. */ -@property (nonatomic, nonatomic) bool buffersWrites; +@property (nonatomic) bool buffersWrites; /** * @brief Whether data is present in the internal read buffer. */ @property (readonly, nonatomic) bool hasDataInReadBuffer; @@ -526,83 +524,10 @@ * * @return A double from the stream in the native endianess */ - (double)readBigEndianDouble; -/** - * @brief Reads the specified number of uint16_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint16_ts - * @param count The number of uint16_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint32_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint32_ts - * @param count The number of uint32_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint64_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint64_ts - * @param count The number of uint64_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of floats from the stream which are encoded - * in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * floats - * @param count The number of floats to read - * @return The number of bytes read - */ -- (size_t)readBigEndianFloatsIntoBuffer: (float *)buffer count: (size_t)count; - -/** - * @brief Reads the specified number of doubles from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * doubles - * @param count The number of doubles to read - * @return The number of bytes read - */ -- (size_t)readBigEndianDoublesIntoBuffer: (double *)buffer count: (size_t)count; - /** * @brief Reads a uint16_t from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! @@ -649,85 +574,10 @@ * * @return A double from the stream in the native endianess */ - (double)readLittleEndianDouble; -/** - * @brief Reads the specified number of uint16_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint16_ts - * @param count The number of uint16_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint32_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint32_ts - * @param count The number of uint32_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint64_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint64_ts - * @param count The number of uint64_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of floats from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * floats - * @param count The number of floats to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of doubles from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * doubles - * @param count The number of doubles to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count; - /** * @brief Reads the specified number of items with an item size of 1 from the * stream and returns them as OFData. * * @warning Only call this when you know that enough data is available! @@ -965,22 +815,31 @@ - (nullable OFString *)tryReadTillDelimiter: (OFString *)delimiter encoding: (OFStringEncoding)encoding; /** * @brief Writes everything in the write buffer to the stream. + * + * @return Whether the write buffer was flushed entirely. On non-blocking + * sockets, this can return `false` if flushing the write buffer in its + * entirety would block. */ -- (void)flushWriteBuffer; +- (bool)flushWriteBuffer; /** * @brief Writes from a buffer into the stream. + * + * In non-blocking mode, if less than the specified length could be written, an + * @ref OFWriteFailedException is thrown with @ref OFWriteFailedException#errNo + * being set to `EWOULDBLOCK` or `EAGAIN` (you need to check for both, as they + * are not the same on some systems) and + * @ref OFWriteFailedException#bytesWritten being set to the number of bytes + * that were written, if any. * * @param buffer The buffer from which the data is written into the stream * @param length The length of the data that should be written - * @return The number of bytes written. This can only differ from the specified - * length in non-blocking mode. */ -- (size_t)writeBuffer: (const void *)buffer length: (size_t)length; +- (void)writeBuffer: (const void *)buffer length: (size_t)length; #ifdef OF_HAVE_SOCKETS /** * @brief Asynchronously writes data into the stream. * @@ -1129,265 +988,181 @@ #endif /** * @brief Writes a uint8_t into the stream. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int8 A uint8_t */ - (void)writeInt8: (uint8_t)int8; /** * @brief Writes a uint16_t into the stream, encoded in big endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param int16 A uint16_t */ - (void)writeBigEndianInt16: (uint16_t)int16; /** * @brief Writes a uint32_t into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int32 A uint32_t */ - (void)writeBigEndianInt32: (uint32_t)int32; /** * @brief Writes a uint64_t into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int64 A uint64_t */ - (void)writeBigEndianInt64: (uint64_t)int64; /** * @brief Writes a float into the stream, encoded in big endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param float_ A float */ - (void)writeBigEndianFloat: (float)float_; /** * @brief Writes a double into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param double_ A double */ - (void)writeBigEndianDouble: (double)double_; -/** - * @brief Writes the specified number of uint16_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint16_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt16s: (const uint16_t *)buffer count: (size_t)count; - -/** - * @brief Writes the specified number of uint32_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint32_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt32s: (const uint32_t *)buffer count: (size_t)count; - -/** - * @brief Writes the specified number of uint64_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint64_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt64s: (const uint64_t *)buffer count: (size_t)count; - -/** - * @brief Writes the specified number of floats into the stream, encoded in big - * endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of floats to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianFloats: (const float *)buffer count: (size_t)count; - -/** - * @brief Writes the specified number of doubles into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of doubles to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianDoubles: (const double *)buffer count: (size_t)count; - /** * @brief Writes a uint16_t into the stream, encoded in little endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param int16 A uint16_t */ - (void)writeLittleEndianInt16: (uint16_t)int16; /** * @brief Writes a uint32_t into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int32 A uint32_t */ - (void)writeLittleEndianInt32: (uint32_t)int32; /** * @brief Writes a uint64_t into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int64 A uint64_t */ - (void)writeLittleEndianInt64: (uint64_t)int64; /** * @brief Writes a float into the stream, encoded in little endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param float_ A float */ - (void)writeLittleEndianFloat: (float)float_; /** * @brief Writes a double into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param double_ A double */ - (void)writeLittleEndianDouble: (double)double_; -/** - * @brief Writes the specified number of uint16_ts into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint16_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt16s: (const uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint32_ts into the stream, encoded in - * little endian. - * - * @param count The number of uint32_ts to write - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt32s: (const uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint64_ts into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint64_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt64s: (const uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of floats into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of floats to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianFloats: (const float *)buffer count: (size_t)count; - -/** - * @brief Writes the specified number of doubles into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of doubles to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianDoubles: (const double *)buffer count: (size_t)count; - /** * @brief Writes OFData into the stream. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param data The OFData to write into the stream - * @return The number of bytes written */ -- (size_t)writeData: (OFData *)data; +- (void)writeData: (OFData *)data; /** * @brief Writes a string into the stream, without the trailing zero. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream - * @return The number of bytes written */ -- (size_t)writeString: (OFString *)string; +- (void)writeString: (OFString *)string; /** * @brief Writes a string into the stream in the specified encoding, without * the trailing zero. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream * @param encoding The encoding in which to write the string to the stream - * @return The number of bytes written */ -- (size_t)writeString: (OFString *)string encoding: (OFStringEncoding)encoding; +- (void)writeString: (OFString *)string encoding: (OFStringEncoding)encoding; /** * @brief Writes a string into the stream with a trailing newline. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream - * @return The number of bytes written */ -- (size_t)writeLine: (OFString *)string; +- (void)writeLine: (OFString *)string; /** * @brief Writes a string into the stream in the specified encoding with a * trailing newline. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream * @param encoding The encoding in which to write the string to the stream - * @return The number of bytes written + */ +- (void)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding; + +/** + * @brief Writes a formatted string into the stream. + * + * See printf for the format syntax. As an addition, `%@` is available as + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `const OFUnichar *`. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * + * @param format A string used as format */ -- (size_t)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding; +- (void)writeFormat: (OFConstantString *)format, ...; /** * @brief Writes a formatted string into the stream. * * See printf for the format syntax. As an addition, `%@` is available as * format specifier for objects, `%C` for `OFUnichar` and `%S` for * `const OFUnichar *`. * - * @param format A string used as format - * @return The number of bytes written - */ -- (size_t)writeFormat: (OFConstantString *)format, ...; - -/** - * @brief Writes a formatted string into the stream. - * - * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `OFUnichar` and `%S` for - * `const OFUnichar *`. + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param format A string used as format * @param arguments The arguments used in the format string - * @return The number of bytes written */ -- (size_t)writeFormat: (OFConstantString *)format arguments: (va_list)arguments; +- (void)writeFormat: (OFConstantString *)format arguments: (va_list)arguments; #ifdef OF_HAVE_SOCKETS /** * @brief Cancels all pending asynchronous requests on the stream. */ Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -337,105 +337,10 @@ double ret; [self readIntoBuffer: (char *)&ret exactLength: 8]; return OFFromBigEndianDouble(ret); } -- (size_t)readBigEndianInt16sIntoBuffer: (uint16_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap16(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianInt32sIntoBuffer: (uint32_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap32(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianInt64sIntoBuffer: (uint64_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap64(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianFloatsIntoBuffer: (float *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifndef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwapFloat(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianDoublesIntoBuffer: (double *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifndef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwapDouble(buffer[i]); -#endif - - return size; -} - - (uint16_t)readLittleEndianInt16 { uint16_t ret; [self readIntoBuffer: (char *)&ret exactLength: 2]; return OFFromLittleEndian16(ret); @@ -467,110 +372,10 @@ double ret; [self readIntoBuffer: (char *)&ret exactLength: 8]; return OFFromLittleEndianDouble(ret); } -- (size_t)readLittleEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap16(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap32(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwap64(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifdef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwapFloat(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - - [self readIntoBuffer: buffer exactLength: size]; - -#ifdef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OFByteSwapDouble(buffer[i]); -#endif - - return size; -} - - (OFData *)readDataWithCount: (size_t)count { return [self readDataWithItemSize: 1 count: count]; } @@ -1054,44 +859,66 @@ { return [self tryReadTillDelimiter: delimiter encoding: OFStringEncodingUTF8]; } -- (void)flushWriteBuffer +- (bool)flushWriteBuffer { + size_t bytesWritten; + if (_writeBuffer == NULL) - return; + return true; - [self lowlevelWriteBuffer: _writeBuffer length: _writeBufferLength]; + bytesWritten = [self lowlevelWriteBuffer: _writeBuffer + length: _writeBufferLength]; - OFFreeMemory(_writeBuffer); - _writeBuffer = NULL; - _writeBufferLength = 0; + if (bytesWritten == 0) + return false; + + if (bytesWritten == _writeBufferLength) { + OFFreeMemory(_writeBuffer); + _writeBuffer = NULL; + _writeBufferLength = 0; + + return true; + } + + OFEnsure(bytesWritten <= _writeBufferLength); + + memmove(_writeBuffer, _writeBuffer + bytesWritten, + _writeBufferLength - bytesWritten); + _writeBufferLength -= bytesWritten; + @try { + _writeBuffer = OFResizeMemory(_writeBuffer, + _writeBufferLength, 1); + } @catch (OFOutOfMemoryException *e) { + /* We don't care, as we only made it smaller. */ + } + + return false; } -- (size_t)writeBuffer: (const void *)buffer - length: (size_t)length +- (void)writeBuffer: (const void *)buffer length: (size_t)length { if (!_buffersWrites) { size_t bytesWritten = [self lowlevelWriteBuffer: buffer length: length]; - if (_canBlock && bytesWritten < length) + if (bytesWritten < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: bytesWritten errNo: 0]; - - return bytesWritten; } else { + if (SIZE_MAX - _writeBufferLength < length) + @throw [OFOutOfRangeException exception]; + _writeBuffer = OFResizeMemory(_writeBuffer, _writeBufferLength + length, 1); memcpy(_writeBuffer + _writeBufferLength, buffer, length); _writeBufferLength += length; - - return length; } } #ifdef OF_HAVE_SOCKETS - (void)asyncWriteData: (OFData *)data @@ -1237,145 +1064,10 @@ { double_ = OFToBigEndianDouble(double_); [self writeBuffer: (char *)&double_ length: 8]; } -- (size_t)writeBigEndianInt16s: (const uint16_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint16_t *tmp = OFAllocMemory(count, sizeof(uint16_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap16(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeBigEndianInt32s: (const uint32_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint32_t *tmp = OFAllocMemory(count, sizeof(uint32_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap32(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeBigEndianInt64s: (const uint64_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint64_t *tmp = OFAllocMemory(count, sizeof(uint64_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap64(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeBigEndianFloats: (const float *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - -#ifdef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - float *tmp = OFAllocMemory(count, sizeof(float)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwapFloat(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeBigEndianDoubles: (const double *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - -#ifdef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - double *tmp = OFAllocMemory(count, sizeof(double)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwapDouble(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - - (void)writeLittleEndianInt16: (uint16_t)int16 { int16 = OFToLittleEndian16(int16); [self writeBuffer: (char *)&int16 length: 2]; } @@ -1402,146 +1094,11 @@ { double_ = OFToLittleEndianDouble(double_); [self writeBuffer: (char *)&double_ length: 8]; } -- (size_t)writeLittleEndianInt16s: (const uint16_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint16_t *tmp = OFAllocMemory(count, sizeof(uint16_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap16(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeLittleEndianInt32s: (const uint32_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint32_t *tmp = OFAllocMemory(count, sizeof(uint32_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap32(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeLittleEndianInt64s: (const uint64_t *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - uint64_t *tmp = OFAllocMemory(count, sizeof(uint64_t)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwap64(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeLittleEndianFloats: (const float *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - -#ifndef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - float *tmp = OFAllocMemory(count, sizeof(float)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwapFloat(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeLittleEndianDoubles: (const double *)buffer count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - -#ifndef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer length: size]; -#else - double *tmp = OFAllocMemory(count, sizeof(double)); - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OFByteSwapDouble(buffer[i]); - - [self writeBuffer: tmp length: size]; - } @finally { - OFFreeMemory(tmp); - } -#endif - - return size; -} - -- (size_t)writeData: (OFData *)data +- (void)writeData: (OFData *)data { void *pool; size_t length; if (data == nil) @@ -1551,20 +1108,18 @@ length = data.count * data.itemSize; [self writeBuffer: data.items length: length]; objc_autoreleasePoolPop(pool); +} - return length; +- (void)writeString: (OFString *)string +{ + [self writeString: string encoding: OFStringEncodingUTF8]; } -- (size_t)writeString: (OFString *)string -{ - return [self writeString: string encoding: OFStringEncodingUTF8]; -} - -- (size_t)writeString: (OFString *)string encoding: (OFStringEncoding)encoding +- (void)writeString: (OFString *)string encoding: (OFStringEncoding)encoding { void *pool; size_t length; if (string == nil) @@ -1575,20 +1130,18 @@ [self writeBuffer: [string cStringWithEncoding: encoding] length: length]; objc_autoreleasePoolPop(pool); +} - return length; +- (void)writeLine: (OFString *)string +{ + [self writeLine: string encoding: OFStringEncodingUTF8]; } -- (size_t)writeLine: (OFString *)string -{ - return [self writeLine: string encoding: OFStringEncodingUTF8]; -} - -- (size_t)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding +- (void)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding { size_t stringLength = [string cStringLengthWithEncoding: encoding]; char *buffer; buffer = OFAllocMemory(stringLength + 1, 1); @@ -1600,27 +1153,22 @@ [self writeBuffer: buffer length: stringLength + 1]; } @finally { OFFreeMemory(buffer); } - - return stringLength + 1; } -- (size_t)writeFormat: (OFConstantString *)format, ... +- (void)writeFormat: (OFConstantString *)format, ... { va_list arguments; - size_t ret; va_start(arguments, format); - ret = [self writeFormat: format arguments: arguments]; + [self writeFormat: format arguments: arguments]; va_end(arguments); - - return ret; } -- (size_t)writeFormat: (OFConstantString *)format arguments: (va_list)arguments +- (void)writeFormat: (OFConstantString *)format arguments: (va_list)arguments { char *UTF8String; int length; if (format == nil) @@ -1633,12 +1181,10 @@ @try { [self writeBuffer: UTF8String length: length]; } @finally { free(UTF8String); } - - return length; } - (bool)hasDataInReadBuffer { return (_readBufferLength > 0); Index: src/OFStreamSocket+Private.h ================================================================== --- src/OFStreamSocket+Private.h +++ src/OFStreamSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFStreamSocket.h ================================================================== --- src/OFStreamSocket.h +++ src/OFStreamSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFStreamSocket.m ================================================================== --- src/OFStreamSocket.m +++ src/OFStreamSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -162,13 +162,13 @@ #if defined(OF_WINDOWS) || defined(OF_AMIGAOS) - (void)setCanBlock: (bool)canBlock { # ifdef OF_WINDOWS - u_long v = canBlock; + u_long v = !canBlock; # else - char v = canBlock; + char v = !canBlock; # endif if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self @@ -253,27 +253,27 @@ client->_remoteAddress.length = (socklen_t)sizeof(client->_remoteAddress.sockaddr); #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr * )&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, SOCK_CLOEXEC)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, - &client->_remoteAddress.sockaddr.sockaddr, + (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; @@ -284,18 +284,24 @@ #endif assert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); - switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) { + switch (((struct sockaddr *)&client->_remoteAddress.sockaddr) + ->sa_family) { case AF_INET: client->_remoteAddress.family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: client->_remoteAddress.family = OFSocketAddressFamilyIPv6; break; +#endif +#ifdef OF_HAVE_UNIX_SOCKETS + case AF_UNIX: + client->_remoteAddress.family = OFSocketAddressFamilyUNIX; + break; #endif #ifdef OF_HAVE_IPX case AF_IPX: client->_remoteAddress.family = OFSocketAddressFamilyIPX; break; Index: src/OFString+CryptographicHashing.h ================================================================== --- src/OFString+CryptographicHashing.h +++ src/OFString+CryptographicHashing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+CryptographicHashing.m ================================================================== --- src/OFString+CryptographicHashing.m +++ src/OFString+CryptographicHashing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,10 +37,11 @@ size_t digestSize = [class digestSize]; const unsigned char *digest; char cString[digestSize * 2]; [hash updateWithBuffer: self.UTF8String length: self.UTF8StringLength]; + [hash calculate]; digest = hash.digest; for (size_t i = 0; i < digestSize; i++) { uint8_t high, low; Index: src/OFString+JSONParsing.h ================================================================== --- src/OFString+JSONParsing.h +++ src/OFString+JSONParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+JSONParsing.m ================================================================== --- src/OFString+JSONParsing.m +++ src/OFString+JSONParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+PathAdditions.h ================================================================== --- src/OFString+PathAdditions.h +++ src/OFString+PathAdditions.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -75,14 +75,22 @@ * @param component The path component to append * @return A new, autoreleased OFString with the path component appended */ - (OFString *)stringByAppendingPathComponent: (OFString *)component; +/** + * @brief Creates a new string by appending a path extension. + * + * @param extension The extension to append + * @return A new, autoreleased OFString with the path extension appended + */ +- (OFString *)stringByAppendingPathExtension: (OFString *)extension; + - (bool)of_isDirectoryPath; - (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString *__autoreleasing _Nullable *_Nonnull)URLEncodedHost; - (OFString *)of_URLPathToPathWithURLEncodedHost: (nullable OFString *)URLEncodedHost; - (OFString *)of_pathComponentToURLPathComponent; @end OF_ASSUME_NONNULL_END Index: src/OFString+PathAdditions.m ================================================================== --- src/OFString+PathAdditions.m +++ src/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,14 +15,15 @@ #include "config.h" #include "platform.h" -#if defined(OF_WINDOWS) || defined(OF_MSDOS) -# import "platform/windows/OFString+PathAdditions.m" +#if defined(OF_WINDOWS) || defined(OF_MSDOS) || defined(OF_MINT) +# import "platform/Windows/OFString+PathAdditions.m" #elif defined(OF_AMIGAOS) -# import "platform/amiga/OFString+PathAdditions.m" -#elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# import "platform/AmigaOS/OFString+PathAdditions.m" +#elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) # import "platform/libfat/OFString+PathAdditions.m" #else -# import "platform/posix/OFString+PathAdditions.m" +# import "platform/POSIX/OFString+PathAdditions.m" #endif Index: src/OFString+PropertyListParsing.h ================================================================== --- src/OFString+PropertyListParsing.h +++ src/OFString+PropertyListParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+PropertyListParsing.m ================================================================== --- src/OFString+PropertyListParsing.m +++ src/OFString+PropertyListParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+Serialization.h ================================================================== --- src/OFString+Serialization.h +++ src/OFString+Serialization.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+Serialization.m ================================================================== --- src/OFString+Serialization.m +++ src/OFString+Serialization.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+URLEncoding.h ================================================================== --- src/OFString+URLEncoding.h +++ src/OFString+URLEncoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+URLEncoding.m ================================================================== --- src/OFString+URLEncoding.m +++ src/OFString+URLEncoding.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -82,10 +82,11 @@ size_t length = self.UTF8StringLength; char *retCString; char byte = 0; int state = 0; size_t i = 0; + OFString *ret; retCString = OFAllocMemory(length + 1, 1); while (length--) { char c = *string++; @@ -135,14 +136,16 @@ } @catch (OFOutOfMemoryException *e) { /* We don't care if it fails, as we only made it smaller. */ } @try { - return [OFString stringWithUTF8StringNoCopy: retCString - length: i - freeWhenDone: true]; + ret = [OFString stringWithUTF8StringNoCopy: retCString + length: i + freeWhenDone: true]; } @catch (id e) { OFFreeMemory(retCString); @throw e; } + + return ret; } @end Index: src/OFString+XMLEscaping.h ================================================================== --- src/OFString+XMLEscaping.h +++ src/OFString+XMLEscaping.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+XMLEscaping.m ================================================================== --- src/OFString+XMLEscaping.m +++ src/OFString+XMLEscaping.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+XMLUnescaping.h ================================================================== --- src/OFString+XMLUnescaping.h +++ src/OFString+XMLUnescaping.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString+XMLUnescaping.m ================================================================== --- src/OFString+XMLUnescaping.m +++ src/OFString+XMLUnescaping.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -324,12 +324,12 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string without copying * the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when the OFString gets @@ -341,12 +341,12 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string with the * specified length without copying the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string @@ -579,12 +579,12 @@ /** * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string without copying the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when it is not needed @@ -597,12 +597,12 @@ /** * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string with the specified length without copying the string, if * possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -1082,10 +1082,14 @@ data = [OFData dataWithContentsOfURL: URL]; } @catch (id e) { [self release]; @throw e; } + + /* FIXME: Detect encoding where we can. */ + if (encoding == OFStringEncodingAutodetect) + encoding = OFStringEncodingUTF8; self = [self initWithCString: data.items encoding: encoding length: data.count * data.itemSize]; @@ -1378,10 +1382,11 @@ lossy: (bool)lossy { size_t length = self.length; char *cString; size_t cStringLength; + const char *ret; switch (encoding) { case OFStringEncodingUTF8: cString = OFAllocMemory((length * 4) + 1, 1); @@ -1432,17 +1437,19 @@ default: @throw [OFInvalidEncodingException exception]; } @try { - return [[OFData dataWithItemsNoCopy: cString - count: cStringLength + 1 - freeWhenDone: true] items]; + ret = [[OFData dataWithItemsNoCopy: cString + count: cStringLength + 1 + freeWhenDone: true] items]; } @catch (id e) { OFFreeMemory(cString); @throw e; } + + return ret; } - (const char *)cStringWithEncoding: (OFStringEncoding)encoding { return [self of_cStringWithEncoding: encoding lossy: false]; @@ -2537,23 +2544,26 @@ - (const OFUnichar *)characters { size_t length = self.length; OFUnichar *buffer; + const OFUnichar *ret; buffer = OFAllocMemory(length, sizeof(OFUnichar)); @try { [self getCharacters: buffer inRange: OFRangeMake(0, length)]; - return [[OFData dataWithItemsNoCopy: buffer - count: length - itemSize: sizeof(OFUnichar) - freeWhenDone: true] items]; + ret = [[OFData dataWithItemsNoCopy: buffer + count: length + itemSize: sizeof(OFUnichar) + freeWhenDone: true] items]; } @catch (id e) { OFFreeMemory(buffer); @throw e; } + + return ret; } - (const OFChar16 *)UTF16String { return [self UTF16StringWithByteOrder: OFByteOrderNative]; @@ -2565,10 +2575,11 @@ const OFUnichar *characters = self.characters; size_t length = self.length; OFChar16 *buffer; size_t j; bool swap = (byteOrder != OFByteOrderNative); + const OFChar16 *ret; /* Allocate memory for the worst case */ buffer = OFAllocMemory((length + 1) * 2, sizeof(OFChar16)); j = 0; @@ -2606,18 +2617,20 @@ } objc_autoreleasePoolPop(pool); @try { - return [[OFData dataWithItemsNoCopy: buffer - count: j + 1 - itemSize: sizeof(OFChar16) - freeWhenDone: true] items]; + ret = [[OFData dataWithItemsNoCopy: buffer + count: j + 1 + itemSize: sizeof(OFChar16) + freeWhenDone: true] items]; } @catch (id e) { OFFreeMemory(buffer); @throw e; } + + return ret; } - (size_t)UTF16StringLength { const OFUnichar *characters = self.characters; @@ -2639,10 +2652,11 @@ - (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder { size_t length = self.length; OFChar32 *buffer; + const OFChar32 *ret; buffer = OFAllocMemory(length + 1, sizeof(OFChar32)); @try { [self getCharacters: buffer inRange: OFRangeMake(0, length)]; buffer[length] = 0; @@ -2649,18 +2663,20 @@ if (byteOrder != OFByteOrderNative) for (size_t i = 0; i < length; i++) buffer[i] = OFByteSwap32(buffer[i]); - return [[OFData dataWithItemsNoCopy: buffer - count: length + 1 - itemSize: sizeof(OFChar32) - freeWhenDone: true] items]; + ret = [[OFData dataWithItemsNoCopy: buffer + count: length + 1 + itemSize: sizeof(OFChar32) + freeWhenDone: true] items]; } @catch (id e) { OFFreeMemory(buffer); @throw e; } + + return ret; } - (OFData *)dataWithEncoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); Index: src/OFSubarray.h ================================================================== --- src/OFSubarray.h +++ src/OFSubarray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSubarray.m ================================================================== --- src/OFSubarray.m +++ src/OFSubarray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFSubprocess.h ================================================================== --- src/OFSubprocess.h +++ src/OFSubprocess.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -78,11 +78,11 @@ * search path specified in PATH is used. * @param arguments The arguments to pass to the program, or `nil` * @return A new, autoreleased OFSubprocess. */ + (instancetype) - subProcessWithProgram: (OFString *)program + subprocessWithProgram: (OFString *)program arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; /** * @brief Creates a new OFSubprocess with the specified program, program name * and arguments and invokes the program. Index: src/OFSubprocess.m ================================================================== --- src/OFSubprocess.m +++ src/OFSubprocess.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,9 +16,9 @@ #include "config.h" #include "platform.h" #ifdef OF_WINDOWS -# include "platform/windows/OFSubprocess.m" +# include "platform/Windows/OFSubprocess.m" #else -# include "platform/posix/OFSubprocess.m" +# include "platform/POSIX/OFSubprocess.m" #endif Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,10 +16,12 @@ #import "OFObject.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN +@class OFURL; + /** * @class OFSystemInfo OFSystemInfo.h ObjFW/OFSystemInfo.h * * @brief A class for querying information about the system. */ @@ -27,19 +29,18 @@ @interface OFSystemInfo: OFObject #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nonatomic) size_t pageSize; @property (class, readonly, nonatomic) size_t numberOfCPUs; @property (class, readonly, nonatomic) OFString *ObjFWVersion; -@property (class, readonly, nonatomic) unsigned int ObjFWVersionMajor; -@property (class, readonly, nonatomic) unsigned int ObjFWVersionMinor; +@property (class, readonly, nonatomic) unsigned short ObjFWVersionMajor; +@property (class, readonly, nonatomic) unsigned short ObjFWVersionMinor; @property (class, readonly, nullable, nonatomic) OFString *operatingSystemName; @property (class, readonly, nullable, nonatomic) OFString *operatingSystemVersion; -# ifdef OF_HAVE_FILES -@property (class, readonly, nullable, nonatomic) OFString *userDataPath; -@property (class, readonly, nullable, nonatomic) OFString *userConfigPath; -# endif +@property (class, readonly, nullable, nonatomic) OFURL *userDataURL; +@property (class, readonly, nullable, nonatomic) OFURL *userConfigURL; +@property (class, readonly, nullable, nonatomic) OFURL *temporaryDirectoryURL; @property (class, readonly, nullable, nonatomic) OFString *CPUVendor; @property (class, readonly, nullable, nonatomic) OFString *CPUModel; # if defined(OF_X86_64) || defined(OF_X86) || defined(DOXYGEN) @property (class, readonly, nonatomic) bool supportsMMX; @property (class, readonly, nonatomic) bool supportsSSE; @@ -87,18 +88,18 @@ /** * @brief The major version of ObjFW. * * @return The major version of ObjFW */ -+ (unsigned int)ObjFWVersionMajor; ++ (unsigned short)ObjFWVersionMajor; /** * @brief The minor version of ObjFW. * * @return The minor version of ObjFW */ -+ (unsigned int)ObjFWVersionMinor; ++ (unsigned short)ObjFWVersionMinor; /** * @brief Returns the name of the operating system the application is running * on. * @@ -112,37 +113,55 @@ * * @return The version of the operating system the application is running on */ + (nullable OFString *)operatingSystemVersion; -#ifdef OF_HAVE_FILES /** * @brief Returns the path where user data for the application can be stored. * - * On Unix systems, this adheres to the XDG Base Directory specification.@n - * On Mac OS X and iOS, it uses the `NSApplicationSupportDirectory` directory.@n + * On UNIX systems, this adheres to the XDG Base Directory specification.@n + * On macOS and iOS, it uses the `NSApplicationSupportDirectory` directory.@n * On Windows, it uses the `APPDATA` environment variable.@n - * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. + * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory.@n + * On AmigaOS and MorphOS, it returns `PROGDIR:`. * * @return The path where user data for the application can be stored */ -+ (nullable OFString *)userDataPath; ++ (nullable OFURL *)userDataURL; /** * @brief Returns the path where user configuration for the application can be * stored. * - * On Unix systems, this adheres to the XDG Base Directory specification.@n - * On Mac OS X and iOS, it uses the `Preferences` directory inside of + * On UNIX systems, this adheres to the XDG Base Directory specification.@n + * On macOS and iOS, it uses the `Preferences` directory inside of * `NSLibraryDirectory` directory.@n * On Windows, it uses the `APPDATA` environment variable.@n * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. + * On AmigaOS and MorphOS, it returns `PROGDIR:`. * * @return The path where user configuration for the application can be stored */ -+ (nullable OFString *)userConfigPath; -#endif ++ (nullable OFURL *)userConfigURL; + +/** + * @brief Returns a path where temporary files for can be stored. + * + * If possible, returns a temporary directory for the user, otherwise returns a + * global temporary directory. + * + * On UNIX systems, this adheres to the XDG Base Directory specification and + * returns `/tmp` if `XDG_RUNTIME_DIR` is not set.@n + * On macOS and iOS, this uses `_CS_DARWIN_USER_TEMP_DIR`, falling back to + * `/tmp` if this fails.@n + * On Windows, it uses `GetTempPath`.@n + * On Haiku, it uses the `B_SYSTEM_TEMP_DIRECTORY` directory. + * On AmigaOS and MorphOS, it returns `T:`. + * + * @return A path where temporary files can be stored + */ ++ (nullable OFURL *)temporaryDirectoryURL; /** * @brief Returns the vendor of the CPU. * * If the vendor could not be determined, `nil` is returned instead. Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,31 +24,39 @@ #include "platform.h" #ifdef HAVE_SYS_UTSNAME_H # include #endif -#if defined(OF_MACOS) || defined(OF_NETBSD) +#if defined(OF_MACOS) || defined(OF_IOS) || defined(OF_NETBSD) # include #endif + +#ifdef OF_AMIGAOS +# include +# include +#endif #if defined(OF_AMIGAOS4) # include -# include #elif defined(OF_MORPHOS) # include -# include +#endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# import +# undef nx_id #endif #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFLocale.h" #import "OFOnce.h" #import "OFString.h" - -#import "OFNotImplementedException.h" +#import "OFURL.h" #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H # include # endif @@ -212,16 +220,14 @@ objc_autoreleasePoolPop(pool); } # endif #elif defined(OF_ANDROID) /* TODO */ -#elif defined(OF_MORPHOS) - /* TODO */ -#elif defined(OF_AMIGAOS4) - /* TODO */ -#elif defined(OF_AMIGAOS_M68K) - /* TODO */ +#elif defined(OF_AMIGAOS) + operatingSystemVersion = [[OFString alloc] + initWithFormat: @"Kickstart %u.%u", + SysBase->LibNode.lib_Version, SysBase->SoftVer]; #elif defined(OF_WII) || defined(NINTENDO_3DS) || defined(OF_NINTENDO_DS) || \ defined(OF_PSP) || defined(OF_MSDOS) /* Intentionally nothing */ #elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) struct utsname utsname; @@ -232,10 +238,22 @@ operatingSystemVersion = [[OFString alloc] initWithCString: utsname.release encoding: [OFLocale encoding]]; #endif } + +#ifdef OF_NINTENDO_SWITCH +static OFURL *tmpFSURL = nil; + +static void +mountTmpFS(void) +{ + if (R_SUCCEEDED(fsdevMountTemporaryStorage("tmpfs"))) + tmpFSURL = [[OFURL alloc] initFileURLWithPath: @"tmpfs:/" + isDirectory: true]; +} +#endif #if defined(OF_X86_64) || defined(OF_X86) static OF_INLINE struct X86Regs OF_CONST_FUNC x86CPUID(uint32_t eax, uint32_t ecx) { @@ -318,16 +336,16 @@ + (OFString *)ObjFWVersion { return @PACKAGE_VERSION; } -+ (unsigned int)ObjFWVersionMajor ++ (unsigned short)ObjFWVersionMajor { return OBJFW_VERSION_MAJOR; } -+ (unsigned int)ObjFWVersionMinor ++ (unsigned short)ObjFWVersionMinor { return OBJFW_VERSION_MINOR; } + (OFString *)operatingSystemName @@ -344,39 +362,34 @@ OFOnce(&onceControl, initOperatingSystemVersion); return operatingSystemVersion; } -#ifdef OF_HAVE_FILES -+ (OFString *)userDataPath ++ (OFURL *)userDataURL { +#ifdef OF_HAVE_FILES # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION - /* (1) to disable dead code warning when it is not a weak symbol */ - if ((1) && &sysdir_start_search_path_enumeration != NULL) { + if (@available(macOS 10.12, iOS 10, *)) { sysdir_search_path_enumeration_state state; state = sysdir_start_search_path_enumeration( SYSDIR_DIRECTORY_APPLICATION_SUPPORT, SYSDIR_DOMAIN_MASK_USER); if (sysdir_get_next_search_path_enumeration(state, pathC) == 0) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; } else { # endif NSSearchPathEnumerationState state; state = NSStartSearchPathEnumeration( NSApplicationSupportDirectory, NSUserDomainMask); if (NSGetNextSearchPathEnumeration(state, pathC) == 0) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION } # endif path = [OFMutableString stringWithUTF8String: pathC]; @@ -383,92 +396,89 @@ if ([path hasPrefix: @"~"]) { OFDictionary *env = [OFApplication environment]; OFString *home; if ((home = [env objectForKey: @"HOME"]) == nil) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; [path deleteCharactersInRange: OFRangeMake(0, 1)]; [path prependString: home]; } [path makeImmutable]; - return path; + return [OFURL fileURLWithPath: path isDirectory: true]; # elif defined(OF_WINDOWS) OFDictionary *env = [OFApplication environment]; OFString *appData; if ((appData = [env objectForKey: @"APPDATA"]) == nil) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; - return appData; + return [OFURL fileURLWithPath: appData isDirectory: true]; # elif defined(OF_HAIKU) char pathC[PATH_MAX]; if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, pathC, PATH_MAX) != B_OK) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; - return [OFString stringWithUTF8String: pathC]; + return [OFURL fileURLWithPath: [OFString stringWithUTF8String: pathC] + isDirectory: true]; # elif defined(OF_AMIGAOS) - return @"PROGDIR:"; + return [OFURL fileURLWithPath: @"PROGDIR:" isDirectory: true]; # else OFDictionary *env = [OFApplication environment]; OFString *var; + OFURL *URL; void *pool; if ((var = [env objectForKey: @"XDG_DATA_HOME"]) != nil && var.length > 0) - return var; + return [OFURL fileURLWithPath: var isDirectory: true]; if ((var = [env objectForKey: @"HOME"]) == nil) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; pool = objc_autoreleasePoolPush(); - var = [[OFString pathWithComponents: [OFArray arrayWithObjects: - var, @".local", @"share", nil]] retain]; + var = [OFString pathWithComponents: [OFArray arrayWithObjects: + var, @".local", @"share", nil]]; + URL = [[OFURL alloc] initFileURLWithPath: var isDirectory: true]; objc_autoreleasePoolPop(pool); - return [var autorelease]; + return [URL autorelease]; # endif +#else + return nil; +#endif } -+ (OFString *)userConfigPath ++ (OFURL *)userConfigURL { +#ifdef OF_HAVE_FILES # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION - /* (1) to disable dead code warning when it is not a weak symbol */ - if ((1) && &sysdir_start_search_path_enumeration != NULL) { + if (@available(macOS 10.12, iOS 10, *)) { sysdir_search_path_enumeration_state state; state = sysdir_start_search_path_enumeration( SYSDIR_DIRECTORY_LIBRARY, SYSDIR_DOMAIN_MASK_USER); if (sysdir_get_next_search_path_enumeration(state, pathC) == 0) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; } else { # endif NSSearchPathEnumerationState state; state = NSStartSearchPathEnumeration(NSLibraryDirectory, NSUserDomainMask); if (NSGetNextSearchPathEnumeration(state, pathC) == 0) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION } # endif path = [OFMutableString stringWithUTF8String: pathC]; @@ -475,58 +485,134 @@ if ([path hasPrefix: @"~"]) { OFDictionary *env = [OFApplication environment]; OFString *home; if ((home = [env objectForKey: @"HOME"]) == nil) - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; + return nil; [path deleteCharactersInRange: OFRangeMake(0, 1)]; [path prependString: home]; } [path appendString: @"/Preferences"]; [path makeImmutable]; - return path; + return [OFURL fileURLWithPath: path isDirectory: true]; # elif defined(OF_WINDOWS) OFDictionary *env = [OFApplication environment]; OFString *appData; if ((appData = [env objectForKey: @"APPDATA"]) == nil) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; - return appData; + return [OFURL fileURLWithPath: appData isDirectory: true]; # elif defined(OF_HAIKU) char pathC[PATH_MAX]; if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, pathC, PATH_MAX) != B_OK) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; - return [OFString stringWithUTF8String: pathC]; + return [OFURL fileURLWithPath: [OFString stringWithUTF8String: pathC] + isDirectory: true]; # elif defined(OF_AMIGAOS) - return @"PROGDIR:"; + return [OFURL fileURLWithPath: @"PROGDIR:" isDirectory: true]; # else OFDictionary *env = [OFApplication environment]; OFString *var; if ((var = [env objectForKey: @"XDG_CONFIG_HOME"]) != nil && var.length > 0) - return var; + return [OFURL fileURLWithPath: var isDirectory: true]; if ((var = [env objectForKey: @"HOME"]) == nil) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + return nil; + + var = [var stringByAppendingPathComponent: @".config"]; + + return [OFURL fileURLWithPath: var isDirectory: true]; +# endif +#else + return nil; +#endif +} + ++ (OFURL *)temporaryDirectoryURL +{ +#ifdef OF_HAVE_FILES +# if defined(OF_MACOS) || defined(OF_IOS) + char buffer[PATH_MAX]; + size_t length; + OFString *path; + + if ((length = confstr(_CS_DARWIN_USER_TEMP_DIR, buffer, PATH_MAX)) == 0) + return [OFURL fileURLWithPath: @"/tmp" isDirectory: true]; + + path = [OFString stringWithCString: buffer + encoding: [OFLocale encoding] + length: length - 1]; + + return [OFURL fileURLWithPath: path isDirectory: true]; +# elif defined(OF_WINDOWS) + OFString *path; + + if ([self isWindowsNT]) { + wchar_t buffer[PATH_MAX]; + + if (!GetTempPathW(PATH_MAX, buffer)) + return nil; + + path = [OFString stringWithUTF16String: buffer]; + } else { + char buffer[PATH_MAX]; + + if (!GetTempPathA(PATH_MAX, buffer)) + return nil; + + path = [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; + } + + return [OFURL fileURLWithPath: path isDirectory: true]; +# elif defined(OF_HAIKU) + char pathC[PATH_MAX]; + + if (find_directory(B_SYSTEM_TEMP_DIRECTORY, 0, false, + pathC, PATH_MAX) != B_OK) + return nil; + + return [OFURL fileURLWithPath: [OFString stringWithUTF8String: pathC] + isDirectory: true]; +# elif defined(OF_AMIGAOS) + return [OFURL fileURLWithPath: @"T:" isDirectory: true]; +# elif defined(OF_MSDOS) + OFString *path = [[OFApplication environment] objectForKey: @"TEMP"]; + + if (path == nil) + return nil; + + return [OFURL fileURLWithPath: path isDirectory: true]; +# elif defined(OF_MINT) + return [OFURL fileURLWithPath: @"u:\\tmp" isDirectory: true]; +# elif defined(OF_NINTENDO_SWITCH) + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, mountTmpFS); + + return tmpFSURL; +# else + OFString *path = + [[OFApplication environment] objectForKey: @"XDG_RUNTIME_DIR"]; + + if (path != nil) + return [OFURL fileURLWithPath: path]; - return [var stringByAppendingPathComponent: @".config"]; + return [OFURL fileURLWithPath: @"/tmp"]; # endif -} +#else + return nil; #endif +} + (OFString *)CPUVendor { #if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) struct X86Regs regs = x86CPUID(0, 0); @@ -540,33 +626,49 @@ buffer[2] = regs.ecx; return [OFString stringWithCString: (char *)buffer encoding: OFStringEncodingASCII length: 12]; +#elif defined(OF_M68K) + return @"Motorola"; #else return nil; #endif } + (OFString *)CPUModel { #if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) + struct X86Regs regs = x86CPUID(0x80000000, 0); uint32_t buffer[12]; size_t i; + if (regs.eax < 0x80000004) + return nil; + i = 0; for (uint32_t eax = 0x80000002; eax <= 0x80000004; eax++) { - struct X86Regs regs = x86CPUID(eax, 0); - + regs = x86CPUID(eax, 0); buffer[i++] = regs.eax; buffer[i++] = regs.ebx; buffer[i++] = regs.ecx; buffer[i++] = regs.edx; } return [OFString stringWithCString: (char *)buffer encoding: OFStringEncodingASCII]; +#elif defined(OF_MACOS) || defined(OF_IOS) + char buffer[128]; + size_t length = sizeof(buffer); + + if (sysctlbyname("machdep.cpu.brand_string", &buffer, &length, + NULL, 0) != 0) + return nil; + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding] + length: length]; #elif defined(OF_AMIGAOS4) CONST_STRPTR model, version; GetCPUInfoTags(GCIT_ModelString, &model, GCIT_VersionString, &version, TAG_END); @@ -574,10 +676,23 @@ if (version != NULL) return [OFString stringWithFormat: @"%s V%s", model, version]; else return [OFString stringWithCString: model encoding: OFStringEncodingASCII]; +#elif defined(OF_AMIGAOS_M68K) + if (SysBase->AttnFlags & AFF_68060) + return @"68060"; + if (SysBase->AttnFlags & AFF_68040) + return @"68040"; + if (SysBase->AttnFlags & AFF_68030) + return @"68030"; + if (SysBase->AttnFlags & AFF_68020) + return @"68020"; + if (SysBase->AttnFlags & AFF_68010) + return @"68010"; + else + return @"68000"; #else return nil; #endif } Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -144,27 +144,27 @@ * @return The port to use as a SOCKS5 proxy when creating a new socket */ + (uint16_t)SOCKS5Port; /** - * @brief Connect the OFTCPSocket to the specified destination. + * @brief Connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to */ - (void)connectToHost: (OFString *)host port: (uint16_t)port; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @param runLoopMode The run loop mode in which to perform the async connect */ @@ -172,11 +172,11 @@ port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @param block The block to execute once the connection has been established */ @@ -183,11 +183,11 @@ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port block: (OFTCPSocketAsyncConnectBlock)block; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @param runLoopMode The run loop mode in which to perform the async connect * @param block The block to execute once the connection has been established @@ -197,11 +197,11 @@ runLoopMode: (OFRunLoopMode)runLoopMode block: (OFTCPSocketAsyncConnectBlock)block; #endif /** - * @brief Bind the socket to the specified host and port. + * @brief Binds the socket to the specified host and port. * * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for * IPv6 to bind to all. * @param port The port to bind to. If the port is 0, an unused port will be * chosen, which can be obtained using the return value. @@ -208,14 +208,6 @@ * @return The port the socket was bound to */ - (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; @end -#ifdef __cplusplus -extern "C" { -#endif -extern Class _Nullable OFTLSSocketClass; -#ifdef __cplusplus -} -#endif - OF_ASSUME_NONNULL_END Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -51,12 +51,10 @@ #import "OFSetOptionFailedException.h" static const OFRunLoopMode connectRunLoopMode = @"OFTCPSocketConnectRunLoopMode"; -Class OFTLSSocketClass = Nil; - static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; @interface OFTCPSocket () @end @@ -143,11 +141,12 @@ #endif if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - if ((_socket = socket(address->sockaddr.sockaddr.sa_family, + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) { *errNo = OFSocketErrNo(); return false; } @@ -164,11 +163,11 @@ { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; /* Cast needed for AmigaOS, where the argument is declared non-const */ - if (connect(_socket, (struct sockaddr *)&address->sockaddr.sockaddr, + if (connect(_socket, (struct sockaddr *)&address->sockaddr, address->length) != 0) { *errNo = OFSocketErrNo(); return false; } @@ -187,26 +186,26 @@ id delegate = _delegate; OFTCPSocketConnectDelegate *connectDelegate = [[[OFTCPSocketConnectDelegate alloc] init] autorelease]; OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; - self.delegate = connectDelegate; + _delegate = connectDelegate; [self asyncConnectToHost: host port: port runLoopMode: connectRunLoopMode]; while (!connectDelegate->_done) [runLoop runMode: connectRunLoopMode beforeDate: nil]; /* Cleanup */ [runLoop runMode: connectRunLoopMode beforeDate: [OFDate date]]; + + _delegate = delegate; if (connectDelegate->_exception != nil) @throw connectDelegate->_exception; - self.delegate = delegate; - objc_autoreleasePoolPop(pool); } - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port { @@ -318,11 +317,12 @@ addressFamily: OFSocketAddressFamilyAny]; address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; OFSocketAddressSetPort(&address, port); - if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + if ((_socket = socket( + ((struct sockaddr *)&address.sockaddr)->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithHost: host port: port socket: self @@ -339,11 +339,11 @@ (char *)&one, (socklen_t)sizeof(one)); #if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) if (port != 0) { #endif - if (bind(_socket, &address.sockaddr.sockaddr, + if (bind(_socket, (struct sockaddr *)&address.sockaddr, address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -362,11 +362,12 @@ while (rnd < 1024) rnd = (uint16_t)rand(); OFSocketAddressSetPort(&address, rnd); - if ((ret = bind(_socket, &address.sockaddr.sockaddr, + if ((ret = bind(_socket, + (struct sockaddr *)&address.sockaddr, address.length)) == 0) { port = rnd; break; } @@ -393,11 +394,11 @@ #if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) memset(&address, 0, sizeof(address)); address.length = (socklen_t)sizeof(address.sockaddr); - if (OFGetSockName(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, &address.length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -406,17 +407,18 @@ port: port socket: self errNo: errNo]; } - if (address.sockaddr.sockaddr.sa_family == AF_INET) + switch (((struct sockaddr *)&address.sockaddr)->sa_family) { + case AF_INET: return OFFromBigEndian16(address.sockaddr.in.sin_port); # ifdef OF_HAVE_IPV6 - else if (address.sockaddr.sockaddr.sa_family == AF_INET6) + case AF_INET6: return OFFromBigEndian16(address.sockaddr.in6.sin6_port); # endif - else { + default: closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port Index: src/OFTCPSocketSOCKS5Connector.h ================================================================== --- src/OFTCPSocketSOCKS5Connector.h +++ src/OFTCPSocketSOCKS5Connector.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTCPSocketSOCKS5Connector.m ================================================================== --- src/OFTCPSocketSOCKS5Connector.m +++ src/OFTCPSocketSOCKS5Connector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTLSKey.h ================================================================== --- src/OFTLSKey.h +++ src/OFTLSKey.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTLSKey.m ================================================================== --- src/OFTLSKey.m +++ src/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,13 +16,13 @@ #include "config.h" #include "platform.h" #if defined(OF_HAVE_PTHREADS) -# include "platform/posix/OFTLSKey.m" +# include "platform/POSIX/OFTLSKey.m" #elif defined(OF_WINDOWS) -# include "platform/windows/OFTLSKey.m" +# include "platform/Windows/OFTLSKey.m" #elif defined(OF_MORPHOS) -# include "platform/morphos/OFTLSKey.m" +# include "platform/MorphOS/OFTLSKey.m" #elif defined(OF_AMIGAOS) -# include "platform/amiga/OFTLSKey.m" +# include "platform/AmigaOS/OFTLSKey.m" #endif DELETED src/OFTLSSocket.h Index: src/OFTLSSocket.h ================================================================== --- src/OFTLSSocket.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; -@class OFDictionary OF_GENERIC(KeyType, ObjectType); -@protocol OFTLSSocket; - -/** - * @protocol OFTLSSocketDelegate OFTLSSocket.h ObjFW/OFTLSSocket.h - * - * @brief A delegate for classes implementing the OFTLSSocket protocol. - */ -@protocol OFTLSSocketDelegate -@optional -/** - * @brief This callback is called when the TLS socket wants to know if it - * should accept the received certificate. - * - * @note This is only used to verify certain fields of a certificate to allow - * for protocol specific verification. The certificate chain is verified - * using the specified CAs, or the system's CAs if no CAs have been - * specified. - * - * @param socket The socket which wants to know if it should accept the received - * certificate - * @param certificate A dictionary with the fields of the received certificate - * @return Whether the TLS socket should accept the received certificate chain - */ -- (bool)socket: (id )socket - shouldAcceptCertificate: (OFDictionary *)certificate; -@end - -/** - * @protocol OFTLSSocket OFTLSSocket.h ObjFW/OFTLSSocket.h - * - * @brief A protocol that should be implemented by 3rd-party libraries - * implementing TLS. - */ -@protocol OFTLSSocket -/** - * @brief The delegate for the TLS socket. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - id delegate; - -/** - * @brief The path to the X.509 certificate file to use. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; - -/** - * @brief The path to the PKCS#8 private key file to use. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; - -/** - * @brief The passphrase to decrypt the PKCS#8 private key file. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - const char *privateKeyPassphrase; - -/** - * @brief Whether certificates are verified. - * - * The default is enabled. - */ -@property (nonatomic) bool verifiesCertificates; - -/** - * @brief Initializes the TLS socket with the specified TCP socket as its - * underlying socket. - * - * @param socket The TCP socket to use as underlying socket - */ -- (instancetype)initWithSocket: (OFTCPSocket *)socket; - -/** - * @brief Initiates the TLS handshake. - * - * @note This is only useful if you used @ref initWithSocket: to start TLS on - * a TCP socket which is already connected! - * - * @param host The host to expect for certificate verification. - * May be `nil` if certificate verification is disabled. - */ -- (void)startTLSWithExpectedHost: (nullable OFString *)host; - -/** - * @brief Sets the path to the X.509 certificate file to use for the specified - * SNI host. - * - * @param SNIHost The SNI host for which the path of the X.509 certificate file - * should be set - * - * @param certificateFile The path to the X.509 certificate file - */ -- (void)setCertificateFile: (OFString *)certificateFile - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the path of the X.509 certificate file used by the TLS socket - * for the specified SNI host. - * - * @param SNIHost The SNI host for which the path of the X.509 certificate file - * should be returned - * - * @return The path of the X.509 certificate file used by the TLS socket for - * the specified SNI host - */ -- (nullable OFString *)certificateFileForSNIHost: (OFString *)SNIHost; - -/** - * @brief Sets the path to the PKCS#8 private key file to use for the specified - * SNI host. - * - * @param privateKeyFile The path to the PKCS#8 private key file - * @param SNIHost The SNI host for which the path to the PKCS#8 private key - * file should be set - */ -- (void)setPrivateKeyFile: (OFString *)privateKeyFile - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the path of the PKCS#8 private key file used by the TLS - * socket for the specified SNI host. - * - * @param SNIHost The SNI host for which the path of the PKCS#8 private key - * file should be returned - * - * @return The path of the PKCS#8 private key file used by the TLS socket for - * the specified SNI host - */ -- (nullable OFString *)privateKeyFileForSNIHost: (OFString *)SNIHost; - -/** - * @brief Sets the passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - * - * @param privateKeyPassphrase The passphrase to decrypt the PKCS#8 private - * key file for the specified SNI host - * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8 - * private key file should be set - */ -- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host. - * - * @warning You should not copy this to insecure memory which is swappable! - * - * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8 - * private key file should be returned - * - * @return The passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host - */ -- (nullable const char *)privateKeyPassphraseForSNIHost: (OFString *)SNIHost; -@end - -OF_ASSUME_NONNULL_END ADDED src/OFTLSStream.h Index: src/OFTLSStream.h ================================================================== --- /dev/null +++ src/OFTLSStream.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2008-2022 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 "OFStream.h" +#import "OFRunLoop.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFTLSStream; + +/** + * @brief An enum representing an error of an OFTLSStream. + */ +typedef enum { + /** @brief An unknown error. */ + OFTLSStreamErrorCodeUnknown, + /** @brief Initialization of the TLS context failed. */ + OFTLSStreamErrorCodeInitializationFailed +} OFTLSStreamErrorCode; + +/** + * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h + * + * A delegate for OFTLSStream. + */ +@protocol OFTLSStreamDelegate +/** + * @brief A method which is called when a TLS stream performed the client + * handshake. + * + * @param stream The TLS stream which performed the handshake + * @param host The host for which the handshake was performed + * @param exception An exception that occurred during the handshake, or nil on + * success + */ +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (nullable id)exception; +@end + +/** + * @class OFTLSStream OFTLSStream.h ObjFW/OFTLSStream.h + * + * @brief A class that provides Transport Layer Security on top of a stream. + * + * This class is a class cluster and returns a suitable OFTLSStream subclass, + * if available. + * + * Subclasses need to override @ref lowlevelReadIntoBuffer:length:, + * @ref lowlevelWriteBuffer:length: and + * @ref asyncPerformClientHandshakeWithHost:runLoopMode:. The method + * @ref hasDataInReadBuffer should be overridden to return `true` if the TLS + * stream has cached unprocessed data internally, while returning + * `self.underlyingStream.hasDataInReadBuffer` if it does not have any + * unprocessed data. In order to get access to the underlying stream, + * @ref underlyingStream can be used. + */ +@interface OFTLSStream: OFStream +{ + OFStream + *_underlyingStream; + bool _verifiesCertificates; + OF_RESERVE_IVARS(OFTLSStream, 4) +} + +/** + * @brief The underlying stream. + */ +@property (readonly, nonatomic) OFStream *underlyingStream; + +/** + * @brief The delegate for asynchronous operations on the stream. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Whether certificates are verified. Default is true. + */ +@property (nonatomic) bool verifiesCertificates; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Creates a new TLS stream with the specified stream as its underlying + * stream. + * + * @param stream The stream to use as underlying stream. Must not be closed + * before the TLS stream is closed. + * @return A new, autoreleased TLS stream + */ ++ (instancetype)streamWithStream: (OFStream *)stream; + +/** + * @brief Initializes the TLS stream with the specified stream as its + * underlying stream. + * + * @param stream The stream to use as underlying stream. Must not be closed + * before the TLS stream is closed. + * @return An initialized TLS stream + */ +- (instancetype)initWithStream: (OFStream *)stream + OF_DESIGNATED_INITIALIZER; + +/** + * @brief Asynchronously performs the TLS client handshake for the specified + * host and calls the delegate afterwards. + * + * @param host The host to perform the handshake with + */ +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host; + +/** + * @brief Asynchronously performs the TLS client handshake for the specified + * host and calls the delegate afterwards. + * + * @param host The host to perform the handshake with + * @param runLoopMode The run loop mode in which to perform the async handshake + */ +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode; + +/** + * @brief Performs the TLS client handshake for the specified host. + * + * @param host The host to perform the handshake with + */ +- (void)performClientHandshakeWithHost: (OFString *)host; +@end + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief The implementation for OFTLSStream to use. + * + * This can be set to a class that is always used for OFTLSStream. This is + * useful to either force a specific implementation or use one that ObjFW does + * not know about. + */ +extern Class OFTLSStreamImplementation; + +/** + * @brief Returns a string description for the TLS stream error code. + * + * @param errorCode The error code to return the description for + * @return A string description for the TLS stream error code + */ +extern OFString *OFTLSStreamErrorCodeDescription( + OFTLSStreamErrorCode errorCode); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFTLSStream.m Index: src/OFTLSStream.m ================================================================== --- /dev/null +++ src/OFTLSStream.m @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSStream.h" +#import "OFDate.h" + +#import "OFNotImplementedException.h" +#import "OFTLSHandshakeFailedException.h" + +@interface OFTLSStreamHandshakeDelegate: OFObject +{ +@public + bool _done; + id _exception; +} +@end + +Class OFTLSStreamImplementation = Nil; +static const OFRunLoopMode handshakeRunLoopMode = + @"OFTLSStreamHandshakeRunLoopMode"; + +/* + * References to exceptions. This is needed because they are only used by + * subclasses that are in a different library. + */ +void +_references_to_exceptions_of_OFTLSStream(void) +{ + _OFTLSHandshakeFailedException_reference = 1; +} + +OFString * +OFTLSStreamErrorCodeDescription(OFTLSStreamErrorCode errorCode) +{ + switch (errorCode) { + case OFTLSStreamErrorCodeInitializationFailed: + return @"Initialization of TLS context failed"; + default: + return @"Unknown error"; + } +} + +@implementation OFTLSStreamHandshakeDelegate +- (void)dealloc +{ + [_exception release]; + + [super dealloc]; +} + +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (id)exception +{ + _done = true; + _exception = [exception retain]; +} +@end + +@implementation OFTLSStream +@synthesize underlyingStream = _underlyingStream; +@dynamic delegate; +@synthesize verifiesCertificates = _verifiesCertificates; + ++ (instancetype)alloc +{ + if (self == [OFTLSStream class]) { + if (OFTLSStreamImplementation != Nil) + return [OFTLSStreamImplementation alloc]; + + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + } + + return [super alloc]; +} + ++ (instancetype)streamWithStream: (OFStream *)stream +{ + return [[[self alloc] initWithStream: stream] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super init]; + + @try { + _underlyingStream = [stream retain]; + _verifiesCertificates = true; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_underlyingStream release]; + + [super dealloc]; +} + +- (void)close +{ + [_underlyingStream release]; + _underlyingStream = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)hasDataInReadBuffer +{ + return (super.hasDataInReadBuffer || + _underlyingStream.hasDataInReadBuffer); +} + +- (bool)lowlevelIsAtEndOfStream +{ + return _underlyingStream.atEndOfStream; +} + +- (int)fileDescriptorForReading +{ + return _underlyingStream.fileDescriptorForReading; +} + +- (int)fileDescriptorForWriting +{ + return _underlyingStream.fileDescriptorForWriting; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host +{ + [self asyncPerformClientHandshakeWithHost: host + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)performClientHandshakeWithHost: (OFString *)host +{ + void *pool = objc_autoreleasePoolPush(); + id delegate = _delegate; + OFTLSStreamHandshakeDelegate *handshakeDelegate = + [[[OFTLSStreamHandshakeDelegate alloc] init] autorelease]; + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + + _delegate = handshakeDelegate; + [self asyncPerformClientHandshakeWithHost: host + runLoopMode: handshakeRunLoopMode]; + + while (!handshakeDelegate->_done) + [runLoop runMode: handshakeRunLoopMode beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: handshakeRunLoopMode beforeDate: [OFDate date]]; + + _delegate = delegate; + + if (handshakeDelegate->_exception != nil) + @throw handshakeDelegate->_exception; + + objc_autoreleasePoolPop(pool); +} +@end Index: src/OFTarArchive.h ================================================================== --- src/OFTarArchive.h +++ src/OFTarArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTarArchive.m ================================================================== --- src/OFTarArchive.m +++ src/OFTarArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -12,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFTarArchive.h" #import "OFTarArchiveEntry.h" #import "OFTarArchiveEntry+Private.h" #import "OFDate.h" @@ -427,29 +429,32 @@ [super dealloc]; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t bytesWritten; - if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if ((uint64_t)length > _toWrite) @throw [OFOutOfRangeException exception]; @try { - bytesWritten = [_stream writeBuffer: buffer - length: length]; + [_stream writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { + OFEnsure(e.bytesWritten <= length); + _toWrite -= e.bytesWritten; + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + @throw e; } - _toWrite -= bytesWritten; + _toWrite -= length; - return bytesWritten; + return length; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) Index: src/OFTarArchiveEntry+Private.h ================================================================== --- src/OFTarArchiveEntry+Private.h +++ src/OFTarArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFThread+Private.h ================================================================== --- src/OFThread+Private.h +++ src/OFThread+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -77,10 +77,15 @@ #ifdef OF_HAVE_THREADS # import "OFThreadJoinFailedException.h" # import "OFThreadStartFailedException.h" # import "OFThreadStillRunningException.h" #endif + +#ifdef OF_MINT +/* freemint-gcc does not have trunc() */ +# define trunc(x) ((int64_t)(x)) +#endif #if defined(OF_HAVE_THREADS) # import "OFTLSKey.h" # if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) # import "OFSocket.h" DELETED src/OFThreadPool.h Index: src/OFThreadPool.h ================================================================== --- src/OFThreadPool.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -#ifdef OF_HAVE_BLOCKS -/** - * @brief A block for a job which should be executed in a thread pool. - */ -typedef void (^OFThreadPoolBlock)(void); -#endif - -@class OFCondition; -@class OFList OF_GENERIC(ObjectType); -@class OFMutableArray OF_GENERIC(ObjectType); -@class OFThreadPoolJob; - -/** - * @class OFThreadPool OFThreadPool.h ObjFW/OFThreadPool.h - * - * @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. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFThreadPool: OFObject -{ - size_t _size; - OFMutableArray *_threads; - volatile int _count; -#ifdef OF_THREAD_POOL_M -@public -#endif - OFList *_queue; - OFCondition *_queueCondition; - volatile int _doneCount; - OFCondition *_countCondition; -} - -/** - * @brief The size of the thread pool. - */ -@property (readonly, nonatomic) size_t size; - -/** - * @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 - */ -+ (instancetype)threadPool; - -/** - * @brief Returns a new thread pool with the specified number of threads. - * - * @param size The number of threads for the pool - * @return A new thread pool with the specified number of threads - */ -+ (instancetype)threadPoolWithSize: (size_t)size; - -/** - * @brief Initializes an already allocated OFThreadPool with the specified - * number of threads. - * - * @param size The number of threads for the pool - * @return An initialized OFThreadPool with the specified number of threads - */ -- (instancetype)initWithSize: (size_t)size OF_DESIGNATED_INITIALIZER; - -/** - * @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: (nullable 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: (OFThreadPoolBlock)block; -#endif - -/** - * @brief Waits until all jobs are done. - */ -- (void)waitUntilDone; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFThreadPool.m Index: src/OFThreadPool.m ================================================================== --- src/OFThreadPool.m +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#define OF_THREAD_POOL_M - -#import "OFThreadPool.h" -#import "OFArray.h" -#import "OFList.h" -#import "OFThread.h" -#import "OFCondition.h" -#import "OFSystemInfo.h" - -OF_DIRECT_MEMBERS -@interface OFThreadPoolJob: OFObject -{ - id _target; - SEL _selector; - id _object; -#ifdef OF_HAVE_BLOCKS - OFThreadPoolBlock _block; -#endif -} - -- (instancetype)initWithTarget: (id)target - selector: (SEL)selector - object: (id)object; -#ifdef OF_HAVE_BLOCKS -- (instancetype)initWithBlock: (OFThreadPoolBlock)block; -#endif -- (void)perform; -@end - -@implementation OFThreadPoolJob -- (instancetype)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 -- (instancetype)initWithBlock: (OFThreadPoolBlock)block -{ - self = [super init]; - - @try { - _block = [block copy]; - } @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 != NULL) - _block(); - else -#endif - [_target performSelector: _selector withObject: _object]; -} -@end - -OF_DIRECT_MEMBERS -@interface OFThreadPoolThread: OFThread -{ - OFList *_queue; - OFCondition *_queueCondition, *_countCondition; -@public - volatile bool _terminate; - volatile int *_doneCount; -} - -+ (instancetype)threadWithThreadPool: (OFThreadPool *)threadPool; -- (instancetype)initWithThreadPool: (OFThreadPool *)threadPool; -@end - -@implementation OFThreadPoolThread -+ (instancetype)threadWithThreadPool: (OFThreadPool *)threadPool -{ - return [[(OFThreadPoolThread *)[self alloc] - initWithThreadPool: threadPool] autorelease]; -} - -- (instancetype)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 -{ - void *pool; - - if (_terminate) - return nil; - - pool = objc_autoreleasePoolPush(); - - for (;;) { - OFThreadPoolJob *job; - - [_queueCondition lock]; - @try { - OFListItem listItem; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - listItem = _queue.firstListItem; - - while (listItem == NULL) { - [_queueCondition wait]; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - listItem = _queue.firstListItem; - } - - job = [[OFListItemObject(listItem) retain] autorelease]; - [_queue removeListItem: listItem]; - } @finally { - [_queueCondition unlock]; - } - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - [job perform]; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - objc_autoreleasePoolPop(pool); - pool = objc_autoreleasePoolPush(); - - [_countCondition lock]; - @try { - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - (*_doneCount)++; - - [_countCondition signal]; - } @finally { - [_countCondition unlock]; - } - } -} -@end - -@implementation OFThreadPool -+ (instancetype)threadPool -{ - return [[[self alloc] init] autorelease]; -} - -+ (instancetype)threadPoolWithSize: (size_t)size -{ - return [[[self alloc] initWithSize: size] autorelease]; -} - -- (instancetype)init -{ - return [self initWithSize: [OFSystemInfo numberOfCPUs]]; -} - -- (instancetype)initWithSize: (size_t)size -{ - self = [super init]; - - @try { - _size = size; - _threads = [[OFMutableArray alloc] init]; - _queue = [[OFList alloc] init]; - _queueCondition = [[OFCondition alloc] init]; - _countCondition = [[OFCondition alloc] init]; - - for (size_t i = 0; i < size; i++) { - void *pool = objc_autoreleasePoolPush(); - - OFThreadPoolThread *thread = - [OFThreadPoolThread threadWithThreadPool: self]; - - [_threads addObject: thread]; - - objc_autoreleasePoolPop(pool); - } - - /* - * We need to start the threads in a separate loop to make sure - * _threads is not modified anymore to prevent a race condition. - */ - for (size_t i = 0; i < size; i++) - [[_threads objectAtIndex: i] start]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_queueCondition lock]; - @try { - [_countCondition lock]; - @try { - for (OFThreadPoolThread *thread in _threads) - thread->_terminate = true; - } @finally { - [_countCondition unlock]; - } - - [_queueCondition broadcast]; - } @finally { - [_queueCondition unlock]; - } - - [_threads release]; - [_queue release]; - [_queueCondition release]; - [_countCondition release]; - - [super dealloc]; -} - -- (void)of_dispatchJob: (OFThreadPoolJob *)job OF_DIRECT -{ - [_countCondition lock]; - _count++; - [_countCondition unlock]; - - [_queueCondition lock]; - @try { - [_queue appendObject: job]; - [_queueCondition signal]; - } @finally { - [_queueCondition unlock]; - } -} - -- (void)waitUntilDone -{ - for (;;) { - [_countCondition lock]; - @try { - if (_doneCount == _count) - return; - - [_countCondition wait]; - } @finally { - [_countCondition unlock]; - } - } -} - -- (void)dispatchWithTarget: (id)target - selector: (SEL)selector - object: (id)object -{ - OFThreadPoolJob *job = [[OFThreadPoolJob alloc] initWithTarget: target - selector: selector - object: object]; - @try { - [self of_dispatchJob: job]; - } @finally { - [job release]; - } -} - -#ifdef OF_HAVE_BLOCKS -- (void)dispatchWithBlock: (OFThreadPoolBlock)block -{ - OFThreadPoolJob *job = [[OFThreadPoolJob alloc] initWithBlock: block]; - @try { - [self of_dispatchJob: job]; - } @finally { - [job release]; - } -} -#endif - -- (size_t)size -{ - return _size; -} -@end Index: src/OFTimer+Private.h ================================================================== --- src/OFTimer+Private.h +++ src/OFTimer+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -67,13 +67,13 @@ * repeating timer. */ @property (readonly, nonatomic) OFTimeInterval timeInterval; /** - * @brief Whether the timer is repeating. + * @brief Whether the timer repeats. */ -@property (readonly, nonatomic, getter=isRepeating) bool repeating; +@property (readonly, nonatomic) bool repeats; /** * @brief Whether the timer is valid. */ @property (readonly, nonatomic, getter=isValid) bool valid; Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,11 +29,11 @@ #endif #import "OFInvalidArgumentException.h" @implementation OFTimer -@synthesize timeInterval = _interval, repeating = _repeats, valid = _valid; +@synthesize timeInterval = _interval, repeats = _repeats, valid = _valid; + (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector repeats: (bool)repeats @@ -664,6 +664,60 @@ } @finally { [_condition unlock]; } } #endif + +- (OFString *)description +{ +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) + return [OFString stringWithFormat: + @"<%@:\n" + @"\tFire date: %@\n" + @"\tInterval: %lf\n" + @"\tRepeats: %s\n" + @"\tBlock: %@\n" + @"\tValid: %s\n" + @">", + self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), + _block, (_valid ? "yes" : "no")]; + else { +#endif + void *pool = objc_autoreleasePoolPush(); + OFString *objects = @"", *ret; + + if (_arguments >= 1) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object1]; + if (_arguments >= 2) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object2]; + if (_arguments >= 3) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object3]; + if (_arguments >= 4) + objects = [objects stringByAppendingFormat: + @"\tObject: %@\n", _object4]; + + ret = [[OFString alloc] initWithFormat: + @"<%@:\n" + @"\tFire date: %@\n" + @"\tInterval: %lf\n" + @"\tRepeats: %s\n" + @"\tTarget: %@\n" + @"\tSelector: %s\n" + @"%@" + @"\tValid: %s\n" + @">", + self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), + _target, sel_getName(_selector), objects, + (_valid ? "yes" : "no")]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +#ifdef OF_HAVE_BLOCKS + } +#endif +} @end Index: src/OFTriple.h ================================================================== --- src/OFTriple.h +++ src/OFTriple.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFTriple.m ================================================================== --- src/OFTriple.m +++ src/OFTriple.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFUDPSocket+Private.h ================================================================== --- src/OFUDPSocket+Private.h +++ src/OFUDPSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -47,11 +47,12 @@ uint16_t port; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if ((_socket = socket(address->sockaddr.sockaddr.sa_family, + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithHost: OFSocketAddressString(address) port: OFSocketAddressPort(address) socket: self @@ -67,11 +68,11 @@ #endif #if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) if (OFSocketAddressPort(address) != 0) { #endif - if (bind(_socket, &address->sockaddr.sockaddr, + if (bind(_socket, (struct sockaddr *)&address->sockaddr, address->length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -91,20 +92,19 @@ while (rnd < 1024) rnd = (uint16_t)rand(); OFSocketAddressSetPort(address, rnd); - if ((ret = bind(_socket, &address->sockaddr.sockaddr, - address->length)) == 0) { - port = rnd; + if ((ret = bind(_socket, + (struct sockaddr *)&address->sockaddr, + address->length)) == 0) break; - } if (OFSocketErrNo() != EADDRINUSE) { int errNo = OFSocketErrNo(); OFString *host = OFSocketAddressString(address); - uint16_t port = OFSocketAddressPort(port); + port = OFSocketAddressPort(address); closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException @@ -124,11 +124,11 @@ #if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) memset(address, 0, sizeof(*address)); address->length = (socklen_t)sizeof(address->sockaddr); - if (OFGetSockName(_socket, &address->sockaddr.sockaddr, + if (OFGetSockName(_socket, (struct sockaddr *)&address->sockaddr, &address->length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -138,17 +138,18 @@ port: OFSocketAddressPort(address) socket: self errNo: errNo]; } - if (address->sockaddr.sockaddr.sa_family == AF_INET) + switch (((struct sockaddr *)&address->sockaddr)->sa_family) { + case AF_INET: return OFFromBigEndian16(address->sockaddr.in.sin_port); # ifdef OF_HAVE_IPV6 - else if (address->sockaddr.sockaddr.sa_family == AF_INET6) + case AF_INET6: return OFFromBigEndian16(address->sockaddr.in6.sin6_port); # endif - else { + default: closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: OFSocketAddressString(address) ADDED src/OFUNIXDatagramSocket.h Index: src/OFUNIXDatagramSocket.h ================================================================== --- /dev/null +++ src/OFUNIXDatagramSocket.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2022 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 "OFDatagramSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @protocol OFUNIXDatagramSocketDelegate OFUNIXDatagramSocket.h \ + * ObjFW/OFUNIXDatagramSocket.h + * + * @brief A delegate for OFUNIXDatagramSocket. + */ +@protocol OFUNIXDatagramSocketDelegate +@end + +/** + * @class OFUNIXDatagramSocket OFUNIXDatagramSocket.h \ + * ObjFW/OFUNIXDatagramSocket.h + * + * @brief A class which provides methods to create and use UNIX datagram + * sockets. + * + * Addresses are of type @ref OFSocketAddress. You can use + * @ref OFSocketAddressMakeUNIX to create an address or + * @ref OFSocketAddressUNIXPath to get the socket path. + * + * @warning Even though the OFCopying protocol is implemented, it does *not* + * return an independent copy of the socket, but instead retains it. + * This is so that the socket can be used as a key for a dictionary, + * so context can be associated with a socket. Using a socket in more + * than one thread at the same time is not thread-safe, even if copy + * was called to create one "instance" for every thread! + */ +@interface OFUNIXDatagramSocket: OFDatagramSocket +{ + OF_RESERVE_IVARS(OFUNIXDatagramSocket, 4) +} + +/** + * @brief The delegate for asynchronous operations on the socket. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Bind the socket to the specified path. + * + * @param path The path to bind to + * @return The address on which this socket can be reached + */ +- (OFSocketAddress)bindToPath: (OFString *)path; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUNIXDatagramSocket.m Index: src/OFUNIXDatagramSocket.m ================================================================== --- /dev/null +++ src/OFUNIXDatagramSocket.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2022 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" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFUNIXDatagramSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindFailedException.h" + +@implementation OFUNIXDatagramSocket +@dynamic delegate; + +- (OFSocketAddress)bindToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.un.sun_family, + SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindFailedException + exceptionWithPath: path + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } + + return address; +} +@end ADDED src/OFUNIXStreamSocket.h Index: src/OFUNIXStreamSocket.h ================================================================== --- /dev/null +++ src/OFUNIXStreamSocket.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2022 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 "OFStreamSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @protocol OFUNIXStreamSocketDelegate OFUNIXStreamSocket.h \ + * ObjFW/OFUNIXStreamSocket.h + * + * A delegate for OFUNIXStreamSocket. + */ +@protocol OFUNIXStreamSocketDelegate +@end + +/** + * @class OFUNIXStreamSocket OFUNIXStreamSocket.h ObjFW/OFUNIXStreamSocket.h + * + * @brief A class which provides methods to create and use UNIX stream sockets. + * + * To connect to a server, create a socket and connect it. + * To create a server, create a socket, bind it and listen on it. + */ +@interface OFUNIXStreamSocket: OFStreamSocket +{ + OF_RESERVE_IVARS(OFUNIXStreamSocket, 4) +} + +/** + * @brief The delegate for asynchronous operations on the socket. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Connects the OFUNIXStreamSocket to the specified destination. + * + * @param path The path to connect to + */ +- (void)connectToPath: (OFString *)path; + +/** + * @brief Binds the socket to the specified host and port. + * + * @param path The path to bind to + */ +- (void)bindToPath: (OFString *)path; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUNIXStreamSocket.m Index: src/OFUNIXStreamSocket.m ================================================================== --- /dev/null +++ src/OFUNIXStreamSocket.m @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2008-2022 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" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFUNIXStreamSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindFailedException.h" +#import "OFConnectionFailedException.h" + +@implementation OFUNIXStreamSocket +@dynamic delegate; + +- (void)connectToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.un.sun_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFConnectionFailedException + exceptionWithPath: path + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (connect(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFConnectionFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } +} + +- (void)bindToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.un.sun_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindFailedException + exceptionWithPath: path + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } +} +@end Index: src/OFURL.h ================================================================== --- src/OFURL.h +++ src/OFURL.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -131,12 +131,12 @@ * * For example, a query like `key1=value1&key2=value2` would correspond to the * following dictionary: * * @{ - * @"key1": "value1", - * @"key2": "value2" + * @"key1": @"value1", + * @"key2": @"value2" * } */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary; @@ -155,11 +155,11 @@ * @brief The URL as a string. */ @property (readonly, nonatomic) OFString *string; /** - * @brief The URL with relative sub paths resolved. + * @brief The URL with relative subpaths resolved. */ @property (readonly, nonatomic) OFURL *URLByStandardizingPath; #ifdef OF_HAVE_FILES /** Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -555,15 +555,21 @@ if (portString.unsignedLongLongValue > 65535) @throw [OFInvalidFormatException exception]; _port = [[OFNumber alloc] initWithUnsignedShort: portString.unsignedLongLongValue]; - } else + } else { _URLEncodedHost = [[OFString alloc] initWithUTF8String: UTF8String]; - if (!isIPv6Host) + if (_URLEncodedHost.length == 0) { + [_URLEncodedHost release]; + _URLEncodedHost = nil; + } + } + + if (_URLEncodedHost != nil && !isIPv6Host) OFURLVerifyIsEscaped(_URLEncodedHost, [OFCharacterSet URLHostAllowedCharacterSet]); if ((UTF8String = tmp) != NULL) { if ((tmp = strchr(UTF8String, '#')) != NULL) { @@ -586,12 +592,29 @@ OFURLVerifyIsEscaped(_URLEncodedQuery, [OFCharacterSet URLQueryAllowedCharacterSet]); } + /* + * Some versions of GCC issue a false-positive warning + * (turned error) about a string overflow. This is a + * false positive because UTF8String is set to tmp + * above and tmp is either NULL or points *after* the + * slash for the path. So all we do here is go back to + * that slash and restore it. + */ +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpragmas" +# pragma GCC diagnostic ignored "-Wunknown-warning-option" +# pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif UTF8String--; *UTF8String = '/'; +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic pop +#endif _URLEncodedPath = [[OFString alloc] initWithUTF8String: UTF8String]; OFURLVerifyIsEscaped(_URLEncodedPath, Index: src/OFURLHandler.h ================================================================== --- src/OFURLHandler.h +++ src/OFURLHandler.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFURLHandler.m ================================================================== --- src/OFURLHandler.m +++ src/OFURLHandler.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -22,10 +22,11 @@ #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif +#import "OFEmbeddedFileURLHandler.h" #ifdef OF_HAVE_FILES # import "OFFileURLHandler.h" #endif #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) # import "OFHTTPURLHandler.h" @@ -54,10 +55,12 @@ #ifdef OF_HAVE_THREADS mutex = [[OFMutex alloc] init]; atexit(releaseMutex); #endif + [self registerClass: [OFEmbeddedFileURLHandler class] + forScheme: @"objfw-embedded"]; #ifdef OF_HAVE_FILES [self registerClass: [OFFileURLHandler class] forScheme: @"file"]; #endif #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) [self registerClass: [OFHTTPURLHandler class] forScheme: @"http"]; Index: src/OFUTF8String+Private.h ================================================================== --- src/OFUTF8String+Private.h +++ src/OFUTF8String+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFUTF8String.h ================================================================== --- src/OFUTF8String.h +++ src/OFUTF8String.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -1155,10 +1155,11 @@ - (const OFUnichar *)characters { OFUnichar *buffer = OFAllocMemory(_s->length, sizeof(OFUnichar)); size_t i = 0, j = 0; + const OFUnichar *ret; while (i < _s->cStringLength) { OFUnichar c; ssize_t cLen; @@ -1172,20 +1173,28 @@ buffer[j++] = c; i += cLen; } - return [[OFData dataWithItemsNoCopy: buffer - count: _s->length - itemSize: sizeof(OFUnichar) - freeWhenDone: true] items]; + @try { + ret = [[OFData dataWithItemsNoCopy: buffer + count: _s->length + itemSize: sizeof(OFUnichar) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } + + return ret; } - (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder { OFChar32 *buffer = OFAllocMemory(_s->length + 1, sizeof(OFChar32)); size_t i = 0, j = 0; + const OFChar32 *ret; while (i < _s->cStringLength) { OFChar32 c; ssize_t cLen; @@ -1204,14 +1213,21 @@ i += cLen; } buffer[j] = 0; - return [[OFData dataWithItemsNoCopy: buffer - count: _s->length + 1 - itemSize: sizeof(OFChar32) - freeWhenDone: true] items]; + @try { + ret = [[OFData dataWithItemsNoCopy: buffer + count: _s->length + 1 + itemSize: sizeof(OFChar32) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } + + return ret; } #ifdef OF_HAVE_BLOCKS - (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block { ADDED src/OFUUID.h Index: src/OFUUID.h ================================================================== --- /dev/null +++ src/OFUUID.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2022 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" +#import "OFSerialization.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @class OFUUID OFUUID.h ObjFW/OFUUID.h + * + * @brief A UUID conforming to RFC 4122. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFUUID: OFObject +{ + unsigned char _bytes[16]; +} + +/** + * @brief The UUID as a string. + */ +@property (readonly, nonatomic) OFString *UUIDString; + +/** + * @brief Creates a new random UUID as per RFC 4122 version 4. + * + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUID; + +/** + * @brief Creates a new UUID with the specified bytes. + * + * @param bytes The bytes for the UUID + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUIDWithUUIDBytes: (const unsigned char [_Nonnull 16])bytes; + +/** + * @brief Creates a new UUID with the specified UUID string. + * + * @param string The UUID string for the UUID + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUIDWithUUIDString: (OFString *)string; + +/** + * @brief Initializes an already allocated OFUUID as a new random UUID as per + * RFC 4122 version 4. + * + * @return An initialized OFUUID + */ +- (instancetype)init; + +/** + * @brief Initializes an already allocated OFUUID with the specified bytes. + * + * @param bytes The bytes to initialize the OFUUID with + * @return An initialized OFUUID + */ +- (instancetype)initWithUUIDBytes: (const unsigned char [_Nonnull 16])bytes; + +/** + * @brief Initializes an already allocated OFUUID with the specified UUID + * string. + * + * @param string The UUID string to initialize the OFUUID with + * @return An initialized OFUUID + */ +- (instancetype)initWithUUIDString: (OFString *)string; + +/** + * @brief Compares the UUID to another UUID. + * + * @param UUID The UUID to compare to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFUUID *)UUID; + +/** + * @brief Gets the bytes of the UUID. + * + * @param bytes An array of 16 bytes into which to write the UUID + */ +- (void)getUUIDBytes: (unsigned char [_Nonnull 16])bytes; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUUID.m Index: src/OFUUID.m ================================================================== --- /dev/null +++ src/OFUUID.m @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2008-2022 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 "OFUUID.h" +#import "OFArray.h" +#import "OFString.h" +#import "OFXMLElement.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFOutOfRangeException.h" + +#define bytesSize 16 + +@implementation OFUUID ++ (instancetype)UUID +{ + return [[[self alloc] init] autorelease]; +} + ++ (instancetype)UUIDWithUUIDBytes: (const unsigned char [16])bytes +{ + return [[[self alloc] initWithUUIDBytes: bytes] autorelease]; +} + ++ (instancetype)UUIDWithUUIDString: (OFString *)string +{ + return [[[self alloc] initWithUUIDString: string] autorelease]; +} + +- (instancetype)init +{ + uint64_t r; + + self = [super init]; + + r = OFRandom64(); + memcpy(_bytes, &r, 8); + r = OFRandom64(); + memcpy(_bytes + 8, &r, 8); + + _bytes[6] &= ~((1 << 7) | (1 << 5) | (1 << 4)); + _bytes[6] |= (1 << 6); + _bytes[8] &= ~(1 << 6); + _bytes[8] |= (1 << 7); + + return self; +} + +- (instancetype)initWithUUIDBytes: (const unsigned char [16])bytes +{ + self = [super init]; + + memcpy(_bytes, bytes, sizeof(_bytes)); + + return self; +} + +static void +decode(OFArray OF_GENERIC(OFString *) *components, size_t componentIndex, + size_t componentLength, unsigned char *bytes, size_t *i) +{ + void *pool = objc_autoreleasePoolPush(); + OFString *component = [components objectAtIndex: componentIndex]; + const char *cString; + + if (component.UTF8StringLength != componentLength) + @throw [OFInvalidFormatException exception]; + + if (*i + componentLength / 2 > bytesSize) + @throw [OFOutOfRangeException exception]; + + cString = component.UTF8String; + + for (size_t j = 0; j < componentLength; j += 2) { + uint8_t value; + + if (cString[j] >= '0' && cString[j] <= '9') + value = cString[j] - '0'; + else if (cString[j] >= 'a' && cString[j] <= 'f') + value = cString[j] - 'a' + 10; + else if (cString[j] >= 'A' && cString[j] <= 'F') + value = cString[j] - 'A' + 10; + else + @throw [OFInvalidFormatException exception]; + + value <<= 4; + + if (cString[j + 1] >= '0' && cString[j + 1] <= '9') + value |= cString[j + 1] - '0'; + else if (cString[j + 1] >= 'a' && cString[j + 1] <= 'f') + value |= cString[j + 1] - 'a' + 10; + else if (cString[j + 1] >= 'A' && cString[j + 1] <= 'F') + value |= cString[j + 1] - 'A' + 10; + else + @throw [OFInvalidFormatException exception]; + + bytes[(*i)++] = value; + } + + objc_autoreleasePoolPop(pool); +} + +- (instancetype)initWithUUIDString: (OFString *)string +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + size_t i = 0; + OFArray OF_GENERIC(OFString *) *components = + [string componentsSeparatedByString: @"-"]; + + if (components.count != 5) + @throw [OFInvalidFormatException exception]; + + decode(components, 0, 8, _bytes, &i); + decode(components, 1, 4, _bytes, &i); + decode(components, 2, 4, _bytes, &i); + decode(components, 3, 4, _bytes, &i); + decode(components, 4, 12, _bytes, &i); + + OFEnsure(i == 16); + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithSerialization: (OFXMLElement *)element +{ + void *pool = objc_autoreleasePoolPush(); + OFString *UUIDString; + + @try { + if (![element.name isEqual: self.className] || + ![element.namespace isEqual: OFSerializationNS]) + @throw [OFInvalidArgumentException exception]; + + UUIDString = element.stringValue; + } @catch (id e) { + [self release]; + @throw e; + } + + self = [self initWithUUIDString: UUIDString]; + + objc_autoreleasePoolPop(pool); + + return self; +} + +- (bool)isEqual: (id)object +{ + OFUUID *UUID; + + if (![object isKindOfClass: [OFUUID class]]) + return false; + + UUID = object; + + return (memcmp(_bytes, UUID->_bytes, sizeof(_bytes)) == 0); +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + for (size_t i = 0; i < sizeof(_bytes); i++) + OFHashAdd(&hash, _bytes[i]); + + OFHashFinalize(&hash); + + return hash; +} + +- (id)copy +{ + return [self retain]; +} + +- (OFComparisonResult)compare: (OFUUID *)UUID +{ + int comparison; + + if (![UUID isKindOfClass: [OFUUID class]]) + @throw [OFInvalidArgumentException exception]; + + if ((comparison = memcmp(_bytes, UUID->_bytes, sizeof(_bytes))) == 0) + return OFOrderedSame; + + if (comparison > 0) + return OFOrderedDescending; + else + return OFOrderedAscending; +} + +- (void)getUUIDBytes: (unsigned char [16])bytes +{ + memcpy(bytes, _bytes, sizeof(_bytes)); +} + +- (OFString *)UUIDString +{ + return [OFString stringWithFormat: + @"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + @"%02x%02x%02x%02x%02x%02x", + _bytes[0], _bytes[1], _bytes[2], _bytes[3], + _bytes[4], _bytes[5], _bytes[6], _bytes[7], + _bytes[8], _bytes[9], _bytes[10], _bytes[11], + _bytes[12], _bytes[13], _bytes[14], _bytes[15]]; +} + +- (OFString *)description +{ + return self.UUIDString; +} + +- (OFXMLElement *)XMLElementBySerializing +{ + void *pool = objc_autoreleasePoolPush(); + OFXMLElement *element = [OFXMLElement elementWithName: self.className + namespace: OFSerializationNS + stringValue: self.UUIDString]; + + [element retain]; + + objc_autoreleasePoolPop(pool); + + return [element autorelease]; +} +@end Index: src/OFValue.h ================================================================== --- src/OFValue.h +++ src/OFValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFValue.m ================================================================== --- src/OFValue.m +++ src/OFValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFWin32ConsoleStdIOStream.h ================================================================== --- src/OFWin32ConsoleStdIOStream.h +++ src/OFWin32ConsoleStdIOStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFWin32ConsoleStdIOStream.m ================================================================== --- src/OFWin32ConsoleStdIOStream.m +++ src/OFWin32ConsoleStdIOStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFWindowsRegistryKey.h ================================================================== --- src/OFWindowsRegistryKey.h +++ src/OFWindowsRegistryKey.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -74,30 +74,28 @@ * @brief Opens the subkey at the specified path. * * @param path The path of the subkey to open * @param securityAndAccessRights Please refer to the `RegOpenKeyEx()` * documentation for `samDesired` - * @return The subkey with the specified path, or nil if it does not exist + * @return The subkey with the specified path */ -- (nullable OFWindowsRegistryKey *) - openSubkeyAtPath: (OFString *)path - securityAndAccessRights: (REGSAM)securityAndAccessRights; +- (OFWindowsRegistryKey *)openSubkeyAtPath: (OFString *)path + securityAndAccessRights: (REGSAM)securityAndAccessRights; /** * @brief Opens the subkey at the specified path. * * @param path The path of the subkey to open * @param options Please refer to the `RegOpenKeyEx()` documentation for * `ulOptions`. Usually 0. * @param securityAndAccessRights Please refer to the `RegOpenKeyEx()` * documentation for `samDesired` - * @return The subkey with the specified path, or nil if it does not exist + * @return The subkey with the specified path */ -- (nullable OFWindowsRegistryKey *) - openSubkeyAtPath: (OFString *)path - options: (DWORD)options - securityAndAccessRights: (REGSAM)securityAndAccessRights; +- (OFWindowsRegistryKey *)openSubkeyAtPath: (OFString *)path + options: (DWORD)options + securityAndAccessRights: (REGSAM)securityAndAccessRights; /** * @brief Creates a subkey at the specified path or opens it if it already * exists. * @@ -190,10 +188,42 @@ */ - (void)setString: (nullable OFString *)string forValueNamed: (nullable OFString *)name type: (DWORD)type; +/** + * @brief Returns the DWORD for the specified value at the specified path. + * + * @param name The name of the value to return + * @return The DWORD for the specified value + */ +- (uint32_t)DWORDForValueNamed: (nullable OFString *)name; + +/** + * @brief Sets the DWORD for the specified value. + * + * @param dword The DWORD to set the value to + * @param name The name of the value to set + */ +- (void)setDWORD: (uint32_t)dword forValueNamed: (nullable OFString *)name; + +/** + * @brief Returns the QWORD for the specified value at the specified path. + * + * @param name The name of the value to return + * @return The QWORD for the specified value + */ +- (uint64_t)QWORDForValueNamed: (nullable OFString *)name; + +/** + * @brief Sets the QWORD for the specified value. + * + * @param qword The QWORD to set the value to + * @param name The name of the value to set + */ +- (void)setQWORD: (uint64_t)qword forValueNamed: (nullable OFString *)name; + /** * @brief Deletes the specified value. * * @param name The value to delete */ Index: src/OFWindowsRegistryKey.m ================================================================== --- src/OFWindowsRegistryKey.m +++ src/OFWindowsRegistryKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,10 +29,11 @@ #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOpenWindowsRegistryKeyFailedException.h" #import "OFOutOfRangeException.h" #import "OFSetWindowsRegistryValueFailedException.h" +#import "OFUndefinedKeyException.h" OF_DIRECT_MEMBERS @interface OFWindowsRegistryKey () - (instancetype)of_initWithHKey: (HKEY)hKey close: (bool)close; @end @@ -113,23 +114,17 @@ else status = RegOpenKeyExA(_hKey, [path cStringWithEncoding: [OFLocale encoding]], options, securityAndAccessRights, &subKey); - if (status != ERROR_SUCCESS) { - if (status == ERROR_FILE_NOT_FOUND) { - objc_autoreleasePoolPop(pool); - return nil; - } - + if (status != ERROR_SUCCESS) @throw [OFOpenWindowsRegistryKeyFailedException exceptionWithRegistryKey: self path: path options: options securityAndAccessRights: securityAndAccessRights status: status]; - } objc_autoreleasePoolPop(pool); return [[[OFWindowsRegistryKey alloc] of_initWithHKey: subKey close: true] @@ -362,10 +357,75 @@ [self setData: data forValueNamed: name type: type]; objc_autoreleasePoolPop(pool); } + +- (uint32_t)DWORDForValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + DWORD type, ret; + OFData *data = [self dataForValueNamed: name type: &type]; + + if (data == nil) + @throw [OFUndefinedKeyException exceptionWithObject: self + key: name + value: nil]; + + if (type != REG_DWORD) + @throw [OFInvalidEncodingException exception]; + + if (data.count != sizeof(ret) || data.itemSize != 1) + @throw [OFInvalidFormatException exception]; + + memcpy(&ret, data.items, sizeof(ret)); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (void)setDWORD: (uint32_t)dword forValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + OFData *data = [OFData dataWithItems: &dword count: sizeof(dword)]; + [self setData: data forValueNamed: name type: REG_DWORD]; + objc_autoreleasePoolPop(pool); +} + +- (uint64_t)QWORDForValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + DWORD type; + uint64_t ret; + OFData *data = [self dataForValueNamed: name type: &type]; + + if (data == nil) + @throw [OFUndefinedKeyException exceptionWithObject: self + key: name + value: nil]; + + if (type != REG_QWORD) + @throw [OFInvalidEncodingException exception]; + + if (data.count != sizeof(ret) || data.itemSize != 1) + @throw [OFInvalidFormatException exception]; + + memcpy(&ret, data.items, sizeof(ret)); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (void)setQWORD: (uint64_t)qword forValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + OFData *data = [OFData dataWithItems: &qword count: sizeof(qword)]; + [self setData: data forValueNamed: name type: REG_QWORD]; + objc_autoreleasePoolPop(pool); +} - (void)deleteValueNamed: (OFString *)name { void *pool = objc_autoreleasePoolPush(); LSTATUS status; Index: src/OFXMLAttribute.h ================================================================== --- src/OFXMLAttribute.h +++ src/OFXMLAttribute.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -44,11 +44,11 @@ */ #ifndef __cplusplus @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *namespace; #else @property OF_NULLABLE_PROPERTY (readonly, nonatomic, getter=namespace) - OFString *namespace_; + OFString *nameSpace; #endif /** * @brief Creates a new XML attribute. * @@ -61,16 +61,16 @@ /** * @brief Creates a new XML attribute. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The string value of the attribute * @return A new autoreleased OFXMLAttribute with the specified parameters */ + (instancetype)attributeWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; /** * @brief Initializes an already allocated OFXMLAttribute. * @@ -83,17 +83,17 @@ /** * @brief Initializes an already allocated OFXMLAttribute. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The string value of the attribute * @return An initialized OFXMLAttribute with the specified parameters */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; - (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLAttribute.m ================================================================== --- src/OFXMLAttribute.m +++ src/OFXMLAttribute.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLCDATA.h ================================================================== --- src/OFXMLCDATA.h +++ src/OFXMLCDATA.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLCDATA.m ================================================================== --- src/OFXMLCDATA.m +++ src/OFXMLCDATA.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLCharacters.h ================================================================== --- src/OFXMLCharacters.h +++ src/OFXMLCharacters.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLCharacters.m ================================================================== --- src/OFXMLCharacters.m +++ src/OFXMLCharacters.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLComment.h ================================================================== --- src/OFXMLComment.h +++ src/OFXMLComment.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLComment.m ================================================================== --- src/OFXMLComment.m +++ src/OFXMLComment.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLElement+Serialization.h ================================================================== --- src/OFXMLElement+Serialization.h +++ src/OFXMLElement+Serialization.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLElement+Serialization.m ================================================================== --- src/OFXMLElement+Serialization.m +++ src/OFXMLElement+Serialization.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -50,11 +50,11 @@ */ #ifndef __cplusplus @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *namespace; #else @property OF_NULLABLE_PROPERTY (copy, nonatomic, - getter=namespace, setter=setNamespace:) OFString *namespace_; + getter=namespace, setter=setNamespace:) OFString *nameSpace; #endif /** * @brief The default namespace for the element to be used if there is no * parent. @@ -99,29 +99,29 @@ /** * @brief Creates a new XML element with the specified name and namespace. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @return A new autoreleased OFXMLElement with the specified element name and * namespace */ + (instancetype)elementWithName: (OFString *)name - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief Creates a new XML element with the specified name, namespace and * string value. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @param stringValue The value for the element * @return A new autoreleased OFXMLElement with the specified element name, * namespace and value */ + (instancetype)elementWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (nullable OFString *)stringValue; /** * @brief Creates a new element with the specified element. * @@ -173,29 +173,29 @@ /** * @brief Initializes an already allocated OFXMLElement with the specified name * and namespace. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @return An initialized OFXMLElement with the specified element name and * namespace */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief Initializes an already allocated OFXMLElement with the specified name, * namespace and value. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @param stringValue The value for the element * @return An initialized OFXMLElement with the specified element name, * namespace and value */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (nullable OFString *)stringValue; /** * @brief Initializes an already allocated OFXMLElement with the specified * element. @@ -228,21 +228,21 @@ /** * @brief Sets a prefix for a namespace. * * @param prefix The prefix for the namespace - * @param namespace_ The namespace for which the prefix is set + * @param nameSpace The namespace for which the prefix is set */ -- (void)setPrefix: (OFString *)prefix forNamespace: (OFString *)namespace_; +- (void)setPrefix: (OFString *)prefix forNamespace: (OFString *)nameSpace; /** * @brief Binds a prefix for a namespace. * * @param prefix The prefix for the namespace - * @param namespace_ The namespace for which the prefix is bound + * @param nameSpace The namespace for which the prefix is bound */ -- (void)bindPrefix: (OFString *)prefix forNamespace: (OFString *)namespace_; +- (void)bindPrefix: (OFString *)prefix forNamespace: (OFString *)nameSpace; /** * @brief Adds the specified attribute. * * If an attribute with the same name and namespace already exists, it is not @@ -270,15 +270,15 @@ * * If an attribute with the same name and namespace already exists, it is not * added. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The value of the attribute */ - (void)addAttributeWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; /** * @brief Returns the attribute with the specified name. * Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -71,16 +71,16 @@ * an OFMalformedXMLException. * * @param builder The builder which did not expect the close tag * @param name The name of the close tag * @param prefix The prefix of the close tag - * @param namespace_ The namespace of the close tag + * @param nameSpace The namespace of the close tag */ - (void)elementBuilder: (OFXMLElementBuilder *)builder didNotExpectCloseTag: (OFString *)name prefix: (nullable OFString *)prefix - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief This callback is called when the XML parser for the element builder * found an unknown entity. * Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLNode+Private.h ================================================================== --- src/OFXMLNode+Private.h +++ src/OFXMLNode+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLNode.h ================================================================== --- src/OFXMLNode.h +++ src/OFXMLNode.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLNode.m ================================================================== --- src/OFXMLNode.m +++ src/OFXMLNode.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -162,11 +162,11 @@ @property (readonly, nonatomic) size_t lineNumber; /** * @brief Whether the XML parser has finished parsing. */ -@property (readonly, nonatomic) bool hasFinishedParsing; +@property (readonly, nonatomic, getter=hasFinishedParsing) bool finishedParsing; /** * @brief The depth limit for the XML parser. * * If the depth limit is exceeded, an OFMalformedXMLException is thrown. Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLProcessingInstruction.h ================================================================== --- src/OFXMLProcessingInstruction.h +++ src/OFXMLProcessingInstruction.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFXMLProcessingInstruction.m ================================================================== --- src/OFXMLProcessingInstruction.m +++ src/OFXMLProcessingInstruction.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,10 +40,11 @@ #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFSeekFailedException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedVersionException.h" +#import "OFWriteFailedException.h" /* * FIXME: Current limitations: * - Split archives are not supported. * - Encrypted files cannot be read. @@ -432,10 +433,13 @@ void *pool = objc_autoreleasePoolPush(); OFZIPArchiveEntry *entry; OFZIPArchiveLocalFileHeader *localFileHeader; int64_t offset64; + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if ((entry = [_pathToEntryMap objectForKey: path]) == nil) @throw [OFOpenItemFailedException exceptionWithPath: path @@ -482,10 +486,13 @@ OFMutableZIPArchiveEntry *entry; OFString *fileName; OFData *extraField; uint16_t fileNameLength, extraFieldLength; + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + if (_mode != modeWrite && _mode != modeAppend) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); entry = [[entry_ mutableCopy] autorelease]; @@ -874,26 +881,36 @@ [super dealloc]; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t bytesWritten; - #if SIZE_MAX >= INT64_MAX if (length > INT64_MAX) @throw [OFOutOfRangeException exception]; #endif if (INT64_MAX - _bytesWritten < (int64_t)length) @throw [OFOutOfRangeException exception]; - bytesWritten = [_stream writeBuffer: buffer length: length]; + @try { + [_stream writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + OFEnsure(e.bytesWritten <= length); + + _bytesWritten += (int64_t)e.bytesWritten; + _CRC32 = OFCRC32(_CRC32, buffer, e.bytesWritten); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + @throw e; + } - _bytesWritten += (int64_t)bytesWritten; + _bytesWritten += (int64_t)length; _CRC32 = OFCRC32(_CRC32, buffer, length); - return bytesWritten; + return length; } - (void)close { if (_stream == nil) Index: src/OFZIPArchiveEntry+Private.h ================================================================== --- src/OFZIPArchiveEntry+Private.h +++ src/OFZIPArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/OFZIPArchiveEntry.m ================================================================== --- src/OFZIPArchiveEntry.m +++ src/OFZIPArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -43,15 +43,21 @@ #import "OFMethodSignature.h" #import "OFInvocation.h" #import "OFNumber.h" #import "OFDate.h" +#import "OFUUID.h" #import "OFURL.h" #import "OFURLHandler.h" #import "OFColor.h" +#import "OFNotification.h" +#import "OFNotificationCenter.h" + #import "OFStream.h" +#import "OFSeekableStream.h" +#import "OFMemoryStream.h" #import "OFStdIOStream.h" #import "OFInflateStream.h" #import "OFInflate64Stream.h" #import "OFGZIPStream.h" #import "OFLHAArchive.h" @@ -61,20 +67,20 @@ #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFFileManager.h" #ifdef OF_HAVE_FILES # import "OFFile.h" -# import "OFINIFile.h" -# import "OFSettings.h" #endif +#import "OFINIFile.h" +#import "OFSettings.h" #ifdef OF_HAVE_SOCKETS # import "OFStreamSocket.h" # import "OFDatagramSocket.h" # import "OFSequencedPacketSocket.h" # import "OFTCPSocket.h" # import "OFUDPSocket.h" -# import "OFTLSSocket.h" +# import "OFTLSStream.h" # import "OFKernelEventObserver.h" # import "OFDNSQuery.h" # import "OFDNSResourceRecord.h" # import "OFDNSResponse.h" # import "OFDNSResolver.h" @@ -81,10 +87,14 @@ # ifdef OF_HAVE_IPX # import "OFIPXSocket.h" # import "OFSPXSocket.h" # import "OFSPXStreamSocket.h" # endif +# ifdef OF_HAVE_UNIX_SOCKETS +# import "OFUNIXDatagramSocket.h" +# import "OFUNIXStreamSocket.h" +# endif #endif #ifdef OF_HAVE_SOCKETS # ifdef OF_HAVE_THREADS # import "OFHTTPClient.h" # endif @@ -171,10 +181,11 @@ #import "OFGetOptionFailedException.h" #ifdef OF_WINDOWS # import "OFGetWindowsRegistryValueFailedException.h" #endif #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #ifdef OF_HAVE_SOCKETS # import "OFHTTPRequestFailedException.h" #endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" @@ -189,11 +200,10 @@ #ifdef OF_HAVE_PLUGINS # import "OFLoadPluginFailedException.h" #endif #import "OFLockFailedException.h" #import "OFMalformedXMLException.h" -#import "OFMemoryNotPartOfObjectException.h" #import "OFMoveItemFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #ifdef OF_HAVE_SOCKETS # import "OFObserveFailedException.h" @@ -221,10 +231,13 @@ #ifdef OF_HAVE_THREADS # import "OFThreadJoinFailedException.h" # import "OFThreadStartFailedException.h" # import "OFThreadStillRunningException.h" #endif +#ifdef OF_HAVE_SOCKETS +# import "OFTLSHandshakeFailedException.h" +#endif #import "OFTruncatedDataException.h" #import "OFUnboundNamespaceException.h" #import "OFUnboundPrefixException.h" #import "OFUndefinedKeyException.h" #import "OFUnknownXMLEntityException.h" @@ -249,16 +262,9 @@ # import "OFPlainCondition.h" # import "OFPlainMutex.h" # import "OFPlainThread.h" # import "OFRecursiveMutex.h" # import "OFTLSKey.h" -# import "OFThreadPool.h" #endif -#import "OFASPrintF.h" -#import "OFBase64.h" -#import "OFCRC16.h" -#import "OFCRC32.h" -#import "OFHuffmanTree.h" #import "OFPBKDF2.h" #import "OFScrypt.h" -#import "OFStrPTime.h" Index: src/bridge/NSArray+OFObject.h ================================================================== --- src/bridge/NSArray+OFObject.h +++ src/bridge/NSArray+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSArray+OFObject.m ================================================================== --- src/bridge/NSArray+OFObject.m +++ src/bridge/NSArray+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSBridging.h ================================================================== --- src/bridge/NSBridging.h +++ src/bridge/NSBridging.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSDictionary+OFObject.h ================================================================== --- src/bridge/NSDictionary+OFObject.h +++ src/bridge/NSDictionary+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSDictionary+OFObject.m ================================================================== --- src/bridge/NSDictionary+OFObject.m +++ src/bridge/NSDictionary+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSEnumerator+OFObject.h ================================================================== --- src/bridge/NSEnumerator+OFObject.h +++ src/bridge/NSEnumerator+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSEnumerator+OFObject.m ================================================================== --- src/bridge/NSEnumerator+OFObject.m +++ src/bridge/NSEnumerator+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSNumber+OFObject.h ================================================================== --- src/bridge/NSNumber+OFObject.h +++ src/bridge/NSNumber+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSNumber+OFObject.m ================================================================== --- src/bridge/NSNumber+OFObject.m +++ src/bridge/NSNumber+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFArray.h ================================================================== --- src/bridge/NSOFArray.h +++ src/bridge/NSOFArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFArray.m ================================================================== --- src/bridge/NSOFArray.m +++ src/bridge/NSOFArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFDictionary.h ================================================================== --- src/bridge/NSOFDictionary.h +++ src/bridge/NSOFDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFDictionary.m ================================================================== --- src/bridge/NSOFDictionary.m +++ src/bridge/NSOFDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFEnumerator.h ================================================================== --- src/bridge/NSOFEnumerator.h +++ src/bridge/NSOFEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFEnumerator.m ================================================================== --- src/bridge/NSOFEnumerator.m +++ src/bridge/NSOFEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFSet.h ================================================================== --- src/bridge/NSOFSet.h +++ src/bridge/NSOFSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSOFSet.m ================================================================== --- src/bridge/NSOFSet.m +++ src/bridge/NSOFSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSSet+OFObject.h ================================================================== --- src/bridge/NSSet+OFObject.h +++ src/bridge/NSSet+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSSet+OFObject.m ================================================================== --- src/bridge/NSSet+OFObject.m +++ src/bridge/NSSet+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSString+OFObject.h ================================================================== --- src/bridge/NSString+OFObject.h +++ src/bridge/NSString+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/NSString+OFObject.m ================================================================== --- src/bridge/NSString+OFObject.m +++ src/bridge/NSString+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFArray+NSObject.h ================================================================== --- src/bridge/OFArray+NSObject.h +++ src/bridge/OFArray+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFArray+NSObject.m ================================================================== --- src/bridge/OFArray+NSObject.m +++ src/bridge/OFArray+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFBridging.h ================================================================== --- src/bridge/OFBridging.h +++ src/bridge/OFBridging.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFDictionary+NSObject.h ================================================================== --- src/bridge/OFDictionary+NSObject.h +++ src/bridge/OFDictionary+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFDictionary+NSObject.m ================================================================== --- src/bridge/OFDictionary+NSObject.m +++ src/bridge/OFDictionary+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFEnumerator+NSObject.h ================================================================== --- src/bridge/OFEnumerator+NSObject.h +++ src/bridge/OFEnumerator+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFEnumerator+NSObject.m ================================================================== --- src/bridge/OFEnumerator+NSObject.m +++ src/bridge/OFEnumerator+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFException+Swift.h ================================================================== --- src/bridge/OFException+Swift.h +++ src/bridge/OFException+Swift.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFException+Swift.m ================================================================== --- src/bridge/OFException+Swift.m +++ src/bridge/OFException+Swift.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSArray.h ================================================================== --- src/bridge/OFNSArray.h +++ src/bridge/OFNSArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSArray.m ================================================================== --- src/bridge/OFNSArray.m +++ src/bridge/OFNSArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSDictionary.h ================================================================== --- src/bridge/OFNSDictionary.h +++ src/bridge/OFNSDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSDictionary.m ================================================================== --- src/bridge/OFNSDictionary.m +++ src/bridge/OFNSDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSEnumerator.h ================================================================== --- src/bridge/OFNSEnumerator.h +++ src/bridge/OFNSEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSEnumerator.m ================================================================== --- src/bridge/OFNSEnumerator.m +++ src/bridge/OFNSEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSSet.h ================================================================== --- src/bridge/OFNSSet.h +++ src/bridge/OFNSSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNSSet.m ================================================================== --- src/bridge/OFNSSet.m +++ src/bridge/OFNSSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNumber+NSObject.h ================================================================== --- src/bridge/OFNumber+NSObject.h +++ src/bridge/OFNumber+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFNumber+NSObject.m ================================================================== --- src/bridge/OFNumber+NSObject.m +++ src/bridge/OFNumber+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFSet+NSObject.h ================================================================== --- src/bridge/OFSet+NSObject.h +++ src/bridge/OFSet+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFSet+NSObject.m ================================================================== --- src/bridge/OFSet+NSObject.m +++ src/bridge/OFSet+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFString+NSObject.h ================================================================== --- src/bridge/OFString+NSObject.h +++ src/bridge/OFString+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/OFString+NSObject.m ================================================================== --- src/bridge/OFString+NSObject.m +++ src/bridge/OFString+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/bridge/ObjFWBridge.h ================================================================== --- src/bridge/ObjFWBridge.h +++ src/bridge/ObjFWBridge.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/codepage-437.m ================================================================== --- src/encodings/codepage-437.m +++ src/encodings/codepage-437.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/codepage-850.m ================================================================== --- src/encodings/codepage-850.m +++ src/encodings/codepage-850.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/codepage-858.m ================================================================== --- src/encodings/codepage-858.m +++ src/encodings/codepage-858.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/common.h ================================================================== --- src/encodings/common.h +++ src/encodings/common.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/iso-8859-15.m ================================================================== --- src/encodings/iso-8859-15.m +++ src/encodings/iso-8859-15.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/iso-8859-2.m ================================================================== --- src/encodings/iso-8859-2.m +++ src/encodings/iso-8859-2.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/iso-8859-3.m ================================================================== --- src/encodings/iso-8859-3.m +++ src/encodings/iso-8859-3.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/koi8-r.m ================================================================== --- src/encodings/koi8-r.m +++ src/encodings/koi8-r.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/koi8-u.m ================================================================== --- src/encodings/koi8-u.m +++ src/encodings/koi8-u.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/mac-roman.m ================================================================== --- src/encodings/mac-roman.m +++ src/encodings/mac-roman.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/windows-1251.m ================================================================== --- src/encodings/windows-1251.m +++ src/encodings/windows-1251.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/encodings/windows-1252.m ================================================================== --- src/encodings/windows-1252.m +++ src/encodings/windows-1252.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -11,20 +11,20 @@ OFCreateSymbolicLinkFailedException.m \ OFEnumerationMutationException.m \ OFException.m \ OFGetOptionFailedException.m \ OFHashAlreadyCalculatedException.m \ + OFHashNotCalculatedException.m \ OFInitializationFailedException.m \ OFInvalidArgumentException.m \ OFInvalidEncodingException.m \ OFInvalidFormatException.m \ OFInvalidJSONException.m \ OFInvalidServerReplyException.m \ OFLinkFailedException.m \ OFLockFailedException.m \ OFMalformedXMLException.m \ - OFMemoryNotPartOfObjectException.m \ OFMoveItemFailedException.m \ OFNotImplementedException.m \ OFNotOpenException.m \ OFOpenItemFailedException.m \ OFOutOfMemoryException.m \ @@ -59,11 +59,12 @@ OFConnectionFailedException.m \ OFDNSQueryFailedException.m \ OFHTTPRequestFailedException.m \ OFListenFailedException.m \ OFObserveFailedException.m \ - OFResolveHostFailedException.m + OFResolveHostFailedException.m \ + OFTLSHandshakeFailedException.m SRCS_THREADS = OFConditionBroadcastFailedException.m \ OFConditionSignalFailedException.m \ OFConditionStillWaitingException.m \ OFConditionWaitFailedException.m \ OFThreadJoinFailedException.m \ Index: src/exceptions/OFAcceptFailedException.h ================================================================== --- src/exceptions/OFAcceptFailedException.h +++ src/exceptions/OFAcceptFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFAcceptFailedException.m ================================================================== --- src/exceptions/OFAcceptFailedException.m +++ src/exceptions/OFAcceptFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFAllocFailedException.h ================================================================== --- src/exceptions/OFAllocFailedException.h +++ src/exceptions/OFAllocFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFAllocFailedException.m ================================================================== --- src/exceptions/OFAllocFailedException.m +++ src/exceptions/OFAllocFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFAlreadyConnectedException.h ================================================================== --- src/exceptions/OFAlreadyConnectedException.h +++ src/exceptions/OFAlreadyConnectedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFAlreadyConnectedException.m ================================================================== --- src/exceptions/OFAlreadyConnectedException.m +++ src/exceptions/OFAlreadyConnectedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFBindFailedException.h ================================================================== --- src/exceptions/OFBindFailedException.h +++ src/exceptions/OFBindFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,23 +29,25 @@ * * @brief An exception indicating that binding a socket failed. */ @interface OFBindFailedException: OFException { - id _socket; /* IP */ - OFString *_host; + OFString *_Nullable _host; uint16_t _port; /* IPX */ uint8_t _packetType; + /* UNIX socket */ + OFString *_Nullable _path; + id _socket; int _errNo; } /** * @brief The host on which binding failed. */ -@property (readonly, nonatomic) OFString *host; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; /** * @brief The port on which binding failed. */ @property (readonly, nonatomic) uint16_t port; @@ -53,10 +55,15 @@ /** * @brief The IPX packet type for which binding failed. */ @property (readonly, nonatomic) uint8_t packetType; +/** + * @brief The path on which binding failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; + /** * @brief The socket which could not be bound. */ @property (readonly, nonatomic) id socket; @@ -63,12 +70,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased bind failed exception. * * @param host The host on which binding failed * @param port The port on which binding failed @@ -79,10 +84,12 @@ + (instancetype)exceptionWithHost: (OFString *)host port: (uint16_t)port socket: (id)socket errNo: (int)errNo; ++ (instancetype)exception OF_UNAVAILABLE; + /** * @brief Creates a new, autoreleased bind failed exception. * * @param port The IPX port to which binding failed * @param packetType The IPX packet type for which binding failed @@ -93,11 +100,21 @@ + (instancetype)exceptionWithPort: (uint16_t)port packetType: (uint8_t)packetType socket: (id)socket errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; +/** + * @brief Creates a new, autoreleased bind failed exception. + * + * @param path The path on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind failed exception + */ ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; /** * @brief Initializes an already allocated bind failed exception. * * @param host The host on which binding failed @@ -122,8 +139,21 @@ */ - (instancetype)initWithPort: (uint16_t)port packetType: (uint8_t)packetType socket: (id)socket errNo: (int)errNo; +/** + * @brief Initializes an already allocated bind failed exception. + * + * @param path The path on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind failed exception + */ +- (instancetype)initWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFBindFailedException.m ================================================================== --- src/exceptions/OFBindFailedException.m +++ src/exceptions/OFBindFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,11 +17,11 @@ #import "OFBindFailedException.h" #import "OFString.h" @implementation OFBindFailedException -@synthesize host = _host, port = _port, packetType = _packetType; +@synthesize host = _host, port = _port, packetType = _packetType, path = _path; @synthesize socket = _socket, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR @@ -46,10 +46,19 @@ return [[[self alloc] initWithPort: port packetType: packetType socket: sock errNo: errNo] autorelease]; } + ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithPath: path + socket: sock + errNo: errNo] autorelease]; +} - (instancetype)init { OF_INVALID_INIT_METHOD } @@ -91,22 +100,45 @@ @throw e; } return self; } + +- (instancetype)initWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + self = [super init]; + + @try { + _path = [path copy]; + _socket = [sock retain]; + _errNo = errNo; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} - (void)dealloc { [_host release]; + [_path release]; [_socket release]; [super dealloc]; } - (OFString *)description { - if (_host != nil) + if (_path != nil) + return [OFString stringWithFormat: + @"Binding to path %@ failed in socket of type %@: %@", + _path, [_socket class], OFStrError(_errNo)]; + else if (_host != nil) return [OFString stringWithFormat: @"Binding to port %" @PRIu16 @" on host %@ failed in " @"socket of type %@: %@", _port, _host, [_socket class], OFStrError(_errNo)]; else Index: src/exceptions/OFChangeCurrentDirectoryPathFailedException.h ================================================================== --- src/exceptions/OFChangeCurrentDirectoryPathFailedException.h +++ src/exceptions/OFChangeCurrentDirectoryPathFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,12 +40,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased change current directory path failed * exception. * * @param path The path of the directory to which the current path could not be @@ -53,11 +51,11 @@ * @param errNo The errno of the error that occurred * @return A new, autoreleased change current directory path failed exception */ + (instancetype)exceptionWithPath: (OFString *)path errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated change directory failed exception. * * @param path The path of the directory to which the current path could not be @@ -65,8 +63,10 @@ * @param errNo The errno of the error that occurred * @return An initialized change current directory path failed exception */ - (instancetype)initWithPath: (OFString *)path errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFChangeCurrentDirectoryPathFailedException.m ================================================================== --- src/exceptions/OFChangeCurrentDirectoryPathFailedException.m +++ src/exceptions/OFChangeCurrentDirectoryPathFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,23 +19,18 @@ #import "OFString.h" @implementation OFChangeCurrentDirectoryPathFailedException @synthesize path = _path, errNo = _errNo; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithPath: (OFString *)path errNo: (int)errNo { return [[[self alloc] initWithPath: path errNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithPath: (OFString *)path errNo: (int)errNo { self = [super init]; @@ -48,10 +43,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_path release]; Index: src/exceptions/OFChecksumMismatchException.h ================================================================== --- src/exceptions/OFChecksumMismatchException.h +++ src/exceptions/OFChecksumMismatchException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFChecksumMismatchException.m ================================================================== --- src/exceptions/OFChecksumMismatchException.m +++ src/exceptions/OFChecksumMismatchException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFConditionBroadcastFailedException.h ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.h +++ src/exceptions/OFConditionBroadcastFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,11 +37,11 @@ } /** * @brief The condition which could not be broadcasted. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -51,22 +51,24 @@ * * @param condition The condition which could not be broadcasted * @param errNo The errno of the error that occurred * @return A new, autoreleased condition broadcast failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition ++ (instancetype)exceptionWithCondition: (OFCondition *)condition errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated condition broadcast failed exception. * * @param condition The condition which could not be broadcasted * @param errNo The errno of the error that occurred * @return An initialized condition broadcast failed exception */ -- (instancetype)initWithCondition: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionBroadcastFailedException.m ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.m +++ src/exceptions/OFConditionBroadcastFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,10 +28,15 @@ errNo: (int)errNo { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; Index: src/exceptions/OFConditionSignalFailedException.h ================================================================== --- src/exceptions/OFConditionSignalFailedException.h +++ src/exceptions/OFConditionSignalFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,11 +37,11 @@ } /** * @brief The condition which could not be signaled. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -51,22 +51,24 @@ * * @param condition The condition which could not be signaled * @param errNo The errno of the error that occurred * @return A new, autoreleased condition signal failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition ++ (instancetype)exceptionWithCondition: (OFCondition *)condition errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated condition signal failed exception. * * @param condition The condition which could not be signaled * @param errNo The errno of the error that occurred * @return An initialized condition signal failed exception */ -- (instancetype)initWithCondition: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionSignalFailedException.m ================================================================== --- src/exceptions/OFConditionSignalFailedException.m +++ src/exceptions/OFConditionSignalFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,10 +28,15 @@ errNo: (int)errNo { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; Index: src/exceptions/OFConditionStillWaitingException.h ================================================================== --- src/exceptions/OFConditionStillWaitingException.h +++ src/exceptions/OFConditionStillWaitingException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,26 +37,30 @@ } /** * @brief The condition for which is still being waited. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief Creates a new, autoreleased condition still waiting exception. * * @param condition The condition for which is still being waited * @return A new, autoreleased condition still waiting exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition; ++ (instancetype)exceptionWithCondition: (OFCondition *)condition; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated condition still waiting exception. * * @param condition The condition for which is still being waited * @return An initialized condition still waiting exception */ -- (instancetype)initWithCondition: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionStillWaitingException.m ================================================================== --- src/exceptions/OFConditionStillWaitingException.m +++ src/exceptions/OFConditionStillWaitingException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -25,13 +25,13 @@ + (instancetype)exceptionWithCondition: (OFCondition *)condition { return [[[self alloc] initWithCondition: condition] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - return [self initWithCondition: nil]; + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithCondition: (OFCondition *)condition { self = [super init]; @@ -38,10 +38,15 @@ _condition = [condition retain]; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_condition release]; @@ -48,15 +53,11 @@ [super dealloc]; } - (OFString *)description { - if (_condition != nil) - return [OFString stringWithFormat: - @"Deallocation of a condition of type %@ was tried, even " - "though a thread was still waiting for it!", - _condition.class]; - else - return @"Deallocation of a condition was tried, even though a " - "thread was still waiting for it!"; + return [OFString stringWithFormat: + @"Deallocation of a condition of type %@ was tried, even though " + "a thread was still waiting for it!", + _condition.class]; } @end Index: src/exceptions/OFConditionWaitFailedException.h ================================================================== --- src/exceptions/OFConditionWaitFailedException.h +++ src/exceptions/OFConditionWaitFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,11 +37,11 @@ } /** * @brief The condition for which could not be waited. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -51,22 +51,24 @@ * * @param condition The condition for which could not be waited * @param errNo The errno of the error that occurred * @return A new, autoreleased condition wait failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition ++ (instancetype)exceptionWithCondition: (OFCondition *)condition errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated condition wait failed exception. * * @param condition The condition for which could not be waited * @param errNo The errno of the error that occurred * @return An initialized condition wait failed exception */ -- (instancetype)initWithCondition: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionWaitFailedException.m ================================================================== --- src/exceptions/OFConditionWaitFailedException.m +++ src/exceptions/OFConditionWaitFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,10 +28,15 @@ errNo: (int)errNo { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; Index: src/exceptions/OFConnectionFailedException.h ================================================================== --- src/exceptions/OFConnectionFailedException.h +++ src/exceptions/OFConnectionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,23 +29,19 @@ * * @brief An exception indicating that a connection could not be established. */ @interface OFConnectionFailedException: OFException { - id _socket; - OFString *_host; + OFString *_Nullable _host; uint16_t _port; - unsigned char _node[IPX_NODE_LEN]; + OFString *_Nullable _path; uint32_t _network; + unsigned char _node[IPX_NODE_LEN]; + id _socket; int _errNo; } -/** - * @brief The socket which could not connect. - */ -@property (readonly, nonatomic) id socket; - /** * @brief The host to which the connection failed. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; @@ -53,57 +49,78 @@ * @brief The port on the host to which the connection failed. */ @property (readonly, nonatomic) uint16_t port; /** - * @brief The IPX node to which the connection failed. + * @brief The path to which the connection failed. */ -@property (readonly, nonatomic) unsigned char *node; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; /** * @brief The IPX network of the node to which the connection failed. */ @property (readonly, nonatomic) uint32_t network; +/** + * @brief The IPX node to which the connection failed. + */ +@property (readonly, nonatomic) unsigned char *node; + +/** + * @brief The socket which could not connect. + */ +@property (readonly, nonatomic) id socket; + /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased connection failed exception. * * @param host The host to which the connection failed * @param port The port on the host to which the connection failed * @param socket The socket which could not connect * @param errNo The errno of the error that occurred * @return A new, autoreleased connection failed exception */ -+ (instancetype)exceptionWithHost: (nullable OFString *)host ++ (instancetype)exceptionWithHost: (OFString *)host port: (uint16_t)port socket: (id)socket errNo: (int)errNo; /** * @brief Creates a new, autoreleased connection failed exception. * - * @param node The node to which the connection failed + * @param path The path to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return A new, autoreleased connection failed exception + */ ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; + +/** + * @brief Creates a new, autoreleased connection failed exception. + * * @param network The IPX network of the node to which the connection failed + * @param node The node to which the connection failed * @param port The port on the node to which the connection failed * @param socket The socket which could not connect * @param errNo The errno of the error that occurred * @return A new, autoreleased connection failed exception */ -+ (instancetype)exceptionWithNode: (unsigned char [_Nullable IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; ++ (instancetype) + exceptionWithNetwork: (uint32_t)network + node: (unsigned char [_Nullable IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated connection failed exception. * * @param host The host to which the connection failed @@ -110,28 +127,42 @@ * @param port The port on the host to which the connection failed * @param socket The socket which could not connect * @param errNo The errno of the error that occurred * @return An initialized connection failed exception */ -- (instancetype)initWithHost: (nullable OFString *)host +- (instancetype)initWithHost: (OFString *)host port: (uint16_t)port socket: (id)socket errNo: (int)errNo; /** * @brief Initializes an already allocated connection failed exception. * - * @param node The node to which the connection failed + * @param path The path to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return An initialized connection failed exception + */ +- (instancetype)initWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; + +/** + * @brief Initializes an already allocated connection failed exception. + * * @param network The IPX network of the node to which the connection failed + * @param node The node to which the connection failed * @param port The port on the node to which the connection failed * @param socket The socket which could not connect * @param errNo The errno of the error that occurred * @return An initialized connection failed exception */ -- (instancetype)initWithNode: (unsigned char [_Nullable IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; +- (instancetype)initWithNetwork: (uint32_t)network + node: (unsigned char [_Nullable IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConnectionFailedException.m ================================================================== --- src/exceptions/OFConnectionFailedException.m +++ src/exceptions/OFConnectionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,17 +17,12 @@ #import "OFConnectionFailedException.h" #import "OFString.h" @implementation OFConnectionFailedException -@synthesize host = _host, port = _port, network = _network, socket = _socket; -@synthesize errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} +@synthesize host = _host, port = _port, path = _path, network = _network; +@synthesize socket = _socket, errNo = _errNo; + (instancetype)exceptionWithHost: (OFString *)host port: (uint16_t)port socket: (id)sock errNo: (int)errNo @@ -36,26 +31,35 @@ port: port socket: sock errNo: errNo] autorelease]; } -+ (instancetype)exceptionWithNode: (unsigned char [IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithPath: (OFString *)path socket: (id)sock errNo: (int)errNo { - return [[[self alloc] initWithNode: node - network: network - port: port + return [[[self alloc] initWithPath: path socket: sock errNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exceptionWithNetwork: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo { - OF_INVALID_INIT_METHOD + return [[[self alloc] initWithNetwork: network + node: node + port: port + socket: sock + errNo: errNo] autorelease]; } - (instancetype)initWithHost: (OFString *)host port: (uint16_t)port socket: (id)sock @@ -74,21 +78,39 @@ } return self; } -- (instancetype)initWithNode: (unsigned char [IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port +- (instancetype)initWithPath: (OFString *)path socket: (id)sock errNo: (int)errNo { self = [super init]; @try { - memcpy(_node, node, IPX_NODE_LEN); + _path = [path copy]; + _socket = [sock retain]; + _errNo = errNo; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithNetwork: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + self = [super init]; + + @try { _network = network; + memcpy(_node, node, IPX_NODE_LEN); _port = port; _socket = [sock retain]; _errNo = errNo; } @catch (id e) { [self release]; @@ -95,14 +117,20 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_host release]; + [_path release]; [_socket release]; [super dealloc]; } @@ -111,11 +139,16 @@ return _node; } - (OFString *)description { - if (_host != nil) + if (_path != nil) + return [OFString stringWithFormat: + @"A connection to %@ could not be established in socket of " + @"type %@: %@", + _path, [_socket class], OFStrError(_errNo)]; + else if (_host != nil) return [OFString stringWithFormat: @"A connection to %@ on port %" @PRIu16 @" could not be " @"established in socket of type %@: %@", _host, _port, [_socket class], OFStrError(_errNo)]; else if (memcmp(_node, "\0\0\0\0\0", IPX_NODE_LEN) == 0) Index: src/exceptions/OFCopyItemFailedException.h ================================================================== --- src/exceptions/OFCopyItemFailedException.h +++ src/exceptions/OFCopyItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,49 +30,49 @@ OFURL *_sourceURL, *_destinationURL; int _errNo; } /** - * @brief The path of the source item. + * @brief The URL of the source item. */ @property (readonly, nonatomic) OFURL *sourceURL; /** - * @brief The destination path. + * @brief The destination URL. */ @property (readonly, nonatomic) OFURL *destinationURL; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased copy item failed exception. * - * @param sourceURL The original path - * @param destinationURL The new path + * @param sourceURL The URL of the source item + * @param destinationURL The destination URL * @param errNo The errno of the error that occurred * @return A new, autoreleased copy item failed exception */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated copy item failed exception. * - * @param sourceURL The original path - * @param destinationURL The new path + * @param sourceURL The URL of the source item + * @param destinationURL The destination URL * @param errNo The errno of the error that occurred * @return An initialized copy item failed exception */ - (instancetype)initWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCopyItemFailedException.m ================================================================== --- src/exceptions/OFCopyItemFailedException.m +++ src/exceptions/OFCopyItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFCreateDirectoryFailedException.h ================================================================== --- src/exceptions/OFCreateDirectoryFailedException.h +++ src/exceptions/OFCreateDirectoryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,22 +40,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased create directory failed exception. * * @param URL The URL of the directory which could not be created * @param errNo The errno of the error that occurred * @return A new, autoreleased create directory failed exception */ + (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create directory failed exception. * * @param URL The URL of the directory which could not be created @@ -62,8 +60,10 @@ * @param errNo The errno of the error that occurred * @return An initialized create directory failed exception */ - (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCreateDirectoryFailedException.m ================================================================== --- src/exceptions/OFCreateDirectoryFailedException.m +++ src/exceptions/OFCreateDirectoryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFCreateSymbolicLinkFailedException.h ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.h +++ src/exceptions/OFCreateSymbolicLinkFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -46,12 +46,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased create symbolic link failed exception. * * @param URL The URL where the symlink should have been created * @param target The target for the symbolic link @@ -60,11 +58,11 @@ */ + (instancetype)exceptionWithURL: (OFURL *)URL target: (OFString *)target errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create symbolic link failed * exception. * @@ -74,8 +72,10 @@ * @return An initialized create symbolic link failed exception */ - (instancetype)initWithURL: (OFURL *)URL target: (OFString *)target errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCreateSymbolicLinkFailedException.m ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.m +++ src/exceptions/OFCreateSymbolicLinkFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.h +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.m +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFDNSQueryFailedException.h ================================================================== --- src/exceptions/OFDNSQueryFailedException.h +++ src/exceptions/OFDNSQueryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -50,19 +50,23 @@ * @return A new, autoreleased address translation failed exception */ + (instancetype)exceptionWithQuery: (OFDNSQuery *)query errorCode: (OFDNSResolverErrorCode)errorCode; ++ (instancetype)exception OF_UNAVAILABLE; + /** * @brief Initializes an already allocated DNS query failed exception. * * @param query The query which could not be performed * @param errorCode The error from the resolver * @return An initialized address translation failed exception */ - (instancetype)initWithQuery: (OFDNSQuery *)query errorCode: (OFDNSResolverErrorCode)errorCode; + +- (instancetype)init OF_UNAVAILABLE; @end #ifdef __cplusplus extern "C" { #endif Index: src/exceptions/OFDNSQueryFailedException.m ================================================================== --- src/exceptions/OFDNSQueryFailedException.m +++ src/exceptions/OFDNSQueryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -56,10 +56,15 @@ errorCode: (OFDNSResolverErrorCode)errorCode { return [[[self alloc] initWithQuery: query errorCode: errorCode] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithQuery: (OFDNSQuery *)query errorCode: (OFDNSResolverErrorCode)errorCode { self = [super init]; @@ -72,10 +77,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_query release]; Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFEnumerationMutationException.h ================================================================== --- src/exceptions/OFEnumerationMutationException.h +++ src/exceptions/OFEnumerationMutationException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -33,27 +33,27 @@ /** * @brief The object which was mutated during enumeration. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased enumeration mutation exception. * * @param object The object which was mutated during enumeration * @return A new, autoreleased enumeration mutation exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated enumeration mutation exception. * * @param object The object which was mutated during enumeration * @return An initialized enumeration mutation exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFEnumerationMutationException.m ================================================================== --- src/exceptions/OFEnumerationMutationException.m +++ src/exceptions/OFEnumerationMutationException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFException.h ================================================================== --- src/exceptions/OFException.h +++ src/exceptions/OFException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -132,10 +132,14 @@ # endif # ifndef EWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK # endif #endif + +#ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +#endif /** * @class OFException OFException.h ObjFW/OFException.h * * @brief The base class for all exceptions in ObjFW Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFGetCurrentDirectoryPathFailedException.h ================================================================== --- src/exceptions/OFGetCurrentDirectoryPathFailedException.h +++ src/exceptions/OFGetCurrentDirectoryPathFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -33,29 +33,29 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased get current directory path failed * exception. * * @param errNo The errno of the error that occurred * @return A new, autoreleased get current directory failed exception */ + (instancetype)exceptionWithErrNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get current directory path failed * exception. * * @param errNo The errno of the error that occurred * @return An initialized get current directory path failed exception */ - (instancetype)initWithErrNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetCurrentDirectoryPathFailedException.m ================================================================== --- src/exceptions/OFGetCurrentDirectoryPathFailedException.m +++ src/exceptions/OFGetCurrentDirectoryPathFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,23 +19,18 @@ #import "OFString.h" @implementation OFGetCurrentDirectoryPathFailedException @synthesize errNo = _errNo; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithErrNo: (int)errNo { return [[[self alloc] initWithErrNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithErrNo: (int)errNo { self = [super init]; @@ -42,13 +37,18 @@ _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (OFString *)description { return [OFString stringWithFormat: @"Getting the current directory path failed: %@", OFStrError(_errNo)]; } @end Index: src/exceptions/OFGetOptionFailedException.h ================================================================== --- src/exceptions/OFGetOptionFailedException.h +++ src/exceptions/OFGetOptionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,22 +37,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased get option failed exception. * * @param object The object for which the option could not be retrieved * @param errNo The errno of the error that occurred * @return A new, autoreleased get option failed exception */ + (instancetype)exceptionWithObject: (id)object errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get option failed exception. * * @param object The object for which the option could not be retrieved @@ -59,8 +57,10 @@ * @param errNo The errno of the error that occurred * @return An initialized get option failed exception */ - (instancetype)initWithObject: (id)object errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetOptionFailedException.m ================================================================== --- src/exceptions/OFGetOptionFailedException.m +++ src/exceptions/OFGetOptionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFGetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.h +++ src/exceptions/OFGetWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -62,11 +62,11 @@ */ + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey valueName: (nullable OFString *)valueName status: (LSTATUS)status; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get Windows registry value failed * exception. * @@ -77,8 +77,10 @@ * @return An initialized get Windows registry value failed exception */ - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey valueName: (nullable OFString *)valueName status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.m +++ src/exceptions/OFGetWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,13 +28,13 @@ return [[[self alloc] initWithRegistryKey: registryKey valueName: valueName status: status] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey valueName: (OFString *)valueName status: (LSTATUS)status @@ -50,10 +50,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_registryKey release]; [_valueName release]; Index: src/exceptions/OFHTTPRequestFailedException.h ================================================================== --- src/exceptions/OFHTTPRequestFailedException.h +++ src/exceptions/OFHTTPRequestFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -45,12 +45,10 @@ /** * @brief The response for the failed HTTP request. */ @property (readonly, nonatomic) OFHTTPResponse *response; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased HTTP request failed exception. * * @param request The HTTP request which failed * @param response The response for the failed HTTP request @@ -57,11 +55,11 @@ * @return A new, autoreleased HTTP request failed exception */ + (instancetype)exceptionWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated HTTP request failed exception. * * @param request The HTTP request which failed @@ -69,8 +67,10 @@ * @return A new HTTP request failed exception */ - (instancetype)initWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFHTTPRequestFailedException.m ================================================================== --- src/exceptions/OFHTTPRequestFailedException.m +++ src/exceptions/OFHTTPRequestFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,25 +21,20 @@ #import "OFHTTPResponse.h" @implementation OFHTTPRequestFailedException @synthesize request = _request, response = _response; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { return [[[self alloc] initWithRequest: request response: response] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { @@ -48,10 +43,15 @@ _request = [request retain]; _response = [response retain]; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_request release]; [_response release]; Index: src/exceptions/OFHashAlreadyCalculatedException.h ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.h +++ src/exceptions/OFHashAlreadyCalculatedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -32,27 +32,27 @@ /** * @brief The hash which has already been calculated. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased hash already calculated exception. * * @param object The hash which has already been calculated * @return A new, autoreleased hash already calculated exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated hash already calculated exception. * * @param object The hash which has already been calculated * @return An initialized hash already calculated exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFHashAlreadyCalculatedException.m ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.m +++ src/exceptions/OFHashAlreadyCalculatedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 ADDED src/exceptions/OFHashNotCalculatedException.h Index: src/exceptions/OFHashNotCalculatedException.h ================================================================== --- /dev/null +++ src/exceptions/OFHashNotCalculatedException.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2022 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 "OFException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFHashNotCalculatedException OFHashNotCalculatedException.h \ + * ObjFW/OFHashNotCalculatedException.h + * + * @brief An exception indicating that the hash has not been calculated yet. + */ +@interface OFHashNotCalculatedException: OFException +{ + id _object; +} + +/** + * @brief The hash which has not been calculated yet. + */ +@property (readonly, nonatomic) id object; + +/** + * @brief Creates a new, autoreleased hash not calculated exception. + * + * @param object The hash which has not been calculated yet + * @return A new, autoreleased hash not calculated exception + */ ++ (instancetype)exceptionWithObject: (id)object; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated hash not calculated exception. + * + * @param object The hash which has not been calculated yet + * @return An initialized hash not calculated exception + */ +- (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFHashNotCalculatedException.m Index: src/exceptions/OFHashNotCalculatedException.m ================================================================== --- /dev/null +++ src/exceptions/OFHashNotCalculatedException.m @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2022 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 "OFHashNotCalculatedException.h" +#import "OFString.h" + +@implementation OFHashNotCalculatedException +@synthesize object = _object; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithObject: (id)object +{ + return [[[self alloc] initWithObject: object] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithObject: (id)object +{ + self = [super init]; + + _object = [object retain]; + + return self; +} + +- (void)dealloc +{ + [_object release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"The hash of type %@ has not been calculated yet!", + [_object class]]; +} +@end Index: src/exceptions/OFInitializationFailedException.h ================================================================== --- src/exceptions/OFInitializationFailedException.h +++ src/exceptions/OFInitializationFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInitializationFailedException.m ================================================================== --- src/exceptions/OFInitializationFailedException.m +++ src/exceptions/OFInitializationFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidArgumentException.h ================================================================== --- src/exceptions/OFInvalidArgumentException.h +++ src/exceptions/OFInvalidArgumentException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidArgumentException.m ================================================================== --- src/exceptions/OFInvalidArgumentException.m +++ src/exceptions/OFInvalidArgumentException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidEncodingException.h ================================================================== --- src/exceptions/OFInvalidEncodingException.h +++ src/exceptions/OFInvalidEncodingException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidEncodingException.m ================================================================== --- src/exceptions/OFInvalidEncodingException.m +++ src/exceptions/OFInvalidEncodingException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidFormatException.h ================================================================== --- src/exceptions/OFInvalidFormatException.h +++ src/exceptions/OFInvalidFormatException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidFormatException.m ================================================================== --- src/exceptions/OFInvalidFormatException.m +++ src/exceptions/OFInvalidFormatException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidJSONException.h ================================================================== --- src/exceptions/OFInvalidJSONException.h +++ src/exceptions/OFInvalidJSONException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,12 +37,10 @@ /** * @brief The line in which parsing the JSON representation failed. */ @property (readonly, nonatomic) size_t line; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased invalid JSON exception. * * @param string The string containing the invalid JSON representation * @param line The line in which the parsing error was encountered @@ -49,11 +47,11 @@ * @return A new, autoreleased invalid JSON exception */ + (instancetype)exceptionWithString: (nullable OFString *)string line: (size_t)line; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated invalid JSON exception. * * @param string The string containing the invalid JSON representation @@ -60,8 +58,10 @@ * @param line The line in which the parsing error was encountered * @return An initialized invalid JSON exception */ - (instancetype)initWithString: (nullable OFString *)string line: (size_t)line OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFInvalidJSONException.m ================================================================== --- src/exceptions/OFInvalidJSONException.m +++ src/exceptions/OFInvalidJSONException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidServerReplyException.h ================================================================== --- src/exceptions/OFInvalidServerReplyException.h +++ src/exceptions/OFInvalidServerReplyException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFInvalidServerReplyException.m ================================================================== --- src/exceptions/OFInvalidServerReplyException.m +++ src/exceptions/OFInvalidServerReplyException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFLinkFailedException.h ================================================================== --- src/exceptions/OFLinkFailedException.h +++ src/exceptions/OFLinkFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -44,12 +44,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased link failed exception. * * @param sourceURL The source for the link * @param destinationURL The destination for the link @@ -58,11 +56,11 @@ */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated link failed exception. * * @param sourceURL The source for the link @@ -71,8 +69,10 @@ * @return An initialized link failed exception */ - (instancetype)initWithSourceURL: (OFURL*)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLinkFailedException.m ================================================================== --- src/exceptions/OFLinkFailedException.m +++ src/exceptions/OFLinkFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFListenFailedException.h ================================================================== --- src/exceptions/OFListenFailedException.h +++ src/exceptions/OFListenFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -46,12 +46,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased listen failed exception. * * @param socket The socket which failed to listen * @param backlog The requested size of the back log @@ -60,21 +58,23 @@ */ + (instancetype)exceptionWithSocket: (id)socket backlog: (int)backlog errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** - * @brief Initializes an already allocated listen failed exception + * @brief Initializes an already allocated listen failed exception. * * @param socket The socket which failed to listen * @param backlog The requested size of the back log * @param errNo The errno of the error that occurred * @return An initialized listen failed exception */ - (instancetype)initWithSocket: (id)socket backlog: (int)backlog errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFListenFailedException.m ================================================================== --- src/exceptions/OFListenFailedException.m +++ src/exceptions/OFListenFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFLoadPluginFailedException.h ================================================================== --- src/exceptions/OFLoadPluginFailedException.h +++ src/exceptions/OFLoadPluginFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,12 +36,10 @@ /** * @brief The error why the plugin could not be loaded, as a string */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *error; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased load plugin failed exception. * * @param path The path of the plugin which could not be loaded * @param error The error why the plugin could not be loaded, as a string @@ -48,11 +46,11 @@ * @return A new, autoreleased load plugin failed exception */ + (instancetype)exceptionWithPath: (OFString *)path error: (nullable OFString *)error; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated load plugin failed exception. * * @param path The path of the plugin which could not be loaded @@ -60,8 +58,10 @@ * @return An initialized load plugin failed exception */ - (instancetype)initWithPath: (OFString *)path error: (nullable OFString *)error OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLoadPluginFailedException.m ================================================================== --- src/exceptions/OFLoadPluginFailedException.m +++ src/exceptions/OFLoadPluginFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,23 +19,18 @@ #import "OFString.h" @implementation OFLoadPluginFailedException @synthesize path = _path, error = _error; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithPath: (OFString *)path error: (OFString *)error { return [[[self alloc] initWithPath: path error: error] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithPath: (OFString *)path error: (OFString *)error { self = [super init]; @@ -48,10 +43,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_path release]; [_error release]; Index: src/exceptions/OFLockFailedException.h ================================================================== --- src/exceptions/OFLockFailedException.h +++ src/exceptions/OFLockFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,11 +24,11 @@ * * @brief An exception indicating that locking a lock failed. */ @interface OFLockFailedException: OFException { - id _lock; + id _Nullable _lock; int _errNo; } /** * @brief The lock which could not be locked. @@ -57,10 +57,8 @@ * @param errNo The errno of the error that occurred * @return An initialized lock failed exception */ - (instancetype)initWithLock: (nullable id )lock errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLockFailedException.m ================================================================== --- src/exceptions/OFLockFailedException.m +++ src/exceptions/OFLockFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,24 +36,22 @@ _errNo = errNo; return self; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (void)dealloc { [_lock release]; [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"A lock of type %@ could not be locked: %s", - [_lock class], strerror(_errNo)]; + if (_lock != nil) + return [OFString stringWithFormat: + @"A lock of type %@ could not be locked: %s", + [_lock class], strerror(_errNo)]; + else + return @"A lock could not be locked!"; } @end Index: src/exceptions/OFMalformedXMLException.h ================================================================== --- src/exceptions/OFMalformedXMLException.h +++ src/exceptions/OFMalformedXMLException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFMalformedXMLException.m ================================================================== --- src/exceptions/OFMalformedXMLException.m +++ src/exceptions/OFMalformedXMLException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 DELETED src/exceptions/OFMemoryNotPartOfObjectException.h Index: src/exceptions/OFMemoryNotPartOfObjectException.h ================================================================== --- src/exceptions/OFMemoryNotPartOfObjectException.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFException.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFMemoryNotPartOfObjectException \ - * OFMemoryNotPartOfObjectException.h \ - * ObjFW/OFMemoryNotPartOfObjectException.h - * - * @brief An exception indicating the given memory is not part of the object. - */ -@interface OFMemoryNotPartOfObjectException: OFException -{ - void *_Nullable _pointer; - id _object; -} - -/** - * @brief A pointer to the memory which is not part of the object. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *pointer; - -/** - * @brief The object which the memory is not part of. - */ -@property (readonly, nonatomic) id object; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Creates a new, autoreleased memory not part of object exception. - * - * @param pointer A pointer to the memory that is not part of the object - * @param object The object which the memory is not part of - * @return A new, autoreleased memory not part of object exception - */ -+ (instancetype)exceptionWithPointer: (nullable void *)pointer - object: (id)object; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated memory not part of object exception. - * - * @param pointer A pointer to the memory that is not part of the object - * @param object The object which the memory is not part of - * @return An initialized memory not part of object exception - */ -- (instancetype)initWithPointer: (nullable void *)pointer - object: (id)object OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFMemoryNotPartOfObjectException.m Index: src/exceptions/OFMemoryNotPartOfObjectException.m ================================================================== --- src/exceptions/OFMemoryNotPartOfObjectException.m +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFMemoryNotPartOfObjectException.h" -#import "OFString.h" - -@implementation OFMemoryNotPartOfObjectException -@synthesize pointer = _pointer, object = _object; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithPointer: (void *)pointer object: (id)object -{ - return [[[self alloc] initWithPointer: pointer - object: object] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPointer: (void *)pointer object: (id)object -{ - self = [super init]; - - _pointer = pointer; - _object = [object retain]; - - return self; -} - -- (void)dealloc -{ - [_object release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Deallocation or reallocation of memory not allocated as part of " - @"object of type %@ was attempted! It is also possible that there " - @"was an attempt to free the same memory twice.", - [_object class]]; -} -@end Index: src/exceptions/OFMoveItemFailedException.h ================================================================== --- src/exceptions/OFMoveItemFailedException.h +++ src/exceptions/OFMoveItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -44,12 +44,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased move item failed exception. * * @param sourceURL The original URL * @param destinationURL The new URL @@ -58,11 +56,11 @@ */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated move item failed exception. * * @param sourceURL The original URL @@ -71,8 +69,10 @@ * @return An initialized move item failed exception */ - (instancetype)initWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFMoveItemFailedException.m ================================================================== --- src/exceptions/OFMoveItemFailedException.m +++ src/exceptions/OFMoveItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFNotImplementedException.h ================================================================== --- src/exceptions/OFNotImplementedException.h +++ src/exceptions/OFNotImplementedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,13 +36,11 @@ @property (readonly, nonatomic) SEL selector; /** * @brief The object which does not (fully) implement the selector. */ -@property (readonly, nonatomic) id object; - -+ (instancetype)exception OF_UNAVAILABLE; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; /** * @brief Creates a new, autoreleased not implemented exception. * * @param selector The selector which is not or not fully implemented @@ -50,11 +48,11 @@ * @return A new, autoreleased not implemented exception */ + (instancetype)exceptionWithSelector: (SEL)selector object: (nullable id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated not implemented exception. * * @param selector The selector which is not or not fully implemented @@ -61,8 +59,10 @@ * @param object The object which does not (fully) implement the selector * @return An initialized not implemented exception */ - (instancetype)initWithSelector: (SEL)selector object: (nullable id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFNotImplementedException.m ================================================================== --- src/exceptions/OFNotImplementedException.m +++ src/exceptions/OFNotImplementedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFNotOpenException.h ================================================================== --- src/exceptions/OFNotOpenException.h +++ src/exceptions/OFNotOpenException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,27 +30,27 @@ /** * @brief The object which is not open, connected or bound. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased not open exception. * * @param object The object which is not open, connected or bound * @return A new, autoreleased not open exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated not open exception. * * @param object The object which is not open, connected or bound * @return An initialized not open exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFNotOpenException.m ================================================================== --- src/exceptions/OFNotOpenException.m +++ src/exceptions/OFNotOpenException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFObserveFailedException.h ================================================================== --- src/exceptions/OFObserveFailedException.h +++ src/exceptions/OFObserveFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,12 +39,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased observe failed exception. * * @param observer The observer which failed to observe * @param errNo The errno of the error that occurred @@ -51,11 +49,11 @@ * @return A new, autoreleased observe failed exception */ + (instancetype)exceptionWithObserver: (OFKernelEventObserver *)observer errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated observe failed exception. * * @param observer The observer which failed to observe @@ -62,8 +60,10 @@ * @param errNo The errno of the error that occurred * @return An initialized observe failed exception */ - (instancetype)initWithObserver: (OFKernelEventObserver *)observer errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFObserveFailedException.m ================================================================== --- src/exceptions/OFObserveFailedException.m +++ src/exceptions/OFObserveFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFOpenItemFailedException.h ================================================================== --- src/exceptions/OFOpenItemFailedException.h +++ src/exceptions/OFOpenItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -51,12 +51,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased open item failed exception. * * @param URL The URL of the item which could not be opened * @param mode A string with the mode in which the item should have been opened @@ -77,11 +75,11 @@ */ + (instancetype)exceptionWithPath: (OFString *)path mode: (nullable OFString *)mode errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated open item failed exception. * * @param URL The URL of the item which could not be opened @@ -102,8 +100,10 @@ * @return An initialized open item failed exception */ - (instancetype)initWithPath: (OFString *)path mode: (nullable OFString *)mode errNo: (int)errNo; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFOpenItemFailedException.m ================================================================== --- src/exceptions/OFOpenItemFailedException.m +++ src/exceptions/OFOpenItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,15 +20,10 @@ #import "OFURL.h" @implementation OFOpenItemFailedException @synthesize URL = _URL, path = _path, mode = _mode, errNo = _errNo; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithURL: (OFURL *)URL mode: (OFString *)mode errNo: (int)errNo { return [[[self alloc] initWithURL: URL @@ -43,13 +38,13 @@ return [[[self alloc] initWithPath: path mode: mode errNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithURL: (OFURL *)URL mode: (OFString *)mode errNo: (int)errNo @@ -83,10 +78,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_URL release]; [_path release]; Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.h +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -80,11 +80,11 @@ path: (OFString *)path options: (DWORD)options securityAndAccessRights: (REGSAM)securityAndAccessRights status: (LSTATUS)status; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated open Windows registry key failed * exception. * @@ -100,8 +100,10 @@ initWithRegistryKey: (OFWindowsRegistryKey *)registryKey path: (OFString *)path options: (DWORD)options securityAndAccessRights: (REGSAM)securityAndAccessRights status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.m +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -34,13 +34,13 @@ options: options securityAndAccessRights: securityAndAccessRights status: status] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype) initWithRegistryKey: (OFWindowsRegistryKey *)registryKey path: (OFString *)path @@ -61,10 +61,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_registryKey release]; [_path release]; Index: src/exceptions/OFOutOfMemoryException.h ================================================================== --- src/exceptions/OFOutOfMemoryException.h +++ src/exceptions/OFOutOfMemoryException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFOutOfMemoryException.m ================================================================== --- src/exceptions/OFOutOfMemoryException.m +++ src/exceptions/OFOutOfMemoryException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFOutOfRangeException.h ================================================================== --- src/exceptions/OFOutOfRangeException.h +++ src/exceptions/OFOutOfRangeException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFOutOfRangeException.m ================================================================== --- src/exceptions/OFOutOfRangeException.m +++ src/exceptions/OFOutOfRangeException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFReadFailedException.h ================================================================== --- src/exceptions/OFReadFailedException.h +++ src/exceptions/OFReadFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFReadFailedException.m ================================================================== --- src/exceptions/OFReadFailedException.m +++ src/exceptions/OFReadFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,10 +19,15 @@ #import "OFString.h" @implementation OFReadFailedException - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to read %zu bytes from an object of type %@: %@", - _requestedLength, [_object class], OFStrError(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to read %zu bytes from an object of type %@: %@", + _requestedLength, [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to read %zu bytes from an object of type %@", + _requestedLength, [_object class]]; } @end Index: src/exceptions/OFReadOrWriteFailedException.h ================================================================== --- src/exceptions/OFReadOrWriteFailedException.h +++ src/exceptions/OFReadOrWriteFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFReadOrWriteFailedException.m ================================================================== --- src/exceptions/OFReadOrWriteFailedException.m +++ src/exceptions/OFReadOrWriteFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -61,11 +61,17 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to read or write %zu bytes from / to an object of type " - @"%@: %@", - _requestedLength, [_object class], OFStrError(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to read or write %zu bytes from / to an object of " + @"type %@: %@", + _requestedLength, [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to read or write %zu bytes from / to an object of " + @"type %@", + _requestedLength, [_object class]]; } @end Index: src/exceptions/OFRemoveItemFailedException.h ================================================================== --- src/exceptions/OFRemoveItemFailedException.h +++ src/exceptions/OFRemoveItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,22 +39,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased remove failed exception. * * @param URL The URL of the item which could not be removed * @param errNo The errno of the error that occurred * @return A new, autoreleased remove item failed exception */ + (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated remove failed exception. * * @param URL The URL of the item which could not be removed @@ -61,8 +59,10 @@ * @param errNo The errno of the error that occurred * @return An initialized remove item failed exception */ - (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFRemoveItemFailedException.m ================================================================== --- src/exceptions/OFRemoveItemFailedException.m +++ src/exceptions/OFRemoveItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFResolveHostFailedException.h ================================================================== --- src/exceptions/OFResolveHostFailedException.h +++ src/exceptions/OFResolveHostFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -57,10 +57,12 @@ */ + (instancetype)exceptionWithHost: (OFString *)host addressFamily: (OFSocketAddressFamily)addressFamily errorCode: (OFDNSResolverErrorCode)errorCode; ++ (instancetype)exception OF_UNAVAILABLE; + /** * @brief Initializes an already allocated resolve host failed exception. * * @param host The host which could not be resolved * @param addressFamily The address family for which the host could not be @@ -69,8 +71,10 @@ * @return An initialized address translation failed exception */ - (instancetype)initWithHost: (OFString *)host addressFamily: (OFSocketAddressFamily)addressFamily errorCode: (OFDNSResolverErrorCode)errorCode; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFResolveHostFailedException.m ================================================================== --- src/exceptions/OFResolveHostFailedException.m +++ src/exceptions/OFResolveHostFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,10 +29,15 @@ { return [[[self alloc] initWithHost: host addressFamily: addressFamily errorCode: errorCode] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithHost: (OFString *)host addressFamily: (OFSocketAddressFamily)addressFamily errorCode: (OFDNSResolverErrorCode)errorCode { @@ -47,10 +52,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_host release]; Index: src/exceptions/OFRetrieveItemAttributesFailedException.h ================================================================== --- src/exceptions/OFRetrieveItemAttributesFailedException.h +++ src/exceptions/OFRetrieveItemAttributesFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,22 +40,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased retrieve item attributes failed exception. * * @param URL The URL of the item whose attributes could not be retrieved * @param errNo The errno of the error that occurred * @return A new, autoreleased retrieve item attributes failed exception */ + (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated retrieve item attributes failed * exception. * @@ -63,8 +61,10 @@ * @param errNo The errno of the error that occurred * @return An initialized retrieve item attributes failed exception */ - (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFRetrieveItemAttributesFailedException.m ================================================================== --- src/exceptions/OFRetrieveItemAttributesFailedException.m +++ src/exceptions/OFRetrieveItemAttributesFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSandboxActivationFailedException.h ================================================================== --- src/exceptions/OFSandboxActivationFailedException.h +++ src/exceptions/OFSandboxActivationFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSandboxActivationFailedException.m ================================================================== --- src/exceptions/OFSandboxActivationFailedException.m +++ src/exceptions/OFSandboxActivationFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSeekFailedException.h ================================================================== --- src/exceptions/OFSeekFailedException.h +++ src/exceptions/OFSeekFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -49,12 +49,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased seek failed exception. * * @param stream The stream for which seeking failed * @param offset The offset to which seeking failed @@ -65,11 +63,11 @@ + (instancetype)exceptionWithStream: (OFSeekableStream *)stream offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated seek failed exception. * * @param stream The stream for which seeking failed @@ -80,8 +78,10 @@ */ - (instancetype)initWithStream: (OFSeekableStream *)stream offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSeekFailedException.m ================================================================== --- src/exceptions/OFSeekFailedException.m +++ src/exceptions/OFSeekFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSetItemAttributesFailedException.h ================================================================== --- src/exceptions/OFSetItemAttributesFailedException.h +++ src/exceptions/OFSetItemAttributesFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -53,12 +53,10 @@ /** * @brief The first attribute that could not be set. */ @property (readonly, nonatomic) OFFileAttributeKey failedAttribute; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased set item attributes failed exception. * * @param URL The URL of the item whose attributes could not be set * @param attributes The attributes that should have been set for the specified @@ -70,11 +68,11 @@ + (instancetype)exceptionWithURL: (OFURL *)URL attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set item attributes failed exception. * * @param URL The URL of the item whose attributes could not be set @@ -86,8 +84,10 @@ */ - (instancetype)initWithURL: (OFURL *)URL attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetItemAttributesFailedException.m ================================================================== --- src/exceptions/OFSetItemAttributesFailedException.m +++ src/exceptions/OFSetItemAttributesFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSetOptionFailedException.h ================================================================== --- src/exceptions/OFSetOptionFailedException.h +++ src/exceptions/OFSetOptionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -37,22 +37,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased set option failed exception. * * @param object The object for which the option could not be set * @param errNo The errno of the error that occurred * @return A new, autoreleased set option failed exception */ + (instancetype)exceptionWithObject: (id)object errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set option failed exception. * * @param object The object for which the option could not be set @@ -59,8 +57,10 @@ * @param errNo The errno of the error that occurred * @return An initialized set option failed exception */ - (instancetype)initWithObject: (id)object errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetOptionFailedException.m ================================================================== --- src/exceptions/OFSetOptionFailedException.m +++ src/exceptions/OFSetOptionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.h +++ src/exceptions/OFSetWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFSetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.m +++ src/exceptions/OFSetWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFStillLockedException.h ================================================================== --- src/exceptions/OFStillLockedException.h +++ src/exceptions/OFStillLockedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,11 +24,11 @@ * * @brief An exception indicating that a lock is still locked. */ @interface OFStillLockedException: OFException { - id _lock; + id _Nullable _lock; } /** * @brief The lock which is still locked. */ Index: src/exceptions/OFStillLockedException.m ================================================================== --- src/exceptions/OFStillLockedException.m +++ src/exceptions/OFStillLockedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 ADDED src/exceptions/OFTLSHandshakeFailedException.h Index: src/exceptions/OFTLSHandshakeFailedException.h ================================================================== --- /dev/null +++ src/exceptions/OFTLSHandshakeFailedException.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008-2022 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 "OFException.h" + +#ifndef OF_HAVE_SOCKETS +# error No sockets available! +#endif + +#import "OFTLSStream.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFTLSHandshakeFailedException_reference; +#ifdef __cplusplus +} +#endif + +/** + * @class OFTLSHandshakeFailedException \ + * OFTLSHandshakeFailedException.h ObjFW/OFTLSHandshakeFailedException.h + * + * @brief An exception indicating that a TLS handshake. + */ +@interface OFTLSHandshakeFailedException: OFException +{ + OFTLSStream *_stream; + OFString *_Nullable _host; + OFTLSStreamErrorCode _errorCode; +} + +/** + * @brief The TLS stream which failed the handshake. + */ +@property (readonly, nonatomic) OFTLSStream *stream; + +/** + * @brief The host for the handshake. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; + +/** + * @brief The error code from the TLS stream. + */ +@property (readonly, nonatomic) OFTLSStreamErrorCode errorCode; + +/** + * @brief Creates a new, autoreleased TLS handshake failed exception. + * + * @param stream The TLS stream which failed the handshake + * @param host The host for the handshake + * @param errorCode The error code from the TLS stream + * @return A new, autoreleased TLS handshake failed exception + */ ++ (instancetype)exceptionWithStream: (OFTLSStream *)stream + host: (nullable OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated TLS handshake failed exception. + * + * @param stream The TLS stream which failed the handshake + * @param host The host for the handshake + * @param errorCode The error code from the TLS stream + * @return An initialized TLS handshake failed exception + */ +- (instancetype)initWithStream: (OFTLSStream *)stream + host: (nullable OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFTLSHandshakeFailedException.m Index: src/exceptions/OFTLSHandshakeFailedException.m ================================================================== --- /dev/null +++ src/exceptions/OFTLSHandshakeFailedException.m @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSHandshakeFailedException.h" +#import "OFString.h" + +int _OFTLSHandshakeFailedException_reference; + +@implementation OFTLSHandshakeFailedException +@synthesize stream = _stream, host = _host, errorCode = _errorCode; + ++ (instancetype)exceptionWithStream: (OFTLSStream *)stream + host: (OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode +{ + return [[[self alloc] initWithStream: stream + host: host + errorCode: errorCode] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithStream: (OFTLSStream *)stream + host: (OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode +{ + self = [super init]; + + @try { + _stream = [stream retain]; + _host = [host copy]; + _errorCode = errorCode; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_stream release]; + [_host release]; + + [super dealloc]; +} + +- (OFString *)description +{ + if (_host != nil) + return [OFString stringWithFormat: + @"TLS handshake in class %@ with host %@ failed: %@", + _stream.class, _host, + OFTLSStreamErrorCodeDescription(_errorCode)]; + else + return [OFString stringWithFormat: + @"TLS handshake in class %@ failed: %@", + _stream.class, OFTLSStreamErrorCodeDescription(_errorCode)]; +} +@end Index: src/exceptions/OFThreadJoinFailedException.h ================================================================== --- src/exceptions/OFThreadJoinFailedException.h +++ src/exceptions/OFThreadJoinFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,11 +29,11 @@ * * @brief An exception indicating that joining a thread failed. */ @interface OFThreadJoinFailedException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; int _errNo; } /** * @brief The thread which could not be joined. @@ -52,10 +52,12 @@ * @param errNo The errno of the error that occurred * @return A new, autoreleased thread join failed exception */ + (instancetype)exceptionWithThread: (nullable OFThread *)thread errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated thread join failed exception. * * @param thread The thread which could not be joined Index: src/exceptions/OFThreadJoinFailedException.m ================================================================== --- src/exceptions/OFThreadJoinFailedException.m +++ src/exceptions/OFThreadJoinFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,10 +26,15 @@ + (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo { return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo { self = [super init]; Index: src/exceptions/OFThreadStartFailedException.h ================================================================== --- src/exceptions/OFThreadStartFailedException.h +++ src/exceptions/OFThreadStartFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,11 +29,11 @@ * * @brief An exception indicating that starting a thread failed. */ @interface OFThreadStartFailedException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; int _errNo; } /** * @brief The thread which could not be started. @@ -52,10 +52,12 @@ * @param errNo The errno of the error that occurred * @return A new, autoreleased thread start failed exception */ + (instancetype)exceptionWithThread: (nullable OFThread *)thread errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated thread start failed exception. * * @param thread The thread which could not be started Index: src/exceptions/OFThreadStartFailedException.m ================================================================== --- src/exceptions/OFThreadStartFailedException.m +++ src/exceptions/OFThreadStartFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,10 +26,15 @@ + (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo { return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} - (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo { self = [super init]; Index: src/exceptions/OFThreadStillRunningException.h ================================================================== --- src/exceptions/OFThreadStillRunningException.h +++ src/exceptions/OFThreadStillRunningException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,11 +29,11 @@ * * @brief An exception indicating that a thread is still running. */ @interface OFThreadStillRunningException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; } /** * @brief The thread which is still running. */ Index: src/exceptions/OFThreadStillRunningException.m ================================================================== --- src/exceptions/OFThreadStillRunningException.m +++ src/exceptions/OFThreadStillRunningException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFTruncatedDataException.h ================================================================== --- src/exceptions/OFTruncatedDataException.h +++ src/exceptions/OFTruncatedDataException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFTruncatedDataException.m ================================================================== --- src/exceptions/OFTruncatedDataException.m +++ src/exceptions/OFTruncatedDataException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFUnboundNamespaceException.h ================================================================== --- src/exceptions/OFUnboundNamespaceException.h +++ src/exceptions/OFUnboundNamespaceException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -35,40 +35,40 @@ * @brief The unbound namespace. */ #ifndef __cplusplus @property (readonly, nonatomic) OFString *namespace; #else -@property (readonly, nonatomic, getter=namespace) OFString *namespace_; +@property (readonly, nonatomic, getter=namespace) OFString *nameSpace; #endif /** * @brief The element in which the namespace was not bound. */ @property (readonly, nonatomic) OFXMLElement *element; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unbound namespace exception. * - * @param namespace_ The namespace which is unbound + * @param nameSpace The namespace which is unbound * @param element The element in which the namespace was not bound * @return A new, autoreleased unbound namespace exception */ -+ (instancetype)exceptionWithNamespace: (OFString *)namespace_ ++ (instancetype)exceptionWithNamespace: (OFString *)nameSpace element: (OFXMLElement *)element; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unbound namespace exception. * - * @param namespace_ The namespace which is unbound + * @param nameSpace The namespace which is unbound * @param element The element in which the namespace was not bound * @return An initialized unbound namespace exception */ -- (instancetype)initWithNamespace: (OFString *)namespace_ +- (instancetype)initWithNamespace: (OFString *)nameSpace element: (OFXMLElement *)element OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnboundNamespaceException.m ================================================================== --- src/exceptions/OFUnboundNamespaceException.m +++ src/exceptions/OFUnboundNamespaceException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFUnboundPrefixException.h ================================================================== --- src/exceptions/OFUnboundPrefixException.h +++ src/exceptions/OFUnboundPrefixException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,12 +39,10 @@ /** * @brief The parser which encountered the unbound prefix. */ @property (readonly, nonatomic) OFXMLParser *parser; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unbound prefix exception. * * @param prefix The prefix which is unbound * @param parser The parser which encountered the unbound prefix @@ -51,11 +49,11 @@ * @return A new, autoreleased unbound prefix exception */ + (instancetype)exceptionWithPrefix: (OFString *)prefix parser: (OFXMLParser *)parser; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unbound prefix exception. * * @param prefix The prefix which is unbound @@ -62,8 +60,10 @@ * @param parser The parser which encountered the unbound prefix * @return An initialized unbound prefix exception */ - (instancetype)initWithPrefix: (OFString *)prefix parser: (OFXMLParser *)parser OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnboundPrefixException.m ================================================================== --- src/exceptions/OFUnboundPrefixException.m +++ src/exceptions/OFUnboundPrefixException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFUndefinedKeyException.h ================================================================== --- src/exceptions/OFUndefinedKeyException.h +++ src/exceptions/OFUndefinedKeyException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -25,11 +25,11 @@ * Coding). */ @interface OFUndefinedKeyException: OFException { id _object; - OFString *_key; + OFString *_Nullable _key; id _Nullable _value; } /** * @brief The object on which the key is undefined. @@ -37,19 +37,17 @@ @property (readonly, nonatomic) id object; /** * @brief The key which is undefined. */ -@property (readonly, nonatomic) OFString *key; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *key; /** * @brief The value for the undefined key */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) id value; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased undefined key exception. * * @param object The object on which the key is undefined * @param key The key which is undefined @@ -66,14 +64,14 @@ * @param value The value for the undefined key * * @return A new, autoreleased undefined key exception */ + (instancetype)exceptionWithObject: (id)object - key: (OFString *)key + key: (nullable OFString *)key value: (nullable id)value; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated undefined key exception. * * @param object The object on which the key is undefined @@ -91,10 +89,12 @@ * @param value The value for the undefined key * * @return An initialized undefined key exception */ - (instancetype)initWithObject: (id)object - key: (OFString *)key + key: (nullable OFString *)key value: (nullable id)value OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUndefinedKeyException.m ================================================================== --- src/exceptions/OFUndefinedKeyException.m +++ src/exceptions/OFUndefinedKeyException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFUnknownXMLEntityException.h ================================================================== --- src/exceptions/OFUnknownXMLEntityException.h +++ src/exceptions/OFUnknownXMLEntityException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -40,18 +40,20 @@ * @param entityName The name of the unknown XML entity * @return A new, autoreleased unknown XML entity exception */ + (instancetype)exceptionWithEntityName: (OFString *)entityName; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unknown XML entity exception. * * @param entityName The name of the unknown XML entity * @return An initialized unknown XML entity exception */ - (instancetype)initWithEntityName: (OFString *)entityName OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnknownXMLEntityException.m ================================================================== --- src/exceptions/OFUnknownXMLEntityException.m +++ src/exceptions/OFUnknownXMLEntityException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,13 +24,13 @@ + (instancetype)exceptionWithEntityName: (OFString *)entityName { return [[[self alloc] initWithEntityName: entityName] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithEntityName: (OFString *)entityName { self = [super init]; @@ -42,10 +42,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_entityName release]; Index: src/exceptions/OFUnlockFailedException.h ================================================================== --- src/exceptions/OFUnlockFailedException.h +++ src/exceptions/OFUnlockFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,11 +24,11 @@ * * @brief An exception indicating that unlocking a lock failed. */ @interface OFUnlockFailedException: OFException { - id _lock; + id _Nullable _lock; int _errNo; } /** * @brief The lock which could not be unlocked. @@ -57,10 +57,8 @@ * @param errNo The errno of the error that occurred * @return An initialized unlock failed exception */ - (instancetype)initWithLock: (nullable id )lock errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnlockFailedException.m ================================================================== --- src/exceptions/OFUnlockFailedException.m +++ src/exceptions/OFUnlockFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -36,24 +36,22 @@ _errNo = errNo; return self; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (void)dealloc { [_lock release]; [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"A lock of type %@ could not be unlocked: %s", - [_lock class], strerror(_errNo)]; + if (_lock != nil) + return [OFString stringWithFormat: + @"A lock of type %@ could not be unlocked: %s", + [_lock class], strerror(_errNo)]; + else + return @"A lock could not be unlocked!"; } @end Index: src/exceptions/OFUnsupportedProtocolException.h ================================================================== --- src/exceptions/OFUnsupportedProtocolException.h +++ src/exceptions/OFUnsupportedProtocolException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -27,31 +27,31 @@ * @brief An exception indicating that the protocol specified by the URL is not * supported. */ @interface OFUnsupportedProtocolException: OFException { - OFURL *_URL; + OFURL *_Nullable _URL; } /** * @brief The URL whose protocol is unsupported. */ -@property (readonly, nonatomic) OFURL *URL; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFURL *URL; /** * @brief Creates a new, autoreleased unsupported protocol exception. * * @param URL The URL whose protocol is unsupported * @return A new, autoreleased unsupported protocol exception */ -+ (instancetype)exceptionWithURL: (OFURL*)URL; ++ (instancetype)exceptionWithURL: (nullable OFURL*)URL; /** * @brief Initializes an already allocated unsupported protocol exception * * @param URL The URL whose protocol is unsupported * @return An initialized unsupported protocol exception */ -- (instancetype)initWithURL: (OFURL*)URL OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithURL: (nullable OFURL*)URL OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnsupportedProtocolException.m ================================================================== --- src/exceptions/OFUnsupportedProtocolException.m +++ src/exceptions/OFUnsupportedProtocolException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFUnsupportedVersionException.h ================================================================== --- src/exceptions/OFUnsupportedVersionException.h +++ src/exceptions/OFUnsupportedVersionException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -32,27 +32,27 @@ /** * @brief The version which is unsupported. */ @property (readonly, nonatomic) OFString *version; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unsupported version exception. * * @param version The version which is unsupported * @return A new, autoreleased unsupported version exception */ + (instancetype)exceptionWithVersion: (OFString *)version; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unsupported protocol exception. * * @param version The version which is unsupported * @return An initialized unsupported version exception */ - (instancetype)initWithVersion: (OFString *)version OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnsupportedVersionException.m ================================================================== --- src/exceptions/OFUnsupportedVersionException.m +++ src/exceptions/OFUnsupportedVersionException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/exceptions/OFWriteFailedException.h ================================================================== --- src/exceptions/OFWriteFailedException.h +++ src/exceptions/OFWriteFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -34,14 +34,10 @@ * This can be used to make sure that a retry does not write data already * written before. */ @property (readonly, nonatomic) size_t bytesWritten; -+ (instancetype)exceptionWithObject: (id)object - requestedLength: (size_t)requestedLength - errNo: (int)errNo OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased write failed exception. * * @param object The object from which reading or to which writing failed * @param requestedLength The requested length of the data that could not be @@ -54,13 +50,13 @@ + (instancetype)exceptionWithObject: (id)object requestedLength: (size_t)requestedLength bytesWritten: (size_t)bytesWritten errNo: (int)errNo; -- (instancetype)initWithObject: (id)object - requestedLength: (size_t)requestedLength - errNo: (int)errNo OF_UNAVAILABLE; ++ (instancetype)exceptionWithObject: (id)object + requestedLength: (size_t)requestedLength + errNo: (int)errNo OF_UNAVAILABLE; /** * @brief Initializes an already allocated write failed exception. * * @param object The object from which reading or to which writing failed @@ -73,8 +69,12 @@ */ - (instancetype)initWithObject: (id)object requestedLength: (size_t)requestedLength bytesWritten: (size_t)bytesWritten errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithObject: (id)object + requestedLength: (size_t)requestedLength + errNo: (int)errNo OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFWriteFailedException.m ================================================================== --- src/exceptions/OFWriteFailedException.m +++ src/exceptions/OFWriteFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -62,12 +62,18 @@ return self; } - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to write %zu bytes (after %zu bytes written) to an " - @"object of type %@: %@", - _requestedLength, _bytesWritten, [_object class], - OFStrError(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to write %zu bytes (after %zu bytes written) to " + @"an object of type %@: %@", + _requestedLength, _bytesWritten, [_object class], + OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to write %zu bytes (after %zu bytes written) to " + @"an object of type %@", + _requestedLength, _bytesWritten, [_object class]]; } @end Index: src/forwarding/apple-forwarding-arm.S ================================================================== --- src/forwarding/apple-forwarding-arm.S +++ src/forwarding/apple-forwarding-arm.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/apple-forwarding-arm64.S ================================================================== --- src/forwarding/apple-forwarding-arm64.S +++ src/forwarding/apple-forwarding-arm64.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/apple-forwarding-i386.S ================================================================== --- src/forwarding/apple-forwarding-i386.S +++ src/forwarding/apple-forwarding-i386.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/apple-forwarding-powerpc.S ================================================================== --- src/forwarding/apple-forwarding-powerpc.S +++ src/forwarding/apple-forwarding-powerpc.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/apple-forwarding-x86_64.S ================================================================== --- src/forwarding/apple-forwarding-x86_64.S +++ src/forwarding/apple-forwarding-x86_64.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-arm-elf.S ================================================================== --- src/forwarding/forwarding-arm-elf.S +++ src/forwarding/forwarding-arm-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-arm64-elf.S ================================================================== --- src/forwarding/forwarding-arm64-elf.S +++ src/forwarding/forwarding-arm64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-mips-elf.S ================================================================== --- src/forwarding/forwarding-mips-elf.S +++ src/forwarding/forwarding-mips-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-powerpc-elf.S ================================================================== --- src/forwarding/forwarding-powerpc-elf.S +++ src/forwarding/forwarding-powerpc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -192,11 +192,11 @@ stfd %f7, 88(%r1) stfd %f8, 96(%r1) mr %r3, %r4 #ifdef OF_PIC - bl object_getClass+0x800@plt + bl object_getClass+0x8000@plt lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) bl class_respondsToSelector+0x8000@plt #else bl object_getClass Index: src/forwarding/forwarding-sparc-elf.S ================================================================== --- src/forwarding/forwarding-sparc-elf.S +++ src/forwarding/forwarding-sparc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-sparc64-elf.S ================================================================== --- src/forwarding/forwarding-sparc64-elf.S +++ src/forwarding/forwarding-sparc64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-x86-elf.S ================================================================== --- src/forwarding/forwarding-x86-elf.S +++ src/forwarding/forwarding-x86-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-x86-win32.S ================================================================== --- src/forwarding/forwarding-x86-win32.S +++ src/forwarding/forwarding-x86-win32.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-x86_64-elf.S ================================================================== --- src/forwarding/forwarding-x86_64-elf.S +++ src/forwarding/forwarding-x86_64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-x86_64-macho.S ================================================================== --- src/forwarding/forwarding-x86_64-macho.S +++ src/forwarding/forwarding-x86_64-macho.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding-x86_64-win64.S ================================================================== --- src/forwarding/forwarding-x86_64-win64.S +++ src/forwarding/forwarding-x86_64-win64.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/forwarding/forwarding.S ================================================================== --- src/forwarding/forwarding.S +++ src/forwarding/forwarding.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/libbases.m ================================================================== --- src/libbases.m +++ src/libbases.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -254,11 +254,10 @@ # define OF_WARN_UNUSED_RESULT #endif #if __has_attribute(__unavailable__) # define OF_UNAVAILABLE __attribute__((__unavailable__)) -# define OF_HAVE_UNAVAILABLE #else # define OF_UNAVAILABLE #endif #if __has_attribute(__objc_requires_super__) @@ -411,27 +410,33 @@ OF_PREPROCESSOR_CONCAT(destructor, __LINE__)(void) static OF_INLINE uint16_t OF_CONST_FUNC OFByteSwap16Const(uint16_t i) { - return (i & 0xFF00) >> 8 | (i & 0x00FF) << 8; + return (i & UINT16_C(0xFF00)) >> 8 | (i & UINT16_C(0x00FF)) << 8; } static OF_INLINE uint32_t OF_CONST_FUNC OFByteSwap32Const(uint32_t i) { - return (i & 0xFF000000) >> 24 | (i & 0x00FF0000) >> 8 | - (i & 0x0000FF00) << 8 | (i & 0x000000FF) << 24; + return (i & UINT32_C(0xFF000000)) >> 24 | + (i & UINT32_C(0x00FF0000)) >> 8 | + (i & UINT32_C(0x0000FF00)) << 8 | + (i & UINT32_C(0x000000FF)) << 24; } static OF_INLINE uint64_t OF_CONST_FUNC OFByteSwap64Const(uint64_t i) { - return (i & 0xFF00000000000000) >> 56 | (i & 0x00FF000000000000) >> 40 | - (i & 0x0000FF0000000000) >> 24 | (i & 0x000000FF00000000) >> 8 | - (i & 0x00000000FF000000) << 8 | (i & 0x0000000000FF0000) << 24 | - (i & 0x000000000000FF00) << 40 | (i & 0x00000000000000FF) << 56; + return (i & UINT64_C(0xFF00000000000000)) >> 56 | + (i & UINT64_C(0x00FF000000000000)) >> 40 | + (i & UINT64_C(0x0000FF0000000000)) >> 24 | + (i & UINT64_C(0x000000FF00000000)) >> 8 | + (i & UINT64_C(0x00000000FF000000)) << 8 | + (i & UINT64_C(0x0000000000FF0000)) << 24 | + (i & UINT64_C(0x000000000000FF00)) << 40 | + (i & UINT64_C(0x00000000000000FF)) << 56; } static OF_INLINE uint16_t OF_CONST_FUNC OFByteSwap16NonConst(uint16_t i) { @@ -512,11 +517,12 @@ "xchgl %%eax, %%edx" : "=A"(i) : "0"(i) ); #else - i = (uint64_t)OFByteSwap32NonConst((uint32_t)(i & 0xFFFFFFFF)) << 32 | + i = (uint64_t)OFByteSwap32NonConst( + (uint32_t)(i & UINT32_C(0xFFFFFFFF))) << 32 | OFByteSwap32NonConst((uint32_t)(i >> 32)); #endif return i; } @@ -607,15 +613,15 @@ #ifdef OF_FLOAT_BIG_ENDIAN # define OFFromBigEndianFloat(f) (f) # define OFFromBigEndianDouble(d) (d) # define OFFromLittleEndianFloat(f) OFByteSwapFloat(f) -# define OFFromLittleEndianDouble(i) OFByteSwapDouble(d) +# define OFFromLittleEndianDouble(d) OFByteSwapDouble(d) # define OFToBigEndianFloat(f) (f) # define OFToBigEndianDouble(d) (d) # define OFToLittleEndianFloat(f) OFByteSwapFloat(f) -# define OFToLittleEndianDouble(i) OFByteSwapDouble(d) +# define OFToLittleEndianDouble(d) OFByteSwapDouble(d) #else # define OFFromBigEndianFloat(f) OFByteSwapFloat(f) # define OFFromBigEndianDouble(d) OFByteSwapDouble(d) # define OFFromLittleEndianFloat(f) (f) # define OFFromLittleEndianDouble(d) (d) Index: src/module.modulemap ================================================================== --- src/module.modulemap +++ src/module.modulemap @@ -3,14 +3,13 @@ /* * These are included by OFAtomic.h, but should never be included * directly. */ - exclude header "OFAtomic_builtins.h" - exclude header "OFAtomic_no_threads.h" - exclude header "OFAtomic_osatomic.h" - exclude header "OFAtomic_powerpc.h" - exclude header "OFAtomic_sync_builtins.h" - exclude header "OFAtomic_x86.h" + exclude header "platform/GCC4/OFAtomic.h" + exclude header "platform/GCC4.7/OFAtomic.h" + exclude header "platform/PowerPC/OFAtomic.h" + exclude header "platform/macOS/OFAtomic.h" + exclude header "platform/x86/OFAtomic.h" export * } Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,8 +1,9 @@ #undef OF_APPLE_RUNTIME #undef OF_BIG_ENDIAN #undef OF_FLOAT_BIG_ENDIAN +#undef OF_HAVE_AFUNIX_H #undef OF_HAVE_ATOMIC_BUILTINS #undef OF_HAVE_ATOMIC_OPS #undef OF_HAVE_BUILTIN_BSWAP16 #undef OF_HAVE_BUILTIN_BSWAP32 #undef OF_HAVE_BUILTIN_BSWAP64 @@ -21,11 +22,11 @@ #undef OF_HAVE_OSATOMIC #undef OF_HAVE_OSATOMIC_64 #undef OF_HAVE_PIPE #undef OF_HAVE_PLEDGE #undef OF_HAVE_PLUGINS -#undef OF_HAVE_PROCESSES +#undef OF_HAVE_SUBPROCESSES #undef OF_HAVE_PTHREADS #undef OF_HAVE_PTHREAD_SPINLOCKS #undef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES #undef OF_HAVE_SCHED_YIELD #undef OF_HAVE_SOCKETS @@ -32,15 +33,19 @@ #undef OF_HAVE_STDNORETURN #undef OF_HAVE_SYMLINK #undef OF_HAVE_SYNC_BUILTINS #undef OF_HAVE_SYS_SOCKET_H #undef OF_HAVE_SYS_TYPES_H +#undef OF_HAVE_SYS_UN_H #undef OF_HAVE_THREADS #undef OF_HAVE_UNICODE_TABLES +#undef OF_HAVE_UNIX_SOCKETS #undef OF_HAVE__THREAD_LOCAL #undef OF_HAVE___THREAD #undef OF_NINTENDO_3DS #undef OF_NINTENDO_DS +#undef OF_NINTENDO_SWITCH #undef OF_NO_SHARED #undef OF_OBJFW_RUNTIME #undef OF_UNIVERSAL #undef OF_WII +#undef OF_WII_U Index: src/platform.h ================================================================== --- src/platform.h +++ src/platform.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -147,10 +147,12 @@ #elif defined(__DJGPP__) # define OF_DJGPP # define OF_MSDOS #elif defined(__riscos__) # define OF_ACORN_RISC_OS +#elif defined(__MINT__) +# define OF_MINT #endif #if defined(__ELF__) # define OF_ELF #elif defined(__MACH__) ADDED src/platform/AmigaOS/OFPlainCondition.m Index: src/platform/AmigaOS/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainCondition.m @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFPlainCondition.h" + +#include +#include +#ifndef OF_AMIGAOS4 +# include +#endif + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->waitingTasks = NULL; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + while (condition->waitingTasks != NULL) { + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + ULONG signalMask = 0; + + return OFPlainConditionWaitOrExecSignal(condition, mutex, &signalMask); +} + +int +OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + int error = 0; + ULONG mask; + + if (waitingTask.sigBit == -1) + return EAGAIN; + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + FreeSignal(waitingTask.sigBit); + return error; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + mask = Wait((1ul << waitingTask.sigBit) | *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + FreeSignal(waitingTask.sigBit); + + Permit(); + + return error; +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + ULONG signalMask = 0; + + return OFPlainConditionTimedWaitOrExecSignal(condition, mutex, timeout, + &signalMask); +} + +int +OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + struct MsgPort port = { + .mp_Node = { + .ln_Type = NT_MSGPORT + }, + .mp_Flags = PA_SIGNAL, + .mp_SigTask = waitingTask.task, + .mp_SigBit = AllocSignal(-1) + }; +#ifdef OF_AMIGAOS4 + struct TimeRequest request = { + .Request = { +#else + struct timerequest request = { + .tr_node = { +#endif + .io_Message = { + .mn_Node = { + .ln_Type = NT_MESSAGE + }, + .mn_ReplyPort = &port, + .mn_Length = sizeof(request) + }, + .io_Command = TR_ADDREQUEST + }, +#ifdef OF_AMIGAOS4 + .Time = { + .Seconds = (ULONG)timeout, + .Microseconds = + (timeout - request.Time.Seconds) * 1000000 +#else + .tr_time = { + .tv_sec = (ULONG)timeout, + .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 +#endif + } + }; + int error = 0; + ULONG mask; + + NewList(&port.mp_MsgList); + + if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { + error = EAGAIN; + goto fail; + } + + if (OpenDevice("timer.device", UNIT_MICROHZ, + (struct IORequest *)&request, 0) != 0) { + error = EAGAIN; + goto fail; + } + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + Permit(); + goto fail; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + SendIO((struct IORequest *)&request); + + mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | + *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else if (mask & (1ul << port.mp_SigBit)) + error = ETIMEDOUT; + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + condition->waitingTasks = waitingTask.next; + + if (!CheckIO((struct IORequest *)&request)) { + AbortIO((struct IORequest *)&request); + WaitIO((struct IORequest *)&request); + } + CloseDevice((struct IORequest *)&request); + + Permit(); + +fail: + if (waitingTask.sigBit != -1) + FreeSignal(waitingTask.sigBit); + if (port.mp_SigBit != -1) + FreeSignal(port.mp_SigBit); + + return error; +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks != NULL) + return EBUSY; + } @finally { + Permit(); + } + + return 0; +} ADDED src/platform/AmigaOS/OFPlainMutex.m Index: src/platform/AmigaOS/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainMutex.m @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + ObtainSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!AttemptSemaphore(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + ReleaseSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/AmigaOS/OFPlainThread.m Index: src/platform/AmigaOS/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainThread.m @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2008-2022 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" + +#include +#include + +#import "OFPlainThread.h" +#import "OFData.h" +#import "OFTLSKey.h" + +#include +#include +#include + +#ifndef OF_MORPHOS +extern void OFTLSKeyThreadExited(void); +#endif +static OFTLSKey threadKey; + +OF_CONSTRUCTOR() +{ + OFEnsure(OFTLSKeyNew(&threadKey) == 0); +} + +static void +functionWrapper(void) +{ + bool detached = false; + OFPlainThread thread = + (OFPlainThread)((struct Process *)FindTask(NULL))->pr_ExitData; + OFEnsure(OFTLSKeySet(threadKey, thread) == 0); + + thread->function(thread->object); + + ObtainSemaphore(&thread->semaphore); + @try { + thread->done = true; + +#ifndef OF_MORPHOS + OFTLSKeyThreadExited(); +#endif + + if (thread->detached) + detached = true; + else if (thread->joinTask != NULL) + Signal(thread->joinTask, (1ul << thread->joinSigBit)); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + if (detached) + free(thread); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + OFMutableData *tags = nil; + + if ((*thread = calloc(1, sizeof(**thread))) == NULL) + return ENOMEM; + + @try { + (*thread)->function = function; + (*thread)->object = object; + InitSemaphore(&(*thread)->semaphore); + + tags = [[OFMutableData alloc] + initWithItemSize: sizeof(struct TagItem) + capacity: 12]; +#define ADD_TAG(tag, data) \ + { \ + struct TagItem t = { \ + .ti_Tag = tag, \ + .ti_Data = data \ + }; \ + [tags addItem: &t]; \ + } + ADD_TAG(NP_Entry, (ULONG)functionWrapper) + ADD_TAG(NP_ExitData, (ULONG)*thread) +#ifdef OF_AMIGAOS4 + ADD_TAG(NP_Child, TRUE) +#endif +#ifdef OF_MORPHOS + ADD_TAG(NP_CodeType, CODETYPE_PPC); +#endif + if (name != NULL) + ADD_TAG(NP_Name, (ULONG)name); + + ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) + ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) + ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) + ADD_TAG(NP_CloseInput, FALSE) + ADD_TAG(NP_CloseOutput, FALSE) + ADD_TAG(NP_CloseError, FALSE) + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < 1 || attr->priority > 1) + return EINVAL; + + /* + * -1 should be -128 (lowest possible priority) while + * +1 should be +127 (highest possible priority). + */ + ADD_TAG(NP_Priority, (attr->priority > 0 + ? attr->priority * 127 : attr->priority * 128)) + } + + if (attr != NULL && attr->stackSize != 0) + ADD_TAG(NP_StackSize, attr->stackSize) + else + ADD_TAG(NP_StackSize, + ((struct Process *)FindTask(NULL))->pr_StackSize) + + ADD_TAG(TAG_DONE, 0) +#undef ADD_TAG + + (*thread)->task = (struct Task *)CreateNewProc(tags.items); + if ((*thread)->task == NULL) { + free(*thread); + return EAGAIN; + } + } @catch (id e) { + free(*thread); + @throw e; + } @finally { + [tags release]; + } + + return 0; +} + +OFPlainThread +OFCurrentPlainThread(void) +{ + return OFTLSKeyGet(threadKey); +} + +bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return (thread->task == FindTask(NULL)); +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) { + ReleaseSemaphore(&thread->semaphore); + + free(thread); + return 0; + } + + @try { + if (thread->detached || thread->joinTask != NULL) + return EINVAL; + + if ((thread->joinSigBit = AllocSignal(-1)) == -1) + return EAGAIN; + + thread->joinTask = FindTask(NULL); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + Wait(1ul << thread->joinSigBit); + FreeSignal(thread->joinSigBit); + + assert(thread->done); + free(thread); + + return 0; +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) + free(thread); + else + thread->detached = true; + + ReleaseSemaphore(&thread->semaphore); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/AmigaOS/OFString+PathAdditions.m Index: src/platform/AmigaOS/OFString+PathAdditions.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFString+PathAdditions.m @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2008-2022 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 "OFString+PathAdditions.h" +#import "OFArray.h" +#import "OFFileURLHandler.h" + +#import "OFOutOfRangeException.h" + +int _OFString_PathAdditions_reference; + +@implementation OFString (PathAdditions) ++ (OFString *)pathWithComponents: (OFArray *)components +{ + OFMutableString *ret = [OFMutableString string]; + void *pool = objc_autoreleasePoolPush(); + bool firstAfterDevice = true; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if (!firstAfterDevice) + [ret appendString: @"/"]; + + [ret appendString: component]; + + if (![component hasSuffix: @":"]) + firstAfterDevice = false; + } + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (bool)isAbsolutePath +{ + return [self containsString: @":"]; +} + +- (OFArray *)pathComponents +{ + OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t i, last = 0, cStringLength = self.UTF8StringLength; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return ret; + } + + for (i = 0; i < cStringLength; i++) { + if (cString[i] == '/') { + if (i - last != 0) + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last]]; + else + [ret addObject: @"/"]; + + last = i + 1; + } else if (cString[i] == ':') { + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last + 1]]; + + last = i + 1; + } + } + if (i - last != 0) + [ret addObject: [OFString stringWithUTF8String: cString + last + length: i - last]]; + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (OFString *)lastPathComponent +{ + /* + * AmigaOS needs the full parsing to determine the last path component. + * This could be optimized by not creating the temporary objects, + * though. + */ + void *pool = objc_autoreleasePoolPush(); + OFString *ret = self.pathComponents.lastObject; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)pathExtension +{ + void *pool = objc_autoreleasePoolPush(); + OFString *ret, *fileName; + size_t pos; + + fileName = self.lastPathComponent; + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + ret = [fileName substringFromIndex: pos + 1]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingLastPathComponent +{ + /* + * AmigaOS needs the full parsing to delete the last path component. + * This could be optimized, though. + */ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + size_t count = components.count; + OFString *ret; + + if (count < 2) { + if ([components.firstObject hasSuffix: @":"]) { + ret = [components.firstObject retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } + + objc_autoreleasePoolPop(pool); + return @""; + } + + components = [components objectsInRange: + OFRangeMake(0, components.count - 1)]; + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingPathExtension +{ + void *pool; + OFMutableArray OF_GENERIC(OFString *) *components; + OFString *ret, *fileName; + size_t pos; + + if (self.length == 0) + return [[self copy] autorelease]; + + pool = objc_autoreleasePoolPush(); + components = [[self.pathComponents mutableCopy] autorelease]; + fileName = components.lastObject; + + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + fileName = [fileName substringToIndex: pos]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByStandardizingPath +{ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components; + OFMutableArray OF_GENERIC(OFString *) *array; + OFString *ret; + bool done = false; + + if (self.length == 0) + return @""; + + components = self.pathComponents; + + if (components.count == 1) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + array = [[components mutableCopy] autorelease]; + + while (!done) { + size_t length = array.count; + + done = true; + + for (size_t i = 0; i < length; i++) { + OFString *component = [array objectAtIndex: i]; + OFString *parent = + (i > 0 ? [array objectAtIndex: i - 1] : 0); + + if (component.length == 0) { + [array removeObjectAtIndex: i]; + + done = false; + break; + } + + if ([component isEqual: @"/"] && + parent != nil && ![parent isEqual: @"/"]) { + [array removeObjectsInRange: + OFRangeMake(i - 1, 2)]; + + done = false; + break; + } + } + } + + ret = [OFString pathWithComponents: array]; + + if ([self hasSuffix: @"/"]) + ret = [ret stringByAppendingString: @"/"]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByAppendingPathComponent: (OFString *)component +{ + if ([self hasSuffix: @"/"] || [self hasSuffix: @":"]) + return [self stringByAppendingString: component]; + else { + OFMutableString *ret = [[self mutableCopy] autorelease]; + + [ret appendString: @"/"]; + [ret appendString: component]; + + [ret makeImmutable]; + + return ret; + } +} + +- (OFString *)stringByAppendingPathExtension: (OFString *)extension +{ + if ([self hasSuffix: @"/"]) { + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *components; + OFString *fileName, *ret; + + components = + [[self.pathComponents mutableCopy] autorelease]; + fileName = [components.lastObject + stringByAppendingFormat: @".%@", extension]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [[OFString pathWithComponents: components] retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } else + return [self stringByAppendingFormat: @".%@", extension]; +} + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + OFMutableString *ret = [OFMutableString string]; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if ([component isEqual: @"/"]) + [ret appendString: @"/.."]; + else { + [ret appendString: @"/"]; + [ret appendString: component]; + } + } + + [ret makeImmutable]; + + return ret; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringToIndex: path.length - 1]; + + OFMutableArray OF_GENERIC(OFString *) *components; + size_t count; + + path = [path substringFromIndex: 1]; + components = [[[path + componentsSeparatedByString: @"/"] mutableCopy] autorelease]; + count = components.count; + + for (size_t i = 0; i < count; i++) { + OFString *component = [components objectAtIndex: i]; + + if ([component isEqual: @"."]) { + [components removeObjectAtIndex: i]; + count--; + + i--; + continue; + } + + if ([component isEqual: @".."]) + [components replaceObjectAtIndex: i withObject: @"/"]; + } + + return [OFString pathWithComponents: components]; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} +@end ADDED src/platform/AmigaOS/OFTLSKey.m Index: src/platform/AmigaOS/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFTLSKey.m @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSKey.h" + +#include +#include + +/* + * As we use this file in both the runtime and ObjFW, and since AmigaOS always + * has the runtime, use the hashtable from the runtime. + */ +#import "runtime/private.h" + +static OFTLSKey firstKey = NULL, lastKey = NULL; +static struct SignalSemaphore semaphore; +static bool semaphoreInitialized = false; + +static uint32_t +hashFunc(const void *ptr) +{ + return (uint32_t)(uintptr_t)ptr; +} + +static bool +equalFunc(const void *ptr1, const void *ptr2) +{ + return (ptr1 == ptr2); +} + +OF_CONSTRUCTOR() +{ + if (!semaphoreInitialized) { + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } +} + +int +OFTLSKeyNew(OFTLSKey *key) +{ + if (!semaphoreInitialized) { + /* + * We might be called from another constructor, while ours has + * not run yet. This is safe, as the constructor is definitely + * run before a thread is spawned. + */ + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } + + if ((*key = malloc(sizeof(**key))) == NULL) + return ENOMEM; + + (*key)->table = NULL; + + ObtainSemaphore(&semaphore); + @try { + (*key)->next = NULL; + (*key)->previous = lastKey; + + if (lastKey != NULL) + lastKey->next = *key; + + lastKey = *key; + + if (firstKey == NULL) + firstKey = *key; + } @finally { + ReleaseSemaphore(&semaphore); + } + + /* We create the hash table lazily. */ + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + ObtainSemaphore(&semaphore); + @try { + if (key->previous != NULL) + key->previous->next = key->next; + if (key->next != NULL) + key->next->previous = key->previous; + + if (firstKey == key) + firstKey = key->next; + if (lastKey == key) + lastKey = key->previous; + + objc_hashtable_free(key->table); + free(key); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void * +OFTLSKeyGet(OFTLSKey key) +{ + void *ret; + + ObtainSemaphore(&semaphore); + @try { + if (key->table == NULL) + return NULL; + + ret = objc_hashtable_get(key->table, FindTask(NULL)); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return ret; +} + +int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + if (key->table == NULL) + key->table = objc_hashtable_new(hashFunc, equalFunc, 2); + + if (ptr == NULL) + objc_hashtable_delete(key->table, task); + else + objc_hashtable_set(key->table, task, ptr); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void +OFTLSKeyThreadExited(void) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + for (OFTLSKey iter = firstKey; iter != NULL; iter = iter->next) + if (iter->table != NULL) + objc_hashtable_delete(iter->table, task); + } @finally { + ReleaseSemaphore(&semaphore); + } +} ADDED src/platform/GCC4.7/OFAtomic.h Index: src/platform/GCC4.7/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/GCC4.7/OFAtomic.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_ACQUIRE); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_RELEASE); +} ADDED src/platform/GCC4/OFAtomic.h Index: src/platform/GCC4/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/GCC4/OFAtomic.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_add_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_sub_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __sync_synchronize(); +} ADDED src/platform/MorphOS/OFTLSKey.m Index: src/platform/MorphOS/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/MorphOS/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + *key = TLSAllocA(NULL); + + if (*key == TLS_INVALID_INDEX) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return (TLSFree(key) ? 0 : EINVAL); +} ADDED src/platform/POSIX/OFPlainCondition.m Index: src/platform/POSIX/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainCondition.m @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2022 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 "OFPlainCondition.h" + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + return pthread_cond_init(condition, NULL); +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + return pthread_cond_signal(condition); +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + return pthread_cond_broadcast(condition); +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + return pthread_cond_wait(condition, mutex); +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + struct timespec ts; + + ts.tv_sec = (time_t)timeout; + ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); + + return pthread_cond_timedwait(condition, mutex, &ts); +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + return pthread_cond_destroy(condition); +} ADDED src/platform/POSIX/OFPlainMutex.m Index: src/platform/POSIX/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainMutex.m @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2008-2022 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 "OFPlainMutex.h" + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + return pthread_mutex_lock(mutex); +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + return pthread_mutex_trylock(mutex); +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + return pthread_mutex_unlock(mutex); +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return pthread_mutex_destroy(mutex); +} + +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + pthread_mutexattr_t attr; + + if ((error = pthread_mutexattr_init(&attr)) != 0) + return error; + + if ((error = pthread_mutexattr_settype(&attr, + PTHREAD_MUTEX_RECURSIVE)) != 0) + return error; + + if ((error = pthread_mutex_init(rmutex, &attr)) != 0) + return error; + + if ((error = pthread_mutexattr_destroy(&attr)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} +#else +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexNew(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyNew(&rmutex->count)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexTryLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 1) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count - 1))) != 0) + return error; + + return 0; + } + + if ((error = OFTLSKeySet(rmutex->count, (void *)0)) != 0) + return error; + + if ((error = OFPlainMutexUnlock(&rmutex->mutex)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexFree(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyFree(rmutex->count)) != 0) + return error; + + return 0; +} +#endif ADDED src/platform/POSIX/OFPlainThread.m Index: src/platform/POSIX/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainThread.m @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#ifdef HAVE_PTHREAD_NP_H +# include +#endif + +#ifdef OF_HAIKU +# include +#endif + +#import "OFPlainThread.h" + +#import "macros.h" + +static int minPrio = 0, maxPrio = 0, normalPrio = 0; + +struct ThreadContext { + void (*function)(id object); + id object; + const char *name; +}; + +/* + * This is done here to make sure this is done as early as possible in the main + * thread. + */ +OF_CONSTRUCTOR() +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) == 0) { +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + int policy; +#endif + struct sched_param param; + +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + if (pthread_attr_getschedpolicy(&attr, &policy) == 0) { + minPrio = sched_get_priority_min(policy); + maxPrio = sched_get_priority_max(policy); + + if (minPrio == -1 || maxPrio == -1) + minPrio = maxPrio = 0; + } +#endif + + if (pthread_attr_getschedparam(&attr, ¶m) != 0) + normalPrio = param.sched_priority; + else + minPrio = maxPrio = 0; + + pthread_attr_destroy(&attr); + } +} + +static void * +functionWrapper(void *data) +{ + struct ThreadContext *ctx = data; + + if (ctx->name != NULL) + OFSetThreadName(ctx->name); + + pthread_cleanup_push(free, data); + + ctx->function(ctx->object); + + pthread_cleanup_pop(1); + return NULL; +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + int error; + pthread_attr_t POSIXAttr; + + attr->priority = 0; + attr->stackSize = 0; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + return 0; + + return error; + } + + error = pthread_attr_getstacksize(&POSIXAttr, &attr->stackSize); + + pthread_attr_destroy(&POSIXAttr); + + return error; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + int error = 0; + pthread_attr_t POSIXAttr; + bool POSIXAttrAvailable = true; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + POSIXAttrAvailable = false; + else + return error; + } + + @try { + struct ThreadContext *ctx; + + if (attr != NULL && POSIXAttrAvailable) { +#ifndef OF_HPUX + struct sched_param param; +#endif + + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + +#ifndef OF_HPUX +# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED + if ((error = pthread_attr_setinheritsched(&POSIXAttr, + PTHREAD_EXPLICIT_SCHED)) != 0) + return error; +# endif + + if ((error = pthread_attr_getschedparam(&POSIXAttr, + ¶m)) != 0) + return error; + + if (attr->priority < 0) { + param.sched_priority = minPrio + + (1.0f + attr->priority) * + (normalPrio - minPrio); + } else + param.sched_priority = normalPrio + + attr->priority * (maxPrio - normalPrio); + + if ((error = pthread_attr_setschedparam(&POSIXAttr, + ¶m)) != 0) + return error; +#endif + + if (attr->stackSize > 0) { + if ((error = pthread_attr_setstacksize( + &POSIXAttr, attr->stackSize)) != 0) + return error; + } + } + + if ((ctx = malloc(sizeof(*ctx))) == NULL) + return ENOMEM; + + ctx->function = function; + ctx->object = object; + ctx->name = name; + + error = pthread_create(thread, + (POSIXAttrAvailable ? &POSIXAttr : NULL), functionWrapper, + ctx); + } @finally { + if (POSIXAttrAvailable) + pthread_attr_destroy(&POSIXAttr); + } + + return error; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + void *ret; + + return pthread_join(thread, &ret); +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + return pthread_detach(thread); +} + +void +OFSetThreadName(const char *name) +{ +#if defined(OF_HAIKU) + rename_thread(find_thread(NULL), name); +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(pthread_self(), name); +#elif defined(HAVE_PTHREAD_SETNAME_NP) +# if defined(OF_MACOS) || defined(OF_IOS) + pthread_setname_np(name); +# elif defined(__GLIBC__) + char buffer[16]; + + strncpy(buffer, name, 15); + buffer[15] = 0; + + pthread_setname_np(pthread_self(), buffer); +# endif +#endif +} ADDED src/platform/POSIX/OFString+PathAdditions.m Index: src/platform/POSIX/OFString+PathAdditions.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFString+PathAdditions.m @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2008-2022 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 "OFString+PathAdditions.h" +#import "OFArray.h" +#import "OFFileURLHandler.h" + +#import "OFOutOfRangeException.h" + +int _OFString_PathAdditions_reference; + +@implementation OFString (PathAdditions) ++ (OFString *)pathWithComponents: (OFArray *)components +{ + OFMutableString *ret = [OFMutableString string]; + void *pool = objc_autoreleasePoolPush(); + bool first = true; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if (!first && [component isEqual: @"/"]) + continue; + + if (!first && ![ret hasSuffix: @"/"]) + [ret appendString: @"/"]; + + [ret appendString: component]; + + first = false; + } + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (bool)isAbsolutePath +{ + return [self hasPrefix: @"/"]; +} + +- (OFArray *)pathComponents +{ + OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t i, last = 0, cStringLength = self.UTF8StringLength; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return ret; + } + + for (i = 0; i < cStringLength; i++) { + if (cString[i] == '/') { + if (i == 0) + [ret addObject: @"/"]; + else if (i - last != 0) + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last]]; + + last = i + 1; + } + } + if (i - last != 0) + [ret addObject: [OFString stringWithUTF8String: cString + last + length: i - last]]; + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (OFString *)lastPathComponent +{ + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t cStringLength = self.UTF8StringLength; + ssize_t i; + OFString *ret; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + if (cString[cStringLength - 1] == '/') + cStringLength--; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return @"/"; + } + + if (cStringLength - 1 > SSIZE_MAX) + @throw [OFOutOfRangeException exception]; + + for (i = cStringLength - 1; i >= 0; i--) { + if (cString[i] == '/') { + i++; + break; + } + } + + /* + * Only one component, but the trailing delimiter might have been + * removed, so return a new string anyway. + */ + if (i < 0) + i = 0; + + ret = [[OFString alloc] initWithUTF8String: cString + i + length: cStringLength - i]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)pathExtension +{ + void *pool = objc_autoreleasePoolPush(); + OFString *ret, *fileName; + size_t pos; + + fileName = self.lastPathComponent; + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + ret = [fileName substringFromIndex: pos + 1]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingLastPathComponent +{ + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t cStringLength = self.UTF8StringLength; + OFString *ret; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + if (cString[cStringLength - 1] == '/') + cStringLength--; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return @"/"; + } + + for (size_t i = cStringLength; i >= 1; i--) { + if (cString[i - 1] == '/') { + if (i == 1) { + objc_autoreleasePoolPop(pool); + return @"/"; + } + + ret = [[OFString alloc] initWithUTF8String: cString + length: i - 1]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; + } + } + + objc_autoreleasePoolPop(pool); + + return @"."; +} + +- (OFString *)stringByDeletingPathExtension +{ + void *pool; + OFMutableArray OF_GENERIC(OFString *) *components; + OFString *ret, *fileName; + size_t pos; + + if (self.length == 0) + return [[self copy] autorelease]; + + pool = objc_autoreleasePoolPush(); + components = [[self.pathComponents mutableCopy] autorelease]; + fileName = components.lastObject; + + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + fileName = [fileName substringToIndex: pos]; + [components replaceObjectAtIndex: [components count] - 1 + withObject: fileName]; + + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByStandardizingPath +{ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components; + OFMutableArray OF_GENERIC(OFString *) *array; + OFString *ret; + bool done = false, startsWithSlash; + + if (self.length == 0) + return @""; + + components = self.pathComponents; + + if (components.count == 1) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + array = [[components mutableCopy] autorelease]; + startsWithSlash = [self hasPrefix: @"/"]; + + if (startsWithSlash) + [array removeObjectAtIndex: 0]; + + while (!done) { + size_t length = array.count; + + done = true; + + for (size_t i = 0; i < length; i++) { + OFString *component = [array objectAtIndex: i]; + OFString *parent = + (i > 0 ? [array objectAtIndex: i - 1] : 0); + + if ([component isEqual: @"."] || + component.length == 0) { + [array removeObjectAtIndex: i]; + + done = false; + break; + } + + if ([component isEqual: @".."] && + parent != nil && ![parent isEqual: @".."]) { + [array removeObjectsInRange: + OFRangeMake(i - 1, 2)]; + + done = false; + break; + } + } + } + + if (startsWithSlash) + [array insertObject: @"" atIndex: 0]; + + if ([self hasSuffix: @"/"]) + [array addObject: @""]; + + ret = [[array componentsJoinedByString: @"/"] retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)stringByAppendingPathComponent: (OFString *)component +{ + if ([self hasSuffix: @"/"]) + return [self stringByAppendingString: component]; + else { + OFMutableString *ret = [[self mutableCopy] autorelease]; + + [ret appendString: @"/"]; + [ret appendString: component]; + + [ret makeImmutable]; + + return ret; + } +} + +- (OFString *)stringByAppendingPathExtension: (OFString *)extension +{ + if ([self hasSuffix: @"/"]) { + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *components; + OFString *fileName, *ret; + + components = + [[self.pathComponents mutableCopy] autorelease]; + fileName = [components.lastObject + stringByAppendingFormat: @".%@", extension]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [[OFString pathWithComponents: components] retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } else + return [self stringByAppendingFormat: @".%@", extension]; +} + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + return self; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringToIndex: path.length - 1]; + + return path; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} +@end ADDED src/platform/POSIX/OFSubprocess.m Index: src/platform/POSIX/OFSubprocess.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFSubprocess.m @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2008-2022 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" + +#include +#include + +#include + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#include "unistd_wrapper.h" +#ifdef HAVE_SPAWN_H +# include +#endif + +#import "OFSubprocess.h" +#import "OFString.h" +#import "OFArray.h" +#import "OFDictionary.h" +#import "OFLocale.h" + +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" +#import "OFWriteFailedException.h" + +#ifndef HAVE_POSIX_SPAWNP +extern char **environ; +#endif + +@interface OFSubprocess () +- (void)of_getArgv: (char ***)argv + forProgramName: (OFString *)programName + andArguments: (OFArray *)arguments; +- (char **)of_environmentForDictionary: (OFDictionary *)dictionary; +@end + +@implementation OFSubprocess ++ (instancetype)subprocessWithProgram: (OFString *)program +{ + return [[[self alloc] initWithProgram: program] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments + environment: environment] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithProgram: (OFString *)program +{ + return [self initWithProgram: program + programName: program + arguments: nil + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + const char *path; + char **argv, **env = NULL; + + _pid = -1; + _readPipe[0] = _writePipe[1] = -1; + + if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + path = [program cStringWithEncoding: [OFLocale encoding]]; + [self of_getArgv: &argv + forProgramName: programName + andArguments: arguments]; + + @try { + env = [self of_environmentForDictionary: environment]; +#ifdef HAVE_POSIX_SPAWNP + posix_spawn_file_actions_t actions; + posix_spawnattr_t attr; + + if (posix_spawn_file_actions_init(&actions) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (posix_spawnattr_init(&attr) != 0) { + posix_spawn_file_actions_destroy(&actions); + + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } + + @try { + if (posix_spawn_file_actions_addclose(&actions, + _readPipe[0]) != 0 || + posix_spawn_file_actions_addclose(&actions, + _writePipe[1]) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _writePipe[0], 0) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _readPipe[1], 1) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + +# ifdef POSIX_SPAWN_CLOEXEC_DEFAULT + if (posix_spawnattr_setflags(&attr, + POSIX_SPAWN_CLOEXEC_DEFAULT) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; +# endif + + if (posix_spawnp(&_pid, path, &actions, &attr, + argv, env) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + } +#else + if ((_pid = vfork()) == 0) { + environ = env; + + close(_readPipe[0]); + close(_writePipe[1]); + dup2(_writePipe[0], 0); + dup2(_readPipe[1], 1); + execvp(path, argv); + + _exit(EXIT_FAILURE); + } + + if (_pid == -1) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; +#endif + } @finally { + char **iter; + + close(_readPipe[1]); + close(_writePipe[0]); + OFFreeMemory(argv); + + if (env != NULL) + for (iter = env; *iter != NULL; iter++) + OFFreeMemory(*iter); + + OFFreeMemory(env); + } + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_readPipe[0] != -1) + [self close]; + + [super dealloc]; +} + +- (void)of_getArgv: (char ***)argv + forProgramName: (OFString *)programName + andArguments: (OFArray *)arguments +{ + OFString *const *objects = arguments.objects; + size_t i, count = arguments.count; + OFStringEncoding encoding; + + *argv = OFAllocMemory(count + 2, sizeof(char *)); + + encoding = [OFLocale encoding]; + + (*argv)[0] = (char *)[programName cStringWithEncoding: encoding]; + + for (i = 0; i < count; i++) + (*argv)[i + 1] = + (char *)[objects[i] cStringWithEncoding: encoding]; + + (*argv)[i + 1] = NULL; +} + +- (char **)of_environmentForDictionary: (OFDictionary *)environment +{ + char **envp; + size_t count; + OFStringEncoding encoding; + + if (environment == nil) + return NULL; + + encoding = [OFLocale encoding]; + + count = environment.count; + envp = OFAllocZeroedMemory(count + 1, sizeof(char *)); + + @try { + OFEnumerator *keyEnumerator = [environment keyEnumerator]; + OFEnumerator *objectEnumerator = [environment objectEnumerator]; + + for (size_t i = 0; i < count; i++) { + OFString *key; + OFString *object; + size_t keyLen, objectLen; + + key = [keyEnumerator nextObject]; + object = [objectEnumerator nextObject]; + + keyLen = [key cStringLengthWithEncoding: encoding]; + objectLen = [object + cStringLengthWithEncoding: encoding]; + + envp[i] = OFAllocMemory(keyLen + objectLen + 2, 1); + + memcpy(envp[i], + [key cStringWithEncoding: encoding], keyLen); + envp[i][keyLen] = '='; + memcpy(envp[i] + keyLen + 1, + [object cStringWithEncoding: encoding], objectLen); + envp[i][keyLen + objectLen + 1] = '\0'; + } + } @catch (id e) { + for (size_t i = 0; i < count; i++) + OFFreeMemory(envp[i]); + + OFFreeMemory(envp); + + @throw e; + } + + return envp; +} + +- (bool)lowlevelIsAtEndOfStream +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer + length: (size_t)length +{ + ssize_t ret; + + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = read(_readPipe[0], buffer, length)) < 0) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: errno]; + + if (ret == 0) + _atEndOfStream = true; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + ssize_t bytesWritten; + + if (_writePipe[1] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (length > SSIZE_MAX) + @throw [OFOutOfRangeException exception]; + + if ((bytesWritten = write(_writePipe[1], buffer, length)) < 0) + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: errno]; + + return (size_t)bytesWritten; +} + +- (int)fileDescriptorForReading +{ + return _readPipe[0]; +} + +- (int)fileDescriptorForWriting +{ + return _writePipe[1]; +} + +- (void)closeForWriting +{ + if (_writePipe[1] != -1) + close(_writePipe[1]); + + _writePipe[1] = -1; +} + +- (void)close +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + [self closeForWriting]; + close(_readPipe[0]); + + if (_pid != -1) { + kill(_pid, SIGTERM); + waitpid(_pid, &_status, WNOHANG); + } + + _pid = -1; + _readPipe[0] = -1; + + [super close]; +} + +- (int)waitForTermination +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_pid != -1) { + waitpid(_pid, &_status, 0); + _pid = -1; + } + + return WEXITSTATUS(_status); +} +@end ADDED src/platform/POSIX/OFTLSKey.m Index: src/platform/POSIX/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFTLSKey.m @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + return pthread_key_create(key, NULL); +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return pthread_key_delete(key); +} ADDED src/platform/PowerPC/OFAtomic.h Index: src/platform/PowerPC/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/PowerPC/OFAtomic.h @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} ADDED src/platform/Windows/OFPlainCondition.m Index: src/platform/Windows/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainCondition.m @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFPlainCondition.h" + +#include + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->count = 0; + + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + return EAGAIN; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + int count = condition->count; + + for (int i = 0; i < count; i++) { + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, INFINITE); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, timeout * 1000); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_TIMEOUT: + return ETIMEDOUT; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + if (condition->count != 0) + return EBUSY; + + return (CloseHandle(condition->event) ? 0 : EINVAL); +} ADDED src/platform/Windows/OFPlainMutex.m Index: src/platform/Windows/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainMutex.m @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitializeCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + EnterCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!TryEnterCriticalSection(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + LeaveCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + DeleteCriticalSection(mutex); + + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/Windows/OFPlainThread.m Index: src/platform/Windows/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainThread.m @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFPlainThread.h" + +#import "macros.h" + +#include + +struct ThreadContext { + void (*function)(id); + id object; +}; + +static WINAPI void +functionWrapper(struct ThreadContext *context) +{ + context->function(context->object); + + free(context); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + DWORD priority = THREAD_PRIORITY_NORMAL; + struct ThreadContext *context; + DWORD threadID; + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + + if (attr->priority < 0) + priority = THREAD_PRIORITY_LOWEST + + (1.0 + attr->priority) * + (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); + else + priority = THREAD_PRIORITY_NORMAL + + attr->priority * + (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); + } + + if ((context = malloc(sizeof(*context))) == NULL) + return ENOMEM; + + context->function = function; + context->object = object; + + *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), + (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); + + if (thread == NULL) { + int error; + + switch (GetLastError()) { + case ERROR_NOT_ENOUGH_MEMORY: + error = ENOMEM; + break; + case ERROR_ACCESS_DENIED: + error = EACCES; + break; + default: + OFEnsure(0); + } + + free(context); + return error; + } + + if (attr != NULL && attr->priority != 0) + OFEnsure(!SetThreadPriority(*thread, priority)); + + return 0; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + switch (WaitForSingleObject(thread, INFINITE)) { + case WAIT_OBJECT_0: + CloseHandle(thread); + return 0; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + CloseHandle(thread); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/Windows/OFString+PathAdditions.m Index: src/platform/Windows/OFString+PathAdditions.m ================================================================== --- /dev/null +++ src/platform/Windows/OFString+PathAdditions.m @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +/* + * This file is also used for MS-DOS and MiNT! Don't forget to #ifdef + * Windows-specific parts! + */ + +#include "config.h" + +#import "OFString+PathAdditions.h" +#import "OFArray.h" +#import "OFFileURLHandler.h" +#import "OFURL.h" + +#import "OFInvalidFormatException.h" +#import "OFOutOfRangeException.h" + +int _OFString_PathAdditions_reference; + +@implementation OFString (PathAdditions) ++ (OFString *)pathWithComponents: (OFArray *)components +{ + OFMutableString *ret = [OFMutableString string]; + void *pool = objc_autoreleasePoolPush(); + bool first = true; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if (!first && ![ret hasSuffix: @":"] && + ([component isEqual: @"\\"] || [component isEqual: @"/"])) + continue; + + if (!first && ![ret hasSuffix: @"\\"] && + ![ret hasSuffix: @"/"] && ![ret hasSuffix: @":"]) + [ret appendString: @"\\"]; + + [ret appendString: component]; + + first = false; + } + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (bool)isAbsolutePath +{ +#ifdef OF_WINDOWS + if ([self hasPrefix: @"\\\\"]) + return true; +#endif + + return ([self containsString: @":\\"] || [self containsString: @":/"]); +} + +- (OFArray *)pathComponents +{ + OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t i, last = 0, cStringLength = self.UTF8StringLength; + bool isUNC = false; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return ret; + } + +#ifdef OF_WINDOWS + if ([self hasPrefix: @"\\\\"]) { + isUNC = true; + [ret addObject: @"\\\\"]; + + cString += 2; + cStringLength -= 2; + } +#endif + + for (i = 0; i < cStringLength; i++) { + if (cString[i] == '\\' || cString[i] == '/') { + if (i == 0) + [ret addObject: [OFString + stringWithUTF8String: cString + length: 1]]; + else if (i - last != 0) + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last]]; + + last = i + 1; + } else if (!isUNC && cString[i] == ':') { + if (i + 1 < cStringLength && + (cString[i + 1] == '\\' || cString[i + 1] == '/')) + i++; + + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last + 1]]; + + last = i + 1; + } + } + if (i - last != 0) + [ret addObject: [OFString stringWithUTF8String: cString + last + length: i - last]]; + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (OFString *)lastPathComponent +{ + /* + * Windows/DOS need the full parsing to determine the last path + * component. This could be optimized by not creating the temporary + * objects, though. + */ + void *pool = objc_autoreleasePoolPush(); + OFString *ret = self.pathComponents.lastObject; + + if (ret == nil) { + objc_autoreleasePoolPop(pool); + return @""; + } + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)pathExtension +{ + void *pool = objc_autoreleasePoolPush(); + OFString *ret, *fileName; + size_t pos; + + fileName = self.lastPathComponent; + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + ret = [fileName substringFromIndex: pos + 1]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingLastPathComponent +{ + /* + * Windows/DOS need the full parsing to delete the last path component. + * This could be optimized, though. + */ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + size_t count = components.count; + OFString *ret; + + if (count == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + if (count == 1) { + OFString *firstComponent = components.firstObject; + + if ([firstComponent hasSuffix: @":"] || + [firstComponent hasSuffix: @":\\"] || + [firstComponent hasSuffix: @":/"] || + [firstComponent hasPrefix: @"\\"]) { + ret = [firstComponent retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } + + objc_autoreleasePoolPop(pool); + return @"."; + } + + components = [components objectsInRange: + OFRangeMake(0, components.count - 1)]; + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingPathExtension +{ + void *pool; + OFMutableArray OF_GENERIC(OFString *) *components; + OFString *ret, *fileName; + size_t pos; + + if (self.length == 0) + return [[self copy] autorelease]; + + pool = objc_autoreleasePoolPush(); + components = [[self.pathComponents mutableCopy] autorelease]; + fileName = components.lastObject; + + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + fileName = [fileName substringToIndex: pos]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByStandardizingPath +{ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components; + OFMutableArray OF_GENERIC(OFString *) *array; + OFString *ret; + bool done = false; + + if (self.length == 0) + return @""; + + components = self.pathComponents; + + if (components.count == 1) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + array = [[components mutableCopy] autorelease]; + + while (!done) { + size_t length = array.count; + + done = true; + + for (size_t i = 0; i < length; i++) { + OFString *component = [array objectAtIndex: i]; + OFString *parent = + (i > 0 ? [array objectAtIndex: i - 1] : 0); + + if ([component isEqual: @"."] || + component.length == 0) { + [array removeObjectAtIndex: i]; + + done = false; + break; + } + + if ([component isEqual: @".."] && parent != nil && + ![parent isEqual: @".."] && + ![parent hasSuffix: @":"] && + ![parent hasSuffix: @":\\"] && + ![parent hasSuffix: @"://"] && + (![parent hasPrefix: @"\\"] || i != 1)) { + [array removeObjectsInRange: + OFRangeMake(i - 1, 2)]; + + done = false; + break; + } + } + } + + ret = [[OFString pathWithComponents: array] retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)stringByAppendingPathComponent: (OFString *)component +{ + if ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"]) + return [self stringByAppendingString: component]; + else { + OFMutableString *ret = [[self mutableCopy] autorelease]; + + [ret appendString: @"\\"]; + [ret appendString: component]; + + [ret makeImmutable]; + + return ret; + } +} + +- (OFString *)stringByAppendingPathExtension: (OFString *)extension +{ + if ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"]) { + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *components; + OFString *fileName, *ret; + + components = + [[self.pathComponents mutableCopy] autorelease]; + fileName = [components.lastObject + stringByAppendingFormat: @".%@", extension]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [[OFString pathWithComponents: components] retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } else + return [self stringByAppendingFormat: @".%@", extension]; +} + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + OFString *path = self; + + if ([path hasPrefix: @"\\\\"]) { + OFArray *components = path.pathComponents; + + if (components.count < 2) + @throw [OFInvalidFormatException exception]; + + *URLEncodedHost = [[components objectAtIndex: 1] + stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLHostAllowedCharacterSet]]; + path = [OFString pathWithComponents: [components + objectsInRange: OFRangeMake(2, components.count - 2)]]; + } + + path = [path stringByReplacingOccurrencesOfString: @"\\" + withString: @"/"]; + path = [path stringByPrependingString: @"/"]; + + return path; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"] && + ![path hasSuffix: @":/"]) + path = [path substringToIndex: path.length - 1]; + + path = [path substringFromIndex: 1]; + path = [path stringByReplacingOccurrencesOfString: @"/" + withString: @"\\"]; + + if (URLEncodedHost != nil) { + OFString *host = [URLEncodedHost stringByURLDecoding]; + + if (path.length == 0) + path = [OFString stringWithFormat: @"\\\\%@", host]; + else + path = [OFString stringWithFormat: @"\\\\%@\\%@", + host, path]; + } + + return path; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return [self stringByReplacingOccurrencesOfString: @"\\" + withString: @"/"]; +} +@end ADDED src/platform/Windows/OFSubprocess.m Index: src/platform/Windows/OFSubprocess.m ================================================================== --- /dev/null +++ src/platform/Windows/OFSubprocess.m @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2008-2022 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" + +#include +#include + +#import "OFSubprocess.h" +#import "OFArray.h" +#import "OFData.h" +#import "OFDictionary.h" +#import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" + +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" +#import "OFWriteFailedException.h" + +#include + +@interface OFSubprocess () +- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; +- (char *)of_environmentForDictionary: (OFDictionary *)environment; +@end + +@implementation OFSubprocess ++ (instancetype)subprocessWithProgram: (OFString *)program +{ + return [[[self alloc] initWithProgram: program] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments + environment: environment] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithProgram: (OFString *)program +{ + return [self initWithProgram: program + programName: program + arguments: nil + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + self = [super init]; + + @try { + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pi; + void *pool; + OFMutableString *argumentsString; + + _handle = INVALID_HANDLE_VALUE; + _readPipe[0] = _writePipe[1] = NULL; + + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!SetHandleInformation(_writePipe[1], + HANDLE_FLAG_INHERIT, 0)) + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + memset(&pi, 0, sizeof(pi)); + + pool = objc_autoreleasePoolPush(); + + argumentsString = + [OFMutableString stringWithString: programName]; + [argumentsString replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [argumentsString replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + if ([argumentsString containsString: @" "]) { + [argumentsString prependString: @"\""]; + [argumentsString appendString: @"\""]; + } + + for (OFString *argument in arguments) { + OFMutableString *tmp = + [[argument mutableCopy] autorelease]; + bool containsSpaces = [tmp containsString: @" "]; + + [argumentsString appendString: @" "]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + + [tmp replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [tmp replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + [argumentsString appendString: tmp]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + } + + if ([OFSystemInfo isWindowsNT]) { + size_t length; + OFChar16 *argumentsCopy; + STARTUPINFOW si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + length = argumentsString.UTF16StringLength; + argumentsCopy = OFAllocMemory(length + 1, + sizeof(OFChar16)); + memcpy(argumentsCopy, argumentsString.UTF16String, + (length + 1) * 2); + @try { + if (!CreateProcessW(program.UTF16String, + argumentsCopy, NULL, NULL, TRUE, + CREATE_UNICODE_ENVIRONMENT, + [self of_wideEnvironmentForDictionary: + environment], NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + OFFreeMemory(argumentsCopy); + } + } else { + OFStringEncoding encoding = [OFLocale encoding]; + STARTUPINFO si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + if (!CreateProcessA([program cStringWithEncoding: + encoding], (char *)[argumentsString + cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, + [self of_environmentForDictionary: environment], + NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } + + objc_autoreleasePoolPop(pool); + + _handle = pi.hProcess; + CloseHandle(pi.hThread); + + CloseHandle(_readPipe[1]); + CloseHandle(_writePipe[0]); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_readPipe[0] != NULL) + [self close]; + + [super dealloc]; +} + +- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)environment +{ + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + const OFChar16 equal = '='; + const OFChar16 zero[2] = { 0, 0 }; + + if (environment == nil) + return NULL; + + env = [OFMutableData dataWithItemSize: sizeof(OFChar16)]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: key.UTF16String count: key.UTF16StringLength]; + [env addItems: &equal count: 1]; + [env addItems: object.UTF16String + count: object.UTF16StringLength]; + [env addItems: &zero count: 1]; + } + [env addItems: zero count: 2]; + + return env.mutableItems; +} + +- (char *)of_environmentForDictionary: (OFDictionary *)environment +{ + OFStringEncoding encoding = [OFLocale encoding]; + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + + if (environment == nil) + return NULL; + + env = [OFMutableData data]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: [key cStringWithEncoding: encoding] + count: [key cStringLengthWithEncoding: encoding]]; + [env addItems: "=" count: 1]; + [env addItems: [object cStringWithEncoding: encoding] + count: [object cStringLengthWithEncoding: encoding]]; + [env addItems: "" count: 1]; + } + [env addItems: "\0" count: 2]; + + return env.mutableItems; +} + +- (bool)lowlevelIsAtEndOfStream +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + DWORD ret; + + if (length > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (!ReadFile(_readPipe[0], buffer, (DWORD)length, &ret, NULL)) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + _atEndOfStream = true; + return 0; + } + + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: EIO]; + } + + if (ret == 0) + _atEndOfStream = true; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + DWORD bytesWritten; + + if (length > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (_writePipe[1] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (!WriteFile(_writePipe[1], buffer, (DWORD)length, &bytesWritten, + NULL)) { + int errNo = EIO; + + if (GetLastError() == ERROR_BROKEN_PIPE) + errNo = EPIPE; + + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: errNo]; + } + + return (size_t)bytesWritten; +} + +- (void)closeForWriting +{ + if (_writePipe[1] != NULL) + CloseHandle(_writePipe[1]); + + _writePipe[1] = NULL; +} + +- (void)close +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + [self closeForWriting]; + CloseHandle(_readPipe[0]); + + if (_handle != INVALID_HANDLE_VALUE) { + TerminateProcess(_handle, 0); + CloseHandle(_handle); + } + + _handle = INVALID_HANDLE_VALUE; + _readPipe[0] = NULL; + + [super close]; +} + +- (int)waitForTermination +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handle != INVALID_HANDLE_VALUE) { + DWORD exitCode; + + WaitForSingleObject(_handle, INFINITE); + + if (GetExitCodeProcess(_handle, &exitCode)) + _status = exitCode; + else + _status = GetLastError(); + + CloseHandle(_handle); + _handle = INVALID_HANDLE_VALUE; + } + + return _status; +} +@end ADDED src/platform/Windows/OFTLSKey.m Index: src/platform/Windows/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/Windows/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + *key = TlsAlloc(); + + if (*key == TLS_OUT_OF_INDEXES) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return (TlsFree(key) ? 0 : EINVAL); +} DELETED src/platform/amiga/OFPlainCondition.m Index: src/platform/amiga/OFPlainCondition.m ================================================================== --- src/platform/amiga/OFPlainCondition.m +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "OFPlainCondition.h" - -#include -#include -#ifndef OF_AMIGAOS4 -# include -#endif - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - condition->waitingTasks = NULL; - - return 0; -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return 0; - - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } @finally { - Permit(); - } - - return 0; -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return 0; - - while (condition->waitingTasks != NULL) { - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } - } @finally { - Permit(); - } - - return 0; -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - ULONG signalMask = 0; - - return OFPlainConditionWaitOrExecSignal(condition, mutex, &signalMask); -} - -int -OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, ULONG *signalMask) -{ - struct OFPlainConditionWaitingTask waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - int error = 0; - ULONG mask; - - if (waitingTask.sigBit == -1) - return EAGAIN; - - Forbid(); - - if ((error = OFPlainMutexUnlock(mutex)) != 0) { - FreeSignal(waitingTask.sigBit); - return error; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - mask = Wait((1ul << waitingTask.sigBit) | *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - error = OFPlainMutexLock(mutex); - else - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - error = EINTR; - - FreeSignal(waitingTask.sigBit); - - Permit(); - - return error; -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - ULONG signalMask = 0; - - return OFPlainConditionTimedWaitOrExecSignal(condition, mutex, timeout, - &signalMask); -} - -int -OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, - OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask) -{ - struct OFPlainConditionWaitingTask waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - struct MsgPort port = { - .mp_Node = { - .ln_Type = NT_MSGPORT - }, - .mp_Flags = PA_SIGNAL, - .mp_SigTask = waitingTask.task, - .mp_SigBit = AllocSignal(-1) - }; -#ifdef OF_AMIGAOS4 - struct TimeRequest request = { - .Request = { -#else - struct timerequest request = { - .tr_node = { -#endif - .io_Message = { - .mn_Node = { - .ln_Type = NT_MESSAGE - }, - .mn_ReplyPort = &port, - .mn_Length = sizeof(request) - }, - .io_Command = TR_ADDREQUEST - }, -#ifdef OF_AMIGAOS4 - .Time = { - .Seconds = (ULONG)timeout, - .Microseconds = - (timeout - request.Time.Seconds) * 1000000 -#else - .tr_time = { - .tv_sec = (ULONG)timeout, - .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 -#endif - } - }; - int error = 0; - ULONG mask; - - NewList(&port.mp_MsgList); - - if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { - error = EAGAIN; - goto fail; - } - - if (OpenDevice("timer.device", UNIT_MICROHZ, - (struct IORequest *)&request, 0) != 0) { - error = EAGAIN; - goto fail; - } - - Forbid(); - - if ((error = OFPlainMutexUnlock(mutex)) != 0) { - Permit(); - goto fail; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - SendIO((struct IORequest *)&request); - - mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | - *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - error = OFPlainMutexLock(mutex); - else if (mask & (1ul << port.mp_SigBit)) - error = ETIMEDOUT; - else - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - error = EINTR; - - condition->waitingTasks = waitingTask.next; - - if (!CheckIO((struct IORequest *)&request)) { - AbortIO((struct IORequest *)&request); - WaitIO((struct IORequest *)&request); - } - CloseDevice((struct IORequest *)&request); - - Permit(); - -fail: - if (waitingTask.sigBit != -1) - FreeSignal(waitingTask.sigBit); - if (port.mp_SigBit != -1) - FreeSignal(port.mp_SigBit); - - return error; -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks != NULL) - return EBUSY; - } @finally { - Permit(); - } - - return 0; -} DELETED src/platform/amiga/OFPlainMutex.m Index: src/platform/amiga/OFPlainMutex.m ================================================================== --- src/platform/amiga/OFPlainMutex.m +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "OFPlainMutex.h" - -#include - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - InitSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - ObtainSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - if (!AttemptSemaphore(mutex)) - return EBUSY; - - return 0; -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - ReleaseSemaphore(mutex); - - return 0; -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - return 0; -} - -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexNew(rmutex); -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} DELETED src/platform/amiga/OFPlainThread.m Index: src/platform/amiga/OFPlainThread.m ================================================================== --- src/platform/amiga/OFPlainThread.m +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include -#include - -#import "OFPlainThread.h" -#import "OFData.h" -#import "OFTLSKey.h" - -#include -#include -#include - -#ifndef OF_MORPHOS -extern void OFTLSKeyThreadExited(void); -#endif -static OFTLSKey threadKey; - -OF_CONSTRUCTOR() -{ - OFEnsure(OFTLSKeyNew(&threadKey) == 0); -} - -static void -functionWrapper(void) -{ - bool detached = false; - OFPlainThread thread = - (OFPlainThread)((struct Process *)FindTask(NULL))->pr_ExitData; - OFEnsure(OFTLSKeySet(threadKey, thread) == 0); - - thread->function(thread->object); - - ObtainSemaphore(&thread->semaphore); - @try { - thread->done = true; - -#ifndef OF_MORPHOS - OFTLSKeyThreadExited(); -#endif - - if (thread->detached) - detached = true; - else if (thread->joinTask != NULL) - Signal(thread->joinTask, (1ul << thread->joinSigBit)); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - if (detached) - free(thread); -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return 0; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - OFMutableData *tags = nil; - - if ((*thread = calloc(1, sizeof(**thread))) == NULL) - return ENOMEM; - - @try { - (*thread)->function = function; - (*thread)->object = object; - InitSemaphore(&(*thread)->semaphore); - - tags = [[OFMutableData alloc] - initWithItemSize: sizeof(struct TagItem) - capacity: 12]; -#define ADD_TAG(tag, data) \ - { \ - struct TagItem t = { \ - .ti_Tag = tag, \ - .ti_Data = data \ - }; \ - [tags addItem: &t]; \ - } - ADD_TAG(NP_Entry, (ULONG)functionWrapper) - ADD_TAG(NP_ExitData, (ULONG)*thread) -#ifdef OF_AMIGAOS4 - ADD_TAG(NP_Child, TRUE) -#endif -#ifdef OF_MORPHOS - ADD_TAG(NP_CodeType, CODETYPE_PPC); -#endif - if (name != NULL) - ADD_TAG(NP_Name, (ULONG)name); - - ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) - ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) - ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) - ADD_TAG(NP_CloseInput, FALSE) - ADD_TAG(NP_CloseOutput, FALSE) - ADD_TAG(NP_CloseError, FALSE) - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < 1 || attr->priority > 1) - return EINVAL; - - /* - * -1 should be -128 (lowest possible priority) while - * +1 should be +127 (highest possible priority). - */ - ADD_TAG(NP_Priority, (attr->priority > 0 - ? attr->priority * 127 : attr->priority * 128)) - } - - if (attr != NULL && attr->stackSize != 0) - ADD_TAG(NP_StackSize, attr->stackSize) - else - ADD_TAG(NP_StackSize, - ((struct Process *)FindTask(NULL))->pr_StackSize) - - ADD_TAG(TAG_DONE, 0) -#undef ADD_TAG - - (*thread)->task = (struct Task *)CreateNewProc(tags.items); - if ((*thread)->task == NULL) { - free(*thread); - return EAGAIN; - } - } @catch (id e) { - free(*thread); - @throw e; - } @finally { - [tags release]; - } - - return 0; -} - -OFPlainThread -OFCurrentPlainThread(void) -{ - return OFTLSKeyGet(threadKey); -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) { - ReleaseSemaphore(&thread->semaphore); - - free(thread); - return 0; - } - - @try { - if (thread->detached || thread->joinTask != NULL) - return EINVAL; - - if ((thread->joinSigBit = AllocSignal(-1)) == -1) - return EAGAIN; - - thread->joinTask = FindTask(NULL); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - Wait(1ul << thread->joinSigBit); - FreeSignal(thread->joinSigBit); - - assert(thread->done); - free(thread); - - return 0; -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) - free(thread); - else - thread->detached = true; - - ReleaseSemaphore(&thread->semaphore); - - return 0; -} - -void -OFSetThreadName(const char *name) -{ -} DELETED src/platform/amiga/OFString+PathAdditions.m Index: src/platform/amiga/OFString+PathAdditions.m ================================================================== --- src/platform/amiga/OFString+PathAdditions.m +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFString+PathAdditions.h" -#import "OFArray.h" -#import "OFFileURLHandler.h" - -#import "OFOutOfRangeException.h" - -int _OFString_PathAdditions_reference; - -@implementation OFString (PathAdditions) -+ (OFString *)pathWithComponents: (OFArray *)components -{ - OFMutableString *ret = [OFMutableString string]; - void *pool = objc_autoreleasePoolPush(); - bool firstAfterDevice = true; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if (!firstAfterDevice) - [ret appendString: @"/"]; - - [ret appendString: component]; - - if (![component hasSuffix: @":"]) - firstAfterDevice = false; - } - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (bool)isAbsolutePath -{ - return [self containsString: @":"]; -} - -- (OFArray *)pathComponents -{ - OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t i, last = 0, cStringLength = self.UTF8StringLength; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return ret; - } - - for (i = 0; i < cStringLength; i++) { - if (cString[i] == '/') { - if (i - last != 0) - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last]]; - else - [ret addObject: @"/"]; - - last = i + 1; - } else if (cString[i] == ':') { - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last + 1]]; - - last = i + 1; - } - } - if (i - last != 0) - [ret addObject: [OFString stringWithUTF8String: cString + last - length: i - last]]; - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (OFString *)lastPathComponent -{ - /* - * AmigaOS needs the full parsing to determine the last path component. - * This could be optimized by not creating the temporary objects, - * though. - */ - void *pool = objc_autoreleasePoolPush(); - OFString *ret = self.pathComponents.lastObject; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)pathExtension -{ - void *pool = objc_autoreleasePoolPush(); - OFString *ret, *fileName; - size_t pos; - - fileName = self.lastPathComponent; - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - ret = [fileName substringFromIndex: pos + 1]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingLastPathComponent -{ - /* - * AmigaOS needs the full parsing to delete the last path component. - * This could be optimized, though. - */ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components = self.pathComponents; - size_t count = components.count; - OFString *ret; - - if (count < 2) { - if ([components.firstObject hasSuffix: @":"]) { - ret = [components.firstObject retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; - } - - objc_autoreleasePoolPop(pool); - return @""; - } - - components = [components objectsInRange: - OFRangeMake(0, components.count - 1)]; - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingPathExtension -{ - void *pool; - OFMutableArray OF_GENERIC(OFString *) *components; - OFString *ret, *fileName; - size_t pos; - - if (self.length == 0) - return [[self copy] autorelease]; - - pool = objc_autoreleasePoolPush(); - components = [[self.pathComponents mutableCopy] autorelease]; - fileName = components.lastObject; - - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - fileName = [fileName substringToIndex: pos]; - [components replaceObjectAtIndex: components.count - 1 - withObject: fileName]; - - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByStandardizingPath -{ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components; - OFMutableArray OF_GENERIC(OFString *) *array; - OFString *ret; - bool done = false; - - if (self.length == 0) - return @""; - - components = self.pathComponents; - - if (components.count == 1) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - array = [[components mutableCopy] autorelease]; - - while (!done) { - size_t length = array.count; - - done = true; - - for (size_t i = 0; i < length; i++) { - OFString *component = [array objectAtIndex: i]; - OFString *parent = - (i > 0 ? [array objectAtIndex: i - 1] : 0); - - if (component.length == 0) { - [array removeObjectAtIndex: i]; - - done = false; - break; - } - - if ([component isEqual: @"/"] && - parent != nil && ![parent isEqual: @"/"]) { - [array removeObjectsInRange: - OFRangeMake(i - 1, 2)]; - - done = false; - break; - } - } - } - - ret = [OFString pathWithComponents: array]; - - if ([self hasSuffix: @"/"]) - ret = [ret stringByAppendingString: @"/"]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByAppendingPathComponent: (OFString *)component -{ - if ([self hasSuffix: @"/"] || [self hasSuffix: @":"]) - return [self stringByAppendingString: component]; - else { - OFMutableString *ret = [[self mutableCopy] autorelease]; - - [ret appendString: @"/"]; - [ret appendString: component]; - - [ret makeImmutable]; - - return ret; - } -} - -- (bool)of_isDirectoryPath -{ - return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || - [OFFileURLHandler of_directoryExistsAtPath: self]); -} - -- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost -{ - OFArray OF_GENERIC(OFString *) *components = self.pathComponents; - OFMutableString *ret = [OFMutableString string]; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if ([component isEqual: @"/"]) - [ret appendString: @"/.."]; - else { - [ret appendString: @"/"]; - [ret appendString: component]; - } - } - - [ret makeImmutable]; - - return ret; -} - -- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost -{ - OFString *path = self; - - if (path.length > 1 && [path hasSuffix: @"/"]) - path = [path substringToIndex: path.length - 1]; - - OFMutableArray OF_GENERIC(OFString *) *components; - size_t count; - - path = [path substringFromIndex: 1]; - components = [[[path - componentsSeparatedByString: @"/"] mutableCopy] autorelease]; - count = components.count; - - for (size_t i = 0; i < count; i++) { - OFString *component = [components objectAtIndex: i]; - - if ([component isEqual: @"."]) { - [components removeObjectAtIndex: i]; - count--; - - i--; - continue; - } - - if ([component isEqual: @".."]) - [components replaceObjectAtIndex: i withObject: @"/"]; - } - - return [OFString pathWithComponents: components]; -} - -- (OFString *)of_pathComponentToURLPathComponent -{ - return self; -} -@end DELETED src/platform/amiga/OFTLSKey.m Index: src/platform/amiga/OFTLSKey.m ================================================================== --- src/platform/amiga/OFTLSKey.m +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFTLSKey.h" - -#include -#include - -/* - * As we use this file in both the runtime and ObjFW, and since AmigaOS always - * has the runtime, use the hashtable from the runtime. - */ -#import "runtime/private.h" - -static OFTLSKey firstKey = NULL, lastKey = NULL; -static struct SignalSemaphore semaphore; -static bool semaphoreInitialized = false; - -static uint32_t -hashFunc(const void *ptr) -{ - return (uint32_t)(uintptr_t)ptr; -} - -static bool -equalFunc(const void *ptr1, const void *ptr2) -{ - return (ptr1 == ptr2); -} - -OF_CONSTRUCTOR() -{ - if (!semaphoreInitialized) { - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } -} - -int -OFTLSKeyNew(OFTLSKey *key) -{ - if (!semaphoreInitialized) { - /* - * We might be called from another constructor, while ours has - * not run yet. This is safe, as the constructor is definitely - * run before a thread is spawned. - */ - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } - - if ((*key = malloc(sizeof(**key))) == NULL) - return ENOMEM; - - (*key)->table = NULL; - - ObtainSemaphore(&semaphore); - @try { - (*key)->next = NULL; - (*key)->previous = lastKey; - - if (lastKey != NULL) - lastKey->next = *key; - - lastKey = *key; - - if (firstKey == NULL) - firstKey = *key; - } @finally { - ReleaseSemaphore(&semaphore); - } - - /* We create the hash table lazily. */ - return 0; -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - ObtainSemaphore(&semaphore); - @try { - if (key->previous != NULL) - key->previous->next = key->next; - if (key->next != NULL) - key->next->previous = key->previous; - - if (firstKey == key) - firstKey = key->next; - if (lastKey == key) - lastKey = key->previous; - - objc_hashtable_free(key->table); - free(key); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return 0; -} - -void * -OFTLSKeyGet(OFTLSKey key) -{ - void *ret; - - ObtainSemaphore(&semaphore); - @try { - if (key->table == NULL) - return NULL; - - ret = objc_hashtable_get(key->table, FindTask(NULL)); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return ret; -} - -int -OFTLSKeySet(OFTLSKey key, void *ptr) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - if (key->table == NULL) - key->table = objc_hashtable_new(hashFunc, equalFunc, 2); - - if (ptr == NULL) - objc_hashtable_delete(key->table, task); - else - objc_hashtable_set(key->table, task, ptr); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return 0; -} - -void -OFTLSKeyThreadExited(void) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - for (OFTLSKey iter = firstKey; iter != NULL; iter = iter->next) - if (iter->table != NULL) - objc_hashtable_delete(iter->table, task); - } @finally { - ReleaseSemaphore(&semaphore); - } -} Index: src/platform/libfat/OFString+PathAdditions.m ================================================================== --- src/platform/libfat/OFString+PathAdditions.m +++ src/platform/libfat/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -312,10 +312,31 @@ [ret makeImmutable]; return ret; } } + +- (OFString *)stringByAppendingPathExtension: (OFString *)extension +{ + if ([self hasSuffix: @"/"]) { + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *components; + OFString *fileName, *ret; + + components = + [[self.pathComponents mutableCopy] autorelease]; + fileName = [components.lastObject + stringByAppendingFormat: @".%@", extension]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [[OFString pathWithComponents: components] retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } else + return [self stringByAppendingFormat: @".%@", extension]; +} - (bool)of_isDirectoryPath { return ([self hasSuffix: @"/"] || [OFFileURLHandler of_directoryExistsAtPath: self]); ADDED src/platform/macOS/OFAtomic.h Index: src/platform/macOS/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/macOS/OFAtomic.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2008-2022 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 + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(-i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(-i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return OSAtomicCompareAndSwapInt(o, n, p); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return OSAtomicCompareAndSwap32(o, n, p); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return OSAtomicCompareAndSwapPtr(o, n, p); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + OSMemoryBarrier(); +} DELETED src/platform/morphos/OFTLSKey.m Index: src/platform/morphos/OFTLSKey.m ================================================================== --- src/platform/morphos/OFTLSKey.m +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFTLSKey.h" - -int -OFTLSKeyNew(OFTLSKeyT *key) -{ - *key = TLSAllocA(NULL); - - if (*key == TLS_INVALID_INDEX) - return EAGAIN; - - return 0; -} - -int -OFTLSKeyFree(OFTLSKeyT key) -{ - return (TLSFree(key) ? 0 : EINVAL); -} DELETED src/platform/posix/OFPlainCondition.m Index: src/platform/posix/OFPlainCondition.m ================================================================== --- src/platform/posix/OFPlainCondition.m +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFPlainCondition.h" - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - return pthread_cond_init(condition, NULL); -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - return pthread_cond_signal(condition); -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - return pthread_cond_broadcast(condition); -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - return pthread_cond_wait(condition, mutex); -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - struct timespec ts; - - ts.tv_sec = (time_t)timeout; - ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); - - return pthread_cond_timedwait(condition, mutex, &ts); -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - return pthread_cond_destroy(condition); -} DELETED src/platform/posix/OFPlainMutex.m Index: src/platform/posix/OFPlainMutex.m ================================================================== --- src/platform/posix/OFPlainMutex.m +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFPlainMutex.h" - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - return pthread_mutex_init(mutex, NULL); -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - return pthread_mutex_lock(mutex); -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - return pthread_mutex_trylock(mutex); -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - return pthread_mutex_unlock(mutex); -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - return pthread_mutex_destroy(mutex); -} - -#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - int error; - pthread_mutexattr_t attr; - - if ((error = pthread_mutexattr_init(&attr)) != 0) - return error; - - if ((error = pthread_mutexattr_settype(&attr, - PTHREAD_MUTEX_RECURSIVE)) != 0) - return error; - - if ((error = pthread_mutex_init(rmutex, &attr)) != 0) - return error; - - if ((error = pthread_mutexattr_destroy(&attr)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} -#else -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - int error; - - if ((error = OFPlainMutexNew(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeyNew(&rmutex->count)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 0) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count + 1))) != 0) - return error; - - return 0; - } - - if ((error = OFPlainMutexLock(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { - OFPlainMutexUnlock(&rmutex->mutex); - return error; - } - - return 0; -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 0) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count + 1))) != 0) - return error; - - return 0; - } - - if ((error = OFPlainMutexTryLock(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { - OFPlainMutexUnlock(&rmutex->mutex); - return error; - } - - return 0; -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); - int error; - - if (count > 1) { - if ((error = OFTLSKeySet(rmutex->count, - (void *)(count - 1))) != 0) - return error; - - return 0; - } - - if ((error = OFTLSKeySet(rmutex->count, (void *)0)) != 0) - return error; - - if ((error = OFPlainMutexUnlock(&rmutex->mutex)) != 0) - return error; - - return 0; -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - int error; - - if ((error = OFPlainMutexFree(&rmutex->mutex)) != 0) - return error; - - if ((error = OFTLSKeyFree(rmutex->count)) != 0) - return error; - - return 0; -} -#endif DELETED src/platform/posix/OFPlainThread.m Index: src/platform/posix/OFPlainThread.m ================================================================== --- src/platform/posix/OFPlainThread.m +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#ifdef HAVE_PTHREAD_NP_H -# include -#endif - -#ifdef OF_HAIKU -# include -#endif - -#import "OFPlainThread.h" - -#import "macros.h" - -static int minPrio = 0, maxPrio = 0, normalPrio = 0; - -struct ThreadContext { - void (*function)(id object); - id object; - const char *name; -}; - -/* - * This is done here to make sure this is done as early as possible in the main - * thread. - */ -OF_CONSTRUCTOR() -{ - pthread_attr_t attr; - - if (pthread_attr_init(&attr) == 0) { -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - int policy; -#endif - struct sched_param param; - -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - if (pthread_attr_getschedpolicy(&attr, &policy) == 0) { - minPrio = sched_get_priority_min(policy); - maxPrio = sched_get_priority_max(policy); - - if (minPrio == -1 || maxPrio == -1) - minPrio = maxPrio = 0; - } -#endif - - if (pthread_attr_getschedparam(&attr, ¶m) != 0) - normalPrio = param.sched_priority; - else - minPrio = maxPrio = 0; - - pthread_attr_destroy(&attr); - } -} - -static void * -functionWrapper(void *data) -{ - struct ThreadContext *ctx = data; - - if (ctx->name != NULL) - OFSetThreadName(ctx->name); - - pthread_cleanup_push(free, data); - - ctx->function(ctx->object); - - pthread_cleanup_pop(1); - return NULL; -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - int error; - pthread_attr_t POSIXAttr; - - attr->priority = 0; - attr->stackSize = 0; - - if ((error = pthread_attr_init(&POSIXAttr)) != 0) { - if (error == ENOSYS) - return 0; - - return error; - } - - error = pthread_attr_getstacksize(&POSIXAttr, &attr->stackSize); - - pthread_attr_destroy(&POSIXAttr); - - return error; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - int error = 0; - pthread_attr_t POSIXAttr; - bool POSIXAttrAvailable = true; - - if ((error = pthread_attr_init(&POSIXAttr)) != 0) { - if (error == ENOSYS) - POSIXAttrAvailable = false; - else - return error; - } - - @try { - struct ThreadContext *ctx; - - if (attr != NULL && POSIXAttrAvailable) { -#ifndef OF_HPUX - struct sched_param param; -#endif - - if (attr->priority < -1 || attr->priority > 1) - return EINVAL; - -#ifndef OF_HPUX -# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED - if ((error = pthread_attr_setinheritsched(&POSIXAttr, - PTHREAD_EXPLICIT_SCHED)) != 0) - return error; -# endif - - if ((error = pthread_attr_getschedparam(&POSIXAttr, - ¶m)) != 0) - return error; - - if (attr->priority < 0) { - param.sched_priority = minPrio + - (1.0f + attr->priority) * - (normalPrio - minPrio); - } else - param.sched_priority = normalPrio + - attr->priority * (maxPrio - normalPrio); - - if ((error = pthread_attr_setschedparam(&POSIXAttr, - ¶m)) != 0) - return error; -#endif - - if (attr->stackSize > 0) { - if ((error = pthread_attr_setstacksize( - &POSIXAttr, attr->stackSize)) != 0) - return error; - } - } - - if ((ctx = malloc(sizeof(*ctx))) == NULL) - return ENOMEM; - - ctx->function = function; - ctx->object = object; - ctx->name = name; - - error = pthread_create(thread, - (POSIXAttrAvailable ? &POSIXAttr : NULL), functionWrapper, - ctx); - } @finally { - if (POSIXAttrAvailable) - pthread_attr_destroy(&POSIXAttr); - } - - return error; -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - void *ret; - - return pthread_join(thread, &ret); -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - return pthread_detach(thread); -} - -void -OFSetThreadName(const char *name) -{ -#if defined(OF_HAIKU) - rename_thread(find_thread(NULL), name); -#elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(pthread_self(), name); -#elif defined(HAVE_PTHREAD_SETNAME_NP) -# if defined(OF_MACOS) || defined(OF_IOS) - pthread_setname_np(name); -# elif defined(__GLIBC__) - char buffer[16]; - - strncpy(buffer, name, 15); - buffer[15] = 0; - - pthread_setname_np(pthread_self(), buffer); -# endif -#endif -} DELETED src/platform/posix/OFString+PathAdditions.m Index: src/platform/posix/OFString+PathAdditions.m ================================================================== --- src/platform/posix/OFString+PathAdditions.m +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFString+PathAdditions.h" -#import "OFArray.h" -#import "OFFileURLHandler.h" - -#import "OFOutOfRangeException.h" - -int _OFString_PathAdditions_reference; - -@implementation OFString (PathAdditions) -+ (OFString *)pathWithComponents: (OFArray *)components -{ - OFMutableString *ret = [OFMutableString string]; - void *pool = objc_autoreleasePoolPush(); - bool first = true; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if (!first && [component isEqual: @"/"]) - continue; - - if (!first && ![ret hasSuffix: @"/"]) - [ret appendString: @"/"]; - - [ret appendString: component]; - - first = false; - } - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (bool)isAbsolutePath -{ - return [self hasPrefix: @"/"]; -} - -- (OFArray *)pathComponents -{ - OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t i, last = 0, cStringLength = self.UTF8StringLength; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return ret; - } - - for (i = 0; i < cStringLength; i++) { - if (cString[i] == '/') { - if (i == 0) - [ret addObject: @"/"]; - else if (i - last != 0) - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last]]; - - last = i + 1; - } - } - if (i - last != 0) - [ret addObject: [OFString stringWithUTF8String: cString + last - length: i - last]]; - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (OFString *)lastPathComponent -{ - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t cStringLength = self.UTF8StringLength; - ssize_t i; - OFString *ret; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - if (cString[cStringLength - 1] == '/') - cStringLength--; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return @"/"; - } - - if (cStringLength - 1 > SSIZE_MAX) - @throw [OFOutOfRangeException exception]; - - for (i = cStringLength - 1; i >= 0; i--) { - if (cString[i] == '/') { - i++; - break; - } - } - - /* - * Only one component, but the trailing delimiter might have been - * removed, so return a new string anyway. - */ - if (i < 0) - i = 0; - - ret = [[OFString alloc] initWithUTF8String: cString + i - length: cStringLength - i]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)pathExtension -{ - void *pool = objc_autoreleasePoolPush(); - OFString *ret, *fileName; - size_t pos; - - fileName = self.lastPathComponent; - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - ret = [fileName substringFromIndex: pos + 1]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingLastPathComponent -{ - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t cStringLength = self.UTF8StringLength; - OFString *ret; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - if (cString[cStringLength - 1] == '/') - cStringLength--; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return @"/"; - } - - for (size_t i = cStringLength; i >= 1; i--) { - if (cString[i - 1] == '/') { - if (i == 1) { - objc_autoreleasePoolPop(pool); - return @"/"; - } - - ret = [[OFString alloc] initWithUTF8String: cString - length: i - 1]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; - } - } - - objc_autoreleasePoolPop(pool); - - return @"."; -} - -- (OFString *)stringByDeletingPathExtension -{ - void *pool; - OFMutableArray OF_GENERIC(OFString *) *components; - OFString *ret, *fileName; - size_t pos; - - if (self.length == 0) - return [[self copy] autorelease]; - - pool = objc_autoreleasePoolPush(); - components = [[self.pathComponents mutableCopy] autorelease]; - fileName = components.lastObject; - - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - fileName = [fileName substringToIndex: pos]; - [components replaceObjectAtIndex: [components count] - 1 - withObject: fileName]; - - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByStandardizingPath -{ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components; - OFMutableArray OF_GENERIC(OFString *) *array; - OFString *ret; - bool done = false, startsWithSlash; - - if (self.length == 0) - return @""; - - components = self.pathComponents; - - if (components.count == 1) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - array = [[components mutableCopy] autorelease]; - startsWithSlash = [self hasPrefix: @"/"]; - - if (startsWithSlash) - [array removeObjectAtIndex: 0]; - - while (!done) { - size_t length = array.count; - - done = true; - - for (size_t i = 0; i < length; i++) { - OFString *component = [array objectAtIndex: i]; - OFString *parent = - (i > 0 ? [array objectAtIndex: i - 1] : 0); - - if ([component isEqual: @"."] || - component.length == 0) { - [array removeObjectAtIndex: i]; - - done = false; - break; - } - - if ([component isEqual: @".."] && - parent != nil && ![parent isEqual: @".."]) { - [array removeObjectsInRange: - OFRangeMake(i - 1, 2)]; - - done = false; - break; - } - } - } - - if (startsWithSlash) - [array insertObject: @"" atIndex: 0]; - - if ([self hasSuffix: @"/"]) - [array addObject: @""]; - - ret = [[array componentsJoinedByString: @"/"] retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)stringByAppendingPathComponent: (OFString *)component -{ - if ([self hasSuffix: @"/"]) - return [self stringByAppendingString: component]; - else { - OFMutableString *ret = [[self mutableCopy] autorelease]; - - [ret appendString: @"/"]; - [ret appendString: component]; - - [ret makeImmutable]; - - return ret; - } -} - -- (bool)of_isDirectoryPath -{ - return ([self hasSuffix: @"/"] || - [OFFileURLHandler of_directoryExistsAtPath: self]); -} - -- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost -{ - return self; -} - -- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost -{ - OFString *path = self; - - if (path.length > 1 && [path hasSuffix: @"/"]) - path = [path substringToIndex: path.length - 1]; - - return path; -} - -- (OFString *)of_pathComponentToURLPathComponent -{ - return self; -} -@end DELETED src/platform/posix/OFSubprocess.m Index: src/platform/posix/OFSubprocess.m ================================================================== --- src/platform/posix/OFSubprocess.m +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include -#include - -#include - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#include "unistd_wrapper.h" -#ifdef HAVE_SPAWN_H -# include -#endif - -#import "OFSubprocess.h" -#import "OFString.h" -#import "OFArray.h" -#import "OFDictionary.h" -#import "OFLocale.h" - -#import "OFInitializationFailedException.h" -#import "OFNotOpenException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFWriteFailedException.h" - -#ifndef HAVE_POSIX_SPAWNP -extern char **environ; -#endif - -@interface OFSubprocess () -- (void)of_getArgv: (char ***)argv - forProgramName: (OFString *)programName - andArguments: (OFArray *)arguments; -- (char **)of_environmentForDictionary: (OFDictionary *)dictionary; -@end - -@implementation OFSubprocess -+ (instancetype)subprocessWithProgram: (OFString *)program -{ - return [[[self alloc] initWithProgram: program] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - arguments: arguments] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments - environment: environment] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithProgram: (OFString *)program -{ - return [self initWithProgram: program - programName: program - arguments: nil - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *path; - char **argv, **env = NULL; - - _pid = -1; - _readPipe[0] = _writePipe[1] = -1; - - if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - path = [program cStringWithEncoding: [OFLocale encoding]]; - [self of_getArgv: &argv - forProgramName: programName - andArguments: arguments]; - - @try { - env = [self of_environmentForDictionary: environment]; -#ifdef HAVE_POSIX_SPAWNP - posix_spawn_file_actions_t actions; - posix_spawnattr_t attr; - - if (posix_spawn_file_actions_init(&actions) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (posix_spawnattr_init(&attr) != 0) { - posix_spawn_file_actions_destroy(&actions); - - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } - - @try { - if (posix_spawn_file_actions_addclose(&actions, - _readPipe[0]) != 0 || - posix_spawn_file_actions_addclose(&actions, - _writePipe[1]) != 0 || - posix_spawn_file_actions_adddup2(&actions, - _writePipe[0], 0) != 0 || - posix_spawn_file_actions_adddup2(&actions, - _readPipe[1], 1) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - -# ifdef POSIX_SPAWN_CLOEXEC_DEFAULT - if (posix_spawnattr_setflags(&attr, - POSIX_SPAWN_CLOEXEC_DEFAULT) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; -# endif - - if (posix_spawnp(&_pid, path, &actions, &attr, - argv, env) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } @finally { - posix_spawn_file_actions_destroy(&actions); - posix_spawnattr_destroy(&attr); - } -#else - if ((_pid = vfork()) == 0) { - environ = env; - - close(_readPipe[0]); - close(_writePipe[1]); - dup2(_writePipe[0], 0); - dup2(_readPipe[1], 1); - execvp(path, argv); - - _exit(EXIT_FAILURE); - } - - if (_pid == -1) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; -#endif - } @finally { - char **iter; - - close(_readPipe[1]); - close(_writePipe[0]); - OFFreeMemory(argv); - - for (iter = env; *iter != NULL; iter++) - OFFreeMemory(*iter); - - OFFreeMemory(env); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - if (_readPipe[0] != -1) - [self close]; - - [super dealloc]; -} - -- (void)of_getArgv: (char ***)argv - forProgramName: (OFString *)programName - andArguments: (OFArray *)arguments -{ - OFString *const *objects = arguments.objects; - size_t i, count = arguments.count; - OFStringEncoding encoding; - - *argv = OFAllocMemory(count + 2, sizeof(char *)); - - encoding = [OFLocale encoding]; - - (*argv)[0] = (char *)[programName cStringWithEncoding: encoding]; - - for (i = 0; i < count; i++) - (*argv)[i + 1] = - (char *)[objects[i] cStringWithEncoding: encoding]; - - (*argv)[i + 1] = NULL; -} - -- (char **)of_environmentForDictionary: (OFDictionary *)environment -{ - char **envp; - size_t count; - OFStringEncoding encoding; - - if (environment == nil) - return NULL; - - encoding = [OFLocale encoding]; - - count = environment.count; - envp = OFAllocZeroedMemory(count + 1, sizeof(char *)); - - @try { - OFEnumerator *keyEnumerator = [environment keyEnumerator]; - OFEnumerator *objectEnumerator = [environment objectEnumerator]; - - for (size_t i = 0; i < count; i++) { - OFString *key; - OFString *object; - size_t keyLen, objectLen; - - key = [keyEnumerator nextObject]; - object = [objectEnumerator nextObject]; - - keyLen = [key cStringLengthWithEncoding: encoding]; - objectLen = [object - cStringLengthWithEncoding: encoding]; - - envp[i] = OFAllocMemory(keyLen + objectLen + 2, 1); - - memcpy(envp[i], - [key cStringWithEncoding: encoding], keyLen); - envp[i][keyLen] = '='; - memcpy(envp[i] + keyLen + 1, - [object cStringWithEncoding: encoding], objectLen); - envp[i][keyLen + objectLen + 1] = '\0'; - } - } @catch (id e) { - for (size_t i = 0; i < count; i++) - OFFreeMemory(envp[i]); - - OFFreeMemory(envp); - - @throw e; - } - - return envp; -} - -- (bool)lowlevelIsAtEndOfStream -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _atEndOfStream; -} - -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length -{ - ssize_t ret; - - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if ((ret = read(_readPipe[0], buffer, length)) < 0) - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: errno]; - - if (ret == 0) - _atEndOfStream = true; - - return ret; -} - -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length -{ - ssize_t bytesWritten; - - if (_writePipe[1] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (length > SSIZE_MAX) - @throw [OFOutOfRangeException exception]; - - if ((bytesWritten = write(_writePipe[1], buffer, length)) < 0) - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: errno]; - - return (size_t)bytesWritten; -} - -- (int)fileDescriptorForReading -{ - return _readPipe[0]; -} - -- (int)fileDescriptorForWriting -{ - return _writePipe[1]; -} - -- (void)closeForWriting -{ - if (_writePipe[1] != -1) - close(_writePipe[1]); - - _writePipe[1] = -1; -} - -- (void)close -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - [self closeForWriting]; - close(_readPipe[0]); - - if (_pid != -1) { - kill(_pid, SIGTERM); - waitpid(_pid, &_status, WNOHANG); - } - - _pid = -1; - _readPipe[0] = -1; - - [super close]; -} - -- (int)waitForTermination -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (_pid != -1) { - waitpid(_pid, &_status, 0); - _pid = -1; - } - - return WEXITSTATUS(_status); -} -@end DELETED src/platform/posix/OFTLSKey.m Index: src/platform/posix/OFTLSKey.m ================================================================== --- src/platform/posix/OFTLSKey.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFTLSKey.h" - -int -OFTLSKeyNew(OFTLSKey *key) -{ - return pthread_key_create(key, NULL); -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - return pthread_key_delete(key); -} DELETED src/platform/windows/OFPlainCondition.m Index: src/platform/windows/OFPlainCondition.m ================================================================== --- src/platform/windows/OFPlainCondition.m +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "OFPlainCondition.h" - -#include - -int -OFPlainConditionNew(OFPlainCondition *condition) -{ - condition->count = 0; - - if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) - return EAGAIN; - - return 0; -} - -int -OFPlainConditionSignal(OFPlainCondition *condition) -{ - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - } - - return 0; -} - -int -OFPlainConditionBroadcast(OFPlainCondition *condition) -{ - int count = condition->count; - - for (int i = 0; i < count; i++) { - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - } - } - - return 0; -} - -int -OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) -{ - int error; - DWORD status; - - if ((error = OFPlainMutexUnlock(mutex)) != 0) - return error; - - OFAtomicIntIncrease(&condition->count); - status = WaitForSingleObject(condition->event, INFINITE); - OFAtomicIntDecrease(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return OFPlainMutexLock(mutex); - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, - OFTimeInterval timeout) -{ - int error; - DWORD status; - - if ((error = OFPlainMutexUnlock(mutex)) != 0) - return error; - - OFAtomicIntIncrease(&condition->count); - status = WaitForSingleObject(condition->event, timeout * 1000); - OFAtomicIntDecrease(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return OFPlainMutexLock(mutex); - case WAIT_TIMEOUT: - return ETIMEDOUT; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainConditionFree(OFPlainCondition *condition) -{ - if (condition->count != 0) - return EBUSY; - - return (CloseHandle(condition->event) ? 0 : EINVAL); -} DELETED src/platform/windows/OFPlainMutex.m Index: src/platform/windows/OFPlainMutex.m ================================================================== --- src/platform/windows/OFPlainMutex.m +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "OFPlainMutex.h" - -#include - -int -OFPlainMutexNew(OFPlainMutex *mutex) -{ - InitializeCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexLock(OFPlainMutex *mutex) -{ - EnterCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexTryLock(OFPlainMutex *mutex) -{ - if (!TryEnterCriticalSection(mutex)) - return EBUSY; - - return 0; -} - -int -OFPlainMutexUnlock(OFPlainMutex *mutex) -{ - LeaveCriticalSection(mutex); - - return 0; -} - -int -OFPlainMutexFree(OFPlainMutex *mutex) -{ - DeleteCriticalSection(mutex); - - return 0; -} - -int -OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexNew(rmutex); -} - -int -OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexLock(rmutex); -} - -int -OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexTryLock(rmutex); -} - -int -OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexUnlock(rmutex); -} - -int -OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) -{ - return OFPlainMutexFree(rmutex); -} DELETED src/platform/windows/OFPlainThread.m Index: src/platform/windows/OFPlainThread.m ================================================================== --- src/platform/windows/OFPlainThread.m +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "OFPlainThread.h" - -#import "macros.h" - -#include - -struct ThreadContext { - void (*function)(id); - id object; -}; - -static WINAPI void -functionWrapper(struct ThreadContext *context) -{ - context->function(context->object); - - free(context); -} - -int -OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return 0; -} - -int -OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), - id object, const OFPlainThreadAttributes *attr) -{ - DWORD priority = THREAD_PRIORITY_NORMAL; - struct ThreadContext *context; - DWORD threadID; - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < -1 || attr->priority > 1) - return EINVAL; - - if (attr->priority < 0) - priority = THREAD_PRIORITY_LOWEST + - (1.0 + attr->priority) * - (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); - else - priority = THREAD_PRIORITY_NORMAL + - attr->priority * - (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); - } - - if ((context = malloc(sizeof(*context))) == NULL) - return ENOMEM; - - context->function = function; - context->object = object; - - *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), - (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); - - if (thread == NULL) { - int error; - - switch (GetLastError()) { - case ERROR_NOT_ENOUGH_MEMORY: - error = ENOMEM; - break; - case ERROR_ACCESS_DENIED: - error = EACCES; - break; - default: - OFEnsure(0); - } - - free(context); - return error; - } - - if (attr != NULL && attr->priority != 0) - OFEnsure(!SetThreadPriority(*thread, priority)); - - return 0; -} - -int -OFPlainThreadJoin(OFPlainThread thread) -{ - switch (WaitForSingleObject(thread, INFINITE)) { - case WAIT_OBJECT_0: - CloseHandle(thread); - return 0; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - return EINVAL; - default: - OFEnsure(0); - } - default: - OFEnsure(0); - } -} - -int -OFPlainThreadDetach(OFPlainThread thread) -{ - CloseHandle(thread); - - return 0; -} - -void -OFSetThreadName(const char *name) -{ -} DELETED src/platform/windows/OFString+PathAdditions.m Index: src/platform/windows/OFString+PathAdditions.m ================================================================== --- src/platform/windows/OFString+PathAdditions.m +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2008-2021 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. - */ - -/* - * This file is also used for MS-DOS! Don't forget to #ifdef Windows-specific - * parts! - */ - -#include "config.h" - -#import "OFString+PathAdditions.h" -#import "OFArray.h" -#import "OFFileURLHandler.h" -#import "OFURL.h" - -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" - -int _OFString_PathAdditions_reference; - -@implementation OFString (PathAdditions) -+ (OFString *)pathWithComponents: (OFArray *)components -{ - OFMutableString *ret = [OFMutableString string]; - void *pool = objc_autoreleasePoolPush(); - bool first = true; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if (!first && ![ret hasSuffix: @":"] && - ([component isEqual: @"\\"] || [component isEqual: @"/"])) - continue; - - if (!first && ![ret hasSuffix: @"\\"] && - ![ret hasSuffix: @"/"] && ![ret hasSuffix: @":"]) - [ret appendString: @"\\"]; - - [ret appendString: component]; - - first = false; - } - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (bool)isAbsolutePath -{ -#ifdef OF_WINDOWS - if ([self hasPrefix: @"\\\\"]) - return true; -#endif - - return ([self containsString: @":\\"] || [self containsString: @":/"]); -} - -- (OFArray *)pathComponents -{ - OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t i, last = 0, cStringLength = self.UTF8StringLength; - bool isUNC = false; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return ret; - } - -#ifdef OF_WINDOWS - if ([self hasPrefix: @"\\\\"]) { - isUNC = true; - [ret addObject: @"\\\\"]; - - cString += 2; - cStringLength -= 2; - } -#endif - - for (i = 0; i < cStringLength; i++) { - if (cString[i] == '\\' || cString[i] == '/') { - if (i == 0) - [ret addObject: [OFString - stringWithUTF8String: cString - length: 1]]; - else if (i - last != 0) - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last]]; - - last = i + 1; - } else if (!isUNC && cString[i] == ':') { - if (i + 1 < cStringLength && - (cString[i + 1] == '\\' || cString[i + 1] == '/')) - i++; - - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last + 1]]; - - last = i + 1; - } - } - if (i - last != 0) - [ret addObject: [OFString stringWithUTF8String: cString + last - length: i - last]]; - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (OFString *)lastPathComponent -{ - /* - * Windows/DOS need the full parsing to determine the last path - * component. This could be optimized by not creating the temporary - * objects, though. - */ - void *pool = objc_autoreleasePoolPush(); - OFString *ret = self.pathComponents.lastObject; - - if (ret == nil) { - objc_autoreleasePoolPop(pool); - return @""; - } - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)pathExtension -{ - void *pool = objc_autoreleasePoolPush(); - OFString *ret, *fileName; - size_t pos; - - fileName = self.lastPathComponent; - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - ret = [fileName substringFromIndex: pos + 1]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingLastPathComponent -{ - /* - * Windows/DOS need the full parsing to delete the last path component. - * This could be optimized, though. - */ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components = self.pathComponents; - size_t count = components.count; - OFString *ret; - - if (count == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - if (count == 1) { - OFString *firstComponent = components.firstObject; - - if ([firstComponent hasSuffix: @":"] || - [firstComponent hasSuffix: @":\\"] || - [firstComponent hasSuffix: @":/"] || - [firstComponent hasPrefix: @"\\"]) { - ret = [firstComponent retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; - } - - objc_autoreleasePoolPop(pool); - return @"."; - } - - components = [components objectsInRange: - OFRangeMake(0, components.count - 1)]; - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingPathExtension -{ - void *pool; - OFMutableArray OF_GENERIC(OFString *) *components; - OFString *ret, *fileName; - size_t pos; - - if (self.length == 0) - return [[self copy] autorelease]; - - pool = objc_autoreleasePoolPush(); - components = [[self.pathComponents mutableCopy] autorelease]; - fileName = components.lastObject; - - pos = [fileName rangeOfString: @"." - options: OFStringSearchBackwards].location; - if (pos == OFNotFound || pos == 0) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - fileName = [fileName substringToIndex: pos]; - [components replaceObjectAtIndex: components.count - 1 - withObject: fileName]; - - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByStandardizingPath -{ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components; - OFMutableArray OF_GENERIC(OFString *) *array; - OFString *ret; - bool done = false; - - if (self.length == 0) - return @""; - - components = self.pathComponents; - - if (components.count == 1) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - array = [[components mutableCopy] autorelease]; - - while (!done) { - size_t length = array.count; - - done = true; - - for (size_t i = 0; i < length; i++) { - OFString *component = [array objectAtIndex: i]; - OFString *parent = - (i > 0 ? [array objectAtIndex: i - 1] : 0); - - if ([component isEqual: @"."] || - component.length == 0) { - [array removeObjectAtIndex: i]; - - done = false; - break; - } - - if ([component isEqual: @".."] && parent != nil && - ![parent isEqual: @".."] && - ![parent hasSuffix: @":"] && - ![parent hasSuffix: @":\\"] && - ![parent hasSuffix: @"://"] && - (![parent hasPrefix: @"\\"] || i != 1)) { - [array removeObjectsInRange: - OFRangeMake(i - 1, 2)]; - - done = false; - break; - } - } - } - - ret = [[OFString pathWithComponents: array] retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)stringByAppendingPathComponent: (OFString *)component -{ - if ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"]) - return [self stringByAppendingString: component]; - else { - OFMutableString *ret = [[self mutableCopy] autorelease]; - - [ret appendString: @"\\"]; - [ret appendString: component]; - - [ret makeImmutable]; - - return ret; - } -} - -- (bool)of_isDirectoryPath -{ - return ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"] || - [OFFileURLHandler of_directoryExistsAtPath: self]); -} - -- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost -{ - OFString *path = self; - - if ([path hasPrefix: @"\\\\"]) { - OFArray *components = path.pathComponents; - - if (components.count < 2) - @throw [OFInvalidFormatException exception]; - - *URLEncodedHost = [[components objectAtIndex: 1] - stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLHostAllowedCharacterSet]]; - path = [OFString pathWithComponents: [components - objectsInRange: OFRangeMake(2, components.count - 2)]]; - } - - path = [path stringByReplacingOccurrencesOfString: @"\\" - withString: @"/"]; - path = [path stringByPrependingString: @"/"]; - - return path; -} - -- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost -{ - OFString *path = self; - - if (path.length > 1 && [path hasSuffix: @"/"] && - ![path hasSuffix: @":/"]) - path = [path substringToIndex: path.length - 1]; - - path = [path substringFromIndex: 1]; - path = [path stringByReplacingOccurrencesOfString: @"/" - withString: @"\\"]; - - if (URLEncodedHost != nil) { - OFString *host = [URLEncodedHost stringByURLDecoding]; - - if (path.length == 0) - path = [OFString stringWithFormat: @"\\\\%@", host]; - else - path = [OFString stringWithFormat: @"\\\\%@\\%@", - host, path]; - } - - return path; -} - -- (OFString *)of_pathComponentToURLPathComponent -{ - return [self stringByReplacingOccurrencesOfString: @"\\" - withString: @"/"]; -} -@end DELETED src/platform/windows/OFSubprocess.m Index: src/platform/windows/OFSubprocess.m ================================================================== --- src/platform/windows/OFSubprocess.m +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include -#include - -#import "OFSubprocess.h" -#import "OFArray.h" -#import "OFData.h" -#import "OFDictionary.h" -#import "OFLocale.h" -#import "OFString.h" -#import "OFSystemInfo.h" - -#import "OFInitializationFailedException.h" -#import "OFNotOpenException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFWriteFailedException.h" - -#include - -@interface OFSubprocess () -- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; -- (char *)of_environmentForDictionary: (OFDictionary *)environment; -@end - -@implementation OFSubprocess -+ (instancetype)subprocessWithProgram: (OFString *)program -{ - return [[[self alloc] initWithProgram: program] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - arguments: arguments] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments] autorelease]; -} - -+ (instancetype)subprocessWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments - environment: environment] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithProgram: (OFString *)program -{ - return [self initWithProgram: program - programName: program - arguments: nil - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - self = [super init]; - - @try { - SECURITY_ATTRIBUTES sa; - PROCESS_INFORMATION pi; - void *pool; - OFMutableString *argumentsString; - - _handle = INVALID_HANDLE_VALUE; - _readPipe[0] = _writePipe[1] = NULL; - - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!SetHandleInformation(_writePipe[1], - HANDLE_FLAG_INHERIT, 0)) - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - memset(&pi, 0, sizeof(pi)); - - pool = objc_autoreleasePoolPush(); - - argumentsString = - [OFMutableString stringWithString: programName]; - [argumentsString replaceOccurrencesOfString: @"\\\"" - withString: @"\\\\\""]; - [argumentsString replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; - - if ([argumentsString containsString: @" "]) { - [argumentsString prependString: @"\""]; - [argumentsString appendString: @"\""]; - } - - for (OFString *argument in arguments) { - OFMutableString *tmp = - [[argument mutableCopy] autorelease]; - bool containsSpaces = [tmp containsString: @" "]; - - [argumentsString appendString: @" "]; - - if (containsSpaces) - [argumentsString appendString: @"\""]; - - [tmp replaceOccurrencesOfString: @"\\\"" - withString: @"\\\\\""]; - [tmp replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; - - [argumentsString appendString: tmp]; - - if (containsSpaces) - [argumentsString appendString: @"\""]; - } - - if ([OFSystemInfo isWindowsNT]) { - size_t length; - OFChar16 *argumentsCopy; - STARTUPINFOW si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = _writePipe[0]; - si.hStdOutput = _readPipe[1]; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags |= STARTF_USESTDHANDLES; - - length = argumentsString.UTF16StringLength; - argumentsCopy = OFAllocMemory(length + 1, - sizeof(OFChar16)); - memcpy(argumentsCopy, argumentsString.UTF16String, - (length + 1) * 2); - @try { - if (!CreateProcessW(program.UTF16String, - argumentsCopy, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, - [self of_wideEnvironmentForDictionary: - environment], NULL, &si, &pi)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } @finally { - OFFreeMemory(argumentsCopy); - } - } else { - OFStringEncoding encoding = [OFLocale encoding]; - STARTUPINFO si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = _writePipe[0]; - si.hStdOutput = _readPipe[1]; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags |= STARTF_USESTDHANDLES; - - if (!CreateProcessA([program cStringWithEncoding: - encoding], (char *)[argumentsString - cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, - [self of_environmentForDictionary: environment], - NULL, &si, &pi)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } - - objc_autoreleasePoolPop(pool); - - _handle = pi.hProcess; - CloseHandle(pi.hThread); - - CloseHandle(_readPipe[1]); - CloseHandle(_writePipe[0]); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - if (_readPipe[0] != NULL) - [self close]; - - [super dealloc]; -} - -- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)environment -{ - OFMutableData *env; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; - const OFChar16 equal = '='; - const OFChar16 zero[2] = { 0, 0 }; - - if (environment == nil) - return NULL; - - env = [OFMutableData dataWithItemSize: sizeof(OFChar16)]; - - keyEnumerator = [environment keyEnumerator]; - objectEnumerator = [environment objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - [env addItems: key.UTF16String count: key.UTF16StringLength]; - [env addItems: &equal count: 1]; - [env addItems: object.UTF16String - count: object.UTF16StringLength]; - [env addItems: &zero count: 1]; - } - [env addItems: zero count: 2]; - - return env.mutableItems; -} - -- (char *)of_environmentForDictionary: (OFDictionary *)environment -{ - OFStringEncoding encoding = [OFLocale encoding]; - OFMutableData *env; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; - - if (environment == nil) - return NULL; - - env = [OFMutableData data]; - - keyEnumerator = [environment keyEnumerator]; - objectEnumerator = [environment objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - [env addItems: [key cStringWithEncoding: encoding] - count: [key cStringLengthWithEncoding: encoding]]; - [env addItems: "=" count: 1]; - [env addItems: [object cStringWithEncoding: encoding] - count: [object cStringLengthWithEncoding: encoding]]; - [env addItems: "" count: 1]; - } - [env addItems: "\0" count: 2]; - - return env.mutableItems; -} - -- (bool)lowlevelIsAtEndOfStream -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _atEndOfStream; -} - -- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length -{ - DWORD ret; - - if (length > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (!ReadFile(_readPipe[0], buffer, (DWORD)length, &ret, NULL)) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - _atEndOfStream = true; - return 0; - } - - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: EIO]; - } - - if (ret == 0) - _atEndOfStream = true; - - return ret; -} - -- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length -{ - DWORD bytesWritten; - - if (length > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - if (_writePipe[1] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (!WriteFile(_writePipe[1], buffer, (DWORD)length, &bytesWritten, - NULL)) { - int errNo = EIO; - - if (GetLastError() == ERROR_BROKEN_PIPE) - errNo = EPIPE; - - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: errNo]; - } - - return (size_t)bytesWritten; -} - -- (void)closeForWriting -{ - if (_writePipe[1] != NULL) - CloseHandle(_writePipe[1]); - - _writePipe[1] = NULL; -} - -- (void)close -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - [self closeForWriting]; - CloseHandle(_readPipe[0]); - - if (_handle != INVALID_HANDLE_VALUE) { - TerminateProcess(_handle, 0); - CloseHandle(_handle); - } - - _handle = INVALID_HANDLE_VALUE; - _readPipe[0] = NULL; - - [super close]; -} - -- (int)waitForTermination -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (_handle != INVALID_HANDLE_VALUE) { - DWORD exitCode; - - WaitForSingleObject(_handle, INFINITE); - - if (GetExitCodeProcess(_handle, &exitCode)) - _status = exitCode; - else - _status = GetLastError(); - - CloseHandle(_handle); - _handle = INVALID_HANDLE_VALUE; - } - - return _status; -} -@end DELETED src/platform/windows/OFTLSKey.m Index: src/platform/windows/OFTLSKey.m ================================================================== --- src/platform/windows/OFTLSKey.m +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "OFTLSKey.h" - -int -OFTLSKeyNew(OFTLSKey *key) -{ - *key = TlsAlloc(); - - if (*key == TLS_OUT_OF_INDEXES) - return EAGAIN; - - return 0; -} - -int -OFTLSKeyFree(OFTLSKey key) -{ - return (TlsFree(key) ? 0 : EINVAL); -} ADDED src/platform/x86/OFAtomic.h Index: src/platform/x86/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/x86/OFAtomic.h @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2008-2022 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. + */ + +OF_ASSUME_NONNULL_BEGIN + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "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; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "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_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "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; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "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_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "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; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "orq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "andq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "xorq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchgl %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __asm__ __volatile__ ( + "mfence" ::: "memory" + ); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +OF_ASSUME_NONNULL_END Index: src/runtime/OFOnce.m ================================================================== --- src/runtime/OFOnce.m +++ src/runtime/OFOnce.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/runtime/OFPlainMutex.m ================================================================== --- src/runtime/OFPlainMutex.m +++ src/runtime/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/runtime/OFTLSKey.m ================================================================== --- src/runtime/OFTLSKey.m +++ src/runtime/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -144,18 +144,18 @@ /** * @brief A handler for uncaught exceptions. * * @param exception The exception which was not caught. */ -typedef void (*objc_uncaught_exception_handler_t)(id _Nullable exception); +typedef void (*objc_uncaught_exception_handler)(id _Nullable exception); /** * @brief A handler for mutation during enumeration. * * @param object The object that was mutated during enumeration */ -typedef void (*objc_enumeration_mutation_handler_t)(id _Nonnull object); +typedef void (*objc_enumeration_mutation_handler)(id _Nonnull object); /** * @brief A struct representing a call to super. */ struct objc_super { @@ -518,27 +518,27 @@ */ extern char *_Nullable property_copyAttributeValue( objc_property_t _Nonnull property, const char *_Nonnull name); /** - * @brief Exits the Objective-C runtime. + * @brief Deinitializes the Objective-C runtime. * * This frees all data structures used by the runtime, after which Objective-C * can no longer be used inside the current process. This is only useful for - * debugging. + * debugging and tests. */ -extern void objc_exit(void); +extern void objc_deinit(void); /** * @brief Sets the handler for uncaught exceptions. * * @param handler The new handler for uncaught exceptions * @return The old handler for uncaught exceptions */ -extern _Nullable objc_uncaught_exception_handler_t +extern _Nullable objc_uncaught_exception_handler objc_setUncaughtExceptionHandler( - objc_uncaught_exception_handler_t _Nullable handler); + objc_uncaught_exception_handler _Nullable handler); /** * @brief Sets the forwarding handler for unimplemented methods. * * @param forward The forwarding handler for regular methods @@ -552,11 +552,11 @@ * @brief Sets the handler for mutations during enumeration. * * @param handler The handler for mutations during enumeration */ extern void objc_setEnumerationMutationHandler( - objc_enumeration_mutation_handler_t _Nullable handler); + objc_enumeration_mutation_handler _Nullable handler); /** * @brief Constructs an instance of the specified class in the specified array * of bytes. * Index: src/runtime/amiga-end.m ================================================================== --- src/runtime/amiga-end.m +++ src/runtime/amiga-end.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/runtime/amiga-funcarray.inc ================================================================== --- src/runtime/amiga-funcarray.inc +++ src/runtime/amiga-funcarray.inc @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -11,11 +11,11 @@ * 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. */ -/* This file is automatically generated from library.xml */ +/* This file is automatically generated from amiga-library.xml */ (CONST_APTR)glue_objc_init, (CONST_APTR)glue___objc_exec_class, (CONST_APTR)glue_objc_msg_lookup, (CONST_APTR)glue_objc_msg_lookup_stret, @@ -77,11 +77,11 @@ (CONST_APTR)glue_protocol_conformsToProtocol, (CONST_APTR)glue_objc_setUncaughtExceptionHandler, (CONST_APTR)glue_objc_setForwardHandler, (CONST_APTR)glue_objc_setEnumerationMutationHandler, (CONST_APTR)glue_objc_constructInstance, -(CONST_APTR)glue_objc_exit, +(CONST_APTR)glue_objc_deinit, (CONST_APTR)glue_class_copyIvarList, (CONST_APTR)glue_ivar_getName, (CONST_APTR)glue_ivar_getTypeEncoding, (CONST_APTR)glue_ivar_getOffset, (CONST_APTR)glue_class_copyMethodList, Index: src/runtime/amiga-glue.h ================================================================== --- src/runtime/amiga-glue.h +++ src/runtime/amiga-glue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -11,11 +11,11 @@ * 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. */ -/* This file is automatically generated from library.xml */ +/* This file is automatically generated from amiga-library.xml */ #import "ObjFWRT.h" #import "private.h" #ifdef OF_AMIGAOS_M68K @@ -86,15 +86,15 @@ extern Class _Nullable glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class); extern const char *_Nullable glue_object_getClassName PPC_PARAMS(id _Nullable object); extern const char *_Nonnull glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol); extern bool glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); extern bool glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); -extern _Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler_t _Nullable handler); +extern _Nullable objc_uncaught_exception_handler glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler); extern void glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward); -extern void glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler_t _Nullable hadler); +extern void glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler); extern id _Nullable glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes); -extern void glue_objc_exit(void); +extern void glue_objc_deinit(void); extern Ivar _Nullable *_Nullable glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount); extern const char *_Nonnull glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar); extern const char *_Nonnull glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar); extern ptrdiff_t glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar); extern Method _Nullable *_Nullable glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount); Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -11,11 +11,11 @@ * 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. */ -/* This file is automatically generated from library.xml */ +/* This file is automatically generated from amiga-library.xml */ #include "config.h" #import "amiga-glue.h" @@ -556,14 +556,14 @@ M68K_ARG(Protocol *_Nonnull, protocol2, a1) return protocol_conformsToProtocol(protocol1, protocol2); } -_Nullable objc_uncaught_exception_handler_t __saveds -glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler_t _Nullable handler) +_Nullable objc_uncaught_exception_handler __saveds +glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler) { - M68K_ARG(objc_uncaught_exception_handler_t _Nullable, handler, a0) + M68K_ARG(objc_uncaught_exception_handler _Nullable, handler, a0) return objc_setUncaughtExceptionHandler(handler); } void __saveds @@ -574,13 +574,13 @@ objc_setForwardHandler(forward, stretForward); } void __saveds -glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler_t _Nullable hadler) +glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler) { - M68K_ARG(objc_enumeration_mutation_handler_t _Nullable, hadler, a0) + M68K_ARG(objc_enumeration_mutation_handler _Nullable, hadler, a0) objc_setEnumerationMutationHandler(hadler); } id _Nullable __saveds @@ -591,13 +591,13 @@ return objc_constructInstance(class, bytes); } void __saveds -glue_objc_exit(void) +glue_objc_deinit(void) { - objc_exit(); + objc_deinit(); } Ivar _Nullable *_Nullable __saveds glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) { Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -566,11 +566,11 @@ .rt_Version = OBJFWRT_LIB_MAJOR, .rt_Type = NT_LIBRARY, .rt_Pri = 0, .rt_Name = (char *)OBJFWRT_AMIGA_LIB, .rt_IdString = (char *)"ObjFWRT " VERSION_STRING - " \xA9 2008-2021 Jonathan Schleifer", + " \xA9 2008-2022 Jonathan Schleifer", .rt_Init = &init_table, #ifdef OF_MORPHOS .rt_Revision = OBJFWRT_LIB_MINOR, .rt_Tags = NULL, #endif ADDED src/runtime/amiga-library.xml Index: src/runtime/amiga-library.xml ================================================================== --- /dev/null +++ src/runtime/amiga-library.xml @@ -0,0 +1,345 @@ + + ObjFWRT.h + private.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETED src/runtime/amigaos3.sfd Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ /dev/null @@ -1,98 +0,0 @@ -==base _ObjFWRTBase -==basetype struct Library * -==libname objfwrt68k.library -==bias 30 -==public -* The following function is only for the linklib. -bool glue_objc_init(unsigned int version, struct objc_libc *libc)(d0,a0) -void glue___objc_exec_class(struct objc_module *_Nonnull module)(a0) -IMP _Nonnull glue_objc_msg_lookup(id _Nullable object, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) -Class _Nullable glue_objc_lookUpClass(const char *_Nonnull name)(a0) -Class _Nullable glue_objc_getClass(const char *_Nonnull name)(a0) -Class _Nonnull glue_objc_getRequiredClass(const char *_Nonnull name)(a0) -Class _Nullable glue_objc_lookup_class(const char *_Nonnull name)(a0) -Class _Nonnull glue_objc_get_class(const char *_Nonnull name)(a0) -void glue_objc_exception_throw(id _Nonnull object)(a0) -int glue_objc_sync_enter(id _Nullable object)(a0) -int glue_objc_sync_exit(id _Nullable object)(a0) -id glue_objc_getProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic)(a0,a1,d0,d1) -void glue_objc_setProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id value, bool atomic, signed char copy)(a0,a1,d0,a2,d1,d2) -void glue_objc_getPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2) -void glue_objc_setPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2) -void glue_objc_enumerationMutation(id _Nonnull object)(a0) -int glue___gnu_objc_personality(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1) -id _Nullable glue_objc_retain(id _Nullable object)(a0) -id _Nullable glue_objc_retainBlock(id _Nullable block)(a0) -id _Nullable glue_objc_retainAutorelease(id _Nullable object)(a0) -void glue_objc_release(id _Nullable object)(a0) -id _Nullable glue_objc_autorelease(id _Nullable object)(a0) -id _Nullable glue_objc_autoreleaseReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_retainAutoreleaseReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_retainAutoreleasedReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_storeStrong(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -id _Nullable glue_objc_storeWeak(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -id _Nullable glue_objc_loadWeakRetained(id _Nullable *_Nonnull object)(a0) -id _Nullable glue_objc_initWeak(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -void glue_objc_destroyWeak(id _Nullable *_Nonnull object)(a0) -id _Nullable glue_objc_loadWeak(id _Nullable *_Nonnull object)(a0) -void glue_objc_copyWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1) -void glue_objc_moveWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1) -SEL _Nonnull glue_sel_registerName(const char *_Nonnull name)(a0) -const char *_Nonnull glue_sel_getName(SEL _Nonnull selector)(a0) -bool glue_sel_isEqual(SEL _Nonnull selector1, SEL _Nonnull selector2)(a0,a1) -Class _Nonnull glue_objc_allocateClassPair(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes)(a0,a1,d0) -void glue_objc_registerClassPair(Class _Nonnull class_)(a0) -unsigned int glue_objc_getClassList(Class _Nonnull *_Nullable buffer, unsigned int count)(a0,d0) -Class _Nonnull *_Nonnull glue_objc_copyClassList(unsigned int *_Nullable length)(a0) -bool glue_class_isMetaClass(Class _Nullable class_)(a0) -const char *_Nullable glue_class_getName(Class _Nullable class_)(a0) -Class _Nullable glue_class_getSuperclass(Class _Nullable class_)(a0) -unsigned long glue_class_getInstanceSize(Class _Nullable class_)(a0) -bool glue_class_respondsToSelector(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -bool glue_class_conformsToProtocol(Class _Nullable class_, Protocol *_Nonnull p)(a0,a1) -IMP _Nullable glue_class_getMethodImplementation(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -IMP _Nullable glue_class_getMethodImplementation_stret(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -Method _Nullable glue_class_getInstanceMethod(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -bool glue_class_addMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) -IMP _Nullable glue_class_replaceMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) -Class _Nullable glue_object_getClass(id _Nullable object)(a0) -Class _Nullable glue_object_setClass(id _Nullable object, Class _Nonnull class_)(a0,a1) -const char *_Nullable glue_object_getClassName(id _Nullable object)(a0) -const char *_Nonnull glue_protocol_getName(Protocol *_Nonnull protocol)(a0) -bool glue_protocol_isEqual(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1) -bool glue_protocol_conformsToProtocol(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1) -_Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler)(a0) -void glue_objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)(a0,a1) -void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable handler)(a0) -id _Nullable glue_objc_constructInstance(Class _Nullable class_, void *_Nullable bytes)(a0,a1) -void glue_objc_exit(void)() -Ivar _Nullable *_Nullable glue_class_copyIvarList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -const char *_Nonnull glue_ivar_getName(Ivar _Nonnull ivar)(a0) -const char *_Nonnull glue_ivar_getTypeEncoding(Ivar _Nonnull ivar)(a0) -ptrdiff_t glue_ivar_getOffset(Ivar _Nonnull ivar)(a0) -Method _Nullable *_Nullable glue_class_copyMethodList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -SEL _Nonnull glue_method_getName(Method _Nonnull method)(a0) -const char *_Nullable glue_method_getTypeEncoding(Method _Nonnull method)(a0) -objc_property_t _Nullable *_Nullable glue_class_copyPropertyList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -const char *_Nonnull glue_property_getName(objc_property_t _Nonnull property)(a0) -char *_Nullable glue_property_copyAttributeValue(objc_property_t _Nonnull property, const char *_Nonnull name)(a0,a1) -void *_Nullable glue_objc_destructInstance(id _Nullable object)(a0) -void *_Null_unspecified glue_objc_autoreleasePoolPush(void)() -void glue_objc_autoreleasePoolPop(void *_Null_unspecified pool)(a0) -id _Nullable glue__objc_rootAutorelease(id _Nullable object)(a0) -* The following functions are private! Don't use! -struct objc_hashtable *_Nonnull glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size)(a0,a1,d0) -void glue_objc_hashtable_set(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object)(a0,a1,a2) -void *_Nullable glue_objc_hashtable_get(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) -void glue_objc_hashtable_delete(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) -void glue_objc_hashtable_free(struct objc_hashtable *_Nonnull table)(a0) -* Public functions again -void glue_objc_setTaggedPointerSecret(uintptr_t secret)(d0) -int glue_objc_registerTaggedPointerClass(Class _Nonnull class_)(a0) -bool glue_object_isTaggedPointer(id _Nullable object)(a0) -uintptr_t glue_object_getTaggedPointerValue(id _Nonnull object)(a0) -id _Nullable glue_objc_createTaggedPointer(int class_, uintptr_t value)(d0,d1) -==end Index: src/runtime/arc.m ================================================================== --- src/runtime/arc.m +++ src/runtime/arc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,11 +20,11 @@ #ifdef OF_HAVE_THREADS # import "OFPlainMutex.h" #endif -struct weakref { +struct WeakRef { id **locations; size_t count; }; static struct objc_hashtable *hashtable; @@ -115,11 +115,11 @@ } id objc_storeWeak(id *object, id value) { - struct weakref *old; + struct WeakRef *old; #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&spinlock) != 0) OBJC_ERROR("Failed to lock spinlock!"); #endif @@ -153,11 +153,11 @@ } } if (value != nil && class_respondsToSelector(object_getClass(value), @selector(allowsWeakReference)) && [value allowsWeakReference]) { - struct weakref *ref = objc_hashtable_get(hashtable, value); + struct WeakRef *ref = objc_hashtable_get(hashtable, value); if (ref == NULL) { if ((ref = calloc(1, sizeof(*ref))) == NULL) OBJC_ERROR("Not enough memory to allocate weak " "reference!"); @@ -186,11 +186,11 @@ id objc_loadWeakRetained(id *object) { id value = nil; - struct weakref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&spinlock) != 0) OBJC_ERROR("Failed to lock spinlock!"); #endif @@ -237,11 +237,11 @@ } void objc_moveWeak(id *dest, id *src) { - struct weakref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&spinlock) != 0) OBJC_ERROR("Failed to lock spinlock!"); #endif @@ -264,13 +264,13 @@ OBJC_ERROR("Failed to unlock spinlock!"); #endif } void -objc_zero_weak_references(id value) +objc_zeroWeakReferences(id value) { - struct weakref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&spinlock) != 0) OBJC_ERROR("Failed to lock spinlock!"); #endif Index: src/runtime/autorelease.m ================================================================== --- src/runtime/autorelease.m +++ src/runtime/autorelease.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -33,10 +33,15 @@ #ifndef OF_OBJFW_RUNTIME @interface DummyObject - (void)release; @end #endif + +#ifndef OBJC_ERROR +/* This is also used with old Apple runtimes that lack autorelease pools. */ +# define OBJC_ERROR(...) abort() +#endif #if defined(OF_HAVE_COMPILER_TLS) static thread_local id *objects = NULL; static thread_local uintptr_t count = 0; static thread_local uintptr_t size = 0; @@ -49,13 +54,13 @@ #endif #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) OF_CONSTRUCTOR() { - OFEnsure(OFTLSKeyNew(&objectsKey) == 0); - OFEnsure(OFTLSKeyNew(&countKey) == 0); - OFEnsure(OFTLSKeyNew(&sizeKey) == 0); + if (OFTLSKeyNew(&objectsKey) != 0 || OFTLSKeyNew(&countKey) != 0 || + OFTLSKeyNew(&sizeKey) != 0) + OBJC_ERROR("Failed to create TLS keys!"); } #endif void * objc_autoreleasePoolPush() @@ -96,17 +101,19 @@ free(objects); objects = NULL; #if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) size = 0; #else - OFEnsure(OFTLSKeySet(objectsKey, objects) == 0); - OFEnsure(OFTLSKeySet(sizeKey, (void *)0) == 0); + if (OFTLSKeySet(objectsKey, objects) != 0 || + OFTLSKeySet(sizeKey, (void *)0) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OFEnsure(OFTLSKeySet(countKey, (void *)count) == 0); + if (OFTLSKeySet(countKey, (void *)count) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } id _objc_rootAutorelease(id object) @@ -121,22 +128,24 @@ if (size == 0) size = 16; else size *= 2; - OFEnsure((objects = - realloc(objects, size * sizeof(id))) != NULL); + if ((objects = realloc(objects, size * sizeof(id))) == NULL) + OBJC_ERROR("Failed to resize autorelease pool!"); #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OFEnsure(OFTLSKeySet(objectsKey, objects) == 0); - OFEnsure(OFTLSKeySet(sizeKey, (void *)size) == 0); + if (OFTLSKeySet(objectsKey, objects) != 0 || + OFTLSKeySet(sizeKey, (void *)size) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } objects[count++] = object; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OFEnsure(OFTLSKeySet(countKey, (void *)count) == 0); + if (OFTLSKeySet(countKey, (void *)count) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif return object; } Index: src/runtime/category.m ================================================================== --- src/runtime/category.m +++ src/runtime/category.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,26 +30,26 @@ struct objc_method_list *iter; unsigned int i; for (iter = category->instanceMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); for (iter = category->classMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); } static void registerCategory(struct objc_category *category) { struct objc_category **categories; - Class class = objc_classname_to_class(category->className, false); + Class class = objc_classnameToClass(category->className, false); if (categoriesMap == NULL) categoriesMap = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); categories = (struct objc_category **)objc_hashtable_get( categoriesMap, category->className); if (categories != NULL) { @@ -68,12 +68,12 @@ newCategories[i + 1] = NULL; objc_hashtable_set(categoriesMap, category->className, newCategories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); } return; } @@ -84,17 +84,17 @@ categories[0] = category; categories[1] = NULL; objc_hashtable_set(categoriesMap, category->className, categories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); } } void -objc_register_all_categories(struct objc_symtab *symtab) +objc_registerAllCategories(struct objc_symtab *symtab) { struct objc_category **categories = (struct objc_category **)symtab->defs + symtab->classDefsCount; for (size_t i = 0; i < symtab->categoryDefsCount; i++) { @@ -102,21 +102,21 @@ registerCategory(categories[i]); } } struct objc_category ** -objc_categories_for_class(Class class) +objc_categoriesForClass(Class class) { if (categoriesMap == NULL) return NULL; return (struct objc_category **)objc_hashtable_get(categoriesMap, class->name); } void -objc_unregister_all_categories(void) +objc_unregisterAllCategories(void) { if (categoriesMap == NULL) return; for (uint32_t i = 0; i < categoriesMap->size; i++) Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -34,38 +34,38 @@ static void registerClass(Class class) { if (classes == NULL) classes = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); objc_hashtable_set(classes, class->name, class); if (emptyDTable == NULL) emptyDTable = objc_dtable_new(); - class->DTable = emptyDTable; - class->isa->DTable = emptyDTable; + class->dTable = emptyDTable; + class->isa->dTable = emptyDTable; if (strcmp(class->name, "Protocol") != 0) classesCount++; } bool class_registerAlias_np(Class class, const char *name) { - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (classes == NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NO; } objc_hashtable_set(classes, name, (Class)((uintptr_t)class | 1)); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return YES; } static void @@ -74,15 +74,15 @@ struct objc_method_list *iter; unsigned int i; for (iter = class->methodList; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); } Class -objc_classname_to_class(const char *name, bool cache) +objc_classnameToClass(const char *name, bool cache) { Class class; if (classes == NULL) return Nil; @@ -113,21 +113,21 @@ if (class != Nil) return class; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); class = (Class)((uintptr_t)objc_hashtable_get(classes, name) & ~1); if (cache && fastPath == NULL && --lookupsUntilFastPath == 0) fastPath = objc_sparsearray_new(sizeof(uintptr_t)); if (cache && fastPath != NULL) objc_sparsearray_set(fastPath, (uintptr_t)name, class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return class; } static void @@ -178,31 +178,31 @@ class->info |= OBJC_CLASS_INFO_LOADED; } void -objc_update_dtable(Class class) +objc_updateDTable(Class class) { struct objc_category **categories; if (!(class->info & OBJC_CLASS_INFO_DTABLE)) return; - if (class->DTable == emptyDTable) - class->DTable = objc_dtable_new(); + if (class->dTable == emptyDTable) + class->dTable = objc_dtable_new(); if (class->superclass != Nil) - objc_dtable_copy(class->DTable, class->superclass->DTable); + objc_dtable_copy(class->dTable, class->superclass->dTable); for (struct objc_method_list *methodList = class->methodList; methodList != NULL; methodList = methodList->next) for (unsigned int i = 0; i < methodList->count; i++) - objc_dtable_set(class->DTable, + objc_dtable_set(class->dTable, (uint32_t)methodList->methods[i].selector.UID, methodList->methods[i].implementation); - if ((categories = objc_categories_for_class(class)) != NULL) { + if ((categories = objc_categoriesForClass(class)) != NULL) { for (unsigned int i = 0; categories[i] != NULL; i++) { struct objc_method_list *methodList = (class->info & OBJC_CLASS_INFO_CLASS ? categories[i]->instanceMethods : categories[i]->classMethods); @@ -209,21 +209,21 @@ for (; methodList != NULL; methodList = methodList->next) for (unsigned int j = 0; j < methodList->count; j++) - objc_dtable_set(class->DTable, + objc_dtable_set(class->dTable, (uint32_t)methodList->methods[j] .selector.UID, methodList->methods[j] .implementation); } } if (class->subclassList != NULL) for (Class *iter = class->subclassList; *iter != NULL; iter++) - objc_update_dtable(*iter); + objc_updateDTable(*iter); } static void addSubclass(Class class) { @@ -280,26 +280,26 @@ for (unsigned int i = 0; i < class->ivars->count; i++) *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } static void -setupClass(Class class) +setUpClass(Class class) { const char *superclassName; if (class->info & OBJC_CLASS_INFO_SETUP) return; superclassName = (const char *)class->superclass; if (superclassName != NULL) { - Class super = objc_classname_to_class(superclassName, false); + Class super = objc_classnameToClass(superclassName, false); Class rootClass; if (super == Nil) return; - setupClass(super); + setUpClass(super); if (!(super->info & OBJC_CLASS_INFO_SETUP)) return; /* @@ -349,12 +349,12 @@ return; class->info |= OBJC_CLASS_INFO_DTABLE; class->isa->info |= OBJC_CLASS_INFO_DTABLE; - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); /* * Set it first to prevent calling it recursively due to message sends * in the initialize method */ @@ -373,44 +373,44 @@ initialize(class, initializeSel); } } void -objc_initialize_class(Class class) +objc_initializeClass(Class class) { if (class->info & OBJC_CLASS_INFO_INITIALIZED) return; - objc_global_mutex_lock(); + objc_globalMutex_lock(); /* * It's possible that two threads try to initialize a class at the same * time. Make sure that the thread which held the lock did not already * initialize it. */ if (class->info & OBJC_CLASS_INFO_INITIALIZED) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return; } - setupClass(class); + setUpClass(class); if (!(class->info & OBJC_CLASS_INFO_SETUP)) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return; } initializeClass(class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } static void processLoadQueue() { for (size_t i = 0; i < loadQueueCount; i++) { - setupClass(loadQueue[i]); + setUpClass(loadQueue[i]); if (loadQueue[i]->info & OBJC_CLASS_INFO_SETUP) { callLoad(loadQueue[i]); loadQueueCount--; @@ -431,11 +431,11 @@ } } } void -objc_register_all_classes(struct objc_symtab *symtab) +objc_registerAllClasses(struct objc_symtab *symtab) { for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; registerClass(class); @@ -445,11 +445,11 @@ for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; if (hasLoad(class)) { - setupClass(class); + setUpClass(class); if (class->info & OBJC_CLASS_INFO_SETUP) callLoad(class); else { loadQueue = realloc(loadQueue, @@ -472,13 +472,10 @@ objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) { struct objc_class *class, *metaclass; Class iter, rootclass = Nil; - if (extraBytes > LONG_MAX) - OBJC_ERROR("extraBytes out of range!"); - if ((class = calloc(1, sizeof(*class))) == NULL || (metaclass = calloc(1, sizeof(*class))) == NULL) OBJC_ERROR("Not enough memory to allocate class pair for class " "%s!", name); @@ -485,11 +482,17 @@ class->isa = metaclass; class->superclass = superclass; class->name = name; class->info = OBJC_CLASS_INFO_CLASS; class->instanceSize = (superclass != Nil ? - superclass->instanceSize : 0) + (long)extraBytes; + superclass->instanceSize : 0); + + if (extraBytes > LONG_MAX || + LONG_MAX - class->instanceSize < (long)extraBytes) + OBJC_ERROR("extraBytes too large!"); + + class->instanceSize += (long)extraBytes; for (iter = superclass; iter != Nil; iter = iter->superclass) rootclass = iter; metaclass->isa = (rootclass != Nil ? rootclass->isa : class); @@ -503,11 +506,11 @@ } void objc_registerClassPair(Class class) { - objc_global_mutex_lock(); + objc_globalMutex_lock(); registerClass(class); if (class->superclass != Nil) { addSubclass(class); @@ -522,29 +525,29 @@ else class->info |= OBJC_CLASS_INFO_LOADED; processLoadQueue(); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } Class objc_lookUpClass(const char *name) { Class class; - if ((class = objc_classname_to_class(name, true)) == NULL) + if ((class = objc_classnameToClass(name, true)) == NULL) return Nil; if (class->info & OBJC_CLASS_INFO_SETUP) return class; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - setupClass(class); + setUpClass(class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); if (!(class->info & OBJC_CLASS_INFO_SETUP)) return Nil; return class; @@ -581,11 +584,11 @@ unsigned int objc_getClassList(Class *buffer, unsigned int count) { unsigned int j; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (buffer == NULL) return classesCount; if (classesCount < count) @@ -594,11 +597,11 @@ j = 0; for (uint32_t i = 0; i < classes->size; i++) { void *class; if (j >= count) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return j; } if (classes->data[i] == NULL) continue; @@ -612,11 +615,11 @@ continue; buffer[j++] = class; } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return j; } Class * @@ -623,24 +626,25 @@ objc_copyClassList(unsigned int *length) { Class *ret; unsigned int count; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((ret = malloc((classesCount + 1) * sizeof(Class))) == NULL) OBJC_ERROR("Failed to allocate memory for class list!"); count = objc_getClassList(ret, classesCount); - OFEnsure(count == classesCount); + if (count != classesCount) + OBJC_ERROR("Fatal internal inconsistency!"); ret[count] = Nil; if (length != NULL) *length = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } bool @@ -724,11 +728,11 @@ static struct objc_method * getMethod(Class class, SEL selector) { struct objc_category **categories; - if ((categories = objc_categories_for_class(class)) != NULL) { + if ((categories = objc_categoriesForClass(class)) != NULL) { for (; *categories != NULL; categories++) { struct objc_method_list *methodList = (class->info & OBJC_CLASS_INFO_METACLASS ? (*categories)->classMethods : (*categories)->instanceMethods); @@ -758,11 +762,11 @@ addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) { struct objc_method_list *methodList; - /* FIXME: We need a way to free this at objc_exit() */ + /* FIXME: We need a way to free this at objc_deinit() */ if ((methodList = malloc(sizeof(*methodList))) == NULL) OBJC_ERROR("Not enough memory to replace method!"); methodList->next = class->methodList; methodList->count = 1; @@ -770,11 +774,11 @@ methodList->methods[0].selector.typeEncoding = typeEncoding; methodList->methods[0].implementation = implementation; class->methodList = methodList; - objc_update_dtable(class); + objc_updateDTable(class); } Method class_getInstanceMethod(Class class, SEL selector) { @@ -782,20 +786,20 @@ Class superclass; if (class == Nil) return NULL; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((method = getMethod(class, selector)) != NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return method; } superclass = class->superclass; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); if (superclass != Nil) return class_getInstanceMethod(superclass, selector); return NULL; @@ -805,19 +809,19 @@ class_addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) { bool ret; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (getMethod(class, selector) == NULL) { addMethod(class, selector, implementation, typeEncoding); ret = true; } else ret = false; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } IMP @@ -825,22 +829,22 @@ const char *typeEncoding) { struct objc_method *method; IMP oldImplementation; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((method = getMethod(class, selector)) != NULL) { oldImplementation = method->implementation; method->implementation = implementation; - objc_update_dtable(class); + objc_updateDTable(class); } else { oldImplementation = NULL; addMethod(class, selector, implementation, typeEncoding); } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return oldImplementation; } Class @@ -912,31 +916,33 @@ if (class->subclassList != NULL) { free(class->subclassList); class->subclassList = NULL; } - if (class->DTable != NULL && class->DTable != emptyDTable) - objc_dtable_free(class->DTable); + if (class->dTable != NULL && class->dTable != emptyDTable) + objc_dtable_free(class->dTable); - class->DTable = NULL; + class->dTable = NULL; if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil) class->superclass = (Class)class->superclass->name; class->info &= ~OBJC_CLASS_INFO_SETUP; } void -objc_unregister_class(Class class) +objc_unregisterClass(Class class) { static SEL unloadSel = NULL; + + objc_globalMutex_lock(); if (unloadSel == NULL) unloadSel = sel_registerName("unload"); while (class->subclassList != NULL && class->subclassList[0] != Nil) - objc_unregister_class(class->subclassList[0]); + objc_unregisterClass(class->subclassList[0]); if (class->info & OBJC_CLASS_INFO_LOADED) callSelector(class, unloadSel); objc_hashtable_delete(classes, class->name); @@ -944,27 +950,29 @@ if (strcmp(class_getName(class), "Protocol") != 0) classesCount--; unregisterClass(class); unregisterClass(class->isa); + + objc_globalMutex_unlock(); } void -objc_unregister_all_classes(void) +objc_unregisterAllClasses(void) { if (classes == NULL) return; for (uint32_t i = 0; i < classes->size; i++) { if (classes->data[i] != NULL && - classes->data[i] != &objc_deleted_bucket) { + classes->data[i] != &objc_deletedBucket) { void *class = (Class)classes->data[i]->object; if (class == Nil || (uintptr_t)class & 1) continue; - objc_unregister_class(class); + objc_unregisterClass(class); /* * The table might have been resized, so go back to the * start again. * @@ -974,11 +982,12 @@ */ i = UINT32_MAX; } } - OFEnsure(classesCount == 0); + if (classesCount != 0) + OBJC_ERROR("Fatal internal inconsistency!"); if (emptyDTable != NULL) { objc_dtable_free(emptyDTable); emptyDTable = NULL; } Index: src/runtime/dtable.m ================================================================== --- src/runtime/dtable.m +++ src/runtime/dtable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,15 +28,15 @@ static void init(void) { if ((emptyLevel2 = malloc(sizeof(*emptyLevel2))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + OBJC_ERROR("Not enough memory to allocate dispatch table!"); #ifdef OF_SELUID24 if ((emptyLevel3 = malloc(sizeof(*emptyLevel3))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + OBJC_ERROR("Not enough memory to allocate dispatch table!"); #endif #ifdef OF_SELUID24 for (uint_fast16_t i = 0; i < 256; i++) { emptyLevel2->buckets[i] = emptyLevel3; @@ -49,27 +49,27 @@ } struct objc_dtable * objc_dtable_new(void) { - struct objc_dtable *DTable; + struct objc_dtable *dTable; #ifdef OF_SELUID24 if (emptyLevel2 == NULL || emptyLevel3 == NULL) init(); #else if (emptyLevel2 == NULL) init(); #endif - if ((DTable = malloc(sizeof(*DTable))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + if ((dTable = malloc(sizeof(*dTable))) == NULL) + OBJC_ERROR("Not enough memory to allocate dispatch table!"); for (uint_fast16_t i = 0; i < 256; i++) - DTable->buckets[i] = emptyLevel2; + dTable->buckets[i] = emptyLevel2; - return DTable; + return dTable; } void objc_dtable_copy(struct objc_dtable *dest, struct objc_dtable *src) { @@ -111,11 +111,11 @@ #endif } } void -objc_dtable_set(struct objc_dtable *DTable, uint32_t idx, IMP implementation) +objc_dtable_set(struct objc_dtable *dTable, uint32_t idx, IMP implementation) { #ifdef OF_SELUID24 uint8_t i = idx >> 16; uint8_t j = idx >> 8; uint8_t k = idx; @@ -122,62 +122,64 @@ #else uint8_t i = idx >> 8; uint8_t j = idx; #endif - if (DTable->buckets[i] == emptyLevel2) { + if (dTable->buckets[i] == emptyLevel2) { struct objc_dtable_level2 *level2 = malloc(sizeof(*level2)); if (level2 == NULL) - OBJC_ERROR("Not enough memory to insert into dtable!"); + OBJC_ERROR("Not enough memory to insert into " + "dispatch table!"); for (uint_fast16_t l = 0; l < 256; l++) #ifdef OF_SELUID24 level2->buckets[l] = emptyLevel3; #else level2->buckets[l] = (IMP)0; #endif - DTable->buckets[i] = level2; + dTable->buckets[i] = level2; } #ifdef OF_SELUID24 - if (DTable->buckets[i]->buckets[j] == emptyLevel3) { + if (dTable->buckets[i]->buckets[j] == emptyLevel3) { struct objc_dtable_level3 *level3 = malloc(sizeof(*level3)); if (level3 == NULL) - OBJC_ERROR("Not enough memory to insert into dtable!"); + OBJC_ERROR("Not enough memory to insert into " + "dispatch table!"); for (uint_fast16_t l = 0; l < 256; l++) level3->buckets[l] = (IMP)0; - DTable->buckets[i]->buckets[j] = level3; + dTable->buckets[i]->buckets[j] = level3; } - DTable->buckets[i]->buckets[j]->buckets[k] = implementation; + dTable->buckets[i]->buckets[j]->buckets[k] = implementation; #else - DTable->buckets[i]->buckets[j] = implementation; + dTable->buckets[i]->buckets[j] = implementation; #endif } void -objc_dtable_free(struct objc_dtable *DTable) +objc_dtable_free(struct objc_dtable *dTable) { for (uint_fast16_t i = 0; i < 256; i++) { - if (DTable->buckets[i] == emptyLevel2) + if (dTable->buckets[i] == emptyLevel2) continue; #ifdef OF_SELUID24 for (uint_fast16_t j = 0; j < 256; j++) - if (DTable->buckets[i]->buckets[j] != emptyLevel3) - free(DTable->buckets[i]->buckets[j]); + if (dTable->buckets[i]->buckets[j] != emptyLevel3) + free(dTable->buckets[i]->buckets[j]); #endif - free(DTable->buckets[i]); + free(dTable->buckets[i]); } - free(DTable); + free(dTable); } void objc_dtable_cleanup(void) { Index: src/runtime/exception.m ================================================================== --- src/runtime/exception.m +++ src/runtime/exception.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -67,42 +67,48 @@ #define GNUCOBJC_EXCEPTION_CLASS UINT64_C(0x474E55434F424A43) /* GNUCOBJC */ #define GNUCCXX0_EXCEPTION_CLASS UINT64_C(0x474E5543432B2B00) /* GNUCC++\0 */ #define CLNGCXX0_EXCEPTION_CLASS UINT64_C(0x434C4E47432B2B00) /* CLNGC++\0 */ -#define NUM_EMERGENCY_EXCEPTIONS 4 - -#define _UA_SEARCH_PHASE 0x01 -#define _UA_CLEANUP_PHASE 0x02 -#define _UA_HANDLER_FRAME 0x04 -#define _UA_FORCE_UNWIND 0x08 - -#define DW_EH_PE_absptr 0x00 - -#define DW_EH_PE_uleb128 0x01 -#define DW_EH_PE_udata2 0x02 -#define DW_EH_PE_udata4 0x03 -#define DW_EH_PE_udata8 0x04 - -#define DW_EH_PE_signed 0x08 -#define DW_EH_PE_sleb128 (DW_EH_PE_signed | DW_EH_PE_uleb128) -#define DW_EH_PE_sdata2 (DW_EH_PE_signed | DW_EH_PE_udata2) -#define DW_EH_PE_sdata4 (DW_EH_PE_signed | DW_EH_PE_udata4) -#define DW_EH_PE_sdata8 (DW_EH_PE_signed | DW_EH_PE_udata8) - -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 -#define DW_EH_PE_aligned 0x50 - -#define DW_EH_PE_indirect 0x80 - -#define DW_EH_PE_omit 0xFF - -#define CLEANUP_FOUND 0x01 -#define HANDLER_FOUND 0x02 +#define numEmergencyExceptions 4 + +enum { + _UA_SEARCH_PHASE = 0x01, + _UA_CLEANUP_PHASE = 0x02, + _UA_HANDLER_FRAME = 0x04, + _UA_FORCE_UNWIND = 0x08 +}; + +enum { + DW_EH_PE_absptr = 0x00, + + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = (DW_EH_PE_signed | DW_EH_PE_uleb128), + DW_EH_PE_sdata2 = (DW_EH_PE_signed | DW_EH_PE_udata2), + DW_EH_PE_sdata4 = (DW_EH_PE_signed | DW_EH_PE_udata4), + DW_EH_PE_sdata8 = (DW_EH_PE_signed | DW_EH_PE_udata8), + + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80, + + DW_EH_PE_omit = 0xFF +}; + +enum { + CLEANUP_FOUND = 0x01, + HANDLER_FOUND = 0x02 +}; struct _Unwind_Context; typedef enum { _URC_OK = 0, @@ -156,11 +162,11 @@ uintptr_t landingpad; intptr_t filter; #endif }; -struct lsda { +struct LSDA { uintptr_t regionStart, landingpadsStart; uint8_t typesTableEnc; const uint8_t *typesTable; uintptr_t typesTableBase; uint8_t callsitesEnc; @@ -237,19 +243,19 @@ extern EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT, PDISPATCHER_CONTEXT, _Unwind_Reason_Code (*)(int, int, uint64_t, struct _Unwind_Exception *, struct _Unwind_Context *)); #endif -static objc_uncaught_exception_handler_t uncaughtExceptionHandler; -static struct objc_exception emergencyExceptions[NUM_EMERGENCY_EXCEPTIONS]; +static objc_uncaught_exception_handler uncaughtExceptionHandler; +static struct objc_exception emergencyExceptions[numEmergencyExceptions]; #ifdef OF_HAVE_THREADS static OFSpinlock emergencyExceptionsSpinlock; OF_CONSTRUCTOR() { if (OFSpinlockNew(&emergencyExceptionsSpinlock) != 0) - OBJC_ERROR("Cannot create spinlock!"); + OBJC_ERROR("Failed to create spinlock!"); } #endif static uint64_t readULEB128(const uint8_t **ptr) @@ -397,11 +403,11 @@ return value; } #endif static void -readLSDA(struct _Unwind_Context *ctx, const uint8_t *ptr, struct lsda *LSDA) +readLSDA(struct _Unwind_Context *ctx, const uint8_t *ptr, struct LSDA *LSDA) { uint8_t landingpadsStartEnc; uintptr_t callsitesSize; LSDA->regionStart = _Unwind_GetRegionStart(ctx); @@ -425,11 +431,11 @@ LSDA->actionTable = LSDA->callsites + callsitesSize; } static bool -findCallsite(struct _Unwind_Context *ctx, struct lsda *LSDA, +findCallsite(struct _Unwind_Context *ctx, struct LSDA *LSDA, uintptr_t *landingpad, const uint8_t **actionRecords) { uintptr_t IP = _Unwind_GetIP(ctx); const uint8_t *ptr = LSDA->callsites; @@ -502,11 +508,11 @@ return false; } static uint8_t -findActionRecord(const uint8_t *actionRecords, struct lsda *LSDA, int actions, +findActionRecord(const uint8_t *actionRecords, struct LSDA *LSDA, int actions, bool foreign, struct objc_exception *e, intptr_t *filterPtr) { const uint8_t *ptr; intptr_t filter, displacement; @@ -598,11 +604,11 @@ _Unwind_SetGR(ctx, 12, (uintptr_t)ex); #endif struct objc_exception *e = (struct objc_exception *)ex; bool foreign = (exClass != GNUCOBJC_EXCEPTION_CLASS); const uint8_t *LSDAAddr, *actionRecords; - struct lsda LSDA; + struct LSDA LSDA; uintptr_t landingpad = 0; uint8_t found = 0; intptr_t filter = 0; if (foreign) { @@ -710,18 +716,18 @@ emergencyExceptionCleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *ex) { #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&emergencyExceptionsSpinlock) != 0) - OBJC_ERROR("Cannot lock spinlock!"); + OBJC_ERROR("Failed to lock spinlock!"); #endif ex->class = 0; #ifdef OF_HAVE_THREADS if (OFSpinlockUnlock(&emergencyExceptionsSpinlock) != 0) - OBJC_ERROR("Cannot unlock spinlock!"); + OBJC_ERROR("Failed to unlock spinlock!"); #endif } void objc_exception_throw(id object) @@ -730,14 +736,14 @@ bool emergency = false; if (e == NULL) { #ifdef OF_HAVE_THREADS if (OFSpinlockLock(&emergencyExceptionsSpinlock) != 0) - OBJC_ERROR("Cannot lock spinlock!"); + OBJC_ERROR("Failed to lock spinlock!"); #endif - for (uint_fast8_t i = 0; i < NUM_EMERGENCY_EXCEPTIONS; i++) { + for (uint_fast8_t i = 0; i < numEmergencyExceptions; i++) { if (emergencyExceptions[i].exception.class == 0) { e = &emergencyExceptions[i]; e->exception.class = GNUCOBJC_EXCEPTION_CLASS; emergency = true; @@ -745,11 +751,11 @@ } } #ifdef OF_HAVE_THREADS if (OFSpinlockUnlock(&emergencyExceptionsSpinlock) != 0) - OBJC_ERROR("Cannot lock spinlock!"); + OBJC_ERROR("Failed to lock spinlock!"); #endif } if (e == NULL) OBJC_ERROR("Not enough memory to allocate exception!"); @@ -765,14 +771,14 @@ uncaughtExceptionHandler(object); OBJC_ERROR("_Unwind_RaiseException() returned!"); } -objc_uncaught_exception_handler_t -objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler) +objc_uncaught_exception_handler +objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler) { - objc_uncaught_exception_handler_t old = uncaughtExceptionHandler; + objc_uncaught_exception_handler old = uncaughtExceptionHandler; uncaughtExceptionHandler = handler; return old; } Index: src/runtime/hashtable.m ================================================================== --- src/runtime/hashtable.m +++ src/runtime/hashtable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -22,14 +22,14 @@ #include #import "ObjFWRT.h" #import "private.h" -struct objc_hashtable_bucket objc_deleted_bucket; +struct objc_hashtable_bucket objc_deletedBucket; uint32_t -objc_hash_string(const void *str_) +objc_string_hash(const void *str_) { const char *str = str_; uint32_t hash = 0; while (*str != 0) { @@ -45,11 +45,11 @@ return hash; } bool -objc_equal_string(const void *ptr1, const void *ptr2) +objc_string_equal(const void *ptr1, const void *ptr2) { return (strcmp(ptr1, ptr2) == 0); } struct objc_hashtable * @@ -101,11 +101,11 @@ if ((newData = calloc(newSize, sizeof(*newData))) == NULL) OBJC_ERROR("Not enough memory to resize hash table!"); for (uint32_t i = 0; i < table->size; i++) { if (table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket) { + table->data[i] != &objc_deletedBucket) { uint32_t j, last; last = newSize; for (j = table->data[i]->hash & (newSize - 1); @@ -117,11 +117,11 @@ for (j = 0; j < last && newData[j] != NULL; j++); } if (j >= last) - OBJC_ERROR("No free bucket!"); + OBJC_ERROR("No free bucket in hash table!"); newData[j] = table->data[i]; } } @@ -136,11 +136,11 @@ uint32_t i, hash; hash = table->hash(key) & (table->size - 1); for (i = hash; i < table->size && table->data[i] != NULL; i++) { - if (table->data[i] == &objc_deleted_bucket) + if (table->data[i] == &objc_deletedBucket) continue; if (table->equal(table->data[i]->key, key)) { *idx = i; return true; @@ -149,11 +149,11 @@ if (i < table->size) return false; for (i = 0; i < hash && table->data[i] != NULL; i++) { - if (table->data[i] == &objc_deleted_bucket) + if (table->data[i] == &objc_deletedBucket) continue; if (table->equal(table->data[i]->key, key)) { *idx = i; return true; @@ -179,21 +179,21 @@ hash = table->hash(key); last = table->size; for (i = hash & (table->size - 1); i < last && table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket; i++); + table->data[i] != &objc_deletedBucket; i++); if (i >= last) { last = hash & (table->size - 1); for (i = 0; i < last && table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket; i++); + table->data[i] != &objc_deletedBucket; i++); } if (i >= last) - OBJC_ERROR("No free bucket!"); + OBJC_ERROR("No free bucket in hash table!"); if ((bucket = malloc(sizeof(*bucket))) == NULL) OBJC_ERROR("Not enough memory to allocate hash table bucket!"); bucket->key = key; @@ -222,11 +222,11 @@ if (!indexForKey(table, key, &idx)) return; free(table->data[idx]); - table->data[idx] = &objc_deleted_bucket; + table->data[idx] = &objc_deletedBucket; table->count--; resize(table, table->count); } @@ -233,11 +233,11 @@ void objc_hashtable_free(struct objc_hashtable *table) { for (uint32_t i = 0; i < table->size; i++) if (table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket) + table->data[i] != &objc_deletedBucket) free(table->data[i]); free(table->data); free(table); } Index: src/runtime/init.m ================================================================== --- src/runtime/init.m +++ src/runtime/init.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,28 +19,28 @@ #import "private.h" void __objc_exec_class(struct objc_module *module) { - objc_global_mutex_lock(); - - objc_register_all_selectors(module->symtab); - objc_register_all_classes(module->symtab); - objc_register_all_categories(module->symtab); - objc_init_static_instances(module->symtab); - - objc_global_mutex_unlock(); + objc_globalMutex_lock(); + + objc_registerAllSelectors(module->symtab); + objc_registerAllClasses(module->symtab); + objc_registerAllCategories(module->symtab); + objc_initStaticInstances(module->symtab); + + objc_globalMutex_unlock(); } void -objc_exit(void) -{ - objc_global_mutex_lock(); - - objc_unregister_all_categories(); - objc_unregister_all_classes(); - objc_unregister_all_selectors(); - objc_forget_pending_static_instances(); +objc_deinit(void) +{ + objc_globalMutex_lock(); + + objc_unregisterAllCategories(); + objc_unregisterAllClasses(); + objc_unregisterAllSelectors(); + objc_forgetPendingStaticInstances(); objc_dtable_cleanup(); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } Index: src/runtime/instance.m ================================================================== --- src/runtime/instance.m +++ src/runtime/instance.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -79,11 +79,11 @@ if (object == nil) return NULL; #ifdef OF_OBJFW_RUNTIME - objc_zero_weak_references(object); + objc_zeroWeakReferences(object); #endif if (destructSelector == NULL) destructSelector = sel_registerName(".cxx_destruct"); Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -29,33 +29,33 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = (class->ivars != NULL ? class->ivars->count : 0); if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) - OBJC_ERROR("Not enough memory to copy ivars"); + OBJC_ERROR("Not enough memory to copy ivars!"); for (unsigned int i = 0; i < count; i++) ivars[i] = &class->ivars->ivars[i]; ivars[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ivars; } const char * DELETED src/runtime/library.xml Index: src/runtime/library.xml ================================================================== --- src/runtime/library.xml +++ /dev/null @@ -1,345 +0,0 @@ - - ObjFWRT.h - private.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Index: src/runtime/linklib/init.m ================================================================== --- src/runtime/linklib/init.m +++ src/runtime/linklib/init.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -151,21 +151,21 @@ { CloseLibrary(ObjFWRTBase); } #if defined(OF_AMIGAOS_M68K) -ADD2INIT(ctor, -5); -ADD2EXIT(dtor, -5); +ADD2INIT(ctor, -5) +ADD2EXIT(dtor, -5) #elif defined(OF_MORPHOS) CONSTRUCTOR_P(ObjFWRT, 4000) { ctor(); return 0; } -DESTRUCTOR_P(ObjFWRT, 4000) +DESTRUCTOR_P(ObjFWRT, 0) { dtor(); } #endif Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -11,11 +11,11 @@ * 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. */ -/* This file is automatically generated from library.xml */ +/* This file is automatically generated from amiga-library.xml */ #include "config.h" #import "ObjFWRT.h" #import "private.h" @@ -1042,24 +1042,24 @@ return __extension__ ((bool (*)(Protocol *_Nonnull, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 382))(protocol1, protocol2); #endif } -_Nullable objc_uncaught_exception_handler_t -objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler) +_Nullable objc_uncaught_exception_handler +objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler _Nullable handler) { #if defined(OF_AMIGAOS_M68K) register struct Library *a6 __asm__("a6") = ObjFWRTBase; (void)a6; - return ((_Nullable objc_uncaught_exception_handler_t (*)(objc_uncaught_exception_handler_t _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 390))(handler); + return ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 390))(handler); #elif defined(OF_MORPHOS) __asm__ __volatile__ ( "mr %%r12, %0" :: "r"(ObjFWRTBase) : "r12" ); - return __extension__ ((_Nullable objc_uncaught_exception_handler_t (*)(objc_uncaught_exception_handler_t _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 388))(handler); + return __extension__ ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 388))(handler); #endif } void objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward) @@ -1077,23 +1077,23 @@ __extension__ ((void (*)(IMP _Nullable, IMP _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 394))(forward, stretForward); #endif } void -objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable hadler) +objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler _Nullable hadler) { #if defined(OF_AMIGAOS_M68K) register struct Library *a6 __asm__("a6") = ObjFWRTBase; (void)a6; - ((void (*)(objc_enumeration_mutation_handler_t _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 402))(hadler); + ((void (*)(objc_enumeration_mutation_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 402))(hadler); #elif defined(OF_MORPHOS) __asm__ __volatile__ ( "mr %%r12, %0" :: "r"(ObjFWRTBase) : "r12" ); - __extension__ ((void (*)(objc_enumeration_mutation_handler_t _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 400))(hadler); + __extension__ ((void (*)(objc_enumeration_mutation_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 400))(hadler); #endif } id _Nullable objc_constructInstance(Class _Nullable class, void *_Nullable bytes) @@ -1111,11 +1111,11 @@ return __extension__ ((id _Nullable (*)(Class _Nullable, void *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 406))(class, bytes); #endif } void -objc_exit() +objc_deinit() { #if defined(OF_AMIGAOS_M68K) register struct Library *a6 __asm__("a6") = ObjFWRTBase; (void)a6; ((void (*)())(((uintptr_t)ObjFWRTBase) - 414))(); Index: src/runtime/lookup-asm/lookup-asm-arm-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-arm-elf.S +++ src/runtime/lookup-asm/lookup-asm-arm-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,17 +21,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: cmp r0, #0 - beq ret_nil + beq returnNilMethod tst r0, #1 - bne .Ltagged_pointer_\name + bne .LtaggedPointer_\name ldr r2, [r0, #0] ldr r2, [r2, #32] .Lmain_\name: @@ -54,67 +54,67 @@ ldrb r3, [r1, #3] ldr r2, [r2, r3, lsl #2] #endif cmp r2, #0 - beq \not_found(PLT) + beq \notFound(PLT) mov r0, r2 bx lr -.Ltagged_pointer_\name: - ldr r2, .Lgot$indirect_.Ltagged_pointer_\name +.LtaggedPointer_\name: + ldr r2, .Lgot$indirect_.LtaggedPointer_\name add r2, pc, r2 - ldr r3, .Lgot$indirect_.Ltagged_pointer_\name+4 + ldr r3, .Lgot$indirect_.LtaggedPointer_\name+4 ldr r3, [r2, r3] ldr r3, [r3] eor r0, r0, r3 and r0, r0, #0xE lsl r0, r0, #1 - ldr r3, .Lgot$indirect_.Ltagged_pointer_\name+8 + ldr r3, .Lgot$indirect_.LtaggedPointer_\name+8 ldr r3, [r2, r3] ldr r2, [r3, r0] ldr r2, [r2, #32] b .Lmain_\name .type \name, %function .size \name, .-\name -.Lgot$indirect_.Ltagged_pointer_\name: - .long _GLOBAL_OFFSET_TABLE_-(.Ltagged_pointer_\name+12) - .long objc_tagged_pointer_secret(GOT) - .long objc_tagged_pointer_classes(GOT) +.Lgot$indirect_.LtaggedPointer_\name: + .long _GLOBAL_OFFSET_TABLE_-(.LtaggedPointer_\name+12) + .long objc_taggedPointerSecret(GOT) + .long objc_taggedPointerClasses(GOT) .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov r2, r0 ldr r0, [r0, #0] cmp r0, #0 - beq ret_nil + beq returnNilMethod ldr r2, [r2, #4] ldr r2, [r2, #32] b .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: - adr r0, nil_method +returnNilMethod: + adr r0, nilMethod bx lr -nil_method: +nilMethod: mov r0, #0 bx lr #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-arm64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-arm64-elf.S +++ src/runtime/lookup-asm/lookup-asm-arm64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: - cbz x0, ret_nil + cbz x0, returnNilMethod tst x0, #1 - b.ne .Ltagged_pointer_\name + b.ne .LtaggedPointer_\name ldr x2, [x0] ldr x2, [x2, #64] .Lmain_\name: @@ -41,58 +41,58 @@ ldrb w3, [x1, #1] ldr x2, [x2, x3, lsl #3] ldrb w3, [x1] ldr x2, [x2, x3, lsl #3] - cbz x2, \not_found + cbz x2, \notFound mov x0, x2 ret -.Ltagged_pointer_\name: - adrp x2, :got:objc_tagged_pointer_secret - ldr x2, [x2, #:got_lo12:objc_tagged_pointer_secret] +.LtaggedPointer_\name: + adrp x2, :got:objc_taggedPointerSecret + ldr x2, [x2, #:got_lo12:objc_taggedPointerSecret] ldr x2, [x2] eor x0, x0, x2 and x0, x0, #0xE lsl x0, x0, #2 - adrp x2, :got:objc_tagged_pointer_classes - ldr x2, [x2, #:got_lo12:objc_tagged_pointer_classes] + adrp x2, :got:objc_taggedPointerClasses + ldr x2, [x2, #:got_lo12:objc_taggedPointerClasses] ldr x2, [x2, x0] ldr x2, [x2, #64] b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov x2, x0 ldr x0, [x0] - cbz x0, ret_nil + cbz x0, returnNilMethod ldr x2, [x2, #8] ldr x2, [x2, #64] b .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: - adr x0, nil_method +returnNilMethod: + adr x0, nilMethod ret -nil_method: +nilMethod: mov x0, #0 ret #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-mips-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-mips-elf.S +++ src/runtime/lookup-asm/lookup-asm-mips-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: beqz $a0, 0f andi $t0, $a0, 1 - bnez $t0, .Ltagged_pointer_\name + bnez $t0, .LtaggedPointer_\name lw $t0, 0($a0) lw $t0, 32($t0) .Lmain_\name: @@ -64,21 +64,21 @@ lw $t0, 0($t0) #ifdef OF_PIC beqz $t0, 1f #else - beqz $t0, \not_found + beqz $t0, \notFound #endif move $v0, $t0 jr $ra 0: #ifdef OF_PIC - addiu $v0, $t9, nil_method-\name + addiu $v0, $t9, nilMethod-\name #else - la $v0, nil_method + la $v0, nilMethod #endif jr $ra #ifdef OF_PIC 1: @@ -85,35 +85,35 @@ lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 addiu $gp, $gp, 1b-\name - lw $t9, %call16(\not_found)($gp) + lw $t9, %call16(\notFound)($gp) jr $t9 #endif -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC 0: lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 addiu $gp, $gp, 0b-\name - lw $t0, %got(objc_tagged_pointer_secret)($gp) + lw $t0, %got(objc_taggedPointerSecret)($gp) #else - la $t0, objc_tagged_pointer_secret + la $t0, objc_taggedPointerSecret #endif lw $t0, 0($t0) xor $t0, $a0, $t0 and $t0, $t0, 0xE sll $t0, $t0, 1 #ifdef OF_PIC - lw $t1, %got(objc_tagged_pointer_classes)($gp) + lw $t1, %got(objc_taggedPointerClasses)($gp) #else - la $t1, objc_tagged_pointer_classes + la $t1, objc_taggedPointerClasses #endif addu $t0, $t1, $t0 ld $t0, ($t0) ld $t0, 32($t0) @@ -120,11 +120,11 @@ b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: move $t0, $a0 lw $a0, 0($a0) beqz $a0, 0f @@ -134,26 +134,26 @@ addiu $t9, $t9, \lookup-\name b .Lmain_\lookup 0: #ifdef OF_PIC - addiu $v0, $t9, nil_method-\name + addiu $v0, $t9, nilMethod-\name #else - la $v0, nil_method + la $v0, nilMethod #endif jr $ra .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -nil_method: +nilMethod: move $v0, $zero jr $ra #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S +++ src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: beqz $a0, 0f andi $t0, $a0, 1 - bnez $t0, .Ltagged_pointer_\name + bnez $t0, .LtaggedPointer_\name ld $t0, ($a0) ld $t0, 64($t0) .Lmain_\name: @@ -70,42 +70,42 @@ 0: lui $v0, %hi(%neg(%gp_rel(\name))) daddiu $v0, $v0, %lo(%neg(%gp_rel(\name))) daddu $v0, $v0, $t9 - ld $v0, %got_disp(nil_method)($v0) + ld $v0, %got_disp(nilMethod)($v0) jr $ra 1: lui $t0, %hi(%neg(%gp_rel(\name))) daddiu $t0, $t0, %lo(%neg(%gp_rel(\name))) daddu $t0, $t0, $t9 - ld $t9, %got_disp(\not_found)($t0) + ld $t9, %got_disp(\notFound)($t0) jr $t9 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: lui $t0, %hi(%neg(%gp_rel(\name))) daddiu $t0, $t0, %lo(%neg(%gp_rel(\name))) daddu $t0, $t0, $t9 - ld $t1, %got_disp(objc_tagged_pointer_secret)($t0) + ld $t1, %got_disp(objc_taggedPointerSecret)($t0) ld $t1, 0($t1) xor $t1, $a0, $t1 and $t1, $t1, 0xE dsll $t1, $t1, 2 - ld $t0, %got_disp(objc_tagged_pointer_classes)($t0) + ld $t0, %got_disp(objc_taggedPointerClasses)($t0) daddu $t0, $t0, $t1 ld $t0, ($t0) ld $t0, 64($t0) b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: move $t0, $a0 ld $a0, ($a0) beqz $a0, 0f @@ -117,23 +117,23 @@ 0: lui $v0, %hi(%neg(%gp_rel(\name))) daddiu $v0, $v0, %lo(%neg(%gp_rel(\name))) daddu $v0, $v0, $t9 - ld $v0, %got_disp(nil_method)($v0) + ld $v0, %got_disp(nilMethod)($v0) jr $ra .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -nil_method: +nilMethod: move $v0, $zero jr $ra #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-powerpc-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-powerpc-elf.S +++ src/runtime/lookup-asm/lookup-asm-powerpc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,17 +21,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: cmpwi %r3, 0 - beq- ret_nil + beq- returnNilMethod andi. %r0, %r3, 1 - bne- .Ltagged_pointer_\name + bne- .LtaggedPointer_\name lwz %r5, 0(%r3) lwz %r5, 32(%r5) .Lmain_\name: @@ -65,109 +65,109 @@ 0: mflr %r30 addis %r30, %r30, .Lbiased_got2-0b@ha addi %r30, %r30, .Lbiased_got2-0b@l - lwz %r0, .Lgot_\not_found-.Lbiased_got2(%r30) + lwz %r0, .Lgot_\notFound-.Lbiased_got2(%r30) mtctr %r0 lwz %r30, 8(%r1) lwz %r0, 20(%r1) addi %r1, %r1, 16 mtlr %r0 bctr #else - b \not_found + b \notFound #endif -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #if defined(OF_PIC) mflr %r7 bl 0f 0: mflr %r6 mtlr %r7 addis %r6, %r6, .Lbiased_got2-0b@ha addi %r6, %r6, .Lbiased_got2-0b@l - lwz %r5, .Lgot_objc_tagged_pointer_secret-.Lbiased_got2(%r6) + lwz %r5, .Lgot_objc_taggedPointerSecret-.Lbiased_got2(%r6) lwz %r5, 0(%r5) #elif defined(OF_BASEREL) - addis %r5, %r13, objc_tagged_pointer_secret@drel@ha - lwz %r5, objc_tagged_pointer_secret@drel@l(%r5) + addis %r5, %r13, objc_taggedPointerSecret@drel@ha + lwz %r5, objc_taggedPointerSecret@drel@l(%r5) #else - lis %r5, objc_tagged_pointer_secret@ha - lwz %r5, objc_tagged_pointer_secret@l(%r5) + lis %r5, objc_taggedPointerSecret@ha + lwz %r5, objc_taggedPointerSecret@l(%r5) #endif xor %r5, %r3, %r5 rlwinm %r5, %r5, 1, 0x1C #if defined(OF_PIC) - lwz %r6, .Lgot_objc_tagged_pointer_classes-.Lbiased_got2(%r6) + lwz %r6, .Lgot_objc_taggedPointerClasses-.Lbiased_got2(%r6) #elif defined(OF_BASEREL) - addis %r6, %r13, objc_tagged_pointer_classes@drel@ha - addi %r6, %r6, objc_tagged_pointer_classes@drel@l + addis %r6, %r13, objc_taggedPointerClasses@drel@ha + addi %r6, %r6, objc_taggedPointerClasses@drel@l #else - lis %r6, objc_tagged_pointer_classes@ha - addi %r6, %r6, objc_tagged_pointer_classes@l + lis %r6, objc_taggedPointerClasses@ha + addi %r6, %r6, objc_taggedPointerClasses@l #endif lwzx %r5, %r6, %r5 lwz %r5, 32(%r5) b .Lmain_\name .type \name, @function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mr %r5, %r3 lwz %r3, 0(%r3) cmpwi %r3, 0 - beq- ret_nil + beq- returnNilMethod lwz %r5, 4(%r5) lwz %r5, 32(%r5) b .Lmain_\lookup .type \name, @function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - mflr %r0 - bl get_pc +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret + +returnNilMethod: + mflr %r0 + bl getPC mtlr %r0 0: - addi %r3, %r3, nil_method-0b + addi %r3, %r3, nilMethod-0b blr -nil_method: +nilMethod: li %r3, 0 blr -get_pc: +getPC: mflr %r3 blr #ifdef OF_PIC .section .got2, "aw" .Lbiased_got2 = .+0x8000 -.Lgot_objc_method_not_found: - .long objc_method_not_found -.Lgot_objc_method_not_found_stret: - .long objc_method_not_found_stret -.Lgot_objc_tagged_pointer_secret: - .long objc_tagged_pointer_secret -.Lgot_objc_tagged_pointer_classes: - .long objc_tagged_pointer_classes +.Lgot_objc_methodNotFound: + .long objc_methodNotFound +.Lgot_objc_methodNotFound_stret: + .long objc_methodNotFound_stret +.Lgot_objc_taggedPointerSecret: + .long objc_taggedPointerSecret +.Lgot_objc_taggedPointerClasses: + .long objc_taggedPointerClasses #endif #ifdef OF_LINUX .section .note.GNU-stack, "", @progbits #endif ADDED src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S Index: src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S ================================================================== --- /dev/null +++ src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2008-2022 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" + +#include "platform.h" + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +.abiversion 2 +#endif + +.globl objc_msg_lookup +.globl objc_msg_lookup_stret +.globl objc_msg_lookup_super +.globl objc_msg_lookup_super_stret + +.section .text +.macro GENERATE_LOOKUP name notFound +#if defined(_CALL_ELF) && _CALL_ELF == 2 +\name: + addis %r2, %r12, .TOC.-\name@ha + addi %r2, %r2, .TOC.-\name@l +.localentry \name, .-\name +#else +.section .opd, "aw", @progbits +\name: + .p2align 3 + .quad .Lbegin_\name + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_\name: + cmpdi %r3, 0 + beq- .LreturnNilMethod + + andi. %r0, %r3, 1 + bne- .LtaggedPointer_\name + + ld %r5, 0(%r3) + ld %r5, 64(%r5) + +.Lmain_\name: + ld %r8, 0(%r4) +#ifdef OF_SELUID24 + rlwinm %r6, %r8, 19, 0x7F8 +#endif + rlwinm %r7, %r8, 27, 0x7F8 + rlwinm %r8, %r8, 3, 0x7F8 + +#ifdef OF_SELUID24 + ldx %r5, %r5, %r6 +#endif + ldx %r5, %r5, %r7 + ldx %r5, %r5, %r8 + + cmpdi %r5, 0 + beq- 0f + + mr %r3, %r5 + blr + +0: + mflr %r0 + std %r0, 16(%r1) + stdu %r1, -112(%r1) + bl \notFound + nop + addi %r1, %r1, 112 + ld %r0, 16(%r1) + mtlr %r0 + blr + +.LtaggedPointer_\name: + addis %r5, %r2, objc_taggedPointerSecret@toc@ha + ld %r5, objc_taggedPointerSecret@toc@l(%r5) + xor %r5, %r3, %r5 + rlwinm %r5, %r5, 2, 0x38 + + addis %r6, %r2, objc_taggedPointerClasses@toc@ha + addi %r6, %r6, objc_taggedPointerClasses@toc@l + ldx %r5, %r6, %r5 + ld %r5, 64(%r5) + + b .Lmain_\name +.type \name, @function +.size \name, .-.Lbegin_\name +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +#if defined(_CALL_ELF) && _CALL_ELF == 2 +\name: + addis %r2, %r12, .TOC.-\name@ha + addi %r2, %r2, .TOC.-\name@l +.localentry \name, .-\name +#else +.section .opd, "aw", @progbits +\name: + .p2align 3 + .quad .Lbegin_\name + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_\name: + mr %r5, %r3 + ld %r3, 0(%r3) + cmpdi %r3, 0 + beq- .LreturnNilMethod + + ld %r5, 8(%r5) + ld %r5, 64(%r5) + + b .Lmain_\lookup +.type \name, @function +.size \name, .-.Lbegin_\name +.endm + +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret + +.LreturnNilMethod: + addis %r3, %r2, nilMethod@toc@ha + addi %r3, %r3, nilMethod@toc@l + blr + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +nilMethod: + addis %r2, %r12, .TOC.-nilMethod@ha + addi %r2, %r2, .TOC.-nilMethod@l +.localentry nilMethod, .-nilMethod +#else +.section .opd, "aw", @progbits +nilMethod: + .p2align 3 + .quad .Lbegin_nilMethod + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_nilMethod: + li %r3, 0 + blr +.type nilMethod, @function +.size nilMethod, .-.Lbegin_nilMethod + +#ifdef OF_LINUX +.section .note.GNU-stack, "", @progbits +#endif Index: src/runtime/lookup-asm/lookup-asm-sparc-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-sparc-elf.S +++ src/runtime/lookup-asm/lookup-asm-sparc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: tst %o0 - bz ret_nil + bz returnNilMethod btst 1, %o0 - bnz .Ltagged_pointer_\name + bnz .LtaggedPointer_\name nop ld [%o0], %o2 ld [%o2 + 32], %o2 @@ -60,14 +60,14 @@ retl mov %o2, %o0 0: mov %o7, %g1 - call \not_found + call \notFound mov %g1, %o7 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3 call 0f or %o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3 @@ -74,22 +74,22 @@ 0: add %o7, %o3, %o3 mov %g1, %o7 #endif - sethi %hi(objc_tagged_pointer_secret), %o2 - or %o2, %lo(objc_tagged_pointer_secret), %o2 + sethi %hi(objc_taggedPointerSecret), %o2 + or %o2, %lo(objc_taggedPointerSecret), %o2 #ifdef OF_PIC ld [%o3 + %o2], %o2 #endif ld [%o2], %o2 xor %o0, %o2, %o0 and %o0, 0xE, %o0 sll %o0, 1, %o0 - sethi %hi(objc_tagged_pointer_classes), %o2 - or %o2, %lo(objc_tagged_pointer_classes), %o2 + sethi %hi(objc_taggedPointerClasses), %o2 + or %o2, %lo(objc_taggedPointerClasses), %o2 #ifdef OF_PIC ld [%o3 + %o2], %o2 #endif ld [%o2 + %o0], %o2 @@ -97,53 +97,53 @@ ld [%o2 + 32], %o2 .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov %o0, %o2 ld [%o0], %o0 cmp %o0, 0 - be ret_nil + be returnNilMethod nop ld [%o2 + 4], %o2 ba .Lmain_\lookup ld [%o2 + 32], %o2 .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: +returnNilMethod: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1 call 0f add %o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1 0: add %o7, %o1, %o1 - sethi %hi(nil_method), %o0 - or %o0, %lo(nil_method), %o0 + sethi %hi(nilMethod), %o0 + or %o0, %lo(nilMethod), %o0 jmpl %g1 + 8, %g0 ld [%o1 + %o0], %o0 #else - sethi %hi(nil_method), %o0 + sethi %hi(nilMethod), %o0 retl - or %o0, %lo(nil_method), %o0 + or %o0, %lo(nilMethod), %o0 #endif -nil_method: +nilMethod: retl clr %o0 #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-sparc64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-sparc64-elf.S +++ src/runtime/lookup-asm/lookup-asm-sparc64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,15 +21,15 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: - brz,pn %o0, ret_nil + brz,pn %o0, returnNilMethod and %o0, 1, %o2 - brnz,pn %o2, .Ltagged_pointer_\name + brnz,pn %o2, .LtaggedPointer_\name nop ldx [%o0], %o2 ldx [%o2 + 64], %o2 @@ -58,14 +58,14 @@ retl mov %o2, %o0 0: mov %o7, %g1 - call \not_found + call \notFound mov %g1, %o7 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3 call 0f or %o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3 @@ -72,22 +72,22 @@ 0: add %o7, %o3, %o3 mov %g1, %o7 #endif - sethi %hi(objc_tagged_pointer_secret), %o2 - or %o2, %lo(objc_tagged_pointer_secret), %o2 + sethi %hi(objc_taggedPointerSecret), %o2 + or %o2, %lo(objc_taggedPointerSecret), %o2 #ifdef OF_PIC ldx [%o3 + %o2], %o2 #endif ldx [%o2], %o2 xor %o0, %o2, %o0 and %o0, 0xE, %o0 sll %o0, 2, %o0 - sethi %hi(objc_tagged_pointer_classes), %o2 - or %o2, %lo(objc_tagged_pointer_classes), %o2 + sethi %hi(objc_taggedPointerClasses), %o2 + or %o2, %lo(objc_taggedPointerClasses), %o2 #ifdef OF_PIC ldx [%o3 + %o2], %o2 #endif ldx [%o2 + %o0], %o2 @@ -95,52 +95,52 @@ ldx [%o2 + 64], %o2 .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov %o0, %o2 ldx [%o0], %o0 - brz,pn %o0, ret_nil + brz,pn %o0, returnNilMethod nop ldx [%o2 + 8], %o2 ba .Lmain_\lookup ldx [%o2 + 64], %o2 .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: +returnNilMethod: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1 call 0f or %o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1 0: add %o7, %o1, %o1 - sethi %hi(nil_method), %o0 - or %o0, %lo(nil_method), %o0 + sethi %hi(nilMethod), %o0 + or %o0, %lo(nilMethod), %o0 jmpl %g1 + 8, %g0 ldx [%o1 + %o0], %o0 #else - sethi %hi(nil_method), %o0 + sethi %hi(nilMethod), %o0 retl - or %o0, %lo(nil_method), %o0 + or %o0, %lo(nilMethod), %o0 #endif -nil_method: +nilMethod: retl clr %o0 #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-x86-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,18 +21,18 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: movl 4(%esp), %edx testl %edx, %edx - jz ret_nil + jz returnNilMethod testb $1, %dl - jnz .Ltagged_pointer_\name + jnz .LtaggedPointer_\name movl (%edx), %edx movl 32(%edx), %edx .Lmain_\name: @@ -51,65 +51,65 @@ jz 0f ret 0: - call get_eip + call getEIP addl $_GLOBAL_OFFSET_TABLE_, %eax - lea \not_found@GOTOFF(%eax), %eax + lea \notFound@GOTOFF(%eax), %eax jmp *%eax -.Ltagged_pointer_\name: - call get_eip +.LtaggedPointer_\name: + call getEIP addl $_GLOBAL_OFFSET_TABLE_, %eax - leal objc_tagged_pointer_secret@GOTOFF(%eax), %ecx + leal objc_taggedPointerSecret@GOTOFF(%eax), %ecx xorl (%ecx), %edx andb $0xE, %dl movzbl %dl, %edx - leal objc_tagged_pointer_classes@GOTOFF(%eax), %eax + leal objc_taggedPointerClasses@GOTOFF(%eax), %eax movl (%eax,%edx,2), %edx movl 32(%edx), %edx jmp .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: movl 4(%esp), %edx movl (%edx), %eax testl %eax, %eax - jz ret_nil + jz returnNilMethod movl %eax, 4(%esp) mov 4(%edx), %edx mov 32(%edx), %edx jmp .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - call get_eip - addl $_GLOBAL_OFFSET_TABLE_, %eax - leal nil_method@GOTOFF(%eax), %eax +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret + +returnNilMethod: + call getEIP + addl $_GLOBAL_OFFSET_TABLE_, %eax + leal nilMethod@GOTOFF(%eax), %eax ret -nil_method: +nilMethod: xorl %eax, %eax ret -get_eip: +getEIP: movl (%esp), %eax ret #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-x86-win32.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-win32.S +++ src/runtime/lookup-asm/lookup-asm-x86-win32.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,18 +19,18 @@ .globl _objc_msg_lookup_stret .globl _objc_msg_lookup_super .globl _objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: movl 4(%esp), %edx testl %edx, %edx - jz ret_nil + jz returnNilMethod testb $1, %dl - jnz .Ltagged_pointer_\name + jnz .LtaggedPointer_\name movl (%edx), %edx movl 32(%edx), %edx .Lmain_\name: @@ -44,35 +44,35 @@ movl (%edx,%ecx,4), %edx movzbl (%eax), %ecx movl (%edx,%ecx,4), %eax testl %eax, %eax - jz \not_found + jz \notFound ret -.Ltagged_pointer_\name: - xorl _objc_tagged_pointer_secret, %edx +.LtaggedPointer_\name: + xorl _objc_taggedPointerSecret, %edx andb $0xE, %dl movzbl %dl, %edx - movl _objc_tagged_pointer_classes(,%edx,2), %edx + movl _objc_taggedPointerClasses(,%edx,2), %edx movl 32(%edx), %edx jmp .Lmain_\name .def \name .scl 2 .type 32 .endef .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: movl 4(%esp), %edx movl (%edx), %eax test %eax, %eax - jz ret_nil + jz returnNilMethod movl %eax, 4(%esp) movl 4(%edx), %edx movl 32(%edx), %edx jmp .Lmain_\lookup @@ -80,17 +80,17 @@ .scl 2 .type 32 .endef .endm -generate_lookup _objc_msg_lookup _objc_method_not_found -generate_lookup _objc_msg_lookup_stret _objc_method_not_found_stret -generate_lookup_super _objc_msg_lookup_super _objc_msg_lookup -generate_lookup_super _objc_msg_lookup_super_stret _objc_msg_lookup_stret +GENERATE_LOOKUP _objc_msg_lookup _objc_methodNotFound +GENERATE_LOOKUP _objc_msg_lookup_stret _objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super _objc_msg_lookup +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret _objc_msg_lookup_stret -ret_nil: - movl $nil_method, %eax +returnNilMethod: + movl $nilMethod, %eax ret -nil_method: +nilMethod: xorl %eax, %eax ret Index: src/runtime/lookup-asm/lookup-asm-x86_64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,17 +21,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: testq %rdi, %rdi - jz ret_nil + jz returnNilMethod testb $1, %dil - jnz .Ltagged_pointer_\name + jnz .LtaggedPointer_\name movq (%rdi), %r8 movq 64(%r8), %r8 .Lmain_\name: @@ -45,54 +45,54 @@ #endif movq (%r8,%rcx,8), %r8 movq (%r8,%rdx,8), %rax testq %rax, %rax - jz \not_found@PLT + jz \notFound@PLT ret -.Ltagged_pointer_\name: - movq objc_tagged_pointer_secret@GOTPCREL(%rip), %rax +.LtaggedPointer_\name: + movq objc_taggedPointerSecret@GOTPCREL(%rip), %rax xorq (%rax), %rdi andb $0xE, %dil movzbl %dil, %r8d - movq objc_tagged_pointer_classes@GOTPCREL(%rip), %rax + movq objc_taggedPointerClasses@GOTPCREL(%rip), %rax movq (%rax,%r8,4), %r8 movq 64(%r8), %r8 jmp .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: movq %rdi, %r8 movq (%rdi), %rdi testq %rdi, %rdi - jz ret_nil + jz returnNilMethod movq 8(%r8), %r8 movq 64(%r8), %r8 jmp .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: - leaq nil_method(%rip), %rax +returnNilMethod: + leaq nilMethod(%rip), %rax ret -nil_method: +nilMethod: xorq %rax, %rax ret #ifdef OF_LINUX .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-x86_64-macho.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-macho.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-macho.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,17 +19,17 @@ .globl _objc_msg_lookup_stret .globl _objc_msg_lookup_super .globl _objc_msg_lookup_super_stret .section __TEXT, __text, regular, pure_instructions -.macro generate_lookup +.macro GENERATE_LOOKUP $0: testq %rdi, %rdi - jz ret_nil + jz returnNilMethod testb $$1, %dil - jnz Ltagged_pointer_$0 + jnz LtaggedPointer_$0 movq (%rdi), %r8 movq 64(%r8), %r8 Lmain_$0: @@ -47,42 +47,42 @@ testq %rax, %rax jz $1 ret -Ltagged_pointer_$0: - movq _objc_tagged_pointer_secret@GOTPCREL(%rip), %rax +LtaggedPointer_$0: + movq _objc_taggedPointerSecret@GOTPCREL(%rip), %rax xorq (%rax), %rdi andb $$0xE, %dil movzbl %dil, %r8d - movq _objc_tagged_pointer_classes@GOTPCREL(%rip), %rax + movq _objc_taggedPointerClasses@GOTPCREL(%rip), %rax movq (%rax,%r8,4), %r8 movq 64(%r8), %r8 jmp Lmain_$0 .endmacro -.macro generate_lookup_super +.macro GENERATE_LOOKUP_SUPER $0: movq %rdi, %r8 movq (%rdi), %rdi testq %rdi, %rdi - jz ret_nil + jz returnNilMethod movq 8(%r8), %r8 movq 64(%r8), %r8 jmp Lmain_$1 .endmacro -generate_lookup _objc_msg_lookup, _objc_method_not_found -generate_lookup _objc_msg_lookup_stret, _objc_method_not_found_stret -generate_lookup_super _objc_msg_lookup_super, _objc_msg_lookup -generate_lookup_super _objc_msg_lookup_super_stret, _objc_msg_lookup_stret +GENERATE_LOOKUP _objc_msg_lookup, _objc_methodNotFound +GENERATE_LOOKUP _objc_msg_lookup_stret, _objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super, _objc_msg_lookup +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret, _objc_msg_lookup_stret -ret_nil: - leaq nil_method(%rip), %rax +returnNilMethod: + leaq nilMethod(%rip), %rax ret -nil_method: +nilMethod: xorq %rax, %rax ret Index: src/runtime/lookup-asm/lookup-asm-x86_64-win64.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-win64.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-win64.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,17 +19,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: testq %rcx, %rcx - jz ret_nil + jz returnNilMethod testb $1, %cl - jnz .Ltagged_pointer_\name + jnz .LtaggedPointer_\name movq (%rcx), %r8 movq 56(%r8), %r8 .Lmain_\name: @@ -53,18 +53,18 @@ ret 0: movq %r10, %rcx movq %r11, %rdx - jmp \not_found + jmp \notFound -.Ltagged_pointer_\name: - xorq objc_tagged_pointer_secret(%rip), %rcx +.LtaggedPointer_\name: + xorq objc_taggedPointerSecret(%rip), %rcx andb $0xE, %cl movzbl %cl, %r8d - leaq objc_tagged_pointer_classes(%rip), %rax + leaq objc_taggedPointerClasses(%rip), %rax movq (%rax,%r8,4), %r8 movq 56(%r8), %r8 jmp .Lmain_\name .def \name @@ -71,16 +71,16 @@ .scl 2 .type 32 .endef .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: movq %rcx, %r8 movq (%rcx), %rcx testq %rcx, %rcx - jz ret_nil + jz returnNilMethod movq 8(%r8), %r8 movq 56(%r8), %r8 jmp .Lmain_\lookup .def \name @@ -87,17 +87,17 @@ .scl 2 .type 32 .endef .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret -ret_nil: - leaq nil_method(%rip), %rax +returnNilMethod: + leaq nilMethod(%rip), %rax ret -nil_method: +nilMethod: xorq %rax, %rax ret Index: src/runtime/lookup-asm/lookup-asm.S ================================================================== --- src/runtime/lookup-asm/lookup-asm.S +++ src/runtime/lookup-asm/lookup-asm.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -24,10 +24,12 @@ # include "lookup-asm-x86-elf.S" # elif defined(OF_ARM64) # include "lookup-asm-arm64-elf.S" # elif defined(OF_ARM) # include "lookup-asm-arm-elf.S" +# elif defined(OF_POWERPC64) +# include "lookup-asm-powerpc64-elf.S" # elif defined(OF_POWERPC) # include "lookup-asm-powerpc-elf.S" # elif defined(OF_MIPS64_N64) # include "lookup-asm-mips64-n64-elf.S" # elif defined(OF_MIPS) Index: src/runtime/lookup.m ================================================================== --- src/runtime/lookup.m +++ src/runtime/lookup.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -39,15 +39,16 @@ if (!(object_getClass(object)->info & OBJC_CLASS_INFO_INITIALIZED)) { Class class = (isClass ? (Class)object : object_getClass(object)); - objc_initialize_class(class); + objc_initializeClass(class); if (!(class->info & OBJC_CLASS_INFO_SETUP)) - OBJC_ERROR("Could not dispatch message for incomplete " - "class %s!", class_getName(class)); + OBJC_ERROR("Could not dispatch message %s for " + "incomplete class %s!", + sel_getName(selector), class_getName(class)); /* * We don't need to handle the case that super was called. * The reason for this is that a call to super is not possible * before a message to the class has been sent and it thus has @@ -95,18 +96,18 @@ (isClass ? '+' : '-'), sel_getName(selector), object_getClassName(object)); } IMP -objc_method_not_found(id object, SEL selector) +objc_methodNotFound(id object, SEL selector) { return commonMethodNotFound(object, selector, objc_msg_lookup, forwardHandler); } IMP -objc_method_not_found_stret(id object, SEL selector) +objc_methodNotFound_stret(id object, SEL selector) { return commonMethodNotFound(object, selector, objc_msg_lookup_stret, stretForwardHandler); } @@ -121,11 +122,11 @@ class_respondsToSelector(Class class, SEL selector) { if (class == Nil) return false; - return (objc_dtable_get(class->DTable, + return (objc_dtable_get(class->dTable, (uint32_t)selector->UID) != (IMP)0); } #ifndef OF_ASM_LOOKUP static id @@ -140,11 +141,11 @@ IMP imp; if (object == nil) return (IMP)nilMethod; - imp = objc_dtable_get(object_getClass(object)->DTable, + imp = objc_dtable_get(object_getClass(object)->dTable, (uint32_t)selector->UID); if (imp == (IMP)0) return notFound(object, selector); @@ -152,17 +153,17 @@ } IMP objc_msg_lookup(id object, SEL selector) { - return commonLookup(object, selector, objc_method_not_found); + return commonLookup(object, selector, objc_methodNotFound); } IMP objc_msg_lookup_stret(id object, SEL selector) { - return commonLookup(object, selector, objc_method_not_found_stret); + return commonLookup(object, selector, objc_methodNotFound_stret); } static OF_INLINE IMP commonSuperLookup(struct objc_super *super, SEL selector, IMP (*notFound)(id, SEL)) @@ -170,11 +171,11 @@ IMP imp; if (super->self == nil) return (IMP)nilMethod; - imp = objc_dtable_get(super->class->DTable, (uint32_t)selector->UID); + imp = objc_dtable_get(super->class->dTable, (uint32_t)selector->UID); if (imp == (IMP)0) return notFound(super->self, selector); return imp; @@ -181,14 +182,14 @@ } IMP objc_msg_lookup_super(struct objc_super *super, SEL selector) { - return commonSuperLookup(super, selector, objc_method_not_found); + return commonSuperLookup(super, selector, objc_methodNotFound); } IMP objc_msg_lookup_super_stret(struct objc_super *super, SEL selector) { - return commonSuperLookup(super, selector, objc_method_not_found_stret); + return commonSuperLookup(super, selector, objc_methodNotFound_stret); } #endif Index: src/runtime/method.m ================================================================== --- src/runtime/method.m +++ src/runtime/method.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -30,21 +30,21 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = 0; for (iter = class->methodList; iter != NULL; iter = iter->next) count += iter->count; if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } if ((methods = malloc((count + 1) * sizeof(Method))) == NULL) OBJC_ERROR("Not enough memory to copy methods"); @@ -51,17 +51,20 @@ i = 0; for (iter = class->methodList; iter != NULL; iter = iter->next) for (unsigned int j = 0; j < iter->count; j++) methods[i++] = &iter->methods[j]; - OFEnsure(i == count); + + if (i != count) + OBJC_ERROR("Fatal internal inconsistency!"); + methods[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return methods; } SEL Index: src/runtime/misc.m ================================================================== --- src/runtime/misc.m +++ src/runtime/misc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -35,11 +35,11 @@ # include # undef Class # undef __NOLIBBASE__ #endif -static objc_enumeration_mutation_handler_t enumerationMutationHandler = NULL; +static objc_enumeration_mutation_handler enumerationMutationHandler = NULL; void objc_enumerationMutation(id object) { if (enumerationMutationHandler != NULL) @@ -47,27 +47,27 @@ else OBJC_ERROR("Object was mutated during enumeration!"); } void -objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t handler) +objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler handler) { enumerationMutationHandler = handler; } void objc_error(const char *title, const char *format, ...) { #if defined(OF_WINDOWS) || defined(OF_AMIGAOS) -# define BUF_LEN 512 - char message[BUF_LEN]; +# define messageLen 512 + char message[messageLen]; int status; va_list args; va_start(args, format); - status = vsnprintf(message, BUF_LEN, format, args); - if (status <= 0 || status >= BUF_LEN) + status = vsnprintf(message, messageLen, format, args); + if (status <= 0 || status >= messageLen) message[0] = '\0'; va_end(args); # undef BUF_LEN #endif DELETED src/runtime/morphos-clib.h Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ /dev/null @@ -1,92 +0,0 @@ -/* The following function is only for the linklib. */ -bool glue_objc_init(unsigned int, struct objc_libc *); -void glue___objc_exec_class(struct objc_module *); -IMP glue_objc_msg_lookup(id, SEL); -IMP glue_objc_msg_lookup_stret(id, SEL); -IMP glue_objc_msg_lookup_super(struct objc_super *, SEL); -IMP glue_objc_msg_lookup_super_stret(struct objc_super *, SEL); -Class glue_objc_lookUpClass(const char *); -Class glue_objc_getClass(const char *); -Class glue_objc_getRequiredClass(const char *); -Class glue_objc_lookup_class(const char *); -Class glue_objc_get_class(const char *); -void glue_objc_exception_throw(id); -int glue_objc_sync_enter(id); -int glue_objc_sync_exit(id); -id glue_objc_getProperty(id, SEL, ptrdiff_t, bool); -void glue_objc_setProperty(id, SEL, ptrdiff_t, id, bool, signed char); -void glue_objc_getPropertyStruct(void *, const void *, ptrdiff_t, bool, bool); -void glue_objc_setPropertyStruct(void *, const void *, ptrdiff_t, bool, bool); -void glue_objc_enumerationMutation(id); -int glue___gnu_objc_personality(int, int, uint64_t, void *, void *); -id glue_objc_retain(id); -id glue_objc_retainBlock(id); -id glue_objc_retainAutorelease(id); -void glue_objc_release(id); -id glue_objc_autorelease(id); -id glue_objc_autoreleaseReturnValue(id); -id glue_objc_retainAutoreleaseReturnValue(id); -id glue_objc_retainAutoreleasedReturnValue(id); -id glue_objc_storeStrong(id *, id); -id glue_objc_storeWeak(id *, id); -id glue_objc_loadWeakRetained(id *); -id glue_objc_initWeak(id *, id); -void glue_objc_destroyWeak(id *); -id glue_objc_loadWeak(id *); -void glue_objc_copyWeak(id *, id *); -void glue_objc_moveWeak(id *, id *); -SEL glue_sel_registerName(const char *); -const char *glue_sel_getName(SEL); -bool glue_sel_isEqual(SEL, SEL); -Class glue_objc_allocateClassPair(Class, const char *, size_t); -void glue_objc_registerClassPair(Class); -unsigned int glue_objc_getClassList(Class *, unsigned int); -Class *glue_objc_copyClassList(unsigned int *); -bool glue_class_isMetaClass(Class); -const char *glue_class_getName(Class); -Class glue_class_getSuperclass(Class); -unsigned long glue_class_getInstanceSize(Class); -bool glue_class_respondsToSelector(Class, SEL); -bool glue_class_conformsToProtocol(Class, Protocol *); -IMP glue_class_getMethodImplementation(Class, SEL); -IMP glue_class_getMethodImplementation_stret(Class, SEL); -Method glue_class_getInstanceMethod(Class, SEL); -bool glue_class_addMethod(Class, SEL, IMP, const char *); -IMP glue_class_replaceMethod(Class, SEL, IMP, const char *); -Class glue_object_getClass(id); -Class glue_object_setClass(id, Class); -const char *glue_object_getClassName(id); -const char *glue_protocol_getName(Protocol *); -bool glue_protocol_isEqual(Protocol *, Protocol *); -bool glue_protocol_conformsToProtocol(Protocol *, Protocol *); -objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t); -void glue_objc_setForwardHandler(IMP, IMP); -void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t); -id glue_objc_constructInstance(Class, void *); -void glue_objc_exit(void); -Ivar *glue_class_copyIvarList(Class, unsigned int *); -const char *glue_ivar_getName(Ivar); -const char *glue_ivar_getTypeEncoding(Ivar); -ptrdiff_t glue_ivar_getOffset(Ivar); -Method *glue_class_copyMethodList(Class, unsigned int *); -SEL glue_method_getName(Method); -const char *glue_method_getTypeEncoding(Method); -objc_property_t *glue_class_copyPropertyList(Class, unsigned int *); -const char *glue_property_getName(objc_property_t); -char *glue_property_copyAttributeValue(objc_property_t, const char *); -void *glue_objc_destructInstance(id); -void *glue_objc_autoreleasePoolPush(void); -void glue_objc_autoreleasePoolPop(void *); -id glue__objc_rootAutorelease(id); -/* The following functions are private! Don't use! */ -struct objc_hashtable *glue_objc_hashtable_new(objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); -void glue_objc_hashtable_set(struct objc_hashtable *, const void *, const void *); -void *glue_objc_hashtable_get(struct objc_hashtable *, const void *); -void glue_objc_hashtable_delete(struct objc_hashtable *, const void *); -void glue_objc_hashtable_free(struct objc_hashtable *); -/* Public functions again */ -void glue_objc_setTaggedPointerSecret(uintptr_t); -int glue_objc_registerTaggedPointerClass(Class); -bool glue_object_isTaggedPointer(id); -uintptr_t glue_object_getTaggedPointerValue(id); -id glue_objc_createTaggedPointer(int, uintptr_t); DELETED src/runtime/morphos.fd Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ /dev/null @@ -1,96 +0,0 @@ -##base _ObjFWRTBase -##bias 30 -##public -* The following function is only for the linklib. -glue_objc_init(version,libc)(sysv,r12base) -glue___objc_exec_class(module)(sysv,r12base) -glue_objc_msg_lookup(object,selector)(sysv,r12base) -glue_objc_msg_lookup_stret(object,selector)(sysv,r12base) -glue_objc_msg_lookup_super(super,selector)(sysv,r12base) -glue_objc_msg_lookup_super_stret(super,selector)(sysv,r12base) -glue_objc_lookUpClass(name)(sysv,r12base) -glue_objc_getClass(name)(sysv,r12base) -glue_objc_getRequiredClass(name)(sysv,r12base) -glue_objc_lookup_class(name)(sysv,r12base) -glue_objc_get_class(name)(sysv,r12base) -glue_objc_exception_throw(object)(sysv,r12base) -glue_objc_sync_enter(object)(sysv,r12base) -glue_objc_sync_exit(object)(sysv,r12base) -glue_objc_getProperty(self,_cmd,offset,atomic)(sysv,r12base) -glue_objc_setProperty(self,_cmd,offset,value,atomic,copy)(sysv,r12base) -glue_objc_getPropertyStruct(dest,src,size,atomic,strong)(sysv,r12base) -glue_objc_setPropertyStruct(dest,src,size,atomic,strong)(sysv,r12base) -glue_objc_enumerationMutation(object)(sysv,r12base) -glue___gnu_objc_personality(version,actions,exClass,ex,ctx)(sysv,r12base) -glue_objc_retain(object)(sysv,r12base) -glue_objc_retainBlock(block)(sysv,r12base) -glue_objc_retainAutorelease(object)(sysv,r12base) -glue_objc_release(object)(sysv,r12base) -glue_objc_autorelease(object)(sysv,r12base) -glue_objc_autoreleaseReturnValue(object)(sysv,r12base) -glue_objc_retainAutoreleaseReturnValue(object)(sysv,r12base) -glue_objc_retainAutoreleasedReturnValue(object)(sysv,r12base) -glue_objc_storeStrong(object,value)(sysv,r12base) -glue_objc_storeWeak(object,value)(sysv,r12base) -glue_objc_loadWeakRetained(object)(sysv,r12base) -glue_objc_initWeak(object,value)(sysv,r12base) -glue_objc_destroyWeak(object)(sysv,r12base) -glue_objc_loadWeak(object)(sysv,r12base) -glue_objc_copyWeak(dest,src)(sysv,r12base) -glue_objc_moveWeak(dest,src)(sysv,r12base) -glue_sel_registerName(name)(sysv,r12base) -glue_sel_getName(selector)(sysv,r12base) -glue_sel_isEqual(selector1,selector2)(sysv,r12base) -glue_objc_allocateClassPair(superclass,name,extraBytes)(sysv,r12base) -glue_objc_registerClassPair(class_)(sysv,r12base) -glue_objc_getClassList(buffer,count)(sysv,r12base) -glue_objc_copyClassList(length)(sysv,r12base) -glue_class_isMetaClass(class_)(sysv,r12base) -glue_class_getName(class_)(sysv,r12base) -glue_class_getSuperclass(class_)(sysv,r12base) -glue_class_getInstanceSize(class_)(sysv,r12base) -glue_class_respondsToSelector(class_,selector)(sysv,r12base) -glue_class_conformsToProtocol(class_,p)(sysv,r12base) -glue_class_getMethodImplementation(class_,selector)(sysv,r12base) -glue_class_getMethodImplementation_stret(class_,selector)(sysv,r12base) -glue_class_getInstanceMethod(class_,selector)(sysv,r12base) -glue_class_addMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) -glue_class_replaceMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) -glue_object_getClass(object)(sysv,r12base) -glue_object_setClass(object,class_)(sysv,r12base) -glue_object_getClassName(object)(sysv,r12base) -glue_protocol_getName(protocol)(sysv,r12base) -glue_protocol_isEqual(protocol1,protocol2)(sysv,r12base) -glue_protocol_conformsToProtocol(protocol1,protocol2)(sysv,r12base) -glue_objc_setUncaughtExceptionHandler(handler)(sysv,r12base) -glue_objc_setForwardHandler(forward,stretForward)(sysv,r12base) -glue_objc_setEnumerationMutationHandler(handler)(sysv,r12base) -glue_objc_constructInstance(class_,bytes)(sysv,r12base) -glue_objc_exit()(sysv,r12base) -glue_class_copyIvarList(class_,outCount)(sysv,r12base) -glue_ivar_getName(ivar)(sysv,r12base) -glue_ivar_getTypeEncoding(ivar)(sysv,r12base) -glue_ivar_getOffset(ivar)(sysv,r12base) -glue_class_copyMethodList(class_,outCount)(sysv,r12base) -glue_method_getName(method)(sysv,r12base) -glue_method_getTypeEncoding(method)(sysv,r12base) -glue_class_copyPropertyList(class_,outCount)(sysv,r12base) -glue_property_getName(property)(sysv,r12base) -glue_property_copyAttributeValue(property,name)(sysv,r12base) -glue_objc_destructInstance(object)(sysv,r12base) -glue_objc_autoreleasePoolPush()(sysv,r12base) -glue_objc_autoreleasePoolPop(pool)(sysv,r12base) -glue__objc_rootAutorelease(object)(sysv,r12base) -* The following functions are private! Don't use! -glue_objc_hashtable_new(hash,equal,size)(sysv,r12base) -glue_objc_hashtable_set(table,key,object)(sysv,r12base) -glue_objc_hashtable_get(table,key)(sysv,r12base) -glue_objc_hashtable_delete(table,key)(sysv,r12base) -glue_objc_hashtable_free(table)(sysv,r12base) -* Public functions again -glue_objc_setTaggedPointerSecret(secret)(sysv,r12base) -glue_objc_registerTaggedPointerClass(class_)(sysv,r12base) -glue_object_isTaggedPointer(object)(sysv,r12base) -glue_object_getTaggedPointerValue(object)(sysv,r12base) -glue_objc_createTaggedPointer(class_,value)(sysv,r12base) -##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -38,11 +38,11 @@ unsigned long version; unsigned long info; long instanceSize; struct objc_ivar_list *_Nullable ivars; struct objc_method_list *_Nullable methodList; - struct objc_dtable *_Nonnull DTable; + struct objc_dtable *_Nonnull dTable; Class _Nullable *_Nullable subclassList; void *_Nullable siblingClass; struct objc_protocol_list *_Nullable protocols; void *_Nullable GCObjectType; unsigned long ABIVersion; @@ -199,11 +199,11 @@ struct objc_sparsearray { struct objc_sparsearray_data { void *_Nullable next[256]; } *_Nonnull data; - uint8_t indexSize; + uint8_t levels; }; struct objc_dtable { struct objc_dtable_level2 { #ifdef OF_SELUID24 @@ -279,35 +279,35 @@ # define __gnu_objc_personality(version, actions, exClass, ex, ctx) \ __gnu_objc_personality_v0(version, actions, *exClass, ex, ctx) # endif #endif -extern void objc_register_all_categories(struct objc_symtab *_Nonnull); +extern void objc_registerAllCategories(struct objc_symtab *_Nonnull); extern struct objc_category *_Nullable *_Nullable - objc_categories_for_class(Class _Nonnull); -extern void objc_unregister_all_categories(void); -extern void objc_initialize_class(Class _Nonnull); -extern void objc_update_dtable(Class _Nonnull); -extern void objc_register_all_classes(struct objc_symtab *_Nonnull); -extern Class _Nullable objc_classname_to_class(const char *_Nonnull, bool); -extern void objc_unregister_class(Class _Nonnull); -extern void objc_unregister_all_classes(void); -extern uint32_t objc_hash_string(const void *_Nonnull); -extern bool objc_equal_string(const void *_Nonnull, const void *_Nonnull); + objc_categoriesForClass(Class _Nonnull); +extern void objc_unregisterAllCategories(void); +extern void objc_initializeClass(Class _Nonnull); +extern void objc_updateDTable(Class _Nonnull); +extern void objc_registerAllClasses(struct objc_symtab *_Nonnull); +extern Class _Nullable objc_classnameToClass(const char *_Nonnull, bool); +extern void objc_unregisterClass(Class _Nonnull); +extern void objc_unregisterAllClasses(void); +extern uint32_t objc_string_hash(const void *_Nonnull); +extern bool objc_string_equal(const void *_Nonnull, const void *_Nonnull); extern struct objc_hashtable *_Nonnull objc_hashtable_new( objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); -extern struct objc_hashtable_bucket objc_deleted_bucket; +extern struct objc_hashtable_bucket objc_deletedBucket; extern void objc_hashtable_set(struct objc_hashtable *_Nonnull, const void *_Nonnull, const void *_Nonnull); extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_delete(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_free(struct objc_hashtable *_Nonnull); -extern void objc_register_selector(struct objc_selector *_Nonnull); -extern void objc_register_all_selectors(struct objc_symtab *_Nonnull); -extern void objc_unregister_all_selectors(void); +extern void objc_registerSelector(struct objc_selector *_Nonnull); +extern void objc_registerAllSelectors(struct objc_symtab *_Nonnull); +extern void objc_unregisterAllSelectors(void); extern struct objc_sparsearray *_Nonnull objc_sparsearray_new(uint8_t); extern void *_Nullable objc_sparsearray_get(struct objc_sparsearray *_Nonnull, uintptr_t); extern void objc_sparsearray_set(struct objc_sparsearray *_Nonnull, uintptr_t, void *_Nullable); @@ -317,22 +317,22 @@ struct objc_dtable *_Nonnull); extern void objc_dtable_set(struct objc_dtable *_Nonnull, uint32_t, IMP _Nullable); extern void objc_dtable_free(struct objc_dtable *_Nonnull); extern void objc_dtable_cleanup(void); -extern void objc_init_static_instances(struct objc_symtab *_Nonnull); -extern void objc_forget_pending_static_instances(void); -extern void objc_zero_weak_references(id _Nonnull); +extern void objc_initStaticInstances(struct objc_symtab *_Nonnull); +extern void objc_forgetPendingStaticInstances(void); +extern void objc_zeroWeakReferences(id _Nonnull); extern Class _Nullable object_getTaggedPointerClass(id _Nonnull); #ifdef OF_HAVE_THREADS -extern void objc_global_mutex_lock(void); -extern void objc_global_mutex_unlock(void); -extern void objc_global_mutex_free(void); +extern void objc_globalMutex_lock(void); +extern void objc_globalMutex_unlock(void); +extern void objc_globalMutex_free(void); #else -# define objc_global_mutex_lock() -# define objc_global_mutex_unlock() -# define objc_global_mutex_free() +# define objc_globalMutex_lock() +# define objc_globalMutex_unlock() +# define objc_globalMutex_free() #endif extern char *_Nullable objc_strdup(const char *_Nonnull string); static inline IMP _Nullable objc_dtable_get(const struct objc_dtable *_Nonnull dtable, uint32_t idx) @@ -356,11 +356,12 @@ #define OBJC_ERROR(...) \ objc_error("ObjFWRT @ " __FILE__ ":" OF_STRINGIFY(__LINE__), \ __VA_ARGS__) #if defined(OF_ELF) -# if defined(OF_X86_64) || defined(OF_X86) || defined(OF_POWERPC) || \ +# if defined(OF_X86_64) || defined(OF_X86) || \ + defined(OF_POWERPC64) || defined(OF_POWERPC) || \ defined(OF_ARM64) || defined(OF_ARM) || \ defined(OF_MIPS64_N64) || defined(OF_MIPS) || \ defined(OF_SPARC64) || defined(OF_SPARC) # define OF_ASM_LOOKUP # endif Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,37 +20,44 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS # import "OFPlainMutex.h" -# define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ -# define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1)) -static OFSpinlock spinlocks[NUM_SPINLOCKS]; +# define numSpinlocks 8 /* needs to be a power of 2 */ +static OFSpinlock spinlocks[numSpinlocks]; + +static OF_INLINE size_t +spinlockSlot(const void *ptr) +{ + return ((size_t)((uintptr_t)ptr >> 4) & (numSpinlocks - 1)); +} #endif #ifdef OF_HAVE_THREADS OF_CONSTRUCTOR() { - for (size_t i = 0; i < NUM_SPINLOCKS; i++) + for (size_t i = 0; i < numSpinlocks; i++) if (OFSpinlockNew(&spinlocks[i]) != 0) - OBJC_ERROR("Failed to initialize spinlocks!"); + OBJC_ERROR("Failed to create spinlocks!"); } #endif id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, bool atomic) { if (atomic) { id *ptr = (id *)(void *)((char *)self + offset); #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(ptr); + size_t slot = spinlockSlot(ptr); - OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); @try { return [[*ptr retain] autorelease]; } @finally { - OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); } #else return [[*ptr retain] autorelease]; #endif } @@ -63,13 +70,14 @@ signed char copy) { if (atomic) { id *ptr = (id *)(void *)((char *)self + offset); #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(ptr); + size_t slot = spinlockSlot(ptr); - OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); @try { #endif id old = *ptr; switch (copy) { @@ -84,11 +92,12 @@ } [old release]; #ifdef OF_HAVE_THREADS } @finally { - OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); } #endif return; } @@ -115,17 +124,19 @@ objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, bool strong) { if (atomic) { #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(src); + size_t slot = spinlockSlot(src); - OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif memcpy(dest, src, size); #ifdef OF_HAVE_THREADS - OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif return; } @@ -136,17 +147,19 @@ objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, bool strong) { if (atomic) { #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(src); + size_t slot = spinlockSlot(src); - OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif memcpy(dest, src, size); #ifdef OF_HAVE_THREADS - OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif return; } @@ -165,11 +178,11 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = 0; if (class->info & OBJC_CLASS_INFO_NEW_ABI) for (iter = class->propertyList; iter != NULL; iter = iter->next) @@ -177,11 +190,11 @@ if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } properties = malloc((count + 1) * sizeof(objc_property_t)); if (properties == NULL) @@ -189,17 +202,20 @@ i = 0; for (iter = class->propertyList; iter != NULL; iter = iter->next) for (unsigned int j = 0; j < iter->count; j++) properties[i++] = &iter->properties[j]; - OFEnsure(i == count); + + if (i != count) + OBJC_ERROR("Fatal internal inconsistency!"); + properties[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return properties; } const char * @@ -251,9 +267,9 @@ #undef BOOL_CASE } if (nullIsError && ret == NULL) OBJC_ERROR("Not enough memory to copy property attribute " - "value"); + "value!"); return ret; } Index: src/runtime/protocol.m ================================================================== --- src/runtime/protocol.m +++ src/runtime/protocol.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -65,14 +65,14 @@ for (long i = 0; i < protocolList->count; i++) if (protocol_conformsToProtocol(protocolList->list[i], protocol)) return true; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - if ((categories = objc_categories_for_class(class)) == NULL) { - objc_global_mutex_unlock(); + if ((categories = objc_categoriesForClass(class)) == NULL) { + objc_globalMutex_unlock(); return false; } for (long i = 0; categories[i] != NULL; i++) { for (struct objc_protocol_list *protocolList = @@ -79,16 +79,16 @@ categories[i]->protocols; protocolList != NULL; protocolList = protocolList->next) { for (long j = 0; j < protocolList->count; j++) { if (protocol_conformsToProtocol( protocolList->list[j], protocol)) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return true; } } } } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return false; } Index: src/runtime/selector.m ================================================================== --- src/runtime/selector.m +++ src/runtime/selector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -23,43 +23,43 @@ #import "private.h" #import "macros.h" #ifdef OF_SELUID24 -# define SEL_MAX 0xFFFFFF -# define SEL_SIZE 3 +static const uint32_t maxSel = 0xFFFFFF; +static const uint8_t selLevels = 3; #else -# define SEL_MAX 0xFFFF -# define SEL_SIZE 2 +static const uint32_t maxSel = 0xFFFF; +static const uint8_t selLevels = 2; #endif static struct objc_hashtable *selectors = NULL; static uint32_t selectorsCount = 0; static struct objc_sparsearray *selectorNames = NULL; static void **freeList = NULL; static size_t freeListCount = 0; void -objc_register_selector(struct objc_selector *selector) +objc_registerSelector(struct objc_selector *selector) { SEL existingSelector; const char *name; - if (selectorsCount > SEL_MAX) + if (selectorsCount > maxSel) OBJC_ERROR("Out of selector slots!"); if (selectors == NULL) selectors = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); else if ((existingSelector = objc_hashtable_get(selectors, (const char *)selector->UID)) != NULL) { selector->UID = existingSelector->UID; return; } if (selectorNames == NULL) - selectorNames = objc_sparsearray_new(SEL_SIZE); + selectorNames = objc_sparsearray_new(selLevels); name = (const char *)selector->UID; selector->UID = selectorsCount++; objc_hashtable_set(selectors, name, selector); @@ -70,22 +70,20 @@ SEL sel_registerName(const char *name) { struct objc_selector *selector; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (selectors != NULL && (selector = objc_hashtable_get(selectors, name)) != NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return (SEL)selector; } - if ((selector = malloc(sizeof(*selector))) == NULL) - OBJC_ERROR("Not enough memory to allocate selector!"); - - if ((selector->UID = (uintptr_t)objc_strdup(name)) == 0) + if ((selector = malloc(sizeof(*selector))) == NULL || + (selector->UID = (uintptr_t)objc_strdup(name)) == 0) OBJC_ERROR("Not enough memory to allocate selector!"); selector->typeEncoding = NULL; if ((freeList = realloc(freeList, @@ -93,36 +91,36 @@ OBJC_ERROR("Not enough memory to allocate selector!"); freeList[freeListCount++] = selector; freeList[freeListCount++] = (char *)selector->UID; - objc_register_selector(selector); + objc_registerSelector(selector); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return (SEL)selector; } void -objc_register_all_selectors(struct objc_symtab *symtab) +objc_registerAllSelectors(struct objc_symtab *symtab) { struct objc_selector *selector; if (symtab->selectorRefs == NULL) return; for (selector = symtab->selectorRefs; selector->UID != 0; selector++) - objc_register_selector(selector); + objc_registerSelector(selector); } const char * sel_getName(SEL selector) { const char *ret; - objc_global_mutex_lock(); + objc_globalMutex_lock(); ret = objc_sparsearray_get(selectorNames, (uint32_t)selector->UID); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } bool @@ -130,11 +128,11 @@ { return (selector1->UID == selector2->UID); } void -objc_unregister_all_selectors(void) +objc_unregisterAllSelectors(void) { objc_hashtable_free(selectors); objc_sparsearray_free(selectorNames); if (freeList != NULL) { Index: src/runtime/sparsearray.m ================================================================== --- src/runtime/sparsearray.m +++ src/runtime/sparsearray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -20,33 +20,31 @@ #import "ObjFWRT.h" #import "private.h" struct objc_sparsearray * -objc_sparsearray_new(uint8_t indexSize) +objc_sparsearray_new(uint8_t levels) { struct objc_sparsearray *sparsearray; - if ((sparsearray = calloc(1, sizeof(*sparsearray))) == NULL) + if ((sparsearray = calloc(1, sizeof(*sparsearray))) == NULL || + (sparsearray->data = calloc(1, sizeof(*sparsearray->data))) == NULL) OBJC_ERROR("Failed to allocate memory for sparse array!"); - if ((sparsearray->data = calloc(1, sizeof(*sparsearray->data))) == NULL) - OBJC_ERROR("Failed to allocate memory for sparse array!"); - - sparsearray->indexSize = indexSize; + sparsearray->levels = levels; return sparsearray; } void * objc_sparsearray_get(struct objc_sparsearray *sparsearray, uintptr_t idx) { struct objc_sparsearray_data *iter = sparsearray->data; - for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) { + for (uint8_t i = 0; i < sparsearray->levels - 1; i++) { uintptr_t j = - (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF; + (idx >> ((sparsearray->levels - i - 1) * 8)) & 0xFF; if ((iter = iter->next[j]) == NULL) return NULL; } @@ -57,13 +55,13 @@ objc_sparsearray_set(struct objc_sparsearray *sparsearray, uintptr_t idx, void *value) { struct objc_sparsearray_data *iter = sparsearray->data; - for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) { + for (uint8_t i = 0; i < sparsearray->levels - 1; i++) { uintptr_t j = - (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF; + (idx >> ((sparsearray->levels - i - 1) * 8)) & 0xFF; if (iter->next[j] == NULL) if ((iter->next[j] = calloc(1, sizeof(struct objc_sparsearray_data))) == NULL) OBJC_ERROR("Failed to allocate memory for " @@ -88,8 +86,8 @@ } void objc_sparsearray_free(struct objc_sparsearray *sparsearray) { - freeSparsearrayData(sparsearray->data, sparsearray->indexSize); + freeSparsearrayData(sparsearray->data, sparsearray->levels); free(sparsearray); } Index: src/runtime/static-instances.m ================================================================== --- src/runtime/static-instances.m +++ src/runtime/static-instances.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -23,11 +23,11 @@ static struct objc_static_instances **staticInstancesList = NULL; static size_t staticInstancesCount = 0; void -objc_init_static_instances(struct objc_symtab *symtab) +objc_initStaticInstances(struct objc_symtab *symtab) { struct objc_static_instances **staticInstances; /* Check if the class for a static instance became available */ for (size_t i = 0; i < staticInstancesCount; i++) { @@ -93,11 +93,11 @@ } } } void -objc_forget_pending_static_instances() +objc_forgetPendingStaticInstances() { free(staticInstancesList); staticInstancesList = NULL; staticInstancesCount = 0; } Index: src/runtime/synchronized.m ================================================================== --- src/runtime/synchronized.m +++ src/runtime/synchronized.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -22,15 +22,15 @@ #import "private.h" #ifdef OF_HAVE_THREADS # import "OFPlainMutex.h" -static struct lock { +static struct Lock { id object; int count; OFPlainRecursiveMutex rmutex; - struct lock *next; + struct Lock *next; } *locks = NULL; static OFPlainMutex mutex; OF_CONSTRUCTOR() @@ -45,11 +45,11 @@ { if (object == nil) return 0; #ifdef OF_HAVE_THREADS - struct lock *lock; + struct Lock *lock; if (OFPlainMutexLock(&mutex) != 0) OBJC_ERROR("Failed to lock mutex!"); /* Look if we already have a lock */ @@ -96,11 +96,11 @@ { if (object == nil) return 0; #ifdef OF_HAVE_THREADS - struct lock *lock, *last = NULL; + struct Lock *lock, *last = NULL; if (OFPlainMutexLock(&mutex) != 0) OBJC_ERROR("Failed to lock mutex!"); for (lock = locks; lock != NULL; lock = lock->next) { @@ -128,10 +128,10 @@ OBJC_ERROR("Failed to unlock mutex!"); return 0; } - OBJC_ERROR("objc_sync_exit() was called for an object not locked!"); + OBJC_ERROR("objc_sync_exit() was called for an unlocked object!"); #else return 0; #endif } Index: src/runtime/tagged-pointer.m ================================================================== --- src/runtime/tagged-pointer.m +++ src/runtime/tagged-pointer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,39 +15,39 @@ #import "ObjFWRT.h" #import "private.h" -#define TAGGED_POINTER_BITS 4 -#define NUM_TAGGED_POINTER_CLASSES (1 << (TAGGED_POINTER_BITS - 1)) +#define numTaggedPointerBits 4 +#define maxNumTaggedPointerClasses (1 << (numTaggedPointerBits - 1)) -Class objc_tagged_pointer_classes[NUM_TAGGED_POINTER_CLASSES]; +Class objc_taggedPointerClasses[maxNumTaggedPointerClasses]; static int taggedPointerClassesCount; -uintptr_t objc_tagged_pointer_secret; +uintptr_t objc_taggedPointerSecret; void objc_setTaggedPointerSecret(uintptr_t secret) { - objc_tagged_pointer_secret = secret & ~(uintptr_t)1; + objc_taggedPointerSecret = secret & ~(uintptr_t)1; } int objc_registerTaggedPointerClass(Class class) { int i; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - if (taggedPointerClassesCount == NUM_TAGGED_POINTER_CLASSES) { - objc_global_mutex_unlock(); + if (taggedPointerClassesCount == maxNumTaggedPointerClasses) { + objc_globalMutex_unlock(); return -1; } i = taggedPointerClassesCount++; - objc_tagged_pointer_classes[i] = class; + objc_taggedPointerClasses[i] = class; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return i; } bool @@ -59,42 +59,42 @@ } Class object_getTaggedPointerClass(id object) { - uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret; + uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret; - pointer &= (1 << TAGGED_POINTER_BITS) - 1; + pointer &= (1 << numTaggedPointerBits) - 1; pointer >>= 1; - if (pointer >= NUM_TAGGED_POINTER_CLASSES) + if (pointer >= maxNumTaggedPointerClasses) return Nil; - return objc_tagged_pointer_classes[pointer]; + return objc_taggedPointerClasses[pointer]; } uintptr_t object_getTaggedPointerValue(id object) { - uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret; + uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret; - pointer >>= TAGGED_POINTER_BITS; + pointer >>= numTaggedPointerBits; return pointer; } id objc_createTaggedPointer(int class, uintptr_t value) { uintptr_t pointer; - if (class < 0 || class >= NUM_TAGGED_POINTER_CLASSES) + if (class < 0 || class >= maxNumTaggedPointerClasses) return nil; - if (value > (UINTPTR_MAX >> TAGGED_POINTER_BITS)) + if (value > (UINTPTR_MAX >> numTaggedPointerBits)) return nil; pointer = (class << 1) | 1; - pointer |= (value << TAGGED_POINTER_BITS); + pointer |= (value << numTaggedPointerBits); - return (id)(pointer ^ objc_tagged_pointer_secret); + return (id)(pointer ^ objc_taggedPointerSecret); } Index: src/runtime/threading.m ================================================================== --- src/runtime/threading.m +++ src/runtime/threading.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -32,20 +32,20 @@ if (OFPlainRecursiveMutexNew(&globalMutex) != 0) OBJC_ERROR("Failed to create global mutex!"); } void -objc_global_mutex_lock(void) +objc_globalMutex_lock(void) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, init); if (OFPlainRecursiveMutexLock(&globalMutex) != 0) OBJC_ERROR("Failed to lock global mutex!"); } void -objc_global_mutex_unlock(void) +objc_globalMutex_unlock(void) { if (OFPlainRecursiveMutexUnlock(&globalMutex) != 0) OBJC_ERROR("Failed to unlock global mutex!"); } ADDED src/tls/Info.plist.in Index: src/tls/Info.plist.in ================================================================== --- /dev/null +++ src/tls/Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ObjFWTLS + CFBundleName + ObjFWTLS + CFBundleIdentifier + im.nil.objfw.tls + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleShortVersionString + @BUNDLE_SHORT_VERSION@ + MinimumOSVersion + 9.0 + + ADDED src/tls/Makefile Index: src/tls/Makefile ================================================================== --- /dev/null +++ src/tls/Makefile @@ -0,0 +1,23 @@ +include ../../extra.mk + +DISTCLEAN = Info.plist + +SHARED_LIB = ${OBJFWTLS_SHARED_LIB} +STATIC_LIB = ${OBJFWTLS_STATIC_LIB} +FRAMEWORK = ${OBJFWTLS_FRAMEWORK} +LIB_MAJOR = ${OBJFW_LIB_MAJOR} +LIB_MINOR = ${OBJFW_LIB_MINOR} + +INCLUDES := ObjFWTLS.h +SRCS = ${OF_GNUTLS_TLS_STREAM_M} \ + ${OF_OPENSSL_TLS_STREAM_M} \ + ${OF_SECURE_TRANSPORT_TLS_STREAM_M} + +includesubdir = ObjFWTLS + +include ../../buildsys.mk + +CPPFLAGS += -I. -I.. -I../.. -I../exceptions -I../runtime ${TLS_CPPFLAGS} +LD = ${OBJC} +FRAMEWORK_LIBS := ${TLS_LIBS} -F.. -framework ObjFW ${LIBS} +LIBS := ${TLS_LIBS} -L.. -lobjfw -L../runtime ${RUNTIME_LIBS} ${LIBS} ADDED src/tls/OFGnuTLSTLSStream.h Index: src/tls/OFGnuTLSTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFGnuTLSTLSStream.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSStream.h" + +#include + +OF_ASSUME_NONNULL_BEGIN + +@interface OFGnuTLSTLSStream: OFTLSStream +{ + bool _initialized, _handshakeDone; + gnutls_session_t _session; + OFString *_host; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFGnuTLSTLSStream.m Index: src/tls/OFGnuTLSTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFGnuTLSTLSStream.m @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFGnuTLSTLSStream.h" +#import "OFData.h" + +#import "OFAlreadyConnectedException.h" +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +int _ObjFWTLS_reference; +static gnutls_certificate_credentials_t systemTrustCreds; + +#ifndef GNUTLS_SAFE_PADDING_CHECK +/* Some older versions don't have it. */ +# define GNUTLS_SAFE_PADDING_CHECK 0 +#endif + +@implementation OFGnuTLSTLSStream +static ssize_t +readFunc(gnutls_transport_ptr_t transport, void *buffer, size_t length) +{ + OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport; + + @try { + length = [stream.underlyingStream readIntoBuffer: buffer + length: length]; + } @catch (OFReadFailedException *e) { + gnutls_transport_set_errno(stream->_session, e.errNo); + return -1; + } + + if (length == 0 && !stream.underlyingStream.atEndOfStream) { + gnutls_transport_set_errno(stream->_session, EAGAIN); + return -1; + } + + return length; +} + +static ssize_t +writeFunc(gnutls_transport_ptr_t transport, const void *buffer, size_t length) +{ + OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport; + + @try { + [stream.underlyingStream writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + gnutls_transport_set_errno(stream->_session, e.errNo); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + return -1; + } + + return length; +} + ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + ++ (void)initialize +{ + if (self != [OFGnuTLSTLSStream class]) + return; + + if (gnutls_certificate_allocate_credentials(&systemTrustCreds) != + GNUTLS_E_SUCCESS || + gnutls_certificate_set_x509_system_trust(systemTrustCreds) < 0) + @throw [OFInitializationFailedException exception]; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_initialized) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (!_initialized) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handshakeDone) + gnutls_bye(_session, GNUTLS_SHUT_WR); + + gnutls_deinit(_session); + _initialized = false; + + [_host release]; + _host = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + ssize_t ret; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = gnutls_record_recv(_session, buffer, length)) < 0) { + /* + * The underlying stream might have had data ready, but not + * enough for GnuTLS to return decrypted data. This means the + * caller might have observed the TLS stream for reading, got a + * ready signal and read - and expects the read to succeed, not + * to fail with EWOULDBLOCK/EAGAIN, as it was signaled ready. + * Therefore, return 0, as we could read 0 decrypted bytes, but + * cleared the ready signal of the underlying stream. + */ + if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + } + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + ssize_t ret; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = gnutls_record_send(_session, buffer, length)) < 0) { + if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: ret + errNo: 0]; + } + + return ret; +} + +- (bool)hasDataInReadBuffer +{ + if (gnutls_record_check_pending(_session) > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + int status; + + if (_initialized) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if (gnutls_init(&_session, GNUTLS_CLIENT | GNUTLS_NONBLOCK | + GNUTLS_SAFE_PADDING_CHECK) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _initialized = true; + + gnutls_transport_set_ptr(_session, self); + gnutls_transport_set_pull_function(_session, readFunc); + gnutls_transport_set_push_function(_session, writeFunc); + + if (gnutls_set_default_priority(_session) != GNUTLS_E_SUCCESS || + gnutls_credentials_set(_session, GNUTLS_CRD_CERTIFICATE, + systemTrustCreds) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _host = [host copy]; + + if (gnutls_server_name_set(_session, GNUTLS_NAME_DNS, + _host.UTF8String, _host.UTF8StringLength) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (_verifiesCertificates) + gnutls_session_set_verify_cert(_session, _host.UTF8String, 0); + + status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) + [_underlyingStream + asyncWriteData: [OFData dataWithItems: "" count: 0] + runLoopMode: runLoopMode]; + else + [_underlyingStream asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + + [_delegate retain]; + return; + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: OFTLSStreamErrorCodeUnknown]; + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + int status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || + status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) { + OFData *data = [OFData dataWithItems: "" + count: 0]; + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream asyncWriteData: data + runLoopMode: runLoopMode]; + return false; + } else + return true; + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} + +- (OFData *)stream: (OFStream *)stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception +{ + if (exception == nil) { + int status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || + status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) + return data; + else { + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream + asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + return nil; + } + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return nil; +} +@end ADDED src/tls/OFOpenSSLTLSStream.h Index: src/tls/OFOpenSSLTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFOpenSSLTLSStream.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSStream.h" + +#include +#include + +OF_ASSUME_NONNULL_BEGIN + +#define OFOpenSSLTLSStreamBufferSize 512 + +@interface OFOpenSSLTLSStream: OFTLSStream +{ + bool _handshakeDone; + SSL *_SSL; + BIO *_readBIO, *_writeBIO; + OFString *_host; + char _buffer[OFOpenSSLTLSStreamBufferSize]; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFOpenSSLTLSStream.m Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFOpenSSLTLSStream.m @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFOpenSSLTLSStream.h" +#import "OFData.h" + +#import "OFAlreadyConnectedException.h" +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +#define bufferSize OFOpenSSLTLSStreamBufferSize + +int _ObjFWTLS_reference; +static SSL_CTX *clientContext; + +@implementation OFOpenSSLTLSStream ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + ++ (void)initialize +{ + if (self != [OFOpenSSLTLSStream class]) + return; + + SSL_load_error_strings(); + SSL_library_init(); + + if ((clientContext = SSL_CTX_new(TLS_client_method())) == NULL || + SSL_CTX_set_default_verify_paths(clientContext) != 1) + @throw [OFInitializationFailedException + exceptionWithClass: self]; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + /* + * Buffer writes so that nothing gets lost if we write more + * than the underlying stream can write. + */ + _underlyingStream.buffersWrites = true; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_SSL != NULL) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (_SSL == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handshakeDone) + SSL_shutdown(_SSL); + + SSL_free(_SSL); + _SSL = NULL; + + [_host release]; + _host = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + int ret; + size_t bytesRead; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (BIO_ctrl_pending(_readBIO) < 1) { + @try { + size_t tmp = [_underlyingStream + readIntoBuffer: _buffer + length: bufferSize]; + + OFEnsure(tmp <= INT_MAX); + /* Writing to a memory BIO must never fail. */ + OFEnsure(BIO_write(_readBIO, _buffer, (int)tmp) == + (int)tmp); + } @catch (OFReadFailedException *e) { + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + @throw e; + } + } + + ret = SSL_read_ex(_SSL, buffer, length, &bytesRead); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (ret != 1) { + /* + * The underlying stream might have had data ready, but not + * enough for OpenSSL to return decrypted data. This means the + * caller might have observed the TLS stream for reading, got a + * ready signal and read - and expects the read to succeed, not + * to fail with EWOULDBLOCK, as it was signaled ready. + * Therefore, return 0, as we could read 0 decrypted bytes, but + * cleared the ready signal of the underlying stream. + */ + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_READ) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + } + + return bytesRead; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + int ret; + size_t bytesWritten; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = SSL_write_ex(_SSL, buffer, length, &bytesWritten)) != 1) { + /* FIXME: Translate error to errNo */ + int errNo = 0; + + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_WRITE) + return bytesWritten; + + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: errNo]; + } + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + return bytesWritten; +} + +- (bool)hasDataInReadBuffer +{ + if (SSL_pending(_SSL) > 0 || BIO_ctrl_pending(_readBIO) > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + int status; + + if (_SSL != NULL) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if ((_readBIO = BIO_new(BIO_s_mem())) == NULL) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if ((_writeBIO = BIO_new(BIO_s_mem())) == NULL) { + BIO_free(_readBIO); + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + BIO_set_mem_eof_return(_readBIO, -1); + BIO_set_mem_eof_return(_writeBIO, -1); + + if ((_SSL = SSL_new(clientContext)) == NULL) { + BIO_free(_readBIO); + BIO_free(_writeBIO); + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + SSL_set_bio(_SSL, _readBIO, _writeBIO); + SSL_set_connect_state(_SSL); + + _host = [host copy]; + + if (SSL_set_tlsext_host_name(_SSL, _host.UTF8String) != 1) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (_verifiesCertificates) { + SSL_set_verify(_SSL, SSL_VERIFY_PEER, NULL); + + if (SSL_set1_host(_SSL, _host.UTF8String) != 1) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + [_underlyingStream asyncReadIntoBuffer: _buffer + length: bufferSize + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + case SSL_ERROR_WANT_WRITE: + [_underlyingStream + asyncWriteData: [OFData dataWithItems: "" count: 0] + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + default: + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: OFTLSStreamErrorCodeUnknown]; + break; + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + static const OFTLSStreamErrorCode unknownErrorCode = + OFTLSStreamErrorCodeUnknown; + int status; + OFData *data; + + OFEnsure(length <= INT_MAX); + OFEnsure(BIO_write(_readBIO, buffer, (int)length) == + (int)length); + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + return true; + case SSL_ERROR_WANT_WRITE: + data = [OFData dataWithItems: "" count: 0]; + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream asyncWriteData: data + runLoopMode: runLoopMode]; + return false; + default: + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: unknownErrorCode]; + break; + } + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} + +- (OFData *)stream: (OFStream *)stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception +{ + if (exception == nil) { + static const OFTLSStreamErrorCode unknownErrorCode = + OFTLSStreamErrorCodeUnknown; + int status; + OFRunLoopMode runLoopMode; + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream + asyncReadIntoBuffer: _buffer + length: bufferSize + runLoopMode: runLoopMode]; + return nil; + case SSL_ERROR_WANT_WRITE: + return data; + default: + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: unknownErrorCode]; + break; + } + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return nil; +} +@end ADDED src/tls/OFSecureTransportTLSStream.h Index: src/tls/OFSecureTransportTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFSecureTransportTLSStream.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2022 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 "OFTLSStream.h" + +#include + +OF_ASSUME_NONNULL_BEGIN + +@interface OFSecureTransportTLSStream: OFTLSStream +{ + SSLContextRef _context; + OFString *_host; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFSecureTransportTLSStream.m Index: src/tls/OFSecureTransportTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFSecureTransportTLSStream.m @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "OFSecureTransportTLSStream.h" + +#import "OFAlreadyConnectedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +int _ObjFWTLS_reference; + +static OSStatus +readFunc(SSLConnectionRef connection, void *data, size_t *dataLength) +{ + bool incomplete; + size_t length; + + @try { + length = [((OFTLSStream *)connection).underlyingStream + readIntoBuffer: data + length: *dataLength]; + } @catch (OFReadFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) { + *dataLength = 0; + return errSSLWouldBlock; + } + + @throw e; + } + + incomplete = (length < *dataLength); + *dataLength = length; + + return (incomplete ? errSSLWouldBlock : noErr); +} + +static OSStatus +writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength) +{ + @try { + [((OFTLSStream *)connection).underlyingStream + writeBuffer: data + length: *dataLength]; + } @catch (OFWriteFailedException *e) { + *dataLength = e.bytesWritten; + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return errSSLWouldBlock; + + @throw e; + } + + return noErr; +} + +/* + * Apple deprecated Secure Transport without providing a replacement that can + * work with any socket. On top of that, their replacement, Network.framework, + * doesn't support STARTTLS at all. + */ +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +@implementation OFSecureTransportTLSStream ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_context != NULL) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + [_host release]; + _host = nil; + + SSLClose(_context); +#ifdef HAVE_SSLCREATECONTEXT + CFRelease(_context); +#else + SSLDisposeContext(_context); +#endif + _context = NULL; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + OSStatus status; + size_t ret; + + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + status = SSLRead(_context, buffer, length, &ret); + if (status != noErr && status != errSSLWouldBlock) + /* FIXME: Translate status to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + OSStatus status; + size_t bytesWritten = 0; + + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + status = SSLWrite(_context, buffer, length, &bytesWritten); + if (status != noErr && status != errSSLWouldBlock) + /* FIXME: Translate status to errNo */ + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: 0]; + + return bytesWritten; +} + +- (bool)hasDataInReadBuffer +{ + size_t bufferSize; + + if (SSLGetBufferedReadSize(_context, &bufferSize) == noErr && + bufferSize > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + OSStatus status; + + if (_context != NULL) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + +#ifdef HAVE_SSLCREATECONTEXT + if ((_context = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, + kSSLStreamType)) == NULL) +#else + if (SSLNewContext(false, &_context) != noErr) +#endif + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (SSLSetIOFuncs(_context, readFunc, writeFunc) != noErr || + SSLSetConnection(_context, self) != noErr) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _host = [host copy]; + + if (_verifiesCertificates) + if (SSLSetPeerDomainName(_context, + _host.UTF8String, _host.UTF8StringLength) != noErr) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: initFailedErrorCode]; + + status = SSLHandshake(_context); + + if (status == errSSLWouldBlock) { + /* + * Theoretically it is possible we block because Secure + * Transport cannot write without blocking. But unfortunately, + * Secure Transport does not tell us whether it's blocked on + * reading or writing. Waiting for the stream to be either + * readable or writable doesn't work either, as the stream is + * almost always at least ready for one of the two. + */ + [_underlyingStream asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + } + + if (status != noErr) + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + OSStatus status = SSLHandshake(_context); + + if (status == errSSLWouldBlock) + return true; + + if (status != noErr) + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} +@end ADDED src/tls/ObjFWTLS.h Index: src/tls/ObjFWTLS.h ================================================================== --- /dev/null +++ src/tls/ObjFWTLS.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2022 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 "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern int _ObjFWTLS_reference; +#ifdef __cplusplus +} +#endif Index: src/unicode.h ================================================================== --- src/unicode.h +++ src/unicode.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/unicode.m ================================================================== --- src/unicode.m +++ src/unicode.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: src/unistd_wrapper.h ================================================================== --- src/unistd_wrapper.h +++ src/unistd_wrapper.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: tests/ForwardingTests.m ================================================================== --- tests/ForwardingTests.m +++ tests/ForwardingTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,22 +17,22 @@ #include #import "TestsAppDelegate.h" -#define FMT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g" +#define FORMAT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g" #define ARGS @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", \ 1.5, 2.25, 3.125, 4.0625, 5.03125, 6.5, 7.25, 8.0, 9.0 #define RESULT @"a b c d e f g h i 1.5 2.25 3.125 4.0625 5.03125 6.5 7.25 8 9" -static OFString *module = @"Forwarding"; -static size_t forwardings = 0; +static OFString *const module = @"Forwarding"; +static size_t forwardingsCount = 0; static bool success = false; static id target = nil; -struct stret_test { - char s[1024]; +struct StretTest { + char buffer[1024]; }; @interface ForwardingTest: OFObject @end @@ -41,17 +41,17 @@ - (void)test; - (uint32_t)forwardingTargetTest: (intptr_t)a0 : (intptr_t)a1 : (double)a2 : (double)a3; -- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)fmt, ...; +- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ...; - (long double)forwardingTargetFPRetTest; -- (struct stret_test)forwardingTargetStRetTest; +- (struct StretTest)forwardingTargetStRetTest; - (void)forwardingTargetNilTest; - (void)forwardingTargetSelfTest; -- (struct stret_test)forwardingTargetNilStRetTest; -- (struct stret_test)forwardingTargetSelfStRetTest; +- (struct StretTest)forwardingTargetNilStRetTest; +- (struct StretTest)forwardingTargetSelfStRetTest; @end @interface ForwardingTarget: OFObject @end @@ -62,11 +62,11 @@ } @implementation ForwardingTest + (bool)resolveClassMethod: (SEL)selector { - forwardings++; + forwardingsCount++; if (sel_isEqual(selector, @selector(test))) { class_replaceMethod(object_getClass(self), @selector(test), (IMP)test, "v#:"); return YES; @@ -75,11 +75,11 @@ return NO; } + (bool)resolveInstanceMethod: (SEL)selector { - forwardings++; + forwardingsCount++; if (sel_isEqual(selector, @selector(test))) { class_replaceMethod(self, @selector(test), (IMP)test, "v@:"); return YES; } @@ -139,19 +139,19 @@ return 0; return 0x12345678; } -- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)fmt, ... +- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ... { va_list args; OFString *ret; OFEnsure(self == target); - va_start(args, fmt); - ret = [[[OFString alloc] initWithFormat: fmt + va_start(args, format); + ret = [[[OFString alloc] initWithFormat: format arguments: args] autorelease]; va_end(args); return ret; } @@ -161,17 +161,17 @@ OFEnsure(self == target); return 12345678.00006103515625; } -- (struct stret_test)forwardingTargetStRetTest +- (struct StretTest)forwardingTargetStRetTest { - struct stret_test ret = { { 0 } }; + struct StretTest ret = { { 0 } }; OFEnsure(self == target); - memcpy(ret.s, "abcdefghijklmnopqrstuvwxyz", 27); + memcpy(ret.buffer, "abcdefghijklmnopqrstuvwxyz", 27); return ret; } @end @@ -180,55 +180,58 @@ { void *pool = objc_autoreleasePoolPush(); TEST(@"Forwarding a message and adding a class method", R([ForwardingTest test]) && success && - R([ForwardingTest test]) && forwardings == 1); + R([ForwardingTest test]) && forwardingsCount == 1); - ForwardingTest *t = [[[ForwardingTest alloc] init] autorelease]; + ForwardingTest *testObject = + [[[ForwardingTest alloc] init] autorelease]; success = false; - forwardings = 0; + forwardingsCount = 0; TEST(@"Forwarding a message and adding an instance method", - R([t test]) && success && R([t test]) && forwardings == 1); + R([testObject test]) && success && R([testObject test]) && + forwardingsCount == 1); #ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR target = [[[ForwardingTarget alloc] init] autorelease]; TEST(@"-[forwardingTargetForSelector:]", - [t forwardingTargetTest: 0xDEADBEEF - : -1 - : 1.25 - : 2.75] == 0x12345678) + [testObject forwardingTargetTest: 0xDEADBEEF + : -1 + : 1.25 + : 2.75] == 0x12345678) TEST(@"-[forwardingTargetForSelector:] variable arguments", - [[t forwardingTargetVarArgTest: FMT, ARGS] isEqual: RESULT]) + [[testObject forwardingTargetVarArgTest: FORMAT, ARGS] + isEqual: RESULT]) /* * Don't try fpret on Win64 if we don't have stret forwarding, as * long double is handled as a struct there. */ # if !defined(OF_WINDOWS) || !defined(OF_X86_64) || \ defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET) TEST(@"-[forwardingTargetForSelector:] fp return", - [t forwardingTargetFPRetTest] == 12345678.00006103515625) + [testObject forwardingTargetFPRetTest] == 12345678.00006103515625) # endif # ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET TEST(@"-[forwardingTargetForSelector:] struct return", - !memcmp([t forwardingTargetStRetTest].s, + !memcmp([testObject forwardingTargetStRetTest].buffer, "abcdefghijklmnopqrstuvwxyz", 27)) # endif EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target", - OFNotImplementedException, [t forwardingTargetNilTest]) + OFNotImplementedException, [testObject forwardingTargetNilTest]) EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target", - OFNotImplementedException, [t forwardingTargetSelfTest]) + OFNotImplementedException, [testObject forwardingTargetSelfTest]) # ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target + " @"stret", OFNotImplementedException, - [t forwardingTargetNilStRetTest]) + [testObject forwardingTargetNilStRetTest]) EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target + " @"stret", OFNotImplementedException, - [t forwardingTargetSelfStRetTest]) + [testObject forwardingTargetSelfStRetTest]) # endif #endif objc_autoreleasePoolPop(pool); } @end Index: tests/ImportTest.m ================================================================== --- tests/ImportTest.m +++ tests/ImportTest.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,13 +1,20 @@ include ../extra.mk -SUBDIRS = ${TESTPLUGIN} +SUBDIRS = ${TESTPLUGIN} \ + ${OBJC_SYNC} \ + terminal CLEAN = EBOOT.PBP \ boot.dol \ ${PROG_NOINST}.arm9 \ - ${PROG_NOINST}.nds + ${PROG_NOINST}.nds \ + ${PROG_NOINST}.nro \ + ${PROG_NOINST}.rpx \ + serialization_xml.m \ + testfile_bin.m \ + testfile_ini.m DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ @@ -15,89 +22,104 @@ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ OFDataTests.m \ OFDateTests.m \ OFDictionaryTests.m \ + OFHMACTests.m \ + OFINIFileTests.m \ OFInvocationTests.m \ OFJSONTests.m \ OFListTests.m \ OFLocaleTests.m \ + OFMD5HashTests.m \ + OFMemoryStreamTests.m \ OFMethodSignatureTests.m \ + OFNotificationCenterTests.m \ OFNumberTests.m \ OFObjectTests.m \ + OFPBKDF2Tests.m \ OFPropertyListTests.m \ + OFRIPEMD160HashTests.m \ + OFSHA1HashTests.m \ + OFSHA224HashTests.m \ + OFSHA256HashTests.m \ + OFSHA384HashTests.m \ + OFSHA512HashTests.m \ + OFScryptTests.m \ + OFSerializationTests.m \ OFSetTests.m \ OFStreamTests.m \ OFStringTests.m \ OFSystemInfoTests.m \ OFURLTests.m \ OFValueTests.m \ OFXMLElementBuilderTests.m \ OFXMLNodeTests.m \ OFXMLParserTests.m \ - PBKDF2Tests.m \ RuntimeTests.m \ ${RUNTIME_ARC_TESTS_M} \ - ScryptTests.m \ TestsAppDelegate.m \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ - ${USE_SRCS_WINDOWS} -SRCS_FILES = OFHMACTests.m \ - OFINIFileTests.m \ - OFMD5HashTests.m \ - OFRIPEMD160HashTests.m \ - OFSerializationTests.m \ - OFSHA1HashTests.m \ - OFSHA224HashTests.m \ - OFSHA256HashTests.m \ - OFSHA384HashTests.m \ - OFSHA512HashTests.m -SRCS_IPX = OFIPXSocketTests.m \ - OFSPXSocketTests.m \ - OFSPXStreamSocketTests.m + ${USE_SRCS_WINDOWS} \ + serialization_xml.m \ + testfile_bin.m \ + testfile_ini.m SRCS_PLUGINS = OFPluginTests.m SRCS_SOCKETS = OFDNSResolverTests.m \ ${OF_HTTP_CLIENT_TESTS_M} \ OFHTTPCookieTests.m \ OFHTTPCookieManagerTests.m \ OFKernelEventObserverTests.m \ + OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ - SocketTests.m \ - ${USE_SRCS_IPX} + ${USE_SRCS_IPX} \ + ${USE_SRCS_UNIX_SOCKETS} +SRCS_IPX = OFIPXSocketTests.m \ + OFSPXSocketTests.m \ + OFSPXStreamSocketTests.m +SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ + OFUNIXStreamSocketTests.m SRCS_THREADS = OFThreadTests.m SRCS_WINDOWS = OFWindowsRegistryKeyTests.m IOS_USER ?= mobile IOS_TMP ?= /tmp/objfw-test include ../buildsys.mk -post-all: ${RUN_TESTS} +serialization_xml.m: serialization.xml + ${SHELL} ../utils/objfw-embed serialization.xml /serialization.xml $@ +testfile_bin.m: testfile.bin + ${SHELL} ../utils/objfw-embed testfile.bin /testfile.bin $@ +testfile_ini.m: testfile.ini + ${SHELL} ../utils/objfw-embed testfile.ini /testfile.ini $@ .PHONY: run run-on-ios run-on-android run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../src/libobjfw.so; then \ ${LN_S} ../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ ${LN_S} ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi - if test -f ../src/objfw.dll; then \ - ${LN_S} ../src/objfw.dll objfw.dll; \ + if test -f ../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../src/libobjfw.dylib; then \ ${LN_S} ../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -107,12 +129,13 @@ ${LN_S} ../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ elif test -f ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ ${LN_S} ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi - if test -f ../src/runtime/objfwrt.dll; then \ - ${LN_S} ../src/runtime/objfwrt.dll objfwrt.dll; \ + if test -f ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi @@ -125,14 +148,16 @@ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT run-on-ios: all if [ -z "${IOS_HOST}" ]; then \ @@ -143,12 +168,11 @@ ssh ${IOS_USER}@${IOS_HOST} \ 'rm -fr ${IOS_TMP} && mkdir -p ${IOS_TMP}/plugin' destname=libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ scp -q ../src/libobjfw.dylib \ ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/$$destname - scp -q tests testfile.bin testfile.txt testfile.ini serialization.xml \ - ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/ + scp -q tests testfile.txt ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/ 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} && DYLD_LIBRARY_PATH=. ${WRAPPER} ./tests' @@ -162,14 +186,11 @@ if test -f ../src/runtime/libobjfwrt.so; then \ adb push ../src/runtime/libobjfwrt.so \ /data/local/tmp/objfw/libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ fi adb push tests /data/local/tmp/objfw/tests - adb push testfile.bin /data/local/tmp/objfw/testfile.bin adb push testfile.txt /data/local/tmp/objfw/testfile.txt - adb push testfile.ini /data/local/tmp/objfw/testfile.ini - adb push serialization.xml /data/local/tmp/objfw/serialization.xml if test -f plugin/TestPlugin.so; then \ adb push plugin/TestPlugin.so \ /data/local/tmp/objfw/plugin/TestPlugin.so; \ fi echo "Running tests binary on Android device..." @@ -183,24 +204,36 @@ boot.dol: ${PROG_NOINST} elf2dol ${PROG_NOINST} $@ ${PROG_NOINST}: ${LIBOBJFW_DEP} ${LIBOBJFWRT_DEP} + +${PROG_NOINST}.3dsx: ${PROG_NOINST} + 3dsxtool $< $@ ${PROG_NOINST}.arm9: ${PROG_NOINST} arm-none-eabi-objcopy -O binary $< $@ -${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 +${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 testfile.txt rm -fr nds-data mkdir -p nds-data - cp testfile.bin testfile.txt testfile.ini serialization.xml nds-data - ndstool -c $@ -9 $< -d nds-data + cp testfile.txt nds-data + ndstool -c $@ -9 ${PROG_NOINST} -d nds-data rm -fr nds-data -${PROG_NOINST}.3dsx: ${PROG_NOINST} - 3dsxtool $< $@ +${PROG_NOINST}.nro: ${PROG_NOINST} testfile.txt + rm -fr romfs + mkdir -p romfs + cp testfile.txt romfs + nacptool --create "ObjFW tests" "Jonathan Schleifer" \ + "${PACKAGE_VERSION}" tests.nacp + elf2nro ${PROG_NOINST} $@ --nacp=tests.nacp --romfsdir=romfs + rm -fr romfs tests.nacp + +${PROG_NOINST}.rpx: ${PROG_NOINST} + elf2rpl $< $@ CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -DSTDOUT OBJCFLAGS_RuntimeARCTests.m = -fobjc-arc -fobjc-arc-exceptions LIBS := ${TESTS_LIBS} ${LIBS} LDFLAGS += ${MAP_LDFLAGS} LD = ${OBJC} Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,12 +15,12 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = nil; -static OFString *c_ary[] = { +static OFString *module; +static OFString *const cArray[] = { @"Foo", @"Bar", @"Baz" }; @@ -125,283 +125,302 @@ @implementation TestsAppDelegate (OFArrayTests) - (void)arrayTestsWithClass: (Class)arrayClass mutableClass: (Class)mutableArrayClass { void *pool = objc_autoreleasePoolPush(); - OFArray *a[3]; - OFMutableArray *m[2]; + OFArray *array1, *array2; + OFMutableArray *mutableArray1, *mutableArray2; OFEnumerator *enumerator; - id obj; + id object; bool ok; size_t i; - TEST(@"+[array]", (m[0] = [mutableArrayClass array])) + TEST(@"+[array]", (mutableArray1 = [mutableArrayClass array])) TEST(@"+[arrayWithObjects:]", - (a[0] = [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) + (array1 = + [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) TEST(@"+[arrayWithObjects:count:]", - (a[1] = [arrayClass arrayWithObjects: c_ary count: 3]) && - [a[1] isEqual: a[0]]) + (array2 = [arrayClass arrayWithObjects: cArray count: 3]) && + [array2 isEqual: array1]) TEST(@"-[description]", - [a[0].description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) + [array1.description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) - TEST(@"-[addObject:]", R([m[0] addObject: c_ary[0]]) && - R([m[0] addObject: c_ary[2]])) + TEST(@"-[addObject:]", + R([mutableArray1 addObject: cArray[0]]) && + R([mutableArray1 addObject: cArray[2]])) TEST(@"-[insertObject:atIndex:]", - R([m[0] insertObject: c_ary[1] atIndex: 1])) + R([mutableArray1 insertObject: cArray[1] atIndex: 1])) - TEST(@"-[count]", m[0].count == 3 && a[0].count == 3 && a[1].count == 3) + TEST(@"-[count]", + mutableArray1.count == 3 && array1.count == 3 && array2.count == 3) - TEST(@"-[isEqual:]", [m[0] isEqual: a[0]] && [a[0] isEqual: a[1]]) + TEST(@"-[isEqual:]", + [mutableArray1 isEqual: array1] && [array1 isEqual: array2]) TEST(@"-[objectAtIndex:]", - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[1]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]] && - [[a[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[a[0] objectAtIndex: 1] isEqual: c_ary[1]] && - [[a[0] objectAtIndex: 2] isEqual: c_ary[2]] && - [[a[1] objectAtIndex: 0] isEqual: c_ary[0]] && - [[a[1] objectAtIndex: 1] isEqual: c_ary[1]] && - [[a[1] objectAtIndex: 2] isEqual: c_ary[2]]) + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[1]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]] && + [[array1 objectAtIndex: 0] isEqual: cArray[0]] && + [[array1 objectAtIndex: 1] isEqual: cArray[1]] && + [[array1 objectAtIndex: 2] isEqual: cArray[2]] && + [[array2 objectAtIndex: 0] isEqual: cArray[0]] && + [[array2 objectAtIndex: 1] isEqual: cArray[1]] && + [[array2 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[containsObject:]", - [a[0] containsObject: c_ary[1]] && - ![a[0] containsObject: @"nonexistent"]) + [array1 containsObject: cArray[1]] && + ![array1 containsObject: @"nonexistent"]) TEST(@"-[containsObjectIdenticalTo:]", - [a[0] containsObjectIdenticalTo: c_ary[1]] && - ![a[0] containsObjectIdenticalTo: - [OFString stringWithString: c_ary[1]]]) + [array1 containsObjectIdenticalTo: cArray[1]] && + ![array1 containsObjectIdenticalTo: + [OFString stringWithString: cArray[1]]]) - TEST(@"-[indexOfObject:]", [a[0] indexOfObject: c_ary[1]] == 1) + TEST(@"-[indexOfObject:]", [array1 indexOfObject: cArray[1]] == 1) TEST(@"-[indexOfObjectIdenticalTo:]", - [a[1] indexOfObjectIdenticalTo: c_ary[1]] == 1) + [array2 indexOfObjectIdenticalTo: cArray[1]] == 1) TEST(@"-[objectsInRange:]", - [[a[0] objectsInRange: OFRangeMake(1, 2)] isEqual: - [arrayClass arrayWithObjects: c_ary[1], c_ary[2], nil]]) + [[array1 objectsInRange: OFRangeMake(1, 2)] isEqual: + [arrayClass arrayWithObjects: cArray[1], cArray[2], nil]]) TEST(@"-[replaceObject:withObject:]", - R([m[0] replaceObject: c_ary[1] withObject: c_ary[0]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObject: cArray[1] withObject: cArray[0]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[replaceObject:identicalTo:]", - R([m[0] replaceObjectIdenticalTo: c_ary[0] withObject: c_ary[1]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[1]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObjectIdenticalTo: cArray[0] + withObject: cArray[1]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[1]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[replaceObjectAtIndex:withObject:]", - R([m[0] replaceObjectAtIndex: 0 withObject: c_ary[0]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[removeObject:]", - R([m[0] removeObject: c_ary[0]]) && m[0].count == 2) - - TEST(@"-[removeObjectIdenticalTo:]", - R([m[0] removeObjectIdenticalTo: c_ary[2]]) && m[0].count == 1) - - m[1] = [[a[0] mutableCopy] autorelease]; - TEST(@"-[removeObjectAtIndex:]", R([m[1] removeObjectAtIndex: 1]) && - m[1].count == 2 && [[m[1] objectAtIndex: 1] isEqual: c_ary[2]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - TEST(@"-[removeObjectsInRange:]", - R([m[1] removeObjectsInRange: OFRangeMake(0, 2)]) && - m[1].count == 1 && [[m[1] objectAtIndex: 0] isEqual: c_ary[2]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"qux"]; - [m[1] addObject: @"last"]; - TEST(@"-[reverse]", - R([m[1] reverse]) && [m[1] isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"qux"]; - [m[1] addObject: @"last"]; - TEST(@"-[reversedArray]", - [[m[1] reversedArray] isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"0"]; - [m[1] addObject: @"z"]; - TEST(@"-[sortedArray]", - [[m[1] sortedArray] isEqual: [arrayClass arrayWithObjects: - @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && - [[m[1] sortedArrayUsingSelector: @selector(compare:) - options: OFArraySortDescending] + R([mutableArray1 removeObject: cArray[0]]) && + mutableArray1.count == 1) + + [mutableArray1 addObject: cArray[0]]; + + TEST(@"-[removeObjectIdenticalTo:]", + R([mutableArray1 removeObjectIdenticalTo: cArray[2]]) && + mutableArray1.count == 1) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + TEST(@"-[removeObjectAtIndex:]", + R([mutableArray2 removeObjectAtIndex: 1]) && + mutableArray2.count == 2 && + [[mutableArray2 objectAtIndex: 1] isEqual: cArray[2]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + TEST(@"-[removeObjectsInRange:]", + R([mutableArray2 removeObjectsInRange: OFRangeMake(0, 2)]) && + mutableArray2.count == 1 && + [[mutableArray2 objectAtIndex: 0] isEqual: cArray[2]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"qux"]; + [mutableArray2 addObject: @"last"]; + TEST(@"-[reverse]", + R([mutableArray2 reverse]) && + [mutableArray2 isEqual: [arrayClass arrayWithObjects: + @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"qux"]; + [mutableArray2 addObject: @"last"]; + TEST(@"-[reversedArray]", + [[mutableArray2 reversedArray] isEqual: + [arrayClass arrayWithObjects: + @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"0"]; + [mutableArray2 addObject: @"z"]; + TEST(@"-[sortedArray]", + [[mutableArray2 sortedArray] isEqual: [arrayClass arrayWithObjects: + @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && + [[mutableArray2 sortedArrayUsingSelector: @selector(compare:) + options: OFArraySortDescending] isEqual: [arrayClass arrayWithObjects: @"z", @"Foo", @"Baz", @"Bar", @"0", nil]]) EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]", - OFOutOfRangeException, [a[0] objectAtIndex: a[0].count]) + OFOutOfRangeException, [array1 objectAtIndex: array1.count]) EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]", - OFOutOfRangeException, [m[0] removeObjectsInRange: - OFRangeMake(0, m[0].count + 1)]) + OFOutOfRangeException, [mutableArray1 removeObjectsInRange: + OFRangeMake(0, mutableArray1.count + 1)]) TEST(@"-[componentsJoinedByString:]", - (a[1] = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", + (array2 = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", nil]) && - [[a[1] componentsJoinedByString: @" "] isEqual: @" a b c"] && - (a[1] = [arrayClass arrayWithObject: @"foo"]) && - [[a[1] componentsJoinedByString: @" "] isEqual: @"foo"]) + [[array2 componentsJoinedByString: @" "] isEqual: @" a b c"] && + (array2 = [arrayClass arrayWithObject: @"foo"]) && + [[array2 componentsJoinedByString: @" "] isEqual: @"foo"]) TEST(@"-[componentsJoinedByString:options]", - (a[1] = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", @"bar", - @"", nil]) && - [[a[1] componentsJoinedByString: @" " - options: OFArraySkipEmptyComponents] + (array2 = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", + @"bar", @"", nil]) && + [[array2 componentsJoinedByString: @" " + options: OFArraySkipEmptyComponents] isEqual: @"foo bar"]) - m[0] = [[a[0] mutableCopy] autorelease]; + mutableArray1 = [[array1 mutableCopy] autorelease]; ok = true; i = 0; - TEST(@"-[objectEnumerator]", (enumerator = [m[0] objectEnumerator])) + TEST(@"-[objectEnumerator]", + (enumerator = [mutableArray1 objectEnumerator])) - while ((obj = [enumerator nextObject]) != nil) { - if (![obj isEqual: c_ary[i]]) + while ((object = [enumerator nextObject]) != nil) { + if (![object isEqual: cArray[i]]) ok = false; - [m[0] replaceObjectAtIndex: i withObject: @""]; + [mutableArray1 replaceObjectAtIndex: i withObject: @""]; i++; } - if (m[0].count != i) + if (mutableArray1.count != i) ok = false; TEST(@"OFEnumerator's -[nextObject]", ok) - [m[0] removeObjectAtIndex: 0]; + [mutableArray1 removeObjectAtIndex: 0]; EXPECT_EXCEPTION(@"Detection of mutation during enumeration", OFEnumerationMutationException, [enumerator nextObject]) - m[0] = [[a[0] mutableCopy] autorelease]; + mutableArray1 = [[array1 mutableCopy] autorelease]; ok = true; i = 0; - for (OFString *s in m[0]) { - if (![s isEqual: c_ary[i]]) + for (OFString *string in mutableArray1) { + if (![string isEqual: cArray[i]]) ok = false; - [m[0] replaceObjectAtIndex: i withObject: @""]; + [mutableArray1 replaceObjectAtIndex: i withObject: @""]; i++; } - if (m[0].count != i) + if (mutableArray1.count != i) ok = false; TEST(@"Fast Enumeration", ok) - [m[0] replaceObjectAtIndex: 0 withObject: c_ary[0]]; - [m[0] replaceObjectAtIndex: 1 withObject: c_ary[1]]; - [m[0] replaceObjectAtIndex: 2 withObject: c_ary[2]]; + [mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]; + [mutableArray1 replaceObjectAtIndex: 1 withObject: cArray[1]]; + [mutableArray1 replaceObjectAtIndex: 2 withObject: cArray[2]]; ok = false; i = 0; @try { - for (OFString *s in m[0]) { - (void)s; + for (OFString *string in mutableArray1) { + (void)string; if (i == 0) - [m[0] addObject: @""]; + [mutableArray1 addObject: @""]; i++; } } @catch (OFEnumerationMutationException *e) { ok = true; } TEST(@"Detection of mutation during Fast Enumeration", ok) - [m[0] removeLastObject]; + [mutableArray1 removeLastObject]; #ifdef OF_HAVE_BLOCKS { - __block bool blockOk = true; - __block size_t count = 0; - OFArray *cmp = a[0]; - OFMutableArray *a2; - - m[0] = [[a[0] mutableCopy] autorelease]; - [m[0] enumerateObjectsUsingBlock: - ^ (id object, size_t idx, bool *stop) { - count++; - if (![object isEqual: [cmp objectAtIndex: idx]]) - blockOk = false; - }]; - - if (count != cmp.count) - blockOk = false; - - TEST(@"Enumeration using blocks", blockOk) - - blockOk = false; - a2 = m[0]; - @try { - [a2 enumerateObjectsUsingBlock: - ^ (id object, size_t idx, bool *stop) { - [a2 removeObjectAtIndex: idx]; - }]; - } @catch (OFEnumerationMutationException *e) { - blockOk = true; + __block bool blockOK = true; + __block size_t count = 0; + OFArray *compareArray = array1; + OFMutableArray *mutableArray3; + + mutableArray1 = [[array1 mutableCopy] autorelease]; + [mutableArray1 enumerateObjectsUsingBlock: + ^ (id object_, size_t idx, bool *stop) { + count++; + if (![object_ isEqual: + [compareArray objectAtIndex: idx]]) + blockOK = false; + }]; + + if (count != compareArray.count) + blockOK = false; + + TEST(@"Enumeration using blocks", blockOK) + + blockOK = false; + mutableArray3 = mutableArray1; + @try { + [mutableArray3 enumerateObjectsUsingBlock: + ^ (id object_, size_t idx, bool *stop) { + [mutableArray3 removeObjectAtIndex: idx]; + }]; + } @catch (OFEnumerationMutationException *e) { + blockOK = true; } @catch (OFOutOfRangeException *e) { /* * Out of bounds access due to enumeration not being * detected. */ } TEST(@"Detection of mutation during enumeration using blocks", - blockOk) + blockOK) } TEST(@"-[replaceObjectsUsingBlock:]", - R([m[0] replaceObjectsUsingBlock: ^ id (id object, size_t idx) { - switch (idx) { - case 0: - return @"foo"; - case 1: - return @"bar"; - } - - return nil; - }]) && [m[0].description isEqual: @"(\n\tfoo,\n\tbar\n)"]) + R([mutableArray1 replaceObjectsUsingBlock: + ^ id (id object_, size_t idx) { + switch (idx) { + case 0: + return @"foo"; + case 1: + return @"bar"; + } + + return nil; + }]) && [mutableArray1.description isEqual: @"(\n\tfoo,\n\tbar\n)"]) TEST(@"-[mappedArrayUsingBlock:]", - [[m[0] mappedArrayUsingBlock: ^ id (id object, size_t idx) { - switch (idx) { - case 0: - return @"foobar"; - case 1: - return @"qux"; - } - - return nil; + [[mutableArray1 mappedArrayUsingBlock: + ^ id (id object_, size_t idx) { + switch (idx) { + case 0: + return @"foobar"; + case 1: + return @"qux"; + } + + return nil; }].description isEqual: @"(\n\tfoobar,\n\tqux\n)"]) TEST(@"-[filteredArrayUsingBlock:]", - [[m[0] filteredArrayUsingBlock: ^ bool (id object, size_t idx) { - return [object isEqual: @"foo"]; + [[mutableArray1 filteredArrayUsingBlock: + ^ bool (id object_, size_t idx) { + return [object_ isEqual: @"foo"]; }].description isEqual: @"(\n\tfoo\n)"]) TEST(@"-[foldUsingBlock:]", [[arrayClass arrayWithObjects: [OFMutableString string], @"foo", @"bar", @"baz", nil] foldUsingBlock: ^ id (id left, id right) { - [left appendString: right]; - return left; + [left appendString: right]; + return left; }]) #endif TEST(@"-[valueForKey:]", [[[arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", nil] @@ -409,18 +428,18 @@ [arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && [[[arrayClass arrayWithObjects: @"1", @"2", nil] valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) - m[0] = [mutableArrayClass arrayWithObjects: + mutableArray1 = [mutableArrayClass arrayWithObjects: [OFMutableURL URLWithString: @"http://foo.bar/"], [OFMutableURL URLWithString: @"http://bar.qux/"], [OFMutableURL URLWithString: @"http://qux.quxqux/"], nil]; TEST(@"-[setValue:forKey:]", - R([m[0] setValue: [OFNumber numberWithShort: 1234] - forKey: @"port"]) && - [m[0] isEqual: [arrayClass arrayWithObjects: + R([mutableArray1 setValue: [OFNumber numberWithShort: 1234] + forKey: @"port"]) && + [mutableArray1 isEqual: [arrayClass arrayWithObjects: [OFURL URLWithString: @"http://foo.bar:1234/"], [OFURL URLWithString: @"http://bar.qux:1234/"], [OFURL URLWithString: @"http://qux.quxqux:1234/"], nil]]) objc_autoreleasePoolPop(pool); Index: tests/OFBlockTests.m ================================================================== --- tests/OFBlockTests.m +++ tests/OFBlockTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFBlock"; +static OFString *const module = @"OFBlock"; #if defined(OF_OBJFW_RUNTIME) extern struct objc_class _NSConcreteStackBlock; extern struct objc_class _NSConcreteGlobalBlock; extern struct objc_class _NSConcreteMallocBlock; @@ -27,11 +27,11 @@ extern void *_NSConcreteStackBlock; extern void *_NSConcreteGlobalBlock; extern void *_NSConcreteMallocBlock; #endif -static void (^g)(void) = ^ {}; +static void (^globalBlock)(void) = ^ {}; static int (^returnStackBlock(void))(void) { __block int i = 42; @@ -41,70 +41,76 @@ static double forwardTest(void) { __block double d; - void (^b)(void) = Block_copy(^ { + void (^block)(void) = Block_copy(^ { d = 5; }); - b(); - Block_release(b); + block(); + Block_release(block); return d; } @implementation TestsAppDelegate (OFBlockTests) - (void)blockTests { void *pool = objc_autoreleasePoolPush(); __block int x; - void (^s)(void) = ^ { x = 0; }; - void (^m)(void); - int (^v)(void); + void (^stackBlock)(void) = ^ { + x = 0; + (void)x; + }; + void (^mallocBlock)(void); + int (^voidBlock)(void); TEST(@"Class of stack block", (Class)&_NSConcreteStackBlock == objc_getClass("OFStackBlock") && - [s isKindOfClass: [OFBlock class]]) + [stackBlock isKindOfClass: [OFBlock class]]) #if !defined(OF_WINDOWS) || !defined(__clang__) || !defined(OF_NO_SHARED) /* * Causes a linker error on Windows with Clang when compiling as a * static library. This is a bug in Clang. */ TEST(@"Class of global block", (Class)&_NSConcreteGlobalBlock == objc_getClass("OFGlobalBlock") && - [g isKindOfClass: [OFBlock class]]) + [globalBlock isKindOfClass: [OFBlock class]]) #endif TEST(@"Class of a malloc block", (Class)&_NSConcreteMallocBlock == objc_getClass("OFMallocBlock")) TEST(@"Copying a stack block", - (m = [[s copy] autorelease]) && - [m class] == objc_getClass("OFMallocBlock") && - [m isKindOfClass: [OFBlock class]]) + (mallocBlock = [[stackBlock copy] autorelease]) && + [mallocBlock class] == objc_getClass("OFMallocBlock") && + [mallocBlock isKindOfClass: [OFBlock class]]) TEST(@"Copying a stack block and referencing its variable", forwardTest() == 5) TEST(@"Copying a stack block and using its copied variable", - (v = returnStackBlock()) && v() == 43 && v() == 44 && v() == 45) + (voidBlock = returnStackBlock()) && voidBlock() == 43 && + voidBlock() == 44 && voidBlock() == 45) - TEST(@"Copying a global block", (id)g == [[g copy] autorelease]) + TEST(@"Copying a global block", + (id)globalBlock == [[globalBlock copy] autorelease]) #ifndef __clang_analyzer__ TEST(@"Copying a malloc block", - (id)m == [m copy] && [m retainCount] == 2) + (id)mallocBlock == [mallocBlock copy] && + [mallocBlock retainCount] == 2) #endif - TEST(@"Autorelease a stack block", R([s autorelease])) + TEST(@"Autorelease a stack block", R([stackBlock autorelease])) - TEST(@"Autorelease a global block", R([g autorelease])) + TEST(@"Autorelease a global block", R([globalBlock autorelease])) #ifndef __clang_analyzer__ - TEST(@"Autorelease a malloc block", R([m autorelease])) + TEST(@"Autorelease a malloc block", R([mallocBlock autorelease])) #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFCharacterSetTests.m ================================================================== --- tests/OFCharacterSetTests.m +++ tests/OFCharacterSetTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,11 +19,11 @@ #import "OFCharacterSet.h" #import "OFBitSetCharacterSet.h" #import "OFRangeCharacterSet.h" -static OFString *module = nil; +static OFString *module; @interface SimpleCharacterSet: OFCharacterSet @end @implementation SimpleCharacterSet @@ -35,73 +35,73 @@ @implementation TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests { void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *cs, *ics; + OFCharacterSet *characterSet, *invertedCharacterSet; bool ok; module = @"OFCharacterSet"; - cs = [[[SimpleCharacterSet alloc] init] autorelease]; + characterSet = [[[SimpleCharacterSet alloc] init] autorelease]; ok = true; for (OFUnichar c = 0; c < 65536; c++) { if (c % 2 == 0) { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); module = @"OFBitSetCharacterSet"; TEST(@"+[characterSetWithCharactersInString:]", - (cs = [OFCharacterSet characterSetWithCharactersInString: + (characterSet = [OFCharacterSet characterSetWithCharactersInString: @"0123456789"]) && - [cs isKindOfClass: [OFBitSetCharacterSet class]]) + [characterSet isKindOfClass: [OFBitSetCharacterSet class]]) ok = true; for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); module = @"OFRangeCharacterSet"; TEST(@"+[characterSetWithRange:]", - (cs = [OFCharacterSet + (characterSet = [OFCharacterSet characterSetWithRange: OFRangeMake('0', 10)]) && - [cs isKindOfClass: [OFRangeCharacterSet class]]) + [characterSet isKindOfClass: [OFRangeCharacterSet class]]) ok = true; for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); ok = true; - ics = cs.invertedSet; + invertedCharacterSet = characterSet.invertedSet; for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if ([ics characterIsMember: c]) + if ([invertedCharacterSet characterIsMember: c]) ok = false; - } else if (![ics characterIsMember: c]) + } else if (![invertedCharacterSet characterIsMember: c]) ok = false; } TEST(@"-[invertedSet]", ok); TEST(@"Inverting -[invertedSet] returns original set", - ics.invertedSet == cs) + invertedCharacterSet.invertedSet == characterSet) objc_autoreleasePoolPop(pool); } @end Index: tests/OFDNSResolverTests.m ================================================================== --- tests/OFDNSResolverTests.m +++ tests/OFDNSResolverTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: tests/OFDataTests.m ================================================================== --- tests/OFDataTests.m +++ tests/OFDataTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,210 +17,212 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFData"; -const char *str = "Hello!"; +static OFString *const module = @"OFData"; @implementation TestsAppDelegate (OFDataTests) - (void)dataTests { void *pool = objc_autoreleasePoolPush(); - OFMutableData *mutable; - OFData *immutable; + OFMutableData *mutableData; + OFData *data; void *raw[2]; OFRange range; TEST(@"+[dataWithItemSize:]", - (mutable = [OFMutableData dataWithItemSize: 4096])) + (mutableData = [OFMutableData dataWithItemSize: 4096])) raw[0] = OFAllocMemory(1, 4096); raw[1] = OFAllocMemory(1, 4096); memset(raw[0], 0xFF, 4096); memset(raw[1], 0x42, 4096); - TEST(@"-[addItem:]", R([mutable addItem: raw[0]]) && - R([mutable addItem: raw[1]])) + TEST(@"-[addItem:]", R([mutableData addItem: raw[0]]) && + R([mutableData addItem: raw[1]])) TEST(@"-[itemAtIndex:]", - memcmp([mutable itemAtIndex: 0], raw[0], 4096) == 0 && - memcmp([mutable itemAtIndex: 1], raw[1], 4096) == 0) + memcmp([mutableData itemAtIndex: 0], raw[0], 4096) == 0 && + memcmp([mutableData itemAtIndex: 1], raw[1], 4096) == 0) - TEST(@"-[lastItem]", memcmp(mutable.lastItem, raw[1], 4096) == 0) + TEST(@"-[lastItem]", memcmp(mutableData.lastItem, raw[1], 4096) == 0) - TEST(@"-[count]", mutable.count == 2) + TEST(@"-[count]", mutableData.count == 2) TEST(@"-[isEqual:]", - (immutable = [OFData dataWithItems: mutable.items - count: mutable.count - itemSize: mutable.itemSize]) && - [immutable isEqual: mutable] && - R([mutable removeLastItem]) && ![mutable isEqual: immutable]) + (data = [OFData dataWithItems: mutableData.items + count: mutableData.count + itemSize: mutableData.itemSize]) && + [data isEqual: mutableData] && + R([mutableData removeLastItem]) && ![mutableData isEqual: data]) TEST(@"-[mutableCopy]", - (mutable = [[immutable mutableCopy] autorelease]) && - [mutable isEqual: immutable]) + (mutableData = [[data mutableCopy] autorelease]) && + [mutableData isEqual: data]) - TEST(@"-[compare]", [mutable compare: immutable] == 0 && - R([mutable removeLastItem]) && - [immutable compare: mutable] == OFOrderedDescending && - [mutable compare: immutable] == OFOrderedAscending && + TEST(@"-[compare]", [mutableData compare: data] == 0 && + R([mutableData removeLastItem]) && + [data compare: mutableData] == OFOrderedDescending && + [mutableData compare: data] == OFOrderedAscending && [[OFData dataWithItems: "aa" count: 2] compare: [OFData dataWithItems: "z" count: 1]] == OFOrderedAscending) - TEST(@"-[hash]", immutable.hash == 0x634A529F) + TEST(@"-[hash]", data.hash == 0x634A529F) - mutable = [OFMutableData dataWithItems: "abcdef" count: 6]; + mutableData = [OFMutableData dataWithItems: "abcdef" count: 6]; - TEST(@"-[removeLastItem]", R([mutable removeLastItem]) && - mutable.count == 5 && memcmp(mutable.items, "abcde", 5) == 0) + TEST(@"-[removeLastItem]", + R([mutableData removeLastItem]) && mutableData.count == 5 && + memcmp(mutableData.items, "abcde", 5) == 0) TEST(@"-[removeItemsInRange:]", - R([mutable removeItemsInRange: OFRangeMake(1, 2)]) && - mutable.count == 3 && memcmp(mutable.items, "ade", 3) == 0) + R([mutableData removeItemsInRange: OFRangeMake(1, 2)]) && + mutableData.count == 3 && memcmp(mutableData.items, "ade", 3) == 0) TEST(@"-[insertItems:atIndex:count:]", - R([mutable insertItems: "bc" atIndex: 1 count: 2]) && - mutable.count == 5 && memcmp(mutable.items, "abcde", 5) == 0) - - immutable = [OFData dataWithItems: "aaabaccdacaabb" - count: 7 - itemSize: 2]; - - range = [immutable rangeOfData: [OFData dataWithItems: "aa" - count: 1 - itemSize: 2] - options: 0 - range: OFRangeMake(0, 7)]; + R([mutableData insertItems: "bc" atIndex: 1 count: 2]) && + mutableData.count == 5 && + memcmp(mutableData.items, "abcde", 5) == 0) + + data = [OFData dataWithItems: "aaabaccdacaabb" count: 7 itemSize: 2]; + + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; TEST(@"-[rangeOfData:options:range:] #1", range.location == 0 && range.length == 1) - range = [immutable rangeOfData: [OFData dataWithItems: "aa" - count: 1 - itemSize: 2] - options: OFDataSearchBackwards - range: OFRangeMake(0, 7)]; + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: OFDataSearchBackwards + range: OFRangeMake(0, 7)]; TEST(@"-[rangeOfData:options:range:] #2", range.location == 5 && range.length == 1) - range = [immutable rangeOfData: [OFData dataWithItems: "ac" - count: 1 - itemSize: 2] - options: 0 - range: OFRangeMake(0, 7)]; + range = [data rangeOfData: [OFData dataWithItems: "ac" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; TEST(@"-[rangeOfData:options:range:] #3", range.location == 2 && range.length == 1) - range = [immutable rangeOfData: [OFData dataWithItems: "aabb" - count: 2 - itemSize: 2] - options: 0 - range: OFRangeMake(0, 7)]; + range = [data rangeOfData: [OFData dataWithItems: "aabb" + count: 2 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; TEST(@"-[rangeOfData:options:range:] #4", range.location == 5 && range.length == 2) TEST(@"-[rangeOfData:options:range:] #5", - R(range = [immutable rangeOfData: [OFData dataWithItems: "aa" - count: 1 - itemSize: 2] - options: 0 - range: OFRangeMake(1, 6)]) && + R(range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(1, 6)]) && range.location == 5 && range.length == 1) - range = [immutable rangeOfData: [OFData dataWithItems: "aa" - count: 1 - itemSize: 2] - options: OFDataSearchBackwards - range: OFRangeMake(0, 5)]; + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: OFDataSearchBackwards + range: OFRangeMake(0, 5)]; TEST(@"-[rangeOfData:options:range:] #6", range.location == 0 && range.length == 1) EXPECT_EXCEPTION( @"-[rangeOfData:options:range:] failing on different itemSize", OFInvalidArgumentException, - [immutable rangeOfData: [OFData dataWithItems: "aaa" - count: 1 - itemSize: 3] - options: 0 - range: OFRangeMake(0, 1)]) + [data rangeOfData: [OFData dataWithItems: "aaa" + count: 1 + itemSize: 3] + options: 0 + range: OFRangeMake(0, 1)]) EXPECT_EXCEPTION( @"-[rangeOfData:options:range:] failing on out of range", OFOutOfRangeException, - [immutable rangeOfData: [OFData dataWithItems: "" - count: 0 - itemSize: 2] - options: 0 - range: OFRangeMake(8, 1)]) + [data rangeOfData: [OFData dataWithItems: "" count: 0 itemSize: 2] + options: 0 + range: OFRangeMake(8, 1)]) TEST(@"-[subdataWithRange:]", - [[immutable subdataWithRange: OFRangeMake(2, 4)] - isEqual: [OFData dataWithItems: "accdacaa" - count: 4 - itemSize: 2]] && - [[mutable subdataWithRange: OFRangeMake(2, 3)] - isEqual: [OFData dataWithItems: "cde" - count: 3]]) + [[data subdataWithRange: OFRangeMake(2, 4)] + isEqual: [OFData dataWithItems: "accdacaa" count: 4 itemSize: 2]] && + [[mutableData subdataWithRange: OFRangeMake(2, 3)] + isEqual: [OFData dataWithItems: "cde" count: 3]]) EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #1", OFOutOfRangeException, - [immutable subdataWithRange: OFRangeMake(7, 1)]) + [data subdataWithRange: OFRangeMake(7, 1)]) EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #2", OFOutOfRangeException, - [mutable subdataWithRange: OFRangeMake(6, 1)]) + [mutableData subdataWithRange: OFRangeMake(6, 1)]) - TEST(@"-[stringByMD5Hashing]", [mutable.stringByMD5Hashing + TEST(@"-[stringByMD5Hashing]", + [mutableData.stringByMD5Hashing isEqual: @"ab56b4d92b40713acc5af89985d4b786"]) - TEST(@"-[stringByRIPEMD160Hashing]", [mutable.stringByRIPEMD160Hashing + TEST(@"-[stringByRIPEMD160Hashing]", + [mutableData.stringByRIPEMD160Hashing isEqual: @"973398b6e6c6cfa6b5e6a5173f195ce3274bf828"]) - TEST(@"-[stringBySHA1Hashing]", [mutable.stringBySHA1Hashing + TEST(@"-[stringBySHA1Hashing]", + [mutableData.stringBySHA1Hashing isEqual: @"03de6c570bfe24bfc328ccd7ca46b76eadaf4334"]) - TEST(@"-[stringBySHA224Hashing]", [mutable.stringBySHA224Hashing + TEST(@"-[stringBySHA224Hashing]", + [mutableData.stringBySHA224Hashing isEqual: @"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6" ]) - TEST(@"-[stringBySHA256Hashing]", [mutable.stringBySHA256Hashing + TEST(@"-[stringBySHA256Hashing]", + [mutableData.stringBySHA256Hashing isEqual: @"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0" @"c44ca42c"]) - TEST(@"-[stringBySHA384Hashing]", [mutable.stringBySHA384Hashing + TEST(@"-[stringBySHA384Hashing]", + [mutableData.stringBySHA384Hashing isEqual: @"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813" @"521565abc0ec57a37ee4d8be89d097c0d2ad52f0"]) - TEST(@"-[stringBySHA512Hashing]", [mutable.stringBySHA512Hashing + TEST(@"-[stringBySHA512Hashing]", + [mutableData.stringBySHA512Hashing isEqual: @"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3" @"cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665" @"bef2289a5c70b0a1"]) TEST(@"-[stringByBase64Encoding]", - [mutable.stringByBase64Encoding isEqual: @"YWJjZGU="]) + [mutableData.stringByBase64Encoding isEqual: @"YWJjZGU="]) TEST(@"+[dataWithBase64EncodedString:]", - memcmp([[OFData dataWithBase64EncodedString: @"YWJjZGU="] - items], "abcde", 5) == 0) + memcmp([[OFData dataWithBase64EncodedString: @"YWJjZGU="] items], + "abcde", 5) == 0) TEST(@"Building strings", - (mutable = [OFMutableData dataWithItems: str count: 6]) && - R([mutable addItem: ""]) && - strcmp(mutable.items, str) == 0) + (mutableData = [OFMutableData dataWithItems: "Hello!" count: 6]) && + R([mutableData addItem: ""]) && + strcmp(mutableData.items, "Hello!") == 0) EXPECT_EXCEPTION(@"Detect out of range in -[itemAtIndex:]", - OFOutOfRangeException, [mutable itemAtIndex: mutable.count]) + OFOutOfRangeException, [mutableData itemAtIndex: mutableData.count]) EXPECT_EXCEPTION(@"Detect out of range in -[addItems:count:]", - OFOutOfRangeException, [mutable addItems: raw[0] count: SIZE_MAX]) + OFOutOfRangeException, + [mutableData addItems: raw[0] count: SIZE_MAX]) EXPECT_EXCEPTION(@"Detect out of range in -[removeItemsInRange:]", OFOutOfRangeException, - [mutable removeItemsInRange: OFRangeMake(mutable.count, 1)]) + [mutableData removeItemsInRange: OFRangeMake(mutableData.count, 1)]) OFFreeMemory(raw[0]); OFFreeMemory(raw[1]); objc_autoreleasePoolPop(pool); } @end Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -16,18 +16,19 @@ #include "config.h" #include #import "TestsAppDelegate.h" +#import "OFStrPTime.h" -static OFString *module = @"OFDate"; +static OFString *const module = @"OFDate"; @implementation TestsAppDelegate (OFDateTests) - (void)dateTests { void *pool = objc_autoreleasePoolPush(); - OFDate *d1, *d2; + OFDate *date1, *date2; struct tm tm; int16_t tz; const char *dstr = "Wed, 09 Jun 2021 +0200x"; TEST(@"OFStrPTime()", @@ -34,18 +35,18 @@ OFStrPTime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && tm.tm_wday == 3 && tm.tm_mday == 9 && tm.tm_mon == 5 && tm.tm_year == 2021 - 1900 && tz == 2 * 60) TEST(@"+[dateWithTimeIntervalSince1970:]", - (d1 = [OFDate dateWithTimeIntervalSince1970: 0])) + (date1 = [OFDate dateWithTimeIntervalSince1970: 0])) TEST(@"-[dateByAddingTimeInterval:]", - (d2 = [d1 dateByAddingTimeInterval: 3600 * 25 + 5.000002])) + (date2 = [date1 dateByAddingTimeInterval: 3600 * 25 + 5.000002])) TEST(@"-[description]", - [d1.description isEqual: @"1970-01-01T00:00:00Z"] && - [d2.description isEqual: @"1970-01-02T01:00:05Z"]) + [date1.description isEqual: @"1970-01-01T00:00:00Z"] && + [date2.description isEqual: @"1970-01-02T01:00:05Z"]) TEST(@"+[dateWithDateString:format:]", [[[OFDate dateWithDateString: @"2000-06-20T12:34:56+0200" format: @"%Y-%m-%dT%H:%M:%S%z"] description] isEqual: @"2000-06-20T10:34:56Z"]); @@ -75,35 +76,37 @@ @"+[dateWithLocalDateString:format:] #2", OFInvalidFormatException, [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56+0200x" format: @"%Y-%m-%dT%H:%M:%S%z"]) TEST(@"-[isEqual:]", - [d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && - ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) - - TEST(@"-[compare:]", [d1 compare: d2] == OFOrderedAscending) - - TEST(@"-[second]", d1.second == 0 && d2.second == 5) - - TEST(@"-[microsecond]", d1.microsecond == 0 && d2.microsecond == 2) - - TEST(@"-[minute]", d1.minute == 0 && d2.minute == 0) - - TEST(@"-[hour]", d1.hour == 0 && d2.hour == 1) - - TEST(@"-[dayOfMonth]", d1.dayOfMonth == 1 && d2.dayOfMonth == 2) - - TEST(@"-[monthOfYear]", d1.monthOfYear == 1 && d2.monthOfYear == 1) - - TEST(@"-[year]", d1.year == 1970 && d2.year == 1970) - - TEST(@"-[dayOfWeek]", d1.dayOfWeek == 4 && d2.dayOfWeek == 5) - - TEST(@"-[dayOfYear]", d1.dayOfYear == 1 && d2.dayOfYear == 2) - - TEST(@"-[earlierDate:]", [[d1 earlierDate: d2] isEqual: d1]) - - TEST(@"-[laterDate:]", [[d1 laterDate: d2] isEqual: d2]) + [date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && + ![date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) + + TEST(@"-[compare:]", [date1 compare: date2] == OFOrderedAscending) + + TEST(@"-[second]", date1.second == 0 && date2.second == 5) + + TEST(@"-[microsecond]", + date1.microsecond == 0 && date2.microsecond == 2) + + TEST(@"-[minute]", date1.minute == 0 && date2.minute == 0) + + TEST(@"-[hour]", date1.hour == 0 && date2.hour == 1) + + TEST(@"-[dayOfMonth]", date1.dayOfMonth == 1 && date2.dayOfMonth == 2) + + TEST(@"-[monthOfYear]", + date1.monthOfYear == 1 && date2.monthOfYear == 1) + + TEST(@"-[year]", date1.year == 1970 && date2.year == 1970) + + TEST(@"-[dayOfWeek]", date1.dayOfWeek == 4 && date2.dayOfWeek == 5) + + TEST(@"-[dayOfYear]", date1.dayOfYear == 1 && date2.dayOfYear == 2) + + TEST(@"-[earlierDate:]", [[date1 earlierDate: date2] isEqual: date1]) + + TEST(@"-[laterDate:]", [[date1 laterDate: date2] isEqual: date2]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = nil; +static OFString *module; static OFString *keys[] = { @"key1", @"key2" }; static OFString *values[] = { @@ -102,11 +102,11 @@ return [_dictionary objectForKey: key]; } - (size_t)count { - return [_dictionary count]; + return _dictionary.count; } - (OFEnumerator *)keyEnumerator { return [_dictionary keyEnumerator]; @@ -157,100 +157,101 @@ @implementation TestsAppDelegate (OFDictionaryTests) - (void)dictionaryTestsWithClass: (Class)dictionaryClass mutableClass: (Class)mutableDictionaryClass { void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *mutDict = [mutableDictionaryClass dictionary]; + OFMutableDictionary *mutableDict = [mutableDictionaryClass dictionary]; OFDictionary *dict; OFEnumerator *keyEnumerator, *objectEnumerator; OFArray *keysArray, *valuesArray; - [mutDict setObject: values[0] forKey: keys[0]]; - [mutDict setValue: values[1] forKey: keys[1]]; + [mutableDict setObject: values[0] forKey: keys[0]]; + [mutableDict setValue: values[1] forKey: keys[1]]; TEST(@"-[objectForKey:]", - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutDict objectForKey: keys[1]] isEqual: values[1]] && - [mutDict objectForKey: @"key3"] == nil) + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && + [mutableDict objectForKey: @"key3"] == nil) TEST(@"-[valueForKey:]", - [[mutDict valueForKey: keys[0]] isEqual: values[0]] && - [[mutDict valueForKey: @"@count"] isEqual: + [[mutableDict valueForKey: keys[0]] isEqual: values[0]] && + [[mutableDict valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) EXPECT_EXCEPTION(@"Catching -[setValue:forKey:] on immutable " @"dictionary", OFUndefinedKeyException, [[dictionaryClass dictionary] setValue: @"x" forKey: @"x"]) TEST(@"-[containsObject:]", - [mutDict containsObject: values[0]] && - ![mutDict containsObject: @"nonexistent"]) + [mutableDict containsObject: values[0]] && + ![mutableDict containsObject: @"nonexistent"]) TEST(@"-[containsObjectIdenticalTo:]", - [mutDict containsObjectIdenticalTo: values[0]] && - ![mutDict containsObjectIdenticalTo: + [mutableDict containsObjectIdenticalTo: values[0]] && + ![mutableDict containsObjectIdenticalTo: [OFString stringWithString: values[0]]]) TEST(@"-[description]", - [[mutDict description] isEqual: + [[mutableDict description] isEqual: @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"]) TEST(@"-[allKeys]", - [[mutDict allKeys] isEqual: [OFArray arrayWithObjects: keys[0], - keys[1], nil]]) + [[mutableDict allKeys] isEqual: + [OFArray arrayWithObjects: keys[0], keys[1], nil]]) TEST(@"-[allObjects]", - [[mutDict allObjects] isEqual: [OFArray arrayWithObjects: values[0], - values[1], nil]]) + [[mutableDict allObjects] isEqual: + [OFArray arrayWithObjects: values[0], values[1], nil]]) - TEST(@"-[keyEnumerator]", (keyEnumerator = [mutDict keyEnumerator])) + TEST(@"-[keyEnumerator]", (keyEnumerator = [mutableDict keyEnumerator])) TEST(@"-[objectEnumerator]", - (objectEnumerator = [mutDict objectEnumerator])) + (objectEnumerator = [mutableDict objectEnumerator])) TEST(@"OFEnumerator's -[nextObject]", [[keyEnumerator nextObject] isEqual: keys[0]] && [[objectEnumerator nextObject] isEqual: values[0]] && [[keyEnumerator nextObject] isEqual: keys[1]] && [[objectEnumerator nextObject] isEqual: values[1]] && [keyEnumerator nextObject] == nil && [objectEnumerator nextObject] == nil) - [mutDict removeObjectForKey: keys[0]]; + [mutableDict removeObjectForKey: keys[0]]; EXPECT_EXCEPTION(@"Detection of mutation during enumeration", OFEnumerationMutationException, [keyEnumerator nextObject]); - [mutDict setObject: values[0] forKey: keys[0]]; + [mutableDict setObject: values[0] forKey: keys[0]]; size_t i = 0; bool ok = true; - for (OFString *key in mutDict) { + for (OFString *key in mutableDict) { if (i > 1 || ![key isEqual: keys[i]]) { ok = false; break; } - [mutDict setObject: [mutDict objectForKey: key] forKey: key]; + [mutableDict setObject: [mutableDict objectForKey: key] + forKey: key]; i++; } TEST(@"Fast Enumeration", ok) ok = false; @try { - for (OFString *key in mutDict) { + for (OFString *key in mutableDict) { (void)key; - [mutDict setObject: @"" forKey: @""]; + [mutableDict setObject: @"" forKey: @""]; } } @catch (OFEnumerationMutationException *e) { ok = true; } TEST(@"Detection of mutation during Fast Enumeration", ok) - [mutDict removeObjectForKey: @""]; + [mutableDict removeObjectForKey: @""]; TEST(@"-[stringByURLEncoding]", [[[OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar", @"q&x", @"q=x", nil] stringByURLEncoding] isEqual: @"q%26x=q%3Dx&foo=bar"]) @@ -258,71 +259,71 @@ #ifdef OF_HAVE_BLOCKS { __block size_t j = 0; __block bool blockOk = true; - [mutDict enumerateKeysAndObjectsUsingBlock: + [mutableDict enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { if (j > 1 || ![key isEqual: keys[j]]) { blockOk = false; *stop = true; return; } - [mutDict setObject: [mutDict objectForKey: key] - forKey: key]; + [mutableDict setObject: [mutableDict objectForKey: key] + forKey: key]; j++; }]; TEST(@"Enumeration using blocks", blockOk) blockOk = false; @try { - [mutDict enumerateKeysAndObjectsUsingBlock: + [mutableDict enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { - [mutDict setObject: @"" - forKey: @""]; + [mutableDict setObject: @"" forKey: @""]; }]; } @catch (OFEnumerationMutationException *e) { blockOk = true; } TEST(@"Detection of mutation during enumeration using blocks", blockOk) - [mutDict removeObjectForKey: @""]; + [mutableDict removeObjectForKey: @""]; } TEST(@"-[replaceObjectsUsingBlock:]", - R([mutDict replaceObjectsUsingBlock: ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"value_1"; - if ([key isEqual: keys[1]]) - return @"value_2"; - - return nil; - }]) && [[mutDict objectForKey: keys[0]] isEqual: @"value_1"] && - [[mutDict objectForKey: keys[1]] isEqual: @"value_2"]) + R([mutableDict replaceObjectsUsingBlock: ^ id (id key, id object) { + if ([key isEqual: keys[0]]) + return @"value_1"; + if ([key isEqual: keys[1]]) + return @"value_2"; + + return nil; + }]) && [[mutableDict objectForKey: keys[0]] isEqual: @"value_1"] && + [[mutableDict objectForKey: keys[1]] isEqual: @"value_2"]) TEST(@"-[mappedDictionaryUsingBlock:]", - [[[mutDict mappedDictionaryUsingBlock: ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"val1"; - if ([key isEqual: keys[1]]) - return @"val2"; + [[[mutableDict mappedDictionaryUsingBlock: + ^ id (id key, id object) { + if ([key isEqual: keys[0]]) + return @"val1"; + if ([key isEqual: keys[1]]) + return @"val2"; return nil; }] description] isEqual: @"{\n\tkey1 = val1;\n\tkey2 = val2;\n}"]) TEST(@"-[filteredDictionaryUsingBlock:]", - [[[mutDict filteredDictionaryUsingBlock: - ^ bool (id key, id object) { - return [key isEqual: keys[0]]; + [[[mutableDict filteredDictionaryUsingBlock: + ^ bool (id key, id object) { + return [key isEqual: keys[0]]; }] description] isEqual: @"{\n\tkey1 = value_1;\n}"]) #endif - TEST(@"-[count]", mutDict.count == 2) + TEST(@"-[count]", mutableDict.count == 2) TEST(@"+[dictionaryWithKeysAndObjects:]", (dict = [dictionaryClass dictionaryWithKeysAndObjects: @"foo", @"bar", @"baz", @"qux", nil]) && [[dict objectForKey: @"foo"] isEqual: @"bar"] && @@ -345,30 +346,30 @@ (dict = [[dict copy] autorelease]) && [[dict objectForKey: keys[0]] isEqual: values[0]] && [[dict objectForKey: keys[1]] isEqual: values[1]]) TEST(@"-[mutableCopy]", - (mutDict = [[dict mutableCopy] autorelease]) && - mutDict.count == dict.count && - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutDict objectForKey: keys[1]] isEqual: values[1]] && - R([mutDict setObject: @"value3" forKey: @"key3"]) && - [[mutDict objectForKey: @"key3"] isEqual: @"value3"] && - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - R([mutDict setObject: @"foo" forKey: keys[0]]) && - [[mutDict objectForKey: keys[0]] isEqual: @"foo"]) + (mutableDict = [[dict mutableCopy] autorelease]) && + mutableDict.count == dict.count && + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && + R([mutableDict setObject: @"value3" forKey: @"key3"]) && + [[mutableDict objectForKey: @"key3"] isEqual: @"value3"] && + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + R([mutableDict setObject: @"foo" forKey: keys[0]]) && + [[mutableDict objectForKey: keys[0]] isEqual: @"foo"]) TEST(@"-[removeObjectForKey:]", - R([mutDict removeObjectForKey: keys[0]]) && - [mutDict objectForKey: keys[0]] == nil) - - [mutDict setObject: @"foo" forKey: keys[0]]; - TEST(@"-[isEqual:]", ![mutDict isEqual: dict] && - R([mutDict removeObjectForKey: @"key3"]) && - ![mutDict isEqual: dict] && - R([mutDict setObject: values[0] forKey: keys[0]]) && - [mutDict isEqual: dict]) + R([mutableDict removeObjectForKey: keys[0]]) && + [mutableDict objectForKey: keys[0]] == nil) + + [mutableDict setObject: @"foo" forKey: keys[0]]; + TEST(@"-[isEqual:]", ![mutableDict isEqual: dict] && + R([mutableDict removeObjectForKey: @"key3"]) && + ![mutableDict isEqual: dict] && + R([mutableDict setObject: values[0] forKey: keys[0]]) && + [mutableDict isEqual: dict]) objc_autoreleasePoolPop(pool); } - (void)dictionaryTests Index: tests/OFHMACTests.m ================================================================== --- tests/OFHMACTests.m +++ tests/OFHMACTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,109 +17,115 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFHMAC"; +static OFString *const module = @"OFHMAC"; static const uint8_t key[] = "yM9h8K6IWnJRvxC/0F8XRWG7RnACDBz8wqK2tbXrYVLoKC3vPLeJikyJSM47tVHc" "DlXHww9zULAC2sJUlm2Kg1z4oz2aXY3Y1PQSB4VkC/m0DQ7hCI6cAg4TWnKdzWTy" "cvYGX+Y6HWeDY79/PGSd8fNItme6I8w4HDBqU7BP2sum3jbePJqoiSnhcyJZQTeZ" "jw0ZXoyrfHgOYD2M+NsTDaGpLblFtQ7n5CczjKtafG40PkEwx1dcrd46U9i3GyTK"; -static const size_t key_length = sizeof(key); -static const uint8_t digest_md5[] = +static const size_t keyLength = sizeof(key); +static const uint8_t MD5Digest[] = "\xCC\x1F\xEF\x09\x29\xA3\x25\x1A\x06\xA9\x83\x99\xF9\xBC\x8F\x42"; -static const uint8_t digest_sha1[] = +static const uint8_t SHA1Digest[] = "\x94\xB9\x0A\x6F\xFB\xA7\x13\x6A\x75\x55" "\xD5\x7F\x5D\xB7\xF4\xCA\xEB\x4A\xDE\xBF"; -static const uint8_t digest_rmd160[] = +static const uint8_t RIPEMD160Digest[] = "\x2C\xE1\xED\x41\xC6\xF3\x51\xA8\x04\xD2" "\xC3\x9B\x08\x33\x3B\xD5\xC9\x00\x39\x50"; -static const uint8_t digest_sha256[] = +static const uint8_t SHA256Digest[] = "\xFB\x8C\xDA\x88\xB3\x81\x32\x16\xD7\xD8\x62\xD4\xA6\x26\x9D\x77" "\x01\x99\x62\x65\x29\x02\x41\xE6\xEF\xA1\x02\x31\xA8\x9D\x77\x5D"; -static const uint8_t digest_sha384[] = +static const uint8_t SHA384Digest[] = "\x2F\x4A\x47\xAE\x13\x8E\x96\x52\xF1\x8F\x05\xFD\x65\xCD\x9A\x97" "\x93\x2F\xC9\x02\xD6\xC6\xAB\x2E\x15\x76\xC0\xA7\xA0\x05\xF4\xEF" "\x14\x52\x33\x4B\x9C\x5F\xD8\x07\x4E\x98\xAE\x97\x46\x29\x24\xB4"; -static const uint8_t digest_sha512[] = +static const uint8_t SHA512Digest[] = "\xF5\x8C\x3F\x9C\xA2\x2F\x0A\xF3\x26\xD8\xC0\x7E\x20\x63\x88\x61" "\xC9\xE1\x1F\xD7\xC7\xE5\x59\x33\xD5\x2F\xAF\x56\x1C\x94\xC8\xA4" "\x61\xB3\xF9\x1A\xE3\x09\x43\xA6\x5B\x85\xB1\x50\x5B\xCB\x1A\x2E" "\xB7\xE8\x87\xC1\x73\x19\x63\xF6\xA2\x91\x8D\x7E\x2E\xCC\xEC\x99"; @implementation TestsAppDelegate (OFHMACTests) - (void)HMACTests { void *pool = objc_autoreleasePoolPush(); - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - OFHMAC *HMAC_MD5, *HMAC_SHA1, *HMAC_RMD160; - OFHMAC *HMAC_SHA256, *HMAC_SHA384, *HMAC_SHA512; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; + OFHMAC *HMACMD5, *HMACSHA1, *HMACRMD160; + OFHMAC *HMACSHA256, *HMACSHA384, *HMACSHA512; TEST(@"+[HMACWithHashClass:] with MD5", - (HMAC_MD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] - allowsSwappableMemory: true])) + (HMACMD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-1", - (HMAC_SHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true])) + (HMACSHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with RIPEMD-160", - (HMAC_RMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] - allowsSwappableMemory: true])) + (HMACRMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-256", - (HMAC_SHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: true])) + (HMACSHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-384", - (HMAC_SHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] - allowsSwappableMemory: true])) + (HMACSHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-512", - (HMAC_SHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] - allowsSwappableMemory: true])) + (HMACSHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] + allowsSwappableMemory: true])) EXPECT_EXCEPTION(@"Detection of missing key", - OFInvalidArgumentException, [HMAC_MD5 updateWithBuffer: "" - length: 0]) + OFInvalidArgumentException, + [HMACMD5 updateWithBuffer: "" length: 0]) TEST(@"-[setKey:length:] with MD5", - R([HMAC_MD5 setKey: key length: key_length])) + R([HMACMD5 setKey: key length: keyLength])) TEST(@"-[setKey:length:] with SHA-1", - R([HMAC_SHA1 setKey: key length: key_length])) + R([HMACSHA1 setKey: key length: keyLength])) TEST(@"-[setKey:length:] with RIPEMD-160", - R([HMAC_RMD160 setKey: key length: key_length])) + R([HMACRMD160 setKey: key length: keyLength])) TEST(@"-[setKey:length:] with SHA-256", - R([HMAC_SHA256 setKey: key length: key_length])) + R([HMACSHA256 setKey: key length: keyLength])) TEST(@"-[setKey:length:] with SHA-384", - R([HMAC_SHA384 setKey: key length: key_length])) + R([HMACSHA384 setKey: key length: keyLength])) TEST(@"-[setKey:length:] with SHA-512", - R([HMAC_SHA512 setKey: key length: key_length])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [HMAC_MD5 updateWithBuffer: buf length: len]; - [HMAC_SHA1 updateWithBuffer: buf length: len]; - [HMAC_RMD160 updateWithBuffer: buf length: len]; - [HMAC_SHA256 updateWithBuffer: buf length: len]; - [HMAC_SHA384 updateWithBuffer: buf length: len]; - [HMAC_SHA512 updateWithBuffer: buf length: len]; - } - [f close]; + R([HMACSHA512 setKey: key length: keyLength])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [HMACMD5 updateWithBuffer: buffer length: length]; + [HMACSHA1 updateWithBuffer: buffer length: length]; + [HMACRMD160 updateWithBuffer: buffer length: length]; + [HMACSHA256 updateWithBuffer: buffer length: length]; + [HMACSHA384 updateWithBuffer: buffer length: length]; + [HMACSHA512 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[calculate] with MD5", R([HMACMD5 calculate])) + TEST(@"-[calculate] with SHA-1", R([HMACSHA1 calculate])) + TEST(@"-[calculate] with RIPEMD-160", R([HMACRMD160 calculate])) + TEST(@"-[calculate] with SHA-256", R([HMACSHA256 calculate])) + TEST(@"-[calculate] with SHA-384", R([HMACSHA384 calculate])) + TEST(@"-[calculate] with SHA-512", R([HMACSHA512 calculate])) TEST(@"-[digest] with MD5", - memcmp(HMAC_MD5.digest, digest_md5, HMAC_MD5.digestSize) == 0) + memcmp(HMACMD5.digest, MD5Digest, HMACMD5.digestSize) == 0) TEST(@"-[digest] with SHA-1", - memcmp(HMAC_SHA1.digest, digest_sha1, HMAC_SHA1.digestSize) == 0) + memcmp(HMACSHA1.digest, SHA1Digest, HMACSHA1.digestSize) == 0) TEST(@"-[digest] with RIPEMD-160", - memcmp(HMAC_RMD160.digest, digest_rmd160, - HMAC_RMD160.digestSize) == 0) + memcmp(HMACRMD160.digest, RIPEMD160Digest, + HMACRMD160.digestSize) == 0) TEST(@"-[digest] with SHA-256", - memcmp(HMAC_SHA256.digest, digest_sha256, - HMAC_SHA256.digestSize) == 0) + memcmp(HMACSHA256.digest, SHA256Digest, HMACSHA256.digestSize) == 0) TEST(@"-[digest] with SHA-384", - memcmp(HMAC_SHA384.digest, digest_sha384, - HMAC_SHA384.digestSize) == 0) + memcmp(HMACSHA384.digest, SHA384Digest, HMACSHA384.digestSize) == 0) TEST(@"-[digest] with SHA-512", - memcmp(HMAC_SHA512.digest, digest_sha512, - HMAC_SHA512.digestSize) == 0) + memcmp(HMACSHA512.digest, SHA512Digest, HMACSHA512.digestSize) == 0) objc_autoreleasePoolPop(pool); } @end Index: tests/OFHTTPClientTests.m ================================================================== --- tests/OFHTTPClientTests.m +++ tests/OFHTTPClientTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -18,12 +18,12 @@ #include #include #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPClient"; -static OFCondition *cond; +static OFString *const module = @"OFHTTPClient"; +static OFCondition *condition; static OFHTTPResponse *response = nil; @interface TestsAppDelegate (HTTPClientTests) @end @@ -38,44 +38,35 @@ - (id)main { OFTCPSocket *listener, *client; char buffer[5]; - [cond lock]; + [condition lock]; listener = [OFTCPSocket socket]; _port = [listener bindToHost: @"127.0.0.1" port: 0]; [listener listen]; - [cond signal]; - [cond unlock]; + [condition signal]; + [condition unlock]; client = [listener accept]; - if (![[client readLine] isEqual: @"GET /foo HTTP/1.1"]) - OFEnsure(0); - - if (![[client readLine] hasPrefix: @"User-Agent:"]) - OFEnsure(0); - - if (![[client readLine] isEqual: @"Content-Length: 5"]) - OFEnsure(0); - - if (![[client readLine] isEqual: - @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]) - OFEnsure(0); + OFEnsure([[client readLine] isEqual: @"GET /foo HTTP/1.1"]); + OFEnsure([[client readLine] hasPrefix: @"User-Agent:"]); + OFEnsure([[client readLine] isEqual: @"Content-Length: 5"]); + OFEnsure([[client readLine] isEqual: + @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]); if (![[client readLine] isEqual: [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, _port]]) OFEnsure(0); - if (![[client readLine] isEqual: @""]) - OFEnsure(0); + OFEnsure([[client readLine] isEqual: @""]); [client readIntoBuffer: buffer exactLength: 5]; - if (memcmp(buffer, "Hello", 5) != 0) - OFEnsure(0); + OFEnsure(memcmp(buffer, "Hello", 5) == 0); [client writeString: @"HTTP/1.0 200 OK\r\n" @"cONTeNT-lENgTH: 7\r\n" @"\r\n" @"foo\n" @@ -113,19 +104,19 @@ OFURL *URL; OFHTTPClient *client; OFHTTPRequest *request; OFData *data; - cond = [OFCondition condition]; - [cond lock]; + condition = [OFCondition condition]; + [condition lock]; server = [[[HTTPClientTestsServer alloc] init] autorelease]; server.supportsSockets = true; [server start]; - [cond wait]; - [cond unlock]; + [condition wait]; + [condition unlock]; URL = [OFURL URLWithString: [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo", server->_port]]; Index: tests/OFHTTPCookieManagerTests.m ================================================================== --- tests/OFHTTPCookieManagerTests.m +++ tests/OFHTTPCookieManagerTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,89 +15,89 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPCookieManager"; +static OFString *const module = @"OFHTTPCookieManager"; @implementation TestsAppDelegate (OFHTTPCookieManagerTests) - (void)HTTPCookieManagerTests { void *pool = objc_autoreleasePoolPush(); OFHTTPCookieManager *manager = [OFHTTPCookieManager manager]; - OFURL *URL[4]; - OFHTTPCookie *cookie[5]; - - URL[0] = [OFURL URLWithString: @"http://nil.im/foo"]; - URL[1] = [OFURL URLWithString: @"https://nil.im/foo/bar"]; - URL[2] = [OFURL URLWithString: @"https://test.nil.im/foo/bar"]; - URL[3] = [OFURL URLWithString: @"http://webkeks.org/foo/bar"]; - - cookie[0] = [OFHTTPCookie cookieWithName: @"test" - value: @"1" - domain: @"nil.im"]; - TEST(@"-[addCookie:forURL:] #1", R([manager addCookie: cookie[0] - forURL: URL[0]])) + OFURL *URL1, *URL2, *URL3, *URL4; + OFHTTPCookie *cookie1, *cookie2, *cookie3, *cookie4, *cookie5; + + URL1 = [OFURL URLWithString: @"http://nil.im/foo"]; + URL2 = [OFURL URLWithString: @"https://nil.im/foo/bar"]; + URL3 = [OFURL URLWithString: @"https://test.nil.im/foo/bar"]; + URL4 = [OFURL URLWithString: @"http://webkeks.org/foo/bar"]; + + cookie1 = [OFHTTPCookie cookieWithName: @"test" + value: @"1" + domain: @"nil.im"]; + TEST(@"-[addCookie:forURL:] #1", + R([manager addCookie: cookie1 forURL: URL1])) TEST(@"-[cookiesForURL:] #1", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[0]]]) + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie1]]) - cookie[1] = [OFHTTPCookie cookieWithName: @"test" - value: @"2" - domain: @"webkeks.org"]; + cookie2 = [OFHTTPCookie cookieWithName: @"test" + value: @"2" + domain: @"webkeks.org"]; TEST(@"-[addCookie:forURL:] #2", - R([manager addCookie: cookie[1] forURL: URL[0]])) + R([manager addCookie: cookie2 forURL: URL1])) TEST(@"-[cookiesForURL:] #2", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[0]]] && - [[manager cookiesForURL: URL[3]] isEqual: [OFArray array]]) - - cookie[2] = [OFHTTPCookie cookieWithName: @"test" - value: @"3" - domain: @"nil.im"]; - cookie[2].secure = true; + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie1]] && + [[manager cookiesForURL: URL4] isEqual: [OFArray array]]) + + cookie3 = [OFHTTPCookie cookieWithName: @"test" + value: @"3" + domain: @"nil.im"]; + cookie3.secure = true; TEST(@"-[addCookie:forURL:] #3", - R([manager addCookie: cookie[2] forURL: URL[1]])) + R([manager addCookie: cookie3 forURL: URL2])) TEST(@"-[cookiesForURL:] #3", - [[manager cookiesForURL: URL[1]] isEqual: - [OFArray arrayWithObject: cookie[2]]] && - [[manager cookiesForURL: URL[0]] isEqual: [OFArray array]]) - - cookie[2].expires = [OFDate dateWithTimeIntervalSinceNow: -1]; - cookie[3] = [OFHTTPCookie cookieWithName: @"test" - value: @"4" - domain: @"nil.im"]; - cookie[3].domain = @".nil.im"; + [[manager cookiesForURL: URL2] isEqual: + [OFArray arrayWithObject: cookie3]] && + [[manager cookiesForURL: URL1] isEqual: [OFArray array]]) + + cookie3.expires = [OFDate dateWithTimeIntervalSinceNow: -1]; + cookie4 = [OFHTTPCookie cookieWithName: @"test" + value: @"4" + domain: @"nil.im"]; + cookie4.domain = @".nil.im"; TEST(@"-[addCookie:forURL:] #4", - R([manager addCookie: cookie[3] forURL: URL[1]])) + R([manager addCookie: cookie4 forURL: URL2])) TEST(@"-[cookiesForURL:] #4", - [[manager cookiesForURL: URL[1]] isEqual: - [OFArray arrayWithObject: cookie[3]]] && - [[manager cookiesForURL: URL[2]] isEqual: - [OFArray arrayWithObject: cookie[3]]]) - - cookie[4] = [OFHTTPCookie cookieWithName: @"bar" - value: @"5" - domain: @"test.nil.im"]; - TEST(@"-[addCookie:forURL:] #5", - R([manager addCookie: cookie[4] forURL: URL[0]])) + [[manager cookiesForURL: URL2] isEqual: + [OFArray arrayWithObject: cookie4]] && + [[manager cookiesForURL: URL3] isEqual: + [OFArray arrayWithObject: cookie4]]) + + cookie5 = [OFHTTPCookie cookieWithName: @"bar" + value: @"5" + domain: @"test.nil.im"]; + TEST(@"-[addCookie:forURL:] #5", + R([manager addCookie: cookie5 forURL: URL1])) TEST(@"-[cookiesForURL:] #5", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[3]]] && - [[manager cookiesForURL: URL[2]] isEqual: - [OFArray arrayWithObjects: cookie[3], cookie[4], nil]]) + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie4]] && + [[manager cookiesForURL: URL3] isEqual: + [OFArray arrayWithObjects: cookie4, cookie5, nil]]) TEST(@"-[purgeExpiredCookies]", [manager.cookies isEqual: - [OFArray arrayWithObjects: cookie[2], cookie[3], cookie[4], nil]] && + [OFArray arrayWithObjects: cookie3, cookie4, cookie5, nil]] && R([manager purgeExpiredCookies]) && [manager.cookies isEqual: - [OFArray arrayWithObjects: cookie[3], cookie[4], nil]]) + [OFArray arrayWithObjects: cookie4, cookie5, nil]]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFHTTPCookieTests.m ================================================================== --- tests/OFHTTPCookieTests.m +++ tests/OFHTTPCookieTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,59 +15,59 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPCookie"; +static OFString *const module = @"OFHTTPCookie"; @implementation TestsAppDelegate (OFHTTPCookieTests) - (void)HTTPCookieTests { void *pool = objc_autoreleasePoolPush(); OFURL *URL = [OFURL URLWithString: @"http://nil.im"]; - OFHTTPCookie *cookie[2]; + OFHTTPCookie *cookie1, *cookie2; OFArray OF_GENERIC(OFHTTPCookie *) *cookies; - cookie[0] = [OFHTTPCookie cookieWithName: @"foo" - value: @"bar" - domain: @"nil.im"]; + cookie1 = [OFHTTPCookie cookieWithName: @"foo" + value: @"bar" + domain: @"nil.im"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #1", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar" forKey: @"Set-Cookie"] forURL: URL] - isEqual: [OFArray arrayWithObject: cookie[0]]]) + isEqual: [OFArray arrayWithObject: cookie1]]) - cookie[1] = [OFHTTPCookie cookieWithName: @"qux" - value: @"cookie" - domain: @"nil.im"]; + cookie2 = [OFHTTPCookie cookieWithName: @"qux" + value: @"cookie" + domain: @"nil.im"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #2", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar,qux=cookie" forKey: @"Set-Cookie"] forURL: URL] - isEqual: [OFArray arrayWithObjects: cookie[0], cookie[1], nil]]) - - cookie[0].expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; - cookie[1].expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; - cookie[0].path = @"/x"; - cookie[1].domain = @"webkeks.org"; - cookie[1].path = @"/objfw"; - cookie[1].secure = true; - cookie[1].HTTPOnly = true; - [cookie[1].extensions addObject: @"foo"]; - [cookie[1].extensions addObject: @"bar"]; + isEqual: [OFArray arrayWithObjects: cookie1, cookie2, nil]]) + + cookie1.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; + cookie2.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; + cookie1.path = @"/x"; + cookie2.domain = @"webkeks.org"; + cookie2.path = @"/objfw"; + cookie2.secure = true; + cookie2.HTTPOnly = true; + [cookie2.extensions addObject: @"foo"]; + [cookie2.extensions addObject: @"bar"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #3", [(cookies = [OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar; Expires=Fri, 13 Feb 2009 23:31:30 GMT; Path=/x," @"qux=cookie; Expires=Fri, 13 Feb 2009 23:31:30 GMT; " @"Domain=webkeks.org; Path=/objfw; Secure; HTTPOnly; foo; bar" forKey: @"Set-Cookie"] forURL: URL]) isEqual: - [OFArray arrayWithObjects: cookie[0], cookie[1], nil]]) + [OFArray arrayWithObjects: cookie1, cookie2, nil]]) TEST(@"+[requestHeaderFieldsWithCookies:]", [[OFHTTPCookie requestHeaderFieldsWithCookies: cookies] isEqual: [OFDictionary dictionaryWithObject: @"foo=bar; qux=cookie" forKey: @"Cookie"]]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFINIFileTests.m ================================================================== --- tests/OFINIFileTests.m +++ tests/OFINIFileTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFINIFile"; +static OFString *module; @implementation TestsAppDelegate (OFINIFileTests) - (void)INIFileTests { void *pool = objc_autoreleasePoolPush(); @@ -41,20 +41,24 @@ @"bool=false\r\n" @"float=0.25\r\n" @"array1=foo\r\n" @"array1=bar\r\n" @"double=0.75\r\n"; + OFURL *URL; OFINIFile *file; OFINICategory *tests, *foobar, *types; OFArray *array; -#ifndef OF_NINTENDO_DS - OFString *writePath; +#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) + OFURL *writeURL; #endif - TEST(@"+[fileWithPath:encoding:]", - (file = [OFINIFile fileWithPath: @"testfile.ini" - encoding: OFStringEncodingCodepage437])) + module = @"OFINIFile"; + + URL = [OFURL URLWithString: @"objfw-embedded:///testfile.ini"]; + TEST(@"+[fileWithURL:encoding:]", + (file = [OFINIFile fileWithURL: URL + encoding: OFStringEncodingCodepage437])) tests = [file categoryForName: @"tests"]; foobar = [file categoryForName: @"foobar"]; types = [file categoryForName: @"types"]; TEST(@"-[categoryForName:]", @@ -109,28 +113,23 @@ R([types removeValueForKey: @"array2"])) module = @"OFINIFile"; /* FIXME: Find a way to write files on Nintendo DS */ -#ifndef OF_NINTENDO_DS -# ifndef OF_IOS - writePath = @"tmpfile.ini"; -# else - writePath = [OFString pathWithComponents: [OFArray arrayWithObjects: - [[OFApplication environment] objectForKey: @"HOME"], - @"tmp", @"tmpfile.ini", nil]]; -# endif +#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) + writeURL = [[OFSystemInfo temporaryDirectoryURL] + URLByAppendingPathComponent: @"objfw-tests.ini" + isDirectory: false]; TEST(@"-[writeToFile:encoding:]", - R([file writeToFile: writePath - encoding: OFStringEncodingCodepage437]) && - [[OFString - stringWithContentsOfFile: writePath - encoding: OFStringEncodingCodepage437] + R([file writeToURL: writeURL + encoding: OFStringEncodingCodepage437]) && + [[OFString stringWithContentsOfURL: writeURL + encoding: OFStringEncodingCodepage437] isEqual: output]) - [[OFFileManager defaultManager] removeItemAtPath: writePath]; + [[OFFileManager defaultManager] removeItemAtURL: writeURL]; #else (void)output; #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFIPXSocketTests.m ================================================================== --- tests/OFIPXSocketTests.m +++ tests/OFIPXSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFIPXSocket"; +static OFString *const module = @"OFIPXSocket"; @implementation TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests { void *pool = objc_autoreleasePoolPush(); Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -22,22 +22,22 @@ # include #endif #import "TestsAppDelegate.h" -static OFString *module = @"OFInvocation"; +static OFString *const module = @"OFInvocation"; -struct test_struct { +struct TestStruct { unsigned char c; unsigned int i; }; @implementation TestsAppDelegate (OFInvocationTests) -- (struct test_struct)invocationTestMethod1: (unsigned char)c - : (unsigned int)i - : (struct test_struct *)ptr - : (struct test_struct)st +- (struct TestStruct)invocationTestMethod1: (unsigned char)c + : (unsigned int)i + : (struct TestStruct *)ptr + : (struct TestStruct)st { return st; } #ifdef OF_INVOCATION_CAN_INVOKE @@ -257,11 +257,11 @@ { void *pool = objc_autoreleasePoolPush(); SEL selector = @selector(invocationTestMethod1::::); OFMethodSignature *sig = [self methodSignatureForSelector: selector]; OFInvocation *invocation; - struct test_struct st, st2, *stp = &st, *stp2; + struct TestStruct st, st2, *stp = &st, *stp2; unsigned const char c = 0xAA; unsigned char c2; const unsigned int i = 0x55555555; unsigned int i2; Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,42 +15,46 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFJSON"; +static OFString *const module = @"OFJSON"; @implementation TestsAppDelegate (JSONTests) - (void)JSONTests { void *pool = objc_autoreleasePoolPush(); - OFString *s = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF,null" - @"//bar\n,\"foo\",false]}"; - OFDictionary *d = [OFDictionary dictionaryWithKeysAndObjects: + OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," + @"null//bar\n,\"foo\",false]}"; + OFDictionary *dict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"b\na\r", @"x", [OFArray arrayWithObjects: - [OFNumber numberWithFloat: .5f], - [OFNumber numberWithInt: 0xF], - [OFNull null], - @"foo", - [OFNumber numberWithBool: false], - nil], + [OFNumber numberWithFloat: .5f], + [OFNumber numberWithInt: 0xF], + [OFNull null], + @"foo", + [OFNumber numberWithBool: false], + nil], nil]; - TEST(@"-[objectByParsingJSON] #1", [s.objectByParsingJSON isEqual: d]) + TEST(@"-[objectByParsingJSON] #1", + [string.objectByParsingJSON isEqual: dict]) - TEST(@"-[JSONRepresentation]", [[d JSONRepresentation] isEqual: + TEST(@"-[JSONRepresentation]", + [[dict JSONRepresentation] isEqual: @"{\"x\":[0.5,15,null,\"foo\",false],\"foo\":\"b\\na\\r\"}"]) TEST(@"OFJSONRepresentationOptionPretty", - [[d JSONRepresentationWithOptions: OFJSONRepresentationOptionPretty] - isEqual: @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" - @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"]) + [[dict JSONRepresentationWithOptions: + OFJSONRepresentationOptionPretty] isEqual: + @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" + @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"]) TEST(@"OFJSONRepresentationOptionJSON5", - [[d JSONRepresentationWithOptions: OFJSONRepresentationOptionJSON5] - isEqual: @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) + [[dict JSONRepresentationWithOptions: + OFJSONRepresentationOptionJSON5] isEqual: + @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) EXPECT_EXCEPTION(@"-[objectByParsingJSON] #2", OFInvalidJSONException, [@"{" objectByParsingJSON]) EXPECT_EXCEPTION(@"-[objectByParsingJSON] #3", OFInvalidJSONException, [@"]" objectByParsingJSON]) Index: tests/OFKernelEventObserverTests.m ================================================================== --- tests/OFKernelEventObserverTests.m +++ tests/OFKernelEventObserverTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -28,11 +28,11 @@ # import "OFSelectKernelEventObserver.h" #endif #import "TestsAppDelegate.h" -#define EXPECTED_EVENTS 3 +static const size_t numExpectedEvents = 3; static OFString *module; @interface ObserverTest: OFObject { @@ -88,11 +88,11 @@ [_testsAppDelegate outputTesting: @"-[observe] with listening socket" inModule: module]; deadline = [OFDate dateWithTimeIntervalSinceNow: 1]; - while (_events < EXPECTED_EVENTS) { + while (_events < numExpectedEvents) { if (deadline.timeIntervalSinceNow < 0) { deadlineExceeded = true; break; } @@ -108,11 +108,11 @@ outputFailure: @"-[observe] not exceeding deadline" inModule: module]; _fails++; } - if (_events == EXPECTED_EVENTS) + if (_events == numExpectedEvents) [_testsAppDelegate outputSuccess: @"-[observe] handling all events" inModule: module]; else { [_testsAppDelegate @@ -122,11 +122,11 @@ } } - (void)objectIsReadyForReading: (id)object { - char buf; + char buffer; switch (_events++) { case 0: if (object == _server) [_testsAppDelegate @@ -147,11 +147,12 @@ inModule: module]; break; case 1: if (object == _accepted && - [object readIntoBuffer: &buf length: 1] == 1 && buf == '0') + [object readIntoBuffer: &buffer length: 1] == 1 && + buffer == '0') [_testsAppDelegate outputSuccess: @"-[observe] with data ready to read" inModule: module]; else { [_testsAppDelegate @@ -167,11 +168,11 @@ inModule: module]; break; case 2: if (object == _accepted && - [object readIntoBuffer: &buf length: 1] == 0) + [object readIntoBuffer: &buffer length: 1] == 0) [_testsAppDelegate outputSuccess: @"-[observe] with closed connection" inModule: module]; else { [_testsAppDelegate Index: tests/OFListTests.m ================================================================== --- tests/OFListTests.m +++ tests/OFListTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFList"; +static OFString *const module = @"OFList"; static OFString *strings[] = { @"Foo", @"Bar", @"Baz" }; @@ -29,11 +29,11 @@ { void *pool = objc_autoreleasePoolPush(); OFList *list; OFEnumerator *enumerator; OFListItem iter; - OFString *obj; + OFString *object; size_t i; bool ok; TEST(@"+[list]", (list = [OFList list])) @@ -95,12 +95,12 @@ TEST(@"-[objectEnumerator]", (enumerator = [list objectEnumerator])) iter = list.firstListItem; i = 0; ok = true; - while ((obj = [enumerator nextObject]) != nil) { - if (![obj isEqual: OFListItemObject(iter)]) + while ((object = [enumerator nextObject]) != nil) { + if (![object isEqual: OFListItemObject(iter)]) ok = false; iter = OFListItemNext(iter); i++; } @@ -119,12 +119,12 @@ iter = list.firstListItem; i = 0; ok = true; - for (OFString *object in list) { - if (![object isEqual: OFListItemObject(iter)]) + for (OFString *object_ in list) { + if (![object_ isEqual: OFListItemObject(iter)]) ok = false; iter = OFListItemNext(iter); i++; } @@ -134,12 +134,12 @@ TEST(@"Fast Enumeration", ok) ok = false; @try { - for (OFString *object in list) { - (void)object; + for (OFString *object_ in list) { + (void)object_; [list removeListItem: list.lastListItem]; } } @catch (OFEnumerationMutationException *e) { ok = true; Index: tests/OFLocaleTests.m ================================================================== --- tests/OFLocaleTests.m +++ tests/OFLocaleTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,40 +17,44 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFMD5Hash"; +static OFString *const module = @"OFMD5Hash"; -const uint8_t testfile_md5[16] = - "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; +const uint8_t testFileMD5[16] = + "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; @implementation TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests { void *pool = objc_autoreleasePoolPush(); - OFMD5Hash *md5, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFMD5Hash *MD5, *MD5Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (md5 = [OFMD5Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [md5 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[md5 copy] autorelease])) + (MD5 = [OFMD5Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [MD5 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (MD5Copy = [[MD5 copy] autorelease])) + + TEST(@"-[calculate]", R([MD5 calculate]) && R([MD5Copy calculate])) TEST(@"-[digest]", - memcmp(md5.digest, testfile_md5, 16) == 0 && - memcmp(copy.digest, testfile_md5, 16) == 0) + memcmp(MD5.digest, testFileMD5, 16) == 0 && + memcmp(MD5Copy.digest, testFileMD5, 16) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [md5 updateWithBuffer: "" length: 1]) + [MD5 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFMemoryStreamTests.m Index: tests/OFMemoryStreamTests.m ================================================================== --- /dev/null +++ tests/OFMemoryStreamTests.m @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008-2022 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFMemoryStream"; +static const char string[] = "abcdefghijkl"; + +@implementation TestsAppDelegate (OFMemoryStreamTests) +- (void)memoryStreamTests +{ + void *pool = objc_autoreleasePoolPush(); + OFMemoryStream *stream; + char buffer[10]; + OFMutableData *data; + + TEST(@"+[streamWithMemoryAddress:size:writable:]", + (stream = [OFMemoryStream streamWithMemoryAddress: (char *)string + size: sizeof(string) + writable: false])); + + /* + * Test the lowlevel methods, as otherwise OFStream will do one big + * read and we will not test OFMemoryStream. + */ + + TEST(@"-[lowlevelReadIntoBuffer:length:]", + [stream lowlevelReadIntoBuffer: buffer length: 5] == 5 && + memcmp(buffer, "abcde", 5) == 0 && + [stream lowlevelReadIntoBuffer: buffer length: 3] == 3 && + memcmp(buffer, "fgh", 3) == 0 && + [stream lowlevelReadIntoBuffer: buffer length: 10] == 5 && + memcmp(buffer, "ijkl", 5) == 0) + + TEST(@"-[lowlevelIsAtEndOfStream]", [stream lowlevelIsAtEndOfStream]) + + TEST(@"-[lowlevelSeekToOffset:whence:]", + [stream lowlevelSeekToOffset: 0 whence: SEEK_CUR] == + sizeof(string) && [stream lowlevelIsAtEndOfStream] && + [stream lowlevelSeekToOffset: 4 whence: SEEK_SET] == 4 && + ![stream lowlevelIsAtEndOfStream] && + [stream lowlevelReadIntoBuffer: buffer length: 10] == 9 && + memcmp(buffer, "efghijkl", 9) == 0 && + [stream lowlevelSeekToOffset: -2 whence: SEEK_END] == 11 && + [stream lowlevelReadIntoBuffer: buffer length: 10] == 2 && + memcmp(buffer, "l", 2) == 0 && + [stream lowlevelReadIntoBuffer: buffer length: 10] == 0) + + EXPECT_EXCEPTION(@"Writes rejected on read-only stream", + OFWriteFailedException, [stream lowlevelWriteBuffer: "" length: 1]) + + data = [OFMutableData dataWithCapacity: 13]; + [data increaseCountBy: 13]; + stream = [OFMemoryStream streamWithMemoryAddress: data.mutableItems + size: data.count + writable: true]; + TEST(@"-[lowlevelWriteBuffer:length:]", + [stream lowlevelWriteBuffer: "abcde" length: 5] == 5 && + [stream lowlevelWriteBuffer: "fgh" length: 3] == 3 && + [stream lowlevelWriteBuffer: "ijkl" length: 5] == 5 && + memcmp(data.items, string, data.count) == 0 && + [stream lowlevelSeekToOffset: -3 whence: SEEK_END] == 10) + + EXPECT_EXCEPTION(@"Out of bound writes rejected", + OFWriteFailedException, + [stream lowlevelWriteBuffer: "xyz" length: 4]) + + TEST(@"Partial write for too long write", + memcmp(data.items, "abcdefghijxyz", 13) == 0) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFMethodSignatureTests.m ================================================================== --- tests/OFMethodSignatureTests.m +++ tests/OFMethodSignatureTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,19 +21,19 @@ # include #endif #import "TestsAppDelegate.h" -static OFString *module = @"OFMethodSignature"; +static OFString *const module = @"OFMethodSignature"; -struct test1_struct { +struct Test1Struct { char c; int i; char d; }; -struct test2_struct { +struct Test2Struct { char c; struct { short s; int i; } st; @@ -43,23 +43,23 @@ } u; double d; }; #if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) -struct test3_struct { +struct Test3Struct { char c; complex double cd; }; #endif -union test3_union { +union Test3Union { char c; int i; double d; }; -union test4_union { +union Test4Union { char c; struct { short x, y; } st; int i; @@ -71,38 +71,42 @@ @implementation TestsAppDelegate (OFMethodSignatureTests) - (void)methodSignatureTests { void *pool = objc_autoreleasePoolPush(); - OFMethodSignature *ms; + OFMethodSignature *methodSignature; TEST(@"-[signatureWithObjCTypes:] #1", - (ms = [OFMethodSignature signatureWithObjCTypes: - "i28@0:8S16*20"]) && ms.numberOfArguments == 4 && - strcmp(ms.methodReturnType, "i") == 0 && - strcmp([ms argumentTypeAtIndex: 0], "@") == 0 && - strcmp([ms argumentTypeAtIndex: 1], ":") == 0 && - strcmp([ms argumentTypeAtIndex: 2], "S") == 0 && - strcmp([ms argumentTypeAtIndex: 3], "*") == 0 && - ms.frameLength == 28 && [ms argumentOffsetAtIndex: 0] == 0 && - [ms argumentOffsetAtIndex: 1] == 8 && - [ms argumentOffsetAtIndex: 2] == 16 && - [ms argumentOffsetAtIndex: 3] == 20) + (methodSignature = [OFMethodSignature signatureWithObjCTypes: + "i28@0:8S16*20"]) && + methodSignature.numberOfArguments == 4 && + strcmp(methodSignature.methodReturnType, "i") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 2], "S") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 3], "*") == 0 && + methodSignature.frameLength == 28 && + [methodSignature argumentOffsetAtIndex: 0] == 0 && + [methodSignature argumentOffsetAtIndex: 1] == 8 && + [methodSignature argumentOffsetAtIndex: 2] == 16 && + [methodSignature argumentOffsetAtIndex: 3] == 20) TEST(@"-[signatureWithObjCTypes:] #2", - (ms = [OFMethodSignature signatureWithObjCTypes: + (methodSignature = [OFMethodSignature signatureWithObjCTypes: "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}24@0:8" "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}16"]) && - ms.numberOfArguments == 3 && strcmp(ms.methodReturnType, + methodSignature.numberOfArguments == 3 && + strcmp(methodSignature.methodReturnType, "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - strcmp([ms argumentTypeAtIndex: 0], "@") == 0 && - strcmp([ms argumentTypeAtIndex: 1], ":") == 0 && - strcmp([ms argumentTypeAtIndex: 2], + strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 2], "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - ms.frameLength == 24 && [ms argumentOffsetAtIndex: 0] == 0 && - [ms argumentOffsetAtIndex: 1] == 8 && - [ms argumentOffsetAtIndex: 2] == 16) + methodSignature.frameLength == 24 && + [methodSignature argumentOffsetAtIndex: 0] == 0 && + [methodSignature argumentOffsetAtIndex: 1] == 8 && + [methodSignature argumentOffsetAtIndex: 2] == 16) EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #3", OFInvalidFormatException, [OFMethodSignature signatureWithObjCTypes: "{ii"]) @@ -117,61 +121,61 @@ EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #6", OFInvalidFormatException, [OFMethodSignature signatureWithObjCTypes: "{{}0"]) TEST(@"OFSizeOfTypeEncoding() #1", - OFSizeOfTypeEncoding(@encode(struct test1_struct)) == - sizeof(struct test1_struct)) + OFSizeOfTypeEncoding(@encode(struct Test1Struct)) == + sizeof(struct Test1Struct)) TEST(@"OFSizeOfTypeEncoding() #2", - OFSizeOfTypeEncoding(@encode(struct test2_struct)) == - sizeof(struct test2_struct)) + OFSizeOfTypeEncoding(@encode(struct Test2Struct)) == + sizeof(struct Test2Struct)) #if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ OF_GCC_VERSION >= 402 TEST(@"OFSizeOfTypeEncoding() #3", - OFSizeOfTypeEncoding(@encode(struct test3_struct)) == - sizeof(struct test3_struct)) + OFSizeOfTypeEncoding(@encode(struct Test3Struct)) == + sizeof(struct Test3Struct)) #endif TEST(@"OFSizeOfTypeEncoding() #4", - OFSizeOfTypeEncoding(@encode(union test3_union)) == - sizeof(union test3_union)) + OFSizeOfTypeEncoding(@encode(union Test3Union)) == + sizeof(union Test3Union)) TEST(@"OFSizeOfTypeEncoding() #5", - OFSizeOfTypeEncoding(@encode(union test4_union)) == - sizeof(union test4_union)) + OFSizeOfTypeEncoding(@encode(union Test4Union)) == + sizeof(union Test4Union)) TEST(@"OFSizeOfTypeEncoding() #6", - OFSizeOfTypeEncoding(@encode(struct test1_struct [5])) == - sizeof(struct test1_struct [5])) + OFSizeOfTypeEncoding(@encode(struct Test1Struct [5])) == + sizeof(struct Test1Struct [5])) TEST(@"OFAlignmentOfTypeEncoding() #1", - OFAlignmentOfTypeEncoding(@encode(struct test1_struct)) == - OF_ALIGNOF(struct test1_struct)) + OFAlignmentOfTypeEncoding(@encode(struct Test1Struct)) == + OF_ALIGNOF(struct Test1Struct)) TEST(@"OFAlignmentOfTypeEncoding() #2", - OFAlignmentOfTypeEncoding(@encode(struct test2_struct)) == - OF_ALIGNOF(struct test2_struct)) + OFAlignmentOfTypeEncoding(@encode(struct Test2Struct)) == + OF_ALIGNOF(struct Test2Struct)) #if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ OF_GCC_VERSION >= 402 TEST(@"OFAlignmentOfTypeEncoding() #3", - OFAlignmentOfTypeEncoding(@encode(struct test3_struct)) == - OF_ALIGNOF(struct test3_struct)) + OFAlignmentOfTypeEncoding(@encode(struct Test3Struct)) == + OF_ALIGNOF(struct Test3Struct)) #endif TEST(@"OFAlignmentOfTypeEncoding() #4", - OFAlignmentOfTypeEncoding(@encode(union test3_union)) == - OF_ALIGNOF(union test3_union)) + OFAlignmentOfTypeEncoding(@encode(union Test3Union)) == + OF_ALIGNOF(union Test3Union)) TEST(@"OFAlignmentOfTypeEncoding() #5", - OFAlignmentOfTypeEncoding(@encode(union test4_union)) == - OF_ALIGNOF(union test4_union)) + OFAlignmentOfTypeEncoding(@encode(union Test4Union)) == + OF_ALIGNOF(union Test4Union)) TEST(@"OFAlignmentOfTypeEncoding() #6", - OFAlignmentOfTypeEncoding(@encode(struct test1_struct [5])) == - OF_ALIGNOF(struct test1_struct [5])) + OFAlignmentOfTypeEncoding(@encode(struct Test1Struct [5])) == + OF_ALIGNOF(struct Test1Struct [5])) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFNotificationCenterTests.m Index: tests/OFNotificationCenterTests.m ================================================================== --- /dev/null +++ tests/OFNotificationCenterTests.m @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2008-2022 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFNotificationCenter"; +static const OFNotificationName notificationName = + @"OFNotificationCenterTestName"; +static const OFNotificationName otherNotificationName = + @"OFNotificationCenterTestOtherName"; + +@interface OFNotificationCenterTest: OFObject +{ +@public + id _expectedObject; + int _received; +} + +- (void)handleNotification: (OFNotification *)notification; +@end + +@implementation OFNotificationCenterTest +- (void)handleNotification: (OFNotification *)notification +{ + OFEnsure([notification.name isEqual: notificationName]); + OFEnsure(_expectedObject == nil || + notification.object == _expectedObject); + + _received++; +} +@end + +@implementation TestsAppDelegate (OFNotificationCenterTests) +- (void)notificationCenterTests +{ + void *pool = objc_autoreleasePoolPush(); + OFNotificationCenter *center = [OFNotificationCenter defaultCenter]; + OFNotificationCenterTest *test1, *test2, *test3, *test4; + OFNotification *notification; + + test1 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test1->_expectedObject = self; + test2 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test3 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test3->_expectedObject = self; + test4 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + + /* First one intentionally added twice to test deduplication. */ + TEST(@"-[addObserver:selector:name:object:]", + R([center addObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center addObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center addObserver: test2 + selector: @selector(handleNotification:) + name: notificationName + object: nil]) && + R([center addObserver: test3 + selector: @selector(handleNotification:) + name: otherNotificationName + object: self]) && + R([center addObserver: test4 + selector: @selector(handleNotification:) + name: otherNotificationName + object: nil])) + + notification = [OFNotification notificationWithName: notificationName + object: nil]; + TEST(@"-[postNotification:] #1", + R([center postNotification: notification]) && + test1->_received == 0 && test2->_received == 1 && + test3->_received == 0 && test4->_received == 0) + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[postNotification:] #2", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 2 && + test3->_received == 0 && test4->_received == 0) + + notification = [OFNotification notificationWithName: notificationName + object: @"foo"]; + TEST(@"-[postNotification:] #3", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 3 && + test3->_received == 0 && test4->_received == 0) + +#ifdef OF_HAVE_BLOCKS + __block bool received = false; + OFNotificationCenterHandle *handle; + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[addObserverForName:object:usingBlock:]", + (handle = [center addObserverForName: notificationName + object: self + usingBlock: ^ (OFNotification *notif) { + OFEnsure(notif == notification && !received); + received = true; + }]) && R([center postNotification: notification]) && received && + test1->_received == 2 && test2->_received == 4 && + test3->_received == 0 && test4->_received == 0) + + /* Act like the block test didn't happen. */ + [center removeObserver: handle]; + test1->_received--; + test2->_received--; +#endif + + TEST(@"-[removeObserver:selector:name:object:]", + R([center removeObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center removeObserver: test2 + selector: @selector(handleNotification:) + name: notificationName + object: nil]) && + R([center removeObserver: test3 + selector: @selector(handleNotification:) + name: otherNotificationName + object: self]) && + R([center removeObserver: test4 + selector: @selector(handleNotification:) + name: otherNotificationName + object: nil])) + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[postNotification:] with no observers", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 3 && + test3->_received == 0 && test4->_received == 0) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFNumberTests.m ================================================================== --- tests/OFNumberTests.m +++ tests/OFNumberTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,78 +15,78 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFNumber"; +static OFString *const module = @"OFNumber"; @implementation TestsAppDelegate (OFNumberTests) - (void)numberTests { void *pool = objc_autoreleasePoolPush(); - OFNumber *num; + OFNumber *number; TEST(@"+[numberWithLongLong:]", - (num = [OFNumber numberWithLongLong: 123456789])) + (number = [OFNumber numberWithLongLong: 123456789])) TEST(@"-[isEqual:]", - [num isEqual: [OFNumber numberWithLong: 123456789]]) + [number isEqual: [OFNumber numberWithLong: 123456789]]) + + TEST(@"-[hash]", number.hash == 0x82D8BC42) - TEST(@"-[hash]", num.hash == 0x82D8BC42) + TEST(@"-[charValue]", number.charValue == 21) - TEST(@"-[charValue]", num.charValue == 21) - - TEST(@"-[doubleValue]", num.doubleValue == 123456789.L) + TEST(@"-[doubleValue]", number.doubleValue == 123456789.L) TEST(@"signed char minimum & maximum unmodified", - (num = [OFNumber numberWithChar: SCHAR_MIN]) && - num.charValue == SCHAR_MIN && - (num = [OFNumber numberWithChar: SCHAR_MAX]) && - num.charValue == SCHAR_MAX) + (number = [OFNumber numberWithChar: SCHAR_MIN]) && + number.charValue == SCHAR_MIN && + (number = [OFNumber numberWithChar: SCHAR_MAX]) && + number.charValue == SCHAR_MAX) TEST(@"short minimum & maximum unmodified", - (num = [OFNumber numberWithShort: SHRT_MIN]) && - num.shortValue == SHRT_MIN && - (num = [OFNumber numberWithShort: SHRT_MAX]) && - num.shortValue == SHRT_MAX) + (number = [OFNumber numberWithShort: SHRT_MIN]) && + number.shortValue == SHRT_MIN && + (number = [OFNumber numberWithShort: SHRT_MAX]) && + number.shortValue == SHRT_MAX) TEST(@"int minimum & maximum unmodified", - (num = [OFNumber numberWithInt: INT_MIN]) && - num.intValue == INT_MIN && - (num = [OFNumber numberWithInt: INT_MAX]) && - num.intValue == INT_MAX) + (number = [OFNumber numberWithInt: INT_MIN]) && + number.intValue == INT_MIN && + (number = [OFNumber numberWithInt: INT_MAX]) && + number.intValue == INT_MAX) TEST(@"long minimum & maximum unmodified", - (num = [OFNumber numberWithLong: LONG_MIN]) && - num.longValue == LONG_MIN && - (num = [OFNumber numberWithLong: LONG_MAX]) && - num.longValue == LONG_MAX) + (number = [OFNumber numberWithLong: LONG_MIN]) && + number.longValue == LONG_MIN && + (number = [OFNumber numberWithLong: LONG_MAX]) && + number.longValue == LONG_MAX) TEST(@"long long minimum & maximum unmodified", - (num = [OFNumber numberWithLongLong: LLONG_MIN]) && - num.longLongValue == LLONG_MIN && - (num = [OFNumber numberWithLongLong: LLONG_MAX]) && - num.longLongValue == LLONG_MAX) + (number = [OFNumber numberWithLongLong: LLONG_MIN]) && + number.longLongValue == LLONG_MIN && + (number = [OFNumber numberWithLongLong: LLONG_MAX]) && + number.longLongValue == LLONG_MAX) TEST(@"unsigned char maximum unmodified", - (num = [OFNumber numberWithUnsignedChar: UCHAR_MAX]) && - num.unsignedCharValue == UCHAR_MAX) + (number = [OFNumber numberWithUnsignedChar: UCHAR_MAX]) && + number.unsignedCharValue == UCHAR_MAX) TEST(@"unsigned short maximum unmodified", - (num = [OFNumber numberWithUnsignedShort: USHRT_MAX]) && - num.unsignedShortValue == USHRT_MAX) + (number = [OFNumber numberWithUnsignedShort: USHRT_MAX]) && + number.unsignedShortValue == USHRT_MAX) TEST(@"unsigned int maximum unmodified", - (num = [OFNumber numberWithUnsignedInt: UINT_MAX]) && - num.unsignedIntValue == UINT_MAX) + (number = [OFNumber numberWithUnsignedInt: UINT_MAX]) && + number.unsignedIntValue == UINT_MAX) TEST(@"unsigned long maximum unmodified", - (num = [OFNumber numberWithUnsignedLong: ULONG_MAX]) && - num.unsignedLongValue == ULONG_MAX) + (number = [OFNumber numberWithUnsignedLong: ULONG_MAX]) && + number.unsignedLongValue == ULONG_MAX) TEST(@"unsigned long long maximum unmodified", - (num = [OFNumber numberWithUnsignedLongLong: ULLONG_MAX]) && - num.unsignedLongLongValue == ULLONG_MAX) + (number = [OFNumber numberWithUnsignedLongLong: ULLONG_MAX]) && + number.unsignedLongLongValue == ULLONG_MAX) objc_autoreleasePoolPop(pool); } @end Index: tests/OFObjectTests.m ================================================================== --- tests/OFObjectTests.m +++ tests/OFObjectTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -21,13 +21,13 @@ # define TOO_BIG (SIZE_MAX / 3) #else # define TOO_BIG (SIZE_MAX - 128) #endif -static OFString *module = @"OFObject"; +static OFString *const module = @"OFObject"; -@interface MyObj: OFObject +@interface MyObject: OFObject { id _objectValue; Class _classValue; bool _boolValue; char _charValue; @@ -59,11 +59,11 @@ @property (nonatomic) unsigned long long unsignedLongLongValue; @property (nonatomic) float floatValue; @property (nonatomic) double doubleValue; @end -@implementation MyObj +@implementation MyObject @synthesize objectValue = _objectValue, classValue = _classValue; @synthesize boolValue = _boolValue, charValue = _charValue; @synthesize shortValue = _shortValue, intValue = _intValue; @synthesize longValue = _longValue, longLongValue = _longLongValue; @synthesize unsignedCharValue = _unsignedCharValue; @@ -83,134 +83,139 @@ @implementation TestsAppDelegate (OFObjectTests) - (void)objectTests { void *pool = objc_autoreleasePoolPush(); - OFObject *o; - MyObj *m; + OFObject *object; + MyObject *myObject; TEST(@"+[description]", [[OFObject description] isEqual: @"OFObject"] && - [[MyObj description] isEqual: @"MyObj"]) + [[MyObject description] isEqual: @"MyObject"]) - o = [[[OFObject alloc] init] autorelease]; - m = [[[MyObj alloc] init] autorelease]; + object = [[[OFObject alloc] init] autorelease]; + myObject = [[[MyObject alloc] init] autorelease]; TEST(@"-[description]", - [o.description isEqual: @""] && - [m.description isEqual: @""]) + [object.description isEqual: @""] && + [myObject.description isEqual: @""]) - m.objectValue = @"Hello"; - m.classValue = [m class]; + myObject.objectValue = @"Hello"; + myObject.classValue = myObject.class; TEST(@"-[valueForKey:]", - [[m valueForKey: @"objectValue"] isEqual: @"Hello"] && - [[m valueForKey: @"classValue"] isEqual: m.class] && - [[m valueForKey: @"class"] isEqual: m.class]) + [[myObject valueForKey: @"objectValue"] isEqual: @"Hello"] && + [[myObject valueForKey: @"classValue"] isEqual: myObject.class] && + [[myObject valueForKey: @"class"] isEqual: myObject.class]) EXPECT_EXCEPTION(@"-[valueForKey:] with undefined key", - OFUndefinedKeyException, [m valueForKey: @"undefined"]) + OFUndefinedKeyException, [myObject valueForKey: @"undefined"]) TEST(@"-[setValue:forKey:]", - R([m setValue: @"World" forKey: @"objectValue"]) && - R([m setValue: [OFObject class] forKey: @"classValue"]) && - [m.objectValue isEqual: @"World"] && - [m.classValue isEqual: [OFObject class]]) + R([myObject setValue: @"World" forKey: @"objectValue"]) && + R([myObject setValue: [OFObject class] forKey: @"classValue"]) && + [myObject.objectValue isEqual: @"World"] && + [myObject.classValue isEqual: [OFObject class]]) EXPECT_EXCEPTION(@"-[setValue:forKey:] with undefined key", - OFUndefinedKeyException, [m setValue: @"x" forKey: @"undefined"]) - - m.boolValue = 1; - m.charValue = 2; - m.shortValue = 3; - m.intValue = 4; - m.longValue = 5; - m.longLongValue = 6; - m.unsignedCharValue = 7; - m.unsignedShortValue = 8; - m.unsignedIntValue = 9; - m.unsignedLongValue = 10; - m.unsignedLongLongValue = 11; - m.floatValue = 12; - m.doubleValue = 13; + OFUndefinedKeyException, + [myObject setValue: @"x" forKey: @"undefined"]) + + myObject.boolValue = 1; + myObject.charValue = 2; + myObject.shortValue = 3; + myObject.intValue = 4; + myObject.longValue = 5; + myObject.longLongValue = 6; + myObject.unsignedCharValue = 7; + myObject.unsignedShortValue = 8; + myObject.unsignedIntValue = 9; + myObject.unsignedLongValue = 10; + myObject.unsignedLongLongValue = 11; + myObject.floatValue = 12; + myObject.doubleValue = 13; TEST(@"Auto-wrapping of -[valueForKey:]", - [[m valueForKey: @"boolValue"] isEqual: + [[myObject valueForKey: @"boolValue"] isEqual: [OFNumber numberWithBool: 1]] && - [[m valueForKey: @"charValue"] isEqual: + [[myObject valueForKey: @"charValue"] isEqual: [OFNumber numberWithChar: 2]] && - [[m valueForKey: @"shortValue"] isEqual: + [[myObject valueForKey: @"shortValue"] isEqual: [OFNumber numberWithShort: 3]] && - [[m valueForKey: @"intValue"] isEqual: + [[myObject valueForKey: @"intValue"] isEqual: [OFNumber numberWithInt: 4]] && - [[m valueForKey: @"longValue"] isEqual: + [[myObject valueForKey: @"longValue"] isEqual: [OFNumber numberWithLong: 5]] && - [[m valueForKey: @"longLongValue"] isEqual: + [[myObject valueForKey: @"longLongValue"] isEqual: [OFNumber numberWithLongLong: 6]] && - [[m valueForKey: @"unsignedCharValue"] isEqual: + [[myObject valueForKey: @"unsignedCharValue"] isEqual: [OFNumber numberWithUnsignedChar: 7]] && - [[m valueForKey: @"unsignedShortValue"] isEqual: + [[myObject valueForKey: @"unsignedShortValue"] isEqual: [OFNumber numberWithUnsignedShort: 8]] && - [[m valueForKey: @"unsignedIntValue"] isEqual: + [[myObject valueForKey: @"unsignedIntValue"] isEqual: [OFNumber numberWithUnsignedInt: 9]] && - [[m valueForKey: @"unsignedLongValue"] isEqual: + [[myObject valueForKey: @"unsignedLongValue"] isEqual: [OFNumber numberWithUnsignedLong: 10]] && - [[m valueForKey: @"unsignedLongLongValue"] isEqual: + [[myObject valueForKey: @"unsignedLongLongValue"] isEqual: [OFNumber numberWithUnsignedLongLong: 11]] && - [[m valueForKey: @"floatValue"] isEqual: + [[myObject valueForKey: @"floatValue"] isEqual: [OFNumber numberWithFloat: 12]] && - [[m valueForKey: @"doubleValue"] isEqual: + [[myObject valueForKey: @"doubleValue"] isEqual: [OFNumber numberWithDouble: 13]]) TEST(@"Auto-wrapping of -[setValue:forKey:]", - R([m setValue: [OFNumber numberWithBool: 0] - forKey: @"boolValue"]) && - R([m setValue: [OFNumber numberWithChar: 10] - forKey: @"charValue"]) && - R([m setValue: [OFNumber numberWithShort: 20] - forKey: @"shortValue"]) && - R([m setValue: [OFNumber numberWithInt: 30] - forKey: @"intValue"]) && - R([m setValue: [OFNumber numberWithLong: 40] - forKey: @"longValue"]) && - R([m setValue: [OFNumber numberWithLongLong: 50] - forKey: @"longLongValue"]) && - R([m setValue: [OFNumber numberWithUnsignedChar: 60] - forKey: @"unsignedCharValue"]) && - R([m setValue: [OFNumber numberWithUnsignedShort: 70] - forKey: @"unsignedShortValue"]) && - R([m setValue: [OFNumber numberWithUnsignedInt: 80] - forKey: @"unsignedIntValue"]) && - R([m setValue: [OFNumber numberWithUnsignedLong: 90] - forKey: @"unsignedLongValue"]) && - R([m setValue: [OFNumber numberWithUnsignedLongLong: 100] - forKey: @"unsignedLongLongValue"]) && - R([m setValue: [OFNumber numberWithFloat: 110] - forKey: @"floatValue"]) && - R([m setValue: [OFNumber numberWithDouble: 120] - forKey: @"doubleValue"]) && - m.isBoolValue == 0 && m.charValue == 10 && m.shortValue == 20 && - m.intValue == 30 && m.longValue == 40 && m.longLongValue == 50 && - m.unsignedCharValue == 60 && m.unsignedShortValue == 70 && - m.unsignedIntValue == 80 && m.unsignedLongValue == 90 && - m.unsignedLongLongValue == 100 && m.floatValue == 110 && - m.doubleValue == 120) + R([myObject setValue: [OFNumber numberWithBool: 0] + forKey: @"boolValue"]) && + R([myObject setValue: [OFNumber numberWithChar: 10] + forKey: @"charValue"]) && + R([myObject setValue: [OFNumber numberWithShort: 20] + forKey: @"shortValue"]) && + R([myObject setValue: [OFNumber numberWithInt: 30] + forKey: @"intValue"]) && + R([myObject setValue: [OFNumber numberWithLong: 40] + forKey: @"longValue"]) && + R([myObject setValue: [OFNumber numberWithLongLong: 50] + forKey: @"longLongValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedChar: 60] + forKey: @"unsignedCharValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedShort: 70] + forKey: @"unsignedShortValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedInt: 80] + forKey: @"unsignedIntValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedLong: 90] + forKey: @"unsignedLongValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedLongLong: 100] + forKey: @"unsignedLongLongValue"]) && + R([myObject setValue: [OFNumber numberWithFloat: 110] + forKey: @"floatValue"]) && + R([myObject setValue: [OFNumber numberWithDouble: 120] + forKey: @"doubleValue"]) && + myObject.isBoolValue == 0 && myObject.charValue == 10 && + myObject.shortValue == 20 && myObject.intValue == 30 && + myObject.longValue == 40 && myObject.longLongValue == 50 && + myObject.unsignedCharValue == 60 && + myObject.unsignedShortValue == 70 && + myObject.unsignedIntValue == 80 && + myObject.unsignedLongValue == 90 && + myObject.unsignedLongLongValue == 100 && + myObject.floatValue == 110 && + myObject.doubleValue == 120) EXPECT_EXCEPTION(@"Catch -[setValue:forKey:] with nil key for scalar", - OFInvalidArgumentException, [m setValue: (id _Nonnull)nil - forKey: @"intValue"]) + OFInvalidArgumentException, + [myObject setValue: (id _Nonnull)nil forKey: @"intValue"]) TEST(@"-[valueForKeyPath:]", - (m = [[[MyObj alloc] init] autorelease]) && - (m.objectValue = [[[MyObj alloc] init] autorelease]) && - R([m.objectValue - setObjectValue: [[[MyObj alloc] init] autorelease]]) && - R([[m.objectValue objectValue] setDoubleValue: 0.5]) && - [[m valueForKeyPath: @"objectValue.objectValue.doubleValue"] + (myObject = [[[MyObject alloc] init] autorelease]) && + (myObject.objectValue = [[[MyObject alloc] init] autorelease]) && + R([myObject.objectValue + setObjectValue: [[[MyObject alloc] init] autorelease]]) && + R([[myObject.objectValue objectValue] setDoubleValue: 0.5]) && + [[myObject valueForKeyPath: @"objectValue.objectValue.doubleValue"] doubleValue] == 0.5) TEST(@"[-setValue:forKeyPath:]", - R([m setValue: [OFNumber numberWithDouble: 0.75] - forKeyPath: @"objectValue.objectValue.doubleValue"]) && - [[m.objectValue objectValue] doubleValue] == 0.75) + R([myObject setValue: [OFNumber numberWithDouble: 0.75] + forKeyPath: @"objectValue.objectValue.doubleValue"]) && + [[myObject.objectValue objectValue] doubleValue] == 0.75) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFPBKDF2Tests.m Index: tests/OFPBKDF2Tests.m ================================================================== --- /dev/null +++ tests/OFPBKDF2Tests.m @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFPBKDF2"; + +@implementation TestsAppDelegate (OFPBKDF2Tests) +- (void)PBKDF2Tests +{ + void *pool = objc_autoreleasePoolPush(); + OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true]; + unsigned char key[25]; + + /* Test vectors from RFC 6070 */ + + TEST(@"PBKDF2-SHA1, 1 iteration", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" + "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) + + TEST(@"PBKDF2-SHA1, 2 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 2, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" + "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) + + TEST(@"PBKDF2-SHA1, 4096 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" + "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) + + /* This test takes too long, even on a fast machine. */ +#if 0 + TEST(@"PBKDF2-SHA1, 16777216 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 16777216, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" + "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) +#endif + + TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"saltSALTsaltSALTsalt" + "SALTsaltSALTsalt", + .saltLength = 36, + .password = "passwordPASSWORDpassword", + .passwordLength = 24, + .key = key, + .keyLength = 25, + .allowsSwappableMemory = true + })) && + memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" + "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) + + TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"sa\0lt", + .saltLength = 5, + .password = "pass\0word", + .passwordLength = 9, + .key = key, + .keyLength = 16, + .allowsSwappableMemory = true + })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" + "\xF0\x34\x25\xE0\xC3", 16) == 0) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFPluginTests.m ================================================================== --- tests/OFPluginTests.m +++ tests/OFPluginTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -18,26 +18,39 @@ #import "TestsAppDelegate.h" #import "plugin/TestPlugin.h" #ifndef OF_IOS -# define PLUGIN_PATH @"plugin/TestPlugin" +static OFString *const pluginName = @"plugin/TestPlugin"; #else -# define PLUGIN_PATH @"PlugIns/TestPlugin" +static OFString *const pluginName = @"PlugIns/TestPlugin"; #endif -static OFString *module = @"OFPlugin"; +static OFString *const module = @"OFPlugin"; @implementation TestsAppDelegate (OFPluginTests) - (void)pluginTests { void *pool = objc_autoreleasePoolPush(); - TestPlugin *plugin; + OFString *path; + OFPlugin *plugin; + Class (*class)(void); + TestPlugin *test; + + TEST(@"+[pathForName:]", (path = [OFPlugin pathForName: pluginName])) + + TEST(@"+[pluginWithPath:]", (plugin = [OFPlugin pluginWithPath: path])) - TEST(@"+[pluginWithPath:]", - (plugin = [OFPlugin pluginWithPath: PLUGIN_PATH])) + TEST(@"-[addressForSymbol:]", + (class = (Class (*)(void))(uintptr_t) + [plugin addressForSymbol: @"class"])) - TEST(@"TestPlugin's -[test:]", [plugin test: 1234] == 2468) + test = [[class() alloc] init]; + @try { + TEST(@"TestPlugin's -[test:]", [test test: 1234] == 2468) + } @finally { + [test release]; + } objc_autoreleasePoolPop(pool); } @end Index: tests/OFPropertyListTests.m ================================================================== --- tests/OFPropertyListTests.m +++ tests/OFPropertyListTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -23,23 +23,23 @@ @"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" \ @"\n" \ x @"\n" \ @"" -static OFString *module = @"OFPropertyList"; -static OFString *PLIST1 = PLIST(@"Hello"); -static OFString *PLIST2 = PLIST( +static OFString *const module = @"OFPropertyList"; +static OFString *const PLIST1 = PLIST(@"Hello"); +static OFString *const PLIST2 = PLIST( @"" @" Hello" @" V29ybGQh" @" 2018-03-14T12:34:56Z" @" " @" " @" 12.25" @" -10" @""); -static OFString *PLIST3 = PLIST( +static OFString *const PLIST3 = PLIST( @"" @" array" @" " @" Hello" @" V29ybGQh" Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,41 +17,46 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFRIPEMD160Hash"; +static OFString *const module = @"OFRIPEMD160Hash"; -const uint8_t testfile_rmd160[20] = +const uint8_t testFileRIPEMD160[20] = "\x46\x02\x97\xF5\x85\xDF\xB9\x21\x00\xC8\xF9\x87\xC6\xEC\x84\x0D\xCE" "\xE6\x08\x8B"; @implementation TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests { void *pool = objc_autoreleasePoolPush(); - OFRIPEMD160Hash *rmd160, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFRIPEMD160Hash *RIPEMD160, *RIPEMD160Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (rmd160 = [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [rmd160 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[rmd160 copy] autorelease])) + (RIPEMD160 = [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [RIPEMD160 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (RIPEMD160Copy = [[RIPEMD160 copy] autorelease])) + + TEST(@"-[calculate]", + R([RIPEMD160 calculate]) && R([RIPEMD160Copy calculate])) TEST(@"-[digest]", - memcmp(rmd160.digest, testfile_rmd160, 20) == 0 && - memcmp(copy.digest, testfile_rmd160, 20) == 0) + memcmp(RIPEMD160.digest, testFileRIPEMD160, 20) == 0 && + memcmp(RIPEMD160Copy.digest, testFileRIPEMD160, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [rmd160 updateWithBuffer: "" length: 1]) + [RIPEMD160 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,41 +17,45 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA1Hash"; +static OFString *const module = @"OFSHA1Hash"; -const uint8_t testfile_sha1[20] = +const uint8_t testFileSHA1[20] = "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96\xF5" "\x94\xE7\x17"; @implementation TestsAppDelegate (SHA1HashTests) - (void)SHA1HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA1Hash *sha1, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFSHA1Hash *SHA1, *SHA1Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (sha1 = [OFSHA1Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [sha1 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha1 copy] autorelease])) + (SHA1 = [OFSHA1Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA1 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA1Copy = [[SHA1 copy] autorelease])) + + TEST(@"-[calculate]", R([SHA1 calculate]) && R([SHA1Copy calculate])) TEST(@"-[digest]", - memcmp(sha1.digest, testfile_sha1, 20) == 0 && - memcmp(copy.digest, testfile_sha1, 20) == 0) + memcmp(SHA1.digest, testFileSHA1, 20) == 0 && + memcmp(SHA1Copy.digest, testFileSHA1, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha1 updateWithBuffer: "" length: 1]) + [SHA1 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,41 +17,46 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA224Hash"; +static OFString *const module = @"OFSHA224Hash"; -const uint8_t testfile_sha224[28] = +const uint8_t testFileSHA224[28] = "\x27\x69\xD8\x04\x2D\x0F\xCA\x84\x6C\xF1\x62\x44\xBA\x0C\xBD\x46\x64" "\x5F\x4F\x20\x02\x4D\x15\xED\x1C\x61\x1F\xF7"; @implementation TestsAppDelegate (SHA224HashTests) - (void)SHA224HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA224Hash *sha224, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFSHA224Hash *SHA224, *SHA224Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (sha224 = [OFSHA224Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [sha224 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha224 copy] autorelease])) + (SHA224 = [OFSHA224Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA224 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA224Copy = [[SHA224 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA224 calculate]) && R([SHA224Copy calculate])) TEST(@"-[digest]", - memcmp(sha224.digest, testfile_sha224, 28) == 0 && - memcmp(copy.digest, testfile_sha224, 28) == 0) + memcmp(SHA224.digest, testFileSHA224, 28) == 0 && + memcmp(SHA224Copy.digest, testFileSHA224, 28) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha224 updateWithBuffer: "" length: 1]) + [SHA224 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,41 +17,46 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA256Hash"; +static OFString *const module = @"OFSHA256Hash"; -const uint8_t testfile_sha256[32] = +const uint8_t testFileSHA256[32] = "\x1A\x02\xD6\x46\xF5\xA6\xBA\xAA\xFF\x7F\xD5\x87\xBA\xC3\xF6\xC6\xB5" "\x67\x93\x8F\x0F\x44\x90\xB8\xF5\x35\x89\xF0\x5A\x23\x7F\x69"; @implementation TestsAppDelegate (SHA256HashTests) - (void)SHA256HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA256Hash *sha256, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFSHA256Hash *SHA256, *SHA256Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (sha256 = [OFSHA256Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf length: 64]; - [sha256 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha256 copy] autorelease])) + (SHA256 = [OFSHA256Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA256 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA256Copy = [[SHA256 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA256 calculate]) && R([SHA256Copy calculate])) TEST(@"-[digest]", - memcmp(sha256.digest, testfile_sha256, 32) == 0 && - memcmp(copy.digest, testfile_sha256, 32) == 0) + memcmp(SHA256.digest, testFileSHA256, 32) == 0 && + memcmp(SHA256Copy.digest, testFileSHA256, 32) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha256 updateWithBuffer: "" length: 1]) + [SHA256 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,42 +17,47 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA384Hash"; +static OFString *const module = @"OFSHA384Hash"; -const uint8_t testfile_sha384[48] = +const uint8_t testFileSHA384[48] = "\x7E\xDE\x62\xE2\x10\xA5\x1E\x18\x8A\x11\x7F\x78\xD7\xC7\x55\xB6\x43" "\x94\x1B\xD2\x78\x5C\xCF\xF3\x8A\xB8\x98\x22\xC7\x0E\xFE\xF1\xEC\x53" "\xE9\x1A\xB3\x51\x70\x8C\x1F\x3F\x56\x12\x44\x01\x91\x54"; @implementation TestsAppDelegate (SHA384HashTests) - (void)SHA384HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA384Hash *sha384, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFSHA384Hash *SHA384, *SHA384Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (sha384 = [OFSHA384Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[128]; - size_t len = [f readIntoBuffer: buf length: 128]; - [sha384 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha384 copy] autorelease])) + (SHA384 = [OFSHA384Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[128]; + size_t length = [file readIntoBuffer: buffer length: 128]; + [SHA384 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA384Copy = [[SHA384 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA384 calculate]) && R([SHA384Copy calculate])) TEST(@"-[digest]", - memcmp(sha384.digest, testfile_sha384, 48) == 0 && - memcmp(copy.digest, testfile_sha384, 48) == 0) + memcmp(SHA384.digest, testFileSHA384, 48) == 0 && + memcmp(SHA384Copy.digest, testFileSHA384, 48) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha384 updateWithBuffer: "" length: 1]) + [SHA384 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,43 +17,48 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA512Hash"; +static OFString *const module = @"OFSHA512Hash"; -const uint8_t testfile_sha512[64] = +const uint8_t testFileSHA512[64] = "\x8F\x36\x6E\x3C\x19\x4B\xBB\xC7\x82\xAA\xCD\x7D\x55\xA2\xD3\x29\x29" "\x97\x6A\x3F\xEB\x9B\xB2\xCB\x75\xC9\xEC\xC8\x10\x07\xD6\x07\x31\x4A" "\xB1\x30\x97\x82\x58\xA5\x1F\x71\x42\xE6\x56\x07\x99\x57\xB2\xB8\x3B" "\xA1\x8A\x41\x64\x33\x69\x21\x8C\x2A\x44\x6D\xF2\xA0"; @implementation TestsAppDelegate (SHA512HashTests) - (void)SHA512HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA512Hash *sha512, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFSHA512Hash *SHA512, *SHA512Copy; + OFURL *URL = [OFURL URLWithString: @"objfw-embedded:///testfile.bin"]; + OFStream *file = [[OFURLHandler handlerForURL: URL] + openItemAtURL: URL mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", - (sha512 = [OFSHA512Hash hashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[128]; - size_t len = [f readIntoBuffer: buf length: 128]; - [sha512 updateWithBuffer: buf length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha512 copy] autorelease])) + (SHA512 = [OFSHA512Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[128]; + size_t length = [file readIntoBuffer: buffer length: 128]; + [SHA512 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA512Copy = [[SHA512 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA512 calculate]) && R([SHA512Copy calculate])) TEST(@"-[digest]", - memcmp(sha512.digest, testfile_sha512, 64) == 0 && - memcmp(copy.digest, testfile_sha512, 64) == 0) + memcmp(SHA512.digest, testFileSHA512, 64) == 0 && + memcmp(SHA512Copy.digest, testFileSHA512, 64) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha512 updateWithBuffer: "" length: 1]) + [SHA512 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSPXSocketTests.m ================================================================== --- tests/OFSPXSocketTests.m +++ tests/OFSPXSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSPXSocket"; +static OFString *const module = @"OFSPXSocket"; @interface SPXSocketDelegate: OFObject { @public OFSequencedPacketSocket *_expectedServerSocket; @@ -48,22 +48,22 @@ [[OFRunLoop mainRunLoop] stop]; return false; } -- (void)socket: (OFSPXSocket *)sock - didConnectToNode: (unsigned char [IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - exception: (id)exception +- (void)socket: (OFSPXSocket *)sock + didConnectToNetwork: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + exception: (id)exception { OFEnsure(!_connected); _connected = (sock == _expectedClientSocket && + network == _expectedNetwork && memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 && - network == _expectedNetwork && port == _expectedPort && - exception == nil); + port == _expectedPort && exception == nil); if (_accepted && _connected) [[OFRunLoop mainRunLoop] stop]; } @end @@ -70,15 +70,15 @@ @implementation TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests { void *pool = objc_autoreleasePoolPush(); - OFSPXSocket *sockClient, *sockServer, *sockAccepted;; + OFSPXSocket *sockClient, *sockServer = nil, *sockAccepted; OFSocketAddress address1; const OFSocketAddress *address2; - unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint32_t network; + unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint16_t port; char buffer[5]; SPXSocketDelegate *delegate; TEST(@"+[socket]", (sockClient = [OFSPXSocket socket]) && @@ -113,18 +113,18 @@ objc_autoreleasePoolPop(pool); return; } - OFSocketAddressIPXNode(&address1, node); network = OFSocketAddressIPXNetwork(&address1); + OFSocketAddressIPXNode(&address1, node); port = OFSocketAddressPort(&address1); TEST(@"-[listen]", R([sockServer listen])) - TEST(@"-[connectToNode:network:port:]", - R([sockClient connectToNode: node network: network port: port])) + TEST(@"-[connectToNetwork:node:port:]", + R([sockClient connectToNetwork: network node: node port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) TEST(@"-[sendBuffer:length:]", R([sockAccepted sendBuffer: "Hello" length: 5])) @@ -133,13 +133,13 @@ [sockClient receiveIntoBuffer: buffer length: 5] == 5 && memcmp(buffer, "Hello", 5) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && + OFSocketAddressIPXNetwork(address2) == network && R(OFSocketAddressIPXNode(address2, node2)) && - memcmp(node, node2, IPX_NODE_LEN) == 0 && - OFSocketAddressIPXNetwork(address2) == network) + memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXSocket socket]; delegate->_expectedServerSocket = sockServer; @@ -151,33 +151,33 @@ address1 = [sockServer bindToPort: 0]; [sockServer listen]; [sockServer asyncAccept]; + delegate->_expectedNetwork = network = + OFSocketAddressIPXNetwork(&address1); OFSocketAddressIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); - delegate->_expectedNetwork = network = - OFSocketAddressIPXNetwork(&address1); delegate->_expectedPort = port = OFSocketAddressPort(&address1); @try { - [sockClient asyncConnectToNode: node - network: network - port: port]; + [sockClient asyncConnectToNetwork: network + node: node + port: port]; [[OFRunLoop mainRunLoop] runUntilDate: [OFDate dateWithTimeIntervalSinceNow: 2]]; - TEST(@"-[asyncAccept] & -[asyncConnectToNode:network:port:]", + TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveFailedException *e) { switch (e.errNo) { case ENOTSOCK: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @"\r[OFSPXSocket] -[asyncAccept] & " - @"-[asyncConnectToNode:network:port:]: select() " + @"-[asyncConnectToNetwork:node:port:]: select() " @"not supported for SPX, skipping test"]; break; default: @throw e; } Index: tests/OFSPXStreamSocketTests.m ================================================================== --- tests/OFSPXStreamSocketTests.m +++ tests/OFSPXStreamSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,19 +17,19 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSPXStreamSocket"; +static OFString *const module = @"OFSPXStreamSocket"; @interface SPXStreamSocketDelegate: OFObject { @public OFStreamSocket *_expectedServerSocket; OFSPXStreamSocket *_expectedClientSocket; - unsigned char _expectedNode[IPX_NODE_LEN]; uint32_t _expectedNetwork; + unsigned char _expectedNode[IPX_NODE_LEN]; uint16_t _expectedPort; bool _accepted; bool _connected; } @end @@ -48,22 +48,22 @@ [[OFRunLoop mainRunLoop] stop]; return false; } -- (void)socket: (OFSPXStreamSocket *)sock - didConnectToNode: (unsigned char [IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port - exception: (id)exception +- (void)socket: (OFSPXStreamSocket *)sock + didConnectToNetwork: (uint32_t)network + node: (unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + exception: (id)exception { OFEnsure(!_connected); _connected = (sock == _expectedClientSocket && + network == _expectedNetwork && memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 && - network == _expectedNetwork && port == _expectedPort && - exception == nil); + port == _expectedPort && exception == nil); if (_accepted && _connected) [[OFRunLoop mainRunLoop] stop]; } @end @@ -70,15 +70,15 @@ @implementation TestsAppDelegate (OFSPXStreamSocketTests) - (void)SPXStreamSocketTests { void *pool = objc_autoreleasePoolPush(); - OFSPXStreamSocket *sockClient, *sockServer, *sockAccepted;; + OFSPXStreamSocket *sockClient, *sockServer = nil, *sockAccepted; OFSocketAddress address1; const OFSocketAddress *address2; - unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint32_t network; + unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint16_t port; char buffer[5]; SPXStreamSocketDelegate *delegate; TEST(@"+[socket]", (sockClient = [OFSPXStreamSocket socket]) && @@ -113,18 +113,18 @@ objc_autoreleasePoolPop(pool); return; } - OFSocketAddressIPXNode(&address1, node); network = OFSocketAddressIPXNetwork(&address1); + OFSocketAddressIPXNode(&address1, node); port = OFSocketAddressPort(&address1); TEST(@"-[listen]", R([sockServer listen])) - TEST(@"-[connectToNode:network:port:]", - R([sockClient connectToNode: node network: network port: port])) + TEST(@"-[connectToNetwork:node:port:]", + R([sockClient connectToNetwork: network node: node port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) /* Test reassembly (this would not work with OFSPXSocket) */ TEST(@"-[writeBuffer:length:]", @@ -136,13 +136,13 @@ [sockClient readIntoBuffer: buffer length: 3] == 3 && memcmp(buffer, "llo", 3) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && + OFSocketAddressIPXNetwork(address2) == network && R(OFSocketAddressIPXNode(address2, node2)) && - memcmp(node, node2, IPX_NODE_LEN) == 0 && - OFSocketAddressIPXNetwork(address2) == network) + memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXStreamSocket socket]; delegate->_expectedServerSocket = sockServer; @@ -154,33 +154,33 @@ address1 = [sockServer bindToPort: 0]; [sockServer listen]; [sockServer asyncAccept]; + delegate->_expectedNetwork = network = + OFSocketAddressIPXNetwork(&address1); OFSocketAddressIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); - delegate->_expectedNetwork = network = - OFSocketAddressIPXNetwork(&address1); delegate->_expectedPort = port = OFSocketAddressPort(&address1); @try { - [sockClient asyncConnectToNode: node - network: network - port: port]; + [sockClient asyncConnectToNetwork: network + node: node + port: port]; [[OFRunLoop mainRunLoop] runUntilDate: [OFDate dateWithTimeIntervalSinceNow: 2]]; - TEST(@"-[asyncAccept] & -[asyncConnectToNode:network:port:]", + TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveFailedException *e) { switch (e.errNo) { case ENOTSOCK: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @"\r[OFSPXStreamSocket] -[asyncAccept] & " - @"-[asyncConnectToNode:network:port:]: select() " + @"-[asyncConnectToNetwork:node:port:]: select() " @"not supported for SPX, skipping test"]; break; default: @throw e; } ADDED tests/OFScryptTests.m Index: tests/OFScryptTests.m ================================================================== --- /dev/null +++ tests/OFScryptTests.m @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFScrypt"; +/* Test vectors form RFC 7914 */ +static const unsigned char salsa20Input[64] = { + 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, + 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, + 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, + 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, + 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, + 0xB8, 0xB8, 0xC2, 0x5E +}; +static const unsigned char salsa20Output[64] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81 +}; +static const union { + unsigned char uc[128]; + uint32_t u32[32]; +} blockMixInput = { .uc = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, + 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, + 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, + 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, + 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, + 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, + 0xEA, 0xAF, 0x7E, 0x89 +}}; +static const unsigned char blockMixOutput[128] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81, + 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, + 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, + 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, + 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, + 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, + 0x4E, 0xEF, 0xE4, 0x25 +}; +static const unsigned char ROMixInput[128] = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, + 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, + 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, + 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, + 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, + 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 +}; +static const unsigned char ROMixOutput[128] = { + 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, + 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, + 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, + 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, + 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, + 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, + 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, + 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, + 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, + 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, + 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E +}; +static const unsigned char testVector1[64] = { + 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, + 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, + 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, + 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, + 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, + 0x38, 0xD1, 0x89, 0x06 +}; +static const unsigned char testVector2[64] = { + 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, + 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, + 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, + 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, + 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, + 0xA2, 0xCC, 0x06, 0x40 +}; +/* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K +static const unsigned char testVector3[64] = { + 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, + 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, + 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, + 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, + 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, + 0x45, 0x57, 0x58, 0x87 +}; +#endif +/* The forth test vector is too expensive to include it in the tests. */ +#if 0 +static const unsigned char testVector4[64] = { + 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, + 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, + 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, + 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, + 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, + 0xA7, 0x7A, 0x41, 0xA4 +}; +#endif + +@implementation TestsAppDelegate (OFScryptTests) +- (void)scryptTests +{ + void *pool = objc_autoreleasePoolPush(); + uint32_t salsa20Buffer[16]; + uint32_t blockMixBuffer[32]; + uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; + unsigned char output[64]; + + TEST(@"Salsa20/8 Core", + R(memcpy(salsa20Buffer, salsa20Input, 64)) && + R(OFSalsa20_8Core(salsa20Buffer)) && + memcmp(salsa20Buffer, salsa20Output, 64) == 0) + + TEST(@"Block mix", + R(OFScryptBlockMix(blockMixBuffer, blockMixInput.u32, 1)) && + memcmp(blockMixBuffer, blockMixOutput, 128) == 0) + + TEST(@"ROMix", + R(memcpy(ROMixBuffer, ROMixInput, 128)) && + R(OFScryptROMix(ROMixBuffer, 1, 16, ROMixTmp)) && + memcmp(ROMixBuffer, ROMixOutput, 128) == 0) + + TEST(@"scrypt test vector #1", + R(OFScrypt((OFScryptParameters){ + .blockSize = 1, + .costFactor = 16, + .parallelization = 1, + .salt = (unsigned char *)"", + .saltLength = 0, + .password = "", + .passwordLength = 0, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector1, 64) == 0) + + TEST(@"scrypt test vector #2", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1024, + .parallelization = 16, + .salt = (unsigned char *)"NaCl", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector2, 64) == 0) + + /* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K + TEST(@"scrypt test vector #3", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 16384, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector3, 64) == 0) +#endif + + /* The forth test vector is too expensive to include it in the tests. */ +#if 0 + TEST(@"scrypt test vector #4", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1048576, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector4, 64) == 0) +#endif + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFSerializationTests.m ================================================================== --- tests/OFSerializationTests.m +++ tests/OFSerializationTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,50 +15,58 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFSerialization"; +static OFString *const module = @"OFSerialization"; @implementation TestsAppDelegate (OFSerializationTests) - (void)serializationTests { void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *d = [OFMutableDictionary dictionary]; - OFMutableArray *a = [OFMutableArray array]; - OFList *l = [OFList list]; + OFMutableDictionary *dict = [OFMutableDictionary dictionary]; + OFMutableArray *array = [OFMutableArray array]; + OFList *list = [OFList list]; OFData *data; - OFString *s; - - [a addObject: @"Qu\"xbar\ntest"]; - [a addObject: [OFNumber numberWithInt: 1234]]; - [a addObject: [OFNumber numberWithDouble: 1234.5678]]; - [a addObject: [OFMutableString stringWithString: @"asd"]]; - [a addObject: [OFDate dateWithTimeIntervalSince1970: 1234.5678]]; - - [d setObject: @"Hello" forKey: a]; - [d setObject: @"B\"la" forKey: @"Blub"]; - - [l appendObject: @"Hello"]; - [l appendObject: @"Wo\rld!\nHow are you?"]; - [l appendObject: [OFURL URLWithString: @"https://objfw.nil.im/"]]; - [l appendObject: + OFString *string; + OFUUID *UUID; + + [array addObject: @"Qu\"xbar\ntest"]; + [array addObject: [OFNumber numberWithInt: 1234]]; + [array addObject: [OFNumber numberWithDouble: 1234.5678]]; + [array addObject: [OFMutableString stringWithString: @"asd"]]; + [array addObject: [OFDate dateWithTimeIntervalSince1970: 1234.5678]]; + + [dict setObject: @"Hello" forKey: array]; + [dict setObject: @"B\"la" forKey: @"Blub"]; + + [list appendObject: @"Hello"]; + [list appendObject: @"Wo\rld!\nHow are you?"]; + [list appendObject: [OFURL URLWithString: @"https://objfw.nil.im/"]]; + [list appendObject: [OFXMLElement elementWithXMLString: @""]]; - [l appendObject: [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - [l appendObject: + [list appendObject: + [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; + [list appendObject: [OFCountedSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - [d setObject: @"list" forKey: l]; + [dict setObject: @"list" forKey: list]; data = [OFData dataWithItems: "0123456789:; + * Copyright (c) 2008-2022 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 @@ -19,11 +19,11 @@ #import "OFSet.h" #import "OFMapTableSet.h" #import "OFMutableMapTableSet.h" -static OFString *module = nil; +static OFString *module; @interface SimpleSet: OFSet { OFMutableSet *_set; } ADDED tests/OFSocketTests.m Index: tests/OFSocketTests.m ================================================================== --- /dev/null +++ tests/OFSocketTests.m @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2008-2022 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 "TestsAppDelegate.h" + +#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) +#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; + +static OFString *const module = @"OFSocket"; + +@implementation TestsAppDelegate (OFSocketTests) +- (void)socketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFSocketAddress addr; + + TEST(@"Parsing an IPv4", + R(addr = OFSocketAddressParseIP(@"127.0.0.1", 1234)) && + OFFromBigEndian32(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 && + OFFromBigEndian16(addr.sockaddr.in.sin_port) == 1234) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0.256", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0. 1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", OFInvalidFormatException, + OFSocketAddressParseIP(@" 127.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.a.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0..1", 1234)) + + TEST(@"Port of an IPv4 address", OFSocketAddressPort(&addr) == 1234) + + TEST(@"Converting an IPv4 to a string", + [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"]) + + TEST(@"Parsing an IPv6 #1", + R(addr = OFSocketAddressParseIP( + @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && + COMPARE_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #2", + R(addr = OFSocketAddressParseIP(@"::", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #3", + R(addr = OFSocketAddressParseIP(@"aaAa::bBbb", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #4", + R(addr = OFSocketAddressParseIP(@"aaAa::", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #5", + R(addr = OFSocketAddressParseIP(@"::aaAa", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, + OFSocketAddressParseIP(@"1: ::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:: :2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", OFInvalidFormatException, + OFSocketAddressParseIP(@"1::2::3", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", OFInvalidFormatException, + OFSocketAddressParseIP(@"10000::1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", OFInvalidFormatException, + OFSocketAddressParseIP(@"::10000", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", OFInvalidFormatException, + OFSocketAddressParseIP(@"::1::", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:2", 1234)) + + TEST(@"Port of an IPv6 address", OFSocketAddressPort(&addr) == 1234) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #1", + [OFSocketAddressString(&addr) isEqual: @"::"]) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) + TEST(@"Converting an IPv6 to a string #2", + [OFSocketAddressString(&addr) isEqual: @"::1"]) + + SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #3", + [OFSocketAddressString(&addr) isEqual: @"1::"]) + + SET_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #4", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) + TEST(@"Converting an IPv6 to a string #5", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:0"]) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #6", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc::"]) + + SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #7", + [OFSocketAddressString(&addr) + isEqual: @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #8", + [OFSocketAddressString(&addr) + isEqual: @"::5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #9", + [OFSocketAddressString(&addr) isEqual: @"0:0:5566::ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #10", + [OFSocketAddressString(&addr) + isEqual: @"::5566:7788:99aa:bbcc:0:0"]) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFStreamTests.m ================================================================== --- tests/OFStreamTests.m +++ tests/OFStreamTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,19 +15,19 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFStream"; +static OFString *const module = @"OFStream"; -@interface StreamTester: OFStream +@interface StreamTest: OFStream { int state; } @end -@implementation StreamTester +@implementation StreamTest - (bool)lowlevelIsAtEndOfStream { return (state > 1); } @@ -62,22 +62,25 @@ @implementation TestsAppDelegate (OFStreamTests) - (void)streamTests { void *pool = objc_autoreleasePoolPush(); size_t pageSize = [OFSystemInfo pageSize]; - StreamTester *t = [[[StreamTester alloc] init] autorelease]; - OFString *str; - char *cstr; - - cstr = OFAllocMemory(pageSize - 2, 1); - memset(cstr, 'X', pageSize - 3); - cstr[pageSize - 3] = '\0'; - - TEST(@"-[readLine]", [[t readLine] isEqual: @"foo"] && - [(str = [t readLine]) length] == pageSize - 3 && - !strcmp(str.UTF8String, cstr)) - - OFFreeMemory(cstr); + StreamTest *test = [[[StreamTest alloc] init] autorelease]; + OFString *string; + char *cString; + + cString = OFAllocMemory(pageSize - 2, 1); + memset(cString, 'X', pageSize - 3); + cString[pageSize - 3] = '\0'; + + TEST(@"-[readLine] #1", [[test readLine] isEqual: @"foo"]) + + string = [test readLine]; + TEST(@"-[readLine] #2", string != nil && + string.length == pageSize - 3 && + !strcmp(string.UTF8String, cString)) + + OFFreeMemory(cString); objc_autoreleasePoolPop(pool); } @end Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -27,26 +27,26 @@ #ifndef INFINITY # define INFINITY __builtin_inf() #endif -static OFString *module = nil; -static OFString *whitespace[] = { +static OFString *module; +static OFString *const whitespace[] = { @" \r \t\n\t \tasd \t \t\t\r\n", @" \t\t \t\t \t \t" }; -static OFUnichar ucstr[] = { +static const OFUnichar unicharString[] = { 0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0 }; -static OFUnichar sucstr[] = { +static const OFUnichar swappedUnicharString[] = { 0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000, 0x72000000, 0x3AF00100, 0 }; -static uint16_t utf16str[] = { +static const OFChar16 char16String[] = { 0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0 }; -static uint16_t sutf16str[] = { +static const OFChar16 swappedChar16String[] = { 0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC, 0 }; @interface SimpleString: OFString @@ -211,34 +211,35 @@ @implementation TestsAppDelegate (OFStringTests) - (void)stringTestsWithClass: (Class)stringClass mutableClass: (Class)mutableStringClass { void *pool = objc_autoreleasePoolPush(); - OFMutableString *s[3]; - OFString *is; - OFArray *a; + OFMutableString *mutableString1, *mutableString2, *mutableString3; + OFString *string; + OFArray *array; size_t i; - const OFUnichar *ua; - const uint16_t *u16a; - OFCharacterSet *cs; - EntityHandler *h; + const OFUnichar *characters; + const uint16_t *UTF16Characters; + OFCharacterSet *characterSet; + EntityHandler *entityHandler; #ifdef OF_HAVE_BLOCKS __block int j; __block bool ok; #endif #define C(s) ((OFString *)[stringClass stringWithString: s]) - s[0] = [mutableStringClass stringWithString: @"täs€"]; - s[1] = [mutableStringClass string]; - s[2] = [[s[0] copy] autorelease]; - - TEST(@"-[isEqual:]", [s[0] isEqual: s[2]] && - ![s[0] isEqual: [[[OFObject alloc] init] autorelease]]) - - TEST(@"-[compare:]", [s[0] compare: s[2]] == OFOrderedSame && - [s[0] compare: @""] != OFOrderedSame && + mutableString1 = [mutableStringClass stringWithString: @"täs€"]; + mutableString2 = [mutableStringClass string]; + mutableString3 = [[mutableString1 copy] autorelease]; + + TEST(@"-[isEqual:]", [mutableString1 isEqual: mutableString3] && + ![mutableString1 isEqual: [[[OFObject alloc] init] autorelease]]) + + TEST(@"-[compare:]", + [mutableString1 compare: mutableString3] == OFOrderedSame && + [mutableString1 compare: @""] != OFOrderedSame && [C(@"") compare: @"a"] == OFOrderedAscending && [C(@"a") compare: @"b"] == OFOrderedAscending && [C(@"cd") compare: @"bc"] == OFOrderedDescending && [C(@"ä") compare: @"ö"] == OFOrderedAscending && [C(@"€") compare: @"ß"] == OFOrderedDescending && @@ -263,107 +264,114 @@ [stringClass stringWithUTF8String: "AbD"]] == [C(@"abc") compare: @"abd"]) #endif TEST(@"-[hash] is the same if -[isEqual:] is true", - s[0].hash == s[2].hash) + mutableString1.hash == mutableString3.hash) - TEST(@"-[description]", [s[0].description isEqual: s[0]]) + TEST(@"-[description]", + [mutableString1.description isEqual: mutableString1]) TEST(@"-[appendString:] and -[appendUTF8String:]", - R([s[1] appendUTF8String: "1𝄞"]) && R([s[1] appendString: @"3"]) && - R([s[0] appendString: s[1]]) && [s[0] isEqual: @"täs€1𝄞3"]) + R([mutableString2 appendUTF8String: "1𝄞"]) && + R([mutableString2 appendString: @"3"]) && + R([mutableString1 appendString: mutableString2]) && + [mutableString1 isEqual: @"täs€1𝄞3"]) TEST(@"-[appendCharacters:length:]", - R([s[1] appendCharacters: ucstr + 6 length: 2]) && - [s[1] isEqual: @"1𝄞3r🀺"]) + R([mutableString2 appendCharacters: unicharString + 6 length: 2]) && + [mutableString2 isEqual: @"1𝄞3r🀺"]) - TEST(@"-[length]", s[0].length == 7) - TEST(@"-[UTF8StringLength]", s[0].UTF8StringLength == 13) - TEST(@"-[hash]", s[0].hash == 0x705583C0) + TEST(@"-[length]", mutableString1.length == 7) + TEST(@"-[UTF8StringLength]", mutableString1.UTF8StringLength == 13) + TEST(@"-[hash]", mutableString1.hash == 0x705583C0) TEST(@"-[characterAtIndex:]", - [s[0] characterAtIndex: 0] == 't' && - [s[0] characterAtIndex: 1] == 0xE4 && - [s[0] characterAtIndex: 3] == 0x20AC && - [s[0] characterAtIndex: 5] == 0x1D11E) + [mutableString1 characterAtIndex: 0] == 't' && + [mutableString1 characterAtIndex: 1] == 0xE4 && + [mutableString1 characterAtIndex: 3] == 0x20AC && + [mutableString1 characterAtIndex: 5] == 0x1D11E) EXPECT_EXCEPTION(@"Detect out of range in -[characterAtIndex:]", - OFOutOfRangeException, [s[0] characterAtIndex: 7]) + OFOutOfRangeException, [mutableString1 characterAtIndex: 7]) - TEST(@"-[reverse]", R([s[0] reverse]) && [s[0] isEqual: @"3𝄞1€sät"]) + TEST(@"-[reverse]", + R([mutableString1 reverse]) && [mutableString1 isEqual: @"3𝄞1€sät"]) - s[1] = [mutableStringClass stringWithString: @"abc"]; + mutableString2 = [mutableStringClass stringWithString: @"abc"]; #ifdef OF_HAVE_UNICODE_TABLES - TEST(@"-[uppercase]", R([s[0] uppercase]) && - [s[0] isEqual: @"3𝄞1€SÄT"] && - R([s[1] uppercase]) && [s[1] isEqual: @"ABC"]) + TEST(@"-[uppercase]", R([mutableString1 uppercase]) && + [mutableString1 isEqual: @"3𝄞1€SÄT"] && + R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"]) - TEST(@"-[lowercase]", R([s[0] lowercase]) && - [s[0] isEqual: @"3𝄞1€sät"] && - R([s[1] lowercase]) && [s[1] isEqual: @"abc"]) + TEST(@"-[lowercase]", R([mutableString1 lowercase]) && + [mutableString1 isEqual: @"3𝄞1€sät"] && + R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"]) TEST(@"-[uppercaseString]", - [[s[0] uppercaseString] isEqual: @"3𝄞1€SÄT"]) + [[mutableString1 uppercaseString] isEqual: @"3𝄞1€SÄT"]) - TEST(@"-[lowercaseString]", R([s[0] uppercase]) && - [[s[0] lowercaseString] isEqual: @"3𝄞1€sät"]) + TEST(@"-[lowercaseString]", R([mutableString1 uppercase]) && + [[mutableString1 lowercaseString] isEqual: @"3𝄞1€sät"]) TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString isEqual: @"Džbla Tdžst Tdžst"]) #else - TEST(@"-[uppercase]", R([s[0] uppercase]) && - [s[0] isEqual: @"3𝄞1€SäT"] && - R([s[1] uppercase]) && [s[1] isEqual: @"ABC"]) - - TEST(@"-[lowercase]", R([s[0] lowercase]) && - [s[0] isEqual: @"3𝄞1€sät"] && - R([s[1] lowercase]) && [s[1] isEqual: @"abc"]) - - TEST(@"-[uppercaseString]", [s[0].uppercaseString isEqual: @"3𝄞1€SäT"]) - - TEST(@"-[lowercaseString]", R([s[0] uppercase]) && - [s[0].lowercaseString isEqual: @"3𝄞1€sät"]) + TEST(@"-[uppercase]", R([mutableString1 uppercase]) && + [mutableString1 isEqual: @"3𝄞1€SäT"] && + R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"]) + + TEST(@"-[lowercase]", R([mutableString1 lowercase]) && + [mutableString1 isEqual: @"3𝄞1€sät"] && + R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"]) + + TEST(@"-[uppercaseString]", + [mutableString1.uppercaseString isEqual: @"3𝄞1€SäT"]) + + TEST(@"-[lowercaseString]", + R([mutableString1 uppercase]) && + [mutableString1.lowercaseString isEqual: @"3𝄞1€sät"]) TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString isEqual: @"džbla Tdžst TDŽst"]) #endif TEST(@"+[stringWithUTF8String:length:]", - (s[0] = [mutableStringClass stringWithUTF8String: "\xEF\xBB\xBF" - "foobar" - length: 6]) && - [s[0] isEqual: @"foo"]) + (mutableString1 = [mutableStringClass + stringWithUTF8String: "\xEF\xBB\xBF" "foobar" + length: 6]) && + [mutableString1 isEqual: @"foo"]) TEST(@"+[stringWithUTF16String:]", - (is = [stringClass stringWithUTF16String: utf16str]) && - [is isEqual: @"fööbär🀺"] && - (is = [stringClass stringWithUTF16String: sutf16str]) && - [is isEqual: @"fööbär🀺"]) + (string = [stringClass stringWithUTF16String: char16String]) && + [string isEqual: @"fööbär🀺"] && + (string = [stringClass stringWithUTF16String: + swappedChar16String]) && [string isEqual: @"fööbär🀺"]) TEST(@"+[stringWithUTF32String:]", - (is = [stringClass stringWithUTF32String: ucstr]) && - [is isEqual: @"fööbär🀺"] && - (is = [stringClass stringWithUTF32String: sucstr]) && - [is isEqual: @"fööbär🀺"]) + (string = [stringClass stringWithUTF32String: unicharString]) && + [string isEqual: @"fööbär🀺"] && + (string = [stringClass stringWithUTF32String: + swappedUnicharString]) && [string isEqual: @"fööbär🀺"]) #ifdef OF_HAVE_FILES - TEST(@"+[stringWithContentsOfFile:encoding]", (is = [stringClass + TEST(@"+[stringWithContentsOfFile:encoding]", (string = [stringClass stringWithContentsOfFile: @"testfile.txt" encoding: OFStringEncodingISO8859_1]) && - [is isEqual: @"testäöü"]) + [string isEqual: @"testäöü"]) - TEST(@"+[stringWithContentsOfURL:encoding]", (is = [stringClass + TEST(@"+[stringWithContentsOfURL:encoding]", (string = [stringClass stringWithContentsOfURL: [OFURL fileURLWithPath: @"testfile.txt"] encoding: OFStringEncodingISO8859_1]) && - [is isEqual: @"testäöü"]) + [string isEqual: @"testäöü"]) #endif TEST(@"-[appendUTFString:length:]", - R([s[0] appendUTF8String: "\xEF\xBB\xBF" "barqux" length: 6]) && - [s[0] isEqual: @"foobar"]) + R([mutableString1 appendUTF8String: "\xEF\xBB\xBF" "barqux" + length: 6]) && + [mutableString1 isEqual: @"foobar"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #1", OFInvalidEncodingException, [stringClass stringWithUTF8String: "\xE0\x80"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #2", @@ -473,17 +481,18 @@ !strcmp([C(@"T€st strîng ░▒▓") lossyCStringWithEncoding: OFStringEncodingCodepage437], "T?st str\x8Cng \xB0\xB1\xB2")) #endif TEST(@"+[stringWithFormat:]", - [(s[0] = [mutableStringClass stringWithFormat: @"%@:%d", @"test", - 123]) + [(mutableString1 = [mutableStringClass stringWithFormat: @"%@:%d", + @"test", + 123]) isEqual: @"test:123"]) TEST(@"-[appendFormat:]", - R(([s[0] appendFormat: @"%02X", 15])) && - [s[0] isEqual: @"test:1230F"]) + R(([mutableString1 appendFormat: @"%02X", 15])) && + [mutableString1 isEqual: @"test:1230F"]) TEST(@"-[rangeOfString:]", [C(@"𝄞öö") rangeOfString: @"öö"].location == 1 && [C(@"𝄞öö") rangeOfString: @"ö"].location == 1 && [C(@"𝄞öö") rangeOfString: @"𝄞"].location == 0 && @@ -500,29 +509,29 @@ EXPECT_EXCEPTION( @"Detect out of range in -[rangeOfString:options:range:]", OFOutOfRangeException, [C(@"𝄞öö") rangeOfString: @"ö" options: 0 range: OFRangeMake(3, 1)]) - cs = [OFCharacterSet characterSetWithCharactersInString: @"cđ"]; + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"cđ"]; TEST(@"-[indexOfCharacterFromSet:]", - [C(@"abcđabcđe") indexOfCharacterFromSet: cs] == 2 && - [C(@"abcđabcđë") - indexOfCharacterFromSet: cs - options: OFStringSearchBackwards] == 7 && - [C(@"abcđabcđë") - indexOfCharacterFromSet: cs - options: 0 - range: OFRangeMake(4, 4)] == 6 && - [C(@"abcđabcđëf") - indexOfCharacterFromSet: cs - options: 0 - range: OFRangeMake(8, 2)] == OFNotFound) + [C(@"abcđabcđe") indexOfCharacterFromSet: characterSet] == 2 && + [C(@"abcđabcđë") + indexOfCharacterFromSet: characterSet + options: OFStringSearchBackwards] == 7 && + [C(@"abcđabcđë") indexOfCharacterFromSet: characterSet + options: 0 + range: OFRangeMake(4, 4)] == 6 && + [C(@"abcđabcđëf") + indexOfCharacterFromSet: characterSet + options: 0 + range: OFRangeMake(8, 2)] == OFNotFound) EXPECT_EXCEPTION( @"Detect out of range in -[indexOfCharacterFromSet:options:range:]", OFOutOfRangeException, - [C(@"𝄞öö") indexOfCharacterFromSet: cs + [C(@"𝄞öö") indexOfCharacterFromSet: characterSet options: 0 range: OFRangeMake(3, 1)]) TEST(@"-[substringWithRange:]", [[C(@"𝄞öö") substringWithRange: OFRangeMake(1, 1)] isEqual: @"ö"] && @@ -553,38 +562,59 @@ !C(@"foo").absolutePath && !C(@"b:foo").absolutePath) # elif defined(OF_AMIGAOS) TEST(@"-[isAbsolutePath]", C(@"dh0:foo").absolutePath && C(@"dh0:a/b").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[isAbsolutePath]", C(@"sdmc:/foo").absolutePath && !C(@"sdmc:foo").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) # else TEST(@"-[isAbsolutePath]", C(@"/foo").absolutePath && C(@"/foo/bar").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) # endif - s[0] = [mutableStringClass stringWithString: @"foo"]; -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - [s[0] appendString: @"\\"]; -# else - [s[0] appendString: @"/"]; -# endif - [s[0] appendString: @"bar"]; - s[1] = [mutableStringClass stringWithString: s[0]]; -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - [s[1] appendString: @"\\"]; -# else - [s[1] appendString: @"/"]; -# endif - is = [stringClass stringWithString: s[1]]; - [s[1] appendString: @"baz"]; + mutableString1 = [mutableStringClass stringWithString: @"foo"]; +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + [mutableString1 appendString: @"\\"]; +# else + [mutableString1 appendString: @"/"]; +# endif + [mutableString1 appendString: @"bar"]; + mutableString2 = [mutableStringClass stringWithString: mutableString1]; +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + [mutableString2 appendString: @"\\"]; +# else + [mutableString2 appendString: @"/"]; +# endif + string = [stringClass stringWithString: mutableString2]; + [mutableString2 appendString: @"baz"]; TEST(@"-[stringByAppendingPathComponent:]", - [[s[0] stringByAppendingPathComponent: @"baz"] isEqual: s[1]] && - [[is stringByAppendingPathComponent: @"baz"] isEqual: s[1]]) + [[mutableString1 stringByAppendingPathComponent: @"baz"] + isEqual: mutableString2] && + [[string stringByAppendingPathComponent: @"baz"] + isEqual: mutableString2]) + +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + TEST(@"-[stringByAppendingPathExtension:]", + [[C(@"foo") stringByAppendingPathExtension: @"bar"] + isEqual: @"foo.bar"] && + [[C(@"c:\\tmp\\foo") stringByAppendingPathExtension: @"bar"] + isEqual: @"c:\\tmp\\foo.bar"] && + [[C(@"c:\\tmp\\/\\") stringByAppendingPathExtension: @"bar"] + isEqual: @"c:\\tmp.bar"]) +# else + TEST(@"-[stringByAppendingPathExtension:]", + [[C(@"foo") stringByAppendingPathExtension: @"bar"] + isEqual: @"foo.bar"] && + [[C(@"foo/bar") stringByAppendingPathExtension: @"baz"] + isEqual: @"foo/bar.baz"] && + [[C(@"foo///") stringByAppendingPathExtension: @"bar"] + isEqual: @"foo.bar"]) +# endif #endif TEST(@"-[hasPrefix:]", [C(@"foobar") hasPrefix: @"foo"] && ![C(@"foobar") hasPrefix: @"foobar0"]) @@ -591,61 +621,62 @@ TEST(@"-[hasSuffix:]", [C(@"foobar") hasSuffix: @"bar"] && ![C(@"foobar") hasSuffix: @"foobar0"]) i = 0; TEST(@"-[componentsSeparatedByString:]", - (a = [C(@"fooXXbarXXXXbazXXXX") + (array = [C(@"fooXXbarXXXXbazXXXX") componentsSeparatedByString: @"XX"]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - a.count == i && - (a = [C(@"foo") componentsSeparatedByString: @""]) && - [[a objectAtIndex: 0] isEqual: @"foo"] && - a.count == 1) + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + array.count == i && + (array = [C(@"foo") componentsSeparatedByString: @""]) && + [[array objectAtIndex: 0] isEqual: @"foo"] && + array.count == 1) i = 0; TEST(@"-[componentsSeparatedByString:options:]", - (a = [C(@"fooXXbarXXXXbazXXXX") + (array = [C(@"fooXXbarXXXXbazXXXX") componentsSeparatedByString: @"XX" options: OFStringSkipEmptyComponents]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - a.count == i) + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + array.count == i) - cs = [OFCharacterSet characterSetWithCharactersInString: @"XYZ"]; + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"XYZ"]; i = 0; TEST(@"-[componentsSeparatedByCharactersInSet:]", - (a = [C(@"fooXYbarXYZXbazXYXZx") - componentsSeparatedByCharactersInSet: cs]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"x"] && - a.count == i) + (array = [C(@"fooXYbarXYZXbazXYXZx") + componentsSeparatedByCharactersInSet: characterSet]) && + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"x"] && + array.count == i) i = 0; TEST(@"-[componentsSeparatedByCharactersInSet:options:]", - (a = [C(@"fooXYbarXYZXbazXYXZ") - componentsSeparatedByCharactersInSet: cs + (array = [C(@"fooXYbarXYZXbazXYXZ") + componentsSeparatedByCharactersInSet: characterSet options: OFStringSkipEmptyComponents]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - a.count == i) + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + array.count == i) #ifdef OF_HAVE_FILES # if defined(OF_WINDOWS) TEST(@"+[pathWithComponents:]", [[stringClass pathWithComponents: [OFArray arrayWithObjects: @@ -716,11 +747,12 @@ [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo/", @"bar", @"", @"baz", @"/", nil]] isEqual: @"foo//bar/baz//"] && [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo", nil]] isEqual: @"foo"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"+[pathWithComponents:]", [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] && [[stringClass pathWithComponents: [OFArray arrayWithObjects: @"sdmc:", @"foo", @"bar", @"baz", nil]] @@ -746,151 +778,152 @@ # endif # if defined(OF_WINDOWS) TEST(@"-[pathComponents]", /* c:/tmp */ - (a = C(@"c:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\tmp\ */ - (a = C(@"c:\\tmp\\").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\ */ - (a = C(@"c:\\").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && + (array = C(@"c:\\").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && /* c:/ */ - (a = C(@"c:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && + (array = C(@"c:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && /* c: */ - (a = C(@"c:").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:"] && + (array = C(@"c:").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:"] && /* foo\bar */ - (a = C(@"foo\\bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo\\bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo\bar/baz/ */ - (a = C(@"foo\\bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo\/ */ - (a = C(@"foo\\/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo\\/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && /* \\foo\bar */ - (a = C(@"\\\\foo\\bar").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"\\\\"] && - [[a objectAtIndex: 1] isEqual: @"foo"] && - [[a objectAtIndex: 2] isEqual: @"bar"] && + (array = C(@"\\\\foo\\bar").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"\\\\"] && + [[array objectAtIndex: 1] isEqual: @"foo"] && + [[array objectAtIndex: 2] isEqual: @"bar"] && C(@"").pathComponents.count == 0) # elif defined(OF_MSDOS) TEST(@"-[pathComponents]", /* c:/tmp */ - (a = C(@"c:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\tmp\ */ - (a = C(@"c:\\tmp\\").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\ */ - (a = C(@"c:\\").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && + (array = C(@"c:\\").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && /* c:/ */ - (a = C(@"c:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && + (array = C(@"c:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && /* c: */ - (a = C(@"c:").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:"] && + (array = C(@"c:").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:"] && /* foo\bar */ - (a = C(@"foo\\bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo\\bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo\bar/baz/ */ - (a = C(@"foo\\bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo\/ */ - (a = C(@"foo\\/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo\\/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # elif defined(OF_AMIGAOS) TEST(@"-[pathComponents]", /* dh0:tmp */ - (a = C(@"dh0:tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"dh0:tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* dh0:tmp/ */ - (a = C(@"dh0:tmp/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"dh0:tmp/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* dh0: */ - (a = C(@"dh0:/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"/"] && + (array = C(@"dh0:/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"/"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"/"] && + (array = C(@"foo//").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"/"] && C(@"").pathComponents.count == 0) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[pathComponents]", /* sdmc:/tmp */ - (a = C(@"sdmc:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"sdmc:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"sdmc:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"sdmc:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* sdmc:/ */ - (a = C(@"sdmc:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"sdmc:"] && + (array = C(@"sdmc:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"sdmc:"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo//").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # else TEST(@"-[pathComponents]", /* /tmp */ - (a = C(@"/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* /tmp/ */ - (a = C(@"/tmp/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"/tmp/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* / */ - (a = C(@"/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"/"] && + (array = C(@"/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"/"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo//").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # endif # if defined(OF_WINDOWS) TEST(@"-[lastPathComponent]", @@ -921,11 +954,12 @@ [C(@"dh0:/").lastPathComponent isEqual: @"/"] && [C(@"dh0:").lastPathComponent isEqual: @"dh0:"] && [C(@"foo").lastPathComponent isEqual: @"foo"] && [C(@"foo/bar").lastPathComponent isEqual: @"bar"] && [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[lastPathComponent]", [C(@"sdmc:/tmp").lastPathComponent isEqual: @"tmp"] && [C(@"sdmc:/tmp/").lastPathComponent isEqual: @"tmp"] && [C(@"sdmc:/").lastPathComponent isEqual: @"sdmc:/"] && [C(@"sdmc:").lastPathComponent isEqual: @"sdmc:"] && @@ -987,11 +1021,12 @@ [C(@"dh0:/").stringByDeletingLastPathComponent isEqual: @"dh0:"] && [C(@"dh0:tmp/foo/").stringByDeletingLastPathComponent isEqual: @"dh0:tmp"] && [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] && [C(@"foo").stringByDeletingLastPathComponent isEqual: @""]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[stringByDeletingLastPathComponent]", [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @""] && [C(@"sdmc:/tmp/foo/").stringByDeletingLastPathComponent isEqual: @"sdmc:/tmp"] && [C(@"sdmc:/").stringByDeletingLastPathComponent @@ -1034,11 +1069,12 @@ [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] && [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] && [C(@".foo\\bar").stringByDeletingPathExtension isEqual: @".foo\\bar"] && [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"]) -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) +# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \ + defined(OF_NINTENDO_SWITCH) TEST(@"-[stringByDeletingPathExtension]", [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] && [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] && [C(@"sdmc:/foo./bar").stringByDeletingPathExtension isEqual: @"sdmc:/foo./bar"] && @@ -1183,32 +1219,36 @@ OFOutOfRangeException, [C(@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF") unsignedLongLongValueWithBase: 16]) - TEST(@"-[characters]", (ua = C(@"fööbär🀺").characters) && - !memcmp(ua, ucstr + 1, sizeof(ucstr) - 8)) + TEST(@"-[characters]", (characters = C(@"fööbär🀺").characters) && + !memcmp(characters, unicharString + 1, sizeof(unicharString) - 8)) #ifdef OF_BIG_ENDIAN -# define SWAPPED_BYTE_ORDER OFByteOrderLittleEndian +# define swappedByteOrder OFByteOrderLittleEndian #else -# define SWAPPED_BYTE_ORDER OFByteOrderBigEndian +# define swappedByteOrder OFByteOrderBigEndian #endif - TEST(@"-[UTF16String]", (u16a = C(@"fööbär🀺").UTF16String) && - !memcmp(u16a, utf16str + 1, OFUTF16StringLength(utf16str) * 2) && - (u16a = [C(@"fööbär🀺") - UTF16StringWithByteOrder: SWAPPED_BYTE_ORDER]) && - !memcmp(u16a, sutf16str + 1, OFUTF16StringLength(sutf16str) * 2)) + TEST(@"-[UTF16String]", (UTF16Characters = C(@"fööbär🀺").UTF16String) && + !memcmp(UTF16Characters, char16String + 1, + OFUTF16StringLength(char16String) * 2) && + (UTF16Characters = [C(@"fööbär🀺") + UTF16StringWithByteOrder: swappedByteOrder]) && + !memcmp(UTF16Characters, swappedChar16String + 1, + OFUTF16StringLength(swappedChar16String) * 2)) TEST(@"-[UTF16StringLength]", C(@"fööbär🀺").UTF16StringLength == 8) - TEST(@"-[UTF32String]", (ua = C(@"fööbär🀺").UTF32String) && - !memcmp(ua, ucstr + 1, OFUTF32StringLength(ucstr) * 4) && - (ua = [C(@"fööbär🀺") UTF32StringWithByteOrder: - SWAPPED_BYTE_ORDER]) && - !memcmp(ua, sucstr + 1, OFUTF32StringLength(sucstr) * 4)) -#undef SWAPPED_BYTE_ORDER + TEST(@"-[UTF32String]", (characters = C(@"fööbär🀺").UTF32String) && + !memcmp(characters, unicharString + 1, + OFUTF32StringLength(unicharString) * 4) && + (characters = [C(@"fööbär🀺") UTF32StringWithByteOrder: + swappedByteOrder]) && + !memcmp(characters, swappedUnicharString + 1, + OFUTF32StringLength(swappedUnicharString) * 4)) +#undef swappedByteOrder TEST(@"-[stringByMD5Hashing]", [C(@"asdfoobar").stringByMD5Hashing isEqual: @"184dce2ec49b5422c7cfd8728864db4c"]) TEST(@"-[stringByRIPEMD160Hashing]", @@ -1233,118 +1273,138 @@ TEST(@"-[stringBySHA512Hashing]", [C(@"asdfoobar").stringBySHA512Hashing isEqual: @"0464c427da158b02161bb44a3090bbfc594611ef6a53603640454b56" @"412a9247c3579a329e53a5dc74676b106755e3394f9454a2d4227324" @"2615d32f80437d61"]) - cs = [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$🍏"]; + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$🍏"]; TEST(@"-[stringByURLEncodingWithAllowedCharacters:]", [[C(@"foo\"ba'_~$]🍏🍌") stringByURLEncodingWithAllowedCharacters: - cs] isEqual: @"foo%22ba'_~$%5D🍏%F0%9F%8D%8C"]) + characterSet] isEqual: @"foo%22ba'_~$%5D🍏%F0%9F%8D%8C"]) TEST(@"-[stringByURLDecoding]", [C(@"foo%20bar%22+%24%F0%9F%8D%8C").stringByURLDecoding isEqual: @"foo bar\"+$🍌"]) TEST(@"-[insertString:atIndex:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] insertString: @"äöü" atIndex: 3]) && - [s[0] isEqual: @"𝄞ööäöüöbä€"]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 insertString: @"äöü" atIndex: 3]) && + [mutableString1 isEqual: @"𝄞ööäöüöbä€"]) EXPECT_EXCEPTION(@"Detect invalid format in -[stringByURLDecoding] " @"#1", OFInvalidFormatException, [C(@"foo%xbar") stringByURLDecoding]) EXPECT_EXCEPTION(@"Detect invalid encoding in -[stringByURLDecoding] " @"#2", OFInvalidEncodingException, [C(@"foo%FFbar") stringByURLDecoding]) TEST(@"-[setCharacter:atIndex:]", - (s[0] = [mutableStringClass stringWithString: @"abäde"]) && - R([s[0] setCharacter: 0xF6 atIndex: 2]) && - [s[0] isEqual: @"aböde"] && - R([s[0] setCharacter: 'c' atIndex: 2]) && - [s[0] isEqual: @"abcde"] && - R([s[0] setCharacter: 0x20AC atIndex: 3]) && - [s[0] isEqual: @"abc€e"] && - R([s[0] setCharacter: 'x' atIndex: 1]) && [s[0] isEqual: @"axc€e"]) + (mutableString1 = [mutableStringClass + stringWithString: @"abäde"]) && + R([mutableString1 setCharacter: 0xF6 atIndex: 2]) && + [mutableString1 isEqual: @"aböde"] && + R([mutableString1 setCharacter: 'c' atIndex: 2]) && + [mutableString1 isEqual: @"abcde"] && + R([mutableString1 setCharacter: 0x20AC atIndex: 3]) && + [mutableString1 isEqual: @"abc€e"] && + R([mutableString1 setCharacter: 'x' atIndex: 1]) && + [mutableString1 isEqual: @"axc€e"]) TEST(@"-[deleteCharactersInRange:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] deleteCharactersInRange: OFRangeMake(1, 3)]) && - [s[0] isEqual: @"𝄞bä€"] && - R([s[0] deleteCharactersInRange: OFRangeMake(0, 4)]) && - [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 deleteCharactersInRange: OFRangeMake(1, 3)]) && + [mutableString1 isEqual: @"𝄞bä€"] && + R([mutableString1 deleteCharactersInRange: OFRangeMake(0, 4)]) && + [mutableString1 isEqual: @""]) TEST(@"-[replaceCharactersInRange:withString:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] replaceCharactersInRange: OFRangeMake(1, 3) - withString: @"äöüß"]) && - [s[0] isEqual: @"𝄞äöüßbä€"] && - R([s[0] replaceCharactersInRange: OFRangeMake(4, 2) - withString: @"b"]) && - [s[0] isEqual: @"𝄞äöübä€"] && - R([s[0] replaceCharactersInRange: OFRangeMake(0, 7) - withString: @""]) && - [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 replaceCharactersInRange: OFRangeMake(1, 3) + withString: @"äöüß"]) && + [mutableString1 isEqual: @"𝄞äöüßbä€"] && + R([mutableString1 replaceCharactersInRange: OFRangeMake(4, 2) + withString: @"b"]) && + [mutableString1 isEqual: @"𝄞äöübä€"] && + R([mutableString1 replaceCharactersInRange: OFRangeMake(0, 7) + withString: @""]) && + [mutableString1 isEqual: @""]) EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #1", OFOutOfRangeException, { - s[0] = [mutableStringClass stringWithString: @"𝄞öö"]; - [s[0] deleteCharactersInRange: OFRangeMake(2, 2)]; + mutableString1 = [mutableStringClass stringWithString: @"𝄞öö"]; + [mutableString1 deleteCharactersInRange: OFRangeMake(2, 2)]; }) EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #2", OFOutOfRangeException, - [s[0] deleteCharactersInRange: OFRangeMake(4, 0)]) + [mutableString1 deleteCharactersInRange: OFRangeMake(4, 0)]) EXPECT_EXCEPTION(@"Detect OoR in " @"-[replaceCharactersInRange:withString:] #1", OFOutOfRangeException, - [s[0] replaceCharactersInRange: OFRangeMake(2, 2) withString: @""]) + [mutableString1 replaceCharactersInRange: OFRangeMake(2, 2) + withString: @""]) EXPECT_EXCEPTION(@"Detect OoR in " @"-[replaceCharactersInRange:withString:] #2", OFOutOfRangeException, - [s[0] replaceCharactersInRange: OFRangeMake(4, 0) withString: @""]) + [mutableString1 replaceCharactersInRange: OFRangeMake(4, 0) + withString: @""]) TEST(@"-[replaceOccurrencesOfString:withString:]", - (s[0] = [mutableStringClass stringWithString: + (mutableString1 = [mutableStringClass stringWithString: @"asd fo asd fofo asd"]) && - R([s[0] replaceOccurrencesOfString: @"fo" withString: @"foo"]) && - [s[0] isEqual: @"asd foo asd foofoo asd"] && - (s[0] = [mutableStringClass stringWithString: @"XX"]) && - R([s[0] replaceOccurrencesOfString: @"X" withString: @"XX"]) && - [s[0] isEqual: @"XXXX"]) + R([mutableString1 replaceOccurrencesOfString: @"fo" + withString: @"foo"]) && + [mutableString1 isEqual: @"asd foo asd foofoo asd"] && + (mutableString1 = [mutableStringClass stringWithString: @"XX"]) && + R([mutableString1 replaceOccurrencesOfString: @"X" + withString: @"XX"]) && + [mutableString1 isEqual: @"XXXX"]) TEST(@"-[replaceOccurrencesOfString:withString:options:range:]", - (s[0] = [mutableStringClass stringWithString: - @"foofoobarfoobarfoo"]) && - R([s[0] replaceOccurrencesOfString: @"oo" - withString: @"óò" - options: 0 - range: OFRangeMake(2, 15)]) && - [s[0] isEqual: @"foofóòbarfóòbarfoo"]) + (mutableString1 = [mutableStringClass stringWithString: + @"foofoobarfoobarfoo"]) && R([mutableString1 + replaceOccurrencesOfString: @"oo" + withString: @"óò" + options: 0 + range: OFRangeMake(2, 15)]) && + [mutableString1 isEqual: @"foofóòbarfóòbarfoo"]) TEST(@"-[deleteLeadingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteLeadingWhitespaces]) && - [s[0] isEqual: @"asd \t \t\t\r\n"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteLeadingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteLeadingWhitespaces]) && + [mutableString1 isEqual: @"asd \t \t\t\r\n"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteLeadingWhitespaces]) && + [mutableString1 isEqual: @""]) TEST(@"-[deleteTrailingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteTrailingWhitespaces]) && - [s[0] isEqual: @" \r \t\n\t \tasd"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteTrailingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteTrailingWhitespaces]) && + [mutableString1 isEqual: @" \r \t\n\t \tasd"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteTrailingWhitespaces]) && + [mutableString1 isEqual: @""]) TEST(@"-[deleteEnclosingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteEnclosingWhitespaces]) && [s[0] isEqual: @"asd"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteEnclosingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteEnclosingWhitespaces]) && + [mutableString1 isEqual: @"asd"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteEnclosingWhitespaces]) && + [mutableString1 isEqual: @""]) #ifdef OF_HAVE_UNICODE_TABLES TEST(@"-[decomposedStringWithCanonicalMapping]", [C(@"H\xC3\xA4llj\xC3\xB6").decomposedStringWithCanonicalMapping isEqual: @"H\x61\xCC\x88llj\x6F\xCC\x88"]); @@ -1353,15 +1413,15 @@ [C(@"H\xC3\xA4llj\xC3\xB6").decomposedStringWithCompatibilityMapping isEqual: @"H\x61\xCC\x88llj\x6F\xCC\x88"]); #endif TEST(@"-[stringByXMLEscaping]", - (is = C(@" &world'\"!&").stringByXMLEscaping) && - [is isEqual: @"<hello> &world'"!&"]) + (string = C(@" &world'\"!&").stringByXMLEscaping) && + [string isEqual: @"<hello> &world'"!&"]) TEST(@"-[stringByXMLUnescaping]", - [is.stringByXMLUnescaping isEqual: @" &world'\"!&"] && + [string.stringByXMLUnescaping isEqual: @" &world'\"!&"] && [C(@"y").stringByXMLUnescaping isEqual: @"y"] && [C(@"ä").stringByXMLUnescaping isEqual: @"ä"] && [C(@"€").stringByXMLUnescaping isEqual: @"€"] && [C(@"𝄞").stringByXMLUnescaping isEqual: @"𝄞"]) @@ -1379,18 +1439,18 @@ EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#5", OFInvalidFormatException, [C(@"&#xg;") stringByXMLUnescaping]) TEST(@"-[stringByXMLUnescapingWithDelegate:]", - (h = [[[EntityHandler alloc] init] autorelease]) && - [[C(@"x&foo;y") stringByXMLUnescapingWithDelegate: h] + (entityHandler = [[[EntityHandler alloc] init] autorelease]) && + [[C(@"x&foo;y") stringByXMLUnescapingWithDelegate: entityHandler] isEqual: @"xbary"]) #ifdef OF_HAVE_BLOCKS TEST(@"-[stringByXMLUnescapingWithBlock:]", [[C(@"x&foo;y") stringByXMLUnescapingWithBlock: - ^ OFString *(OFString *str, OFString *entity) { + ^ OFString *(OFString *str, OFString *entity) { if ([entity isEqual: @"foo"]) return @"bar"; return nil; }] isEqual: @"xbary"]) Index: tests/OFSystemInfoTests.m ================================================================== --- tests/OFSystemInfoTests.m +++ tests/OFSystemInfoTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -19,13 +19,10 @@ @implementation TestsAppDelegate (OFSystemInfoTests) - (void)systemInfoTests { void *pool = objc_autoreleasePoolPush(); -#ifdef OF_HAVE_FILES - OFString *userConfigPath, *userDataPath; -#endif [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeFormat: @"[OFSystemInfo] Page size: %zd\n", [OFSystemInfo pageSize]]; @@ -47,27 +44,18 @@ [OFStdOut writeFormat: @"[OFSystemInfo] Operating system version: %@\n", [OFSystemInfo operatingSystemVersion]]; -#ifdef OF_HAVE_FILES - @try { - userConfigPath = [OFSystemInfo userConfigPath]; - } @catch (OFNotImplementedException *e) { - userConfigPath = @"Not implemented"; - } - [OFStdOut writeFormat: @"[OFSystemInfo] User config path: %@\n", - userConfigPath]; - - @try { - userDataPath = [OFSystemInfo userDataPath]; - } @catch (OFNotImplementedException *e) { - userDataPath = @"Not implemented"; - } - [OFStdOut writeFormat: @"[OFSystemInfo] User data path: %@\n", - userDataPath]; -#endif + [OFStdOut writeFormat: @"[OFSystemInfo] User config URL: %@\n", + [OFSystemInfo userConfigURL].string]; + + [OFStdOut writeFormat: @"[OFSystemInfo] User data URL: %@\n", + [OFSystemInfo userDataURL].string]; + + [OFStdOut writeFormat: @"[OFSystemInfo] Temporary directory URL: %@\n", + [OFSystemInfo temporaryDirectoryURL].string]; [OFStdOut writeFormat: @"[OFSystemInfo] CPU vendor: %@\n", [OFSystemInfo CPUVendor]]; [OFStdOut writeFormat: @"[OFSystemInfo] CPU model: %@\n", Index: tests/OFTCPSocketTests.m ================================================================== --- tests/OFTCPSocketTests.m +++ tests/OFTCPSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,19 +17,19 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFTCPSocket"; +static OFString *const module = @"OFTCPSocket"; @implementation TestsAppDelegate (OFTCPSocketTests) - (void)TCPSocketTests { void *pool = objc_autoreleasePoolPush(); OFTCPSocket *server, *client = nil, *accepted; uint16_t port; - char buf[6]; + char buffer[6]; TEST(@"+[socket]", (server = [OFTCPSocket socket]) && (client = [OFTCPSocket socket])) TEST(@"-[bindToHost:port:]", @@ -44,14 +44,14 @@ TEST(@"-[remoteAddress]", [OFSocketAddressString(accepted.remoteAddress) isEqual: @"127.0.0.1"]) - TEST(@"-[writeString:]", [client writeString: @"Hello!"]) + TEST(@"-[writeString:]", R([client writeString: @"Hello!"])) TEST(@"-[readIntoBuffer:length:]", - [accepted readIntoBuffer: buf length: 6] && - !memcmp(buf, "Hello!", 6)) + [accepted readIntoBuffer: buffer length: 6] && + !memcmp(buffer, "Hello!", 6)) objc_autoreleasePoolPop(pool); } @end Index: tests/OFThreadTests.m ================================================================== --- tests/OFThreadTests.m +++ tests/OFThreadTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,38 +15,39 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFThread"; +static OFString *const module = @"OFThread"; @interface TestThread: OFThread @end @implementation TestThread - (id)main { [[OFThread threadDictionary] setObject: @"bar" forKey: @"foo"]; + OFEnsure([[[OFThread threadDictionary] + objectForKey: @"foo"] isEqual: @"bar"]); return @"success"; } @end @implementation TestsAppDelegate (OFThreadTests) - (void)threadTests { void *pool = objc_autoreleasePoolPush(); - TestThread *t; - OFMutableDictionary *d; - - TEST(@"+[thread]", (t = [TestThread thread])) - - TEST(@"-[start]", R([t start])) - - TEST(@"-[join]", [[t join] isEqual: @"success"]) - - TEST(@"-[threadDictionary]", (d = [OFThread threadDictionary]) && - [d objectForKey: @"foo"] == nil) + TestThread *thread; + + TEST(@"+[thread]", (thread = [TestThread thread])) + + TEST(@"-[start]", R([thread start])) + + TEST(@"-[join]", [[thread join] isEqual: @"success"]) + + TEST(@"-[threadDictionary]", + [[OFThread threadDictionary] objectForKey: @"foo"] == nil) objc_autoreleasePoolPop(pool); } @end Index: tests/OFUDPSocketTests.m ================================================================== --- tests/OFUDPSocketTests.m +++ tests/OFUDPSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFUDPSocket"; +static OFString *const module = @"OFUDPSocket"; @implementation TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests { void *pool = objc_autoreleasePoolPush(); ADDED tests/OFUNIXDatagramSocketTests.m Index: tests/OFUNIXDatagramSocketTests.m ================================================================== --- /dev/null +++ tests/OFUNIXDatagramSocketTests.m @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFUNIXDatagramSocket"; + +@implementation TestsAppDelegate (OFUNIXDatagramSocketTests) +- (void)UNIXDatagramSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + OFUNIXDatagramSocket *sock; + OFSocketAddress address1, address2; + char buffer[5]; + +#if defined(OF_HAVE_FILES) && !defined(OF_IOS) + path = [[OFSystemInfo temporaryDirectoryURL] + URLByAppendingPathComponent: [[OFUUID UUID] UUIDString]] + .fileSystemRepresentation; +#else + /* + * We can have sockets, including UNIX sockets, while file support is + * disabled. + * + * We also use this code path for iOS, as the temporaryDirectoryURL is + * too long on the iOS simulator. + */ + path = [OFString stringWithFormat: @"/tmp/%@", + [[OFUUID UUID] UUIDString]]; +#endif + + TEST(@"+[socket]", (sock = [OFUNIXDatagramSocket socket])) + + @try { + TEST(@"-[bindToPath:]", R(address1 = [sock bindToPath: path])) + } @catch (OFBindFailedException *e) { + switch (e.errNo) { + case EAFNOSUPPORT: + case EPERM: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFUNIXDatagramSocket] -[bindToPath:]: " + @"UNIX datagram sockets unsupported, skipping " + @"tests"]; + + objc_autoreleasePoolPop(pool); + return; + default: + @throw e; + } + } + + @try { + TEST(@"-[sendBuffer:length:receiver:]", + R([sock sendBuffer: "Hello" length: 5 receiver: &address1])) + + TEST(@"-[receiveIntoBuffer:length:sender:]", + [sock receiveIntoBuffer: buffer + length: 5 + sender: &address2] == 5 && + memcmp(buffer, "Hello", 5) == 0 && + OFSocketAddressEqual(&address1, &address2) && + OFSocketAddressHash(&address1) == + OFSocketAddressHash(&address2)) + } @finally { +#ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] removeItemAtPath: path]; +#endif + } + + objc_autoreleasePoolPop(pool); +} +@end ADDED tests/OFUNIXStreamSocketTests.m Index: tests/OFUNIXStreamSocketTests.m ================================================================== --- /dev/null +++ tests/OFUNIXStreamSocketTests.m @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008-2022 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" + +#include + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFUNIXStreamSocket"; + +@implementation TestsAppDelegate (OFUNIXStreamSocketTests) +- (void)UNIXStreamSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + OFUNIXStreamSocket *sockClient, *sockServer, *sockAccepted; + char buffer[5]; + +#if defined(OF_HAVE_FILES) && !defined(OF_IOS) + path = [[OFSystemInfo temporaryDirectoryURL] + URLByAppendingPathComponent: [[OFUUID UUID] UUIDString]] + .fileSystemRepresentation; +#else + /* + * We can have sockets, including UNIX sockets, while file support is + * disabled. + * + * We also use this code path for iOS, as the temporaryDirectoryURL is + * too long on the iOS simulator. + */ + path = [OFString stringWithFormat: @"/tmp/%@", + [[OFUUID UUID] UUIDString]]; +#endif + + TEST(@"+[socket]", (sockClient = [OFUNIXStreamSocket socket]) && + (sockServer = [OFUNIXStreamSocket socket])) + + @try { + TEST(@"-[bindToPath:]", R([sockServer bindToPath: path])) + } @catch (OFBindFailedException *e) { + switch (e.errNo) { + case EAFNOSUPPORT: + case EPERM: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFUNIXStreamSocket] -[bindToPath:]: " + @"UNIX stream sockets unsupported, skipping tests"]; + + objc_autoreleasePoolPop(pool); + return; + default: + @throw e; + } + } + + @try { + TEST(@"-[listen]", R([sockServer listen])) + + TEST(@"-[connectToPath:]", + R([sockClient connectToPath: path])) + + TEST(@"-[accept]", (sockAccepted = [sockServer accept])) + + TEST(@"-[writeBuffer:length:]", + R([sockAccepted writeBuffer: "Hello" length: 5])) + + TEST(@"-[readIntoBuffer:length:]", + [sockClient readIntoBuffer: buffer length: 5] == 5 && + memcmp(buffer, "Hello", 5) == 0) + + TEST(@"-[remoteAddress]", + OFSocketAddressUNIXPath(sockAccepted.remoteAddress) == nil) + } @finally { +#ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] removeItemAtPath: path]; +#endif + } + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFURLTests.m ================================================================== --- tests/OFURLTests.m +++ tests/OFURLTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,29 +15,29 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFURL"; -static OFString *url_str = @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/" +static OFString *const module = @"OFURL"; +static OFString *URLString = @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/" @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; @implementation TestsAppDelegate (OFURLTests) - (void)URLTests { void *pool = objc_autoreleasePoolPush(); - OFURL *u1, *u2, *u3, *u4, *u5, *u6, *u7; - OFMutableURL *mu; + OFURL *URL1, *URL2, *URL3, *URL4, *URL5, *URL6, *URL7; + OFMutableURL *mutableURL; TEST(@"+[URLWithString:]", - R(u1 = [OFURL URLWithString: url_str]) && - R(u2 = [OFURL URLWithString: @"http://foo:80"]) && - R(u3 = [OFURL URLWithString: @"http://bar/"]) && - R(u4 = [OFURL URLWithString: @"file:///etc/passwd"]) && - R(u5 = [OFURL URLWithString: @"http://foo/bar/qux/foo%2fbar"]) && - R(u6 = [OFURL URLWithString: @"https://[12:34::56:abcd]/"]) && - R(u7 = [OFURL URLWithString: @"https://[12:34::56:abcd]:234/"])) + R(URL1 = [OFURL URLWithString: URLString]) && + R(URL2 = [OFURL URLWithString: @"http://foo:80"]) && + R(URL3 = [OFURL URLWithString: @"http://bar/"]) && + R(URL4 = [OFURL URLWithString: @"file:///etc/passwd"]) && + R(URL5 = [OFURL URLWithString: @"http://foo/bar/qux/foo%2fbar"]) && + R(URL6 = [OFURL URLWithString: @"https://[12:34::56:abcd]/"]) && + R(URL7 = [OFURL URLWithString: @"https://[12:34::56:abcd]:234/"])) EXPECT_EXCEPTION(@"+[URLWithString:] fails with invalid characters #1", OFInvalidFormatException, [OFURL URLWithString: @"ht,tp://foo"]) @@ -68,20 +68,20 @@ EXPECT_EXCEPTION(@"+[URLWithString:] fails with invalid characters #8", OFInvalidFormatException, [OFURL URLWithString: @"https://[f]:f/"]) TEST(@"+[URLWithString:relativeToURL:]", - [[[OFURL URLWithString: @"/foo" relativeToURL: u1] string] isEqual: - @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && + [[[OFURL URLWithString: @"/foo" relativeToURL: URL1] string] + isEqual: @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && [[[OFURL URLWithString: @"foo/bar?q" relativeToURL: [OFURL URLWithString: @"http://h/qux/quux"]] string] isEqual: @"http://h/qux/foo/bar?q"] && [[[OFURL URLWithString: @"foo/bar" relativeToURL: [OFURL URLWithString: @"http://h/qux/?x"]] string] isEqual: @"http://h/qux/foo/bar"] && [[[OFURL URLWithString: @"http://foo/?q" - relativeToURL: u1] string] isEqual: @"http://foo/?q"] && + relativeToURL: URL1] string] isEqual: @"http://foo/?q"] && [[[OFURL URLWithString: @"foo" relativeToURL: [OFURL URLWithString: @"http://foo/bar"]] string] isEqual: @"http://foo/foo"] && [[[OFURL URLWithString: @"foo" relativeToURL: [OFURL URLWithString: @"http://foo"]] @@ -88,26 +88,26 @@ string] isEqual: @"http://foo/foo"]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #1", OFInvalidFormatException, - [OFURL URLWithString: @"`" relativeToURL: u1]) + [OFURL URLWithString: @"`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #2", OFInvalidFormatException, - [OFURL URLWithString: @"/`" relativeToURL: u1]) + [OFURL URLWithString: @"/`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #3", OFInvalidFormatException, - [OFURL URLWithString: @"?`" relativeToURL: u1]) + [OFURL URLWithString: @"?`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #4", OFInvalidFormatException, - [OFURL URLWithString: @"#`" relativeToURL: u1]) + [OFURL URLWithString: @"#`" relativeToURL: URL1]) #ifdef OF_HAVE_FILES TEST(@"+[fileURLWithPath:]", [[[OFURL fileURLWithPath: @"testfile.txt"] fileSystemRepresentation] isEqual: [[OFFileManager defaultManager].currentDirectoryPath @@ -133,34 +133,35 @@ [tmp.fileSystemRepresentation isEqual: @"\\\\test"]) # endif #endif TEST(@"-[string]", - [u1.string isEqual: url_str] && - [u2.string isEqual: @"http://foo:80"] && - [u3.string isEqual: @"http://bar/"] && - [u4.string isEqual: @"file:///etc/passwd"]) + [URL1.string isEqual: URLString] && + [URL2.string isEqual: @"http://foo:80"] && + [URL3.string isEqual: @"http://bar/"] && + [URL4.string isEqual: @"file:///etc/passwd"]) TEST(@"-[scheme]", - [u1.scheme isEqual: @"ht:tp"] && [u4.scheme isEqual: @"file"]) + [URL1.scheme isEqual: @"ht:tp"] && [URL4.scheme isEqual: @"file"]) - TEST(@"-[user]", [u1.user isEqual: @"us:er"] && u4.user == nil) + TEST(@"-[user]", [URL1.user isEqual: @"us:er"] && URL4.user == nil) TEST(@"-[password]", - [u1.password isEqual: @"p@w"] && u4.password == nil) - TEST(@"-[host]", [u1.host isEqual: @"ho:st"] && - [u6.host isEqual: @"12:34::56:abcd"] && - [u7.host isEqual: @"12:34::56:abcd"]) - TEST(@"-[port]", u1.port.unsignedShortValue == 1234 && - [u4 port] == nil && u7.port.unsignedShortValue == 234) + [URL1.password isEqual: @"p@w"] && URL4.password == nil) + TEST(@"-[host]", [URL1.host isEqual: @"ho:st"] && + [URL6.host isEqual: @"12:34::56:abcd"] && + [URL7.host isEqual: @"12:34::56:abcd"]) + TEST(@"-[port]", URL1.port.unsignedShortValue == 1234 && + [URL4 port] == nil && URL7.port.unsignedShortValue == 234) TEST(@"-[path]", - [u1.path isEqual: @"/pa?th"] && [u4.path isEqual: @"/etc/passwd"]) + [URL1.path isEqual: @"/pa?th"] && + [URL4.path isEqual: @"/etc/passwd"]) TEST(@"-[pathComponents]", - [u1.pathComponents isEqual: + [URL1.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && - [u4.pathComponents isEqual: + [URL4.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil]] && - [u5.pathComponents isEqual: + [URL5.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", nil]]) TEST(@"-[lastPathComponent]", [[[OFURL URLWithString: @"http://host/foo//bar/baz"] lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo//bar/baz/"] @@ -167,124 +168,137 @@ lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo/"] lastPathComponent] isEqual: @"foo"] && [[[OFURL URLWithString: @"http://host/"] lastPathComponent] isEqual: @"/"] && - [u5.lastPathComponent isEqual: @"foo/bar"]) + [URL5.lastPathComponent isEqual: @"foo/bar"]) TEST(@"-[query]", - [u1.query isEqual: @"que#ry=1&f&oo=b=ar"] && u4.query == nil) + [URL1.query isEqual: @"que#ry=1&f&oo=b=ar"] && URL4.query == nil) TEST(@"-[queryDictionary]", - [u1.queryDictionary isEqual: + [URL1.queryDictionary isEqual: [OFDictionary dictionaryWithKeysAndObjects: @"que#ry", @"1", @"f&oo", @"b=ar", nil]]); TEST(@"-[fragment]", - [u1.fragment isEqual: @"frag#ment"] && u4.fragment == nil) - - TEST(@"-[copy]", R(u4 = [[u1 copy] autorelease])) - - TEST(@"-[isEqual:]", [u1 isEqual: u4] && ![u2 isEqual: u3] && - [[OFURL URLWithString: @"HTTP://bar/"] isEqual: u3]) - - TEST(@"-[hash:]", u1.hash == u4.hash && u2.hash != u3.hash) + [URL1.fragment isEqual: @"frag#ment"] && URL4.fragment == nil) + + TEST(@"-[copy]", R(URL4 = [[URL1 copy] autorelease])) + + TEST(@"-[isEqual:]", [URL1 isEqual: URL4] && ![URL2 isEqual: URL3] && + [[OFURL URLWithString: @"HTTP://bar/"] isEqual: URL3]) + + TEST(@"-[hash:]", URL1.hash == URL4.hash && URL2.hash != URL3.hash) EXPECT_EXCEPTION(@"Detection of invalid format", OFInvalidFormatException, [OFURL URLWithString: @"http"]) - mu = [OFMutableURL URL]; + mutableURL = [OFMutableURL URL]; TEST(@"-[setScheme:]", - (mu.scheme = @"ht:tp") && [mu.URLEncodedScheme isEqual: @"ht%3Atp"]) + (mutableURL.scheme = @"ht:tp") && + [mutableURL.URLEncodedScheme isEqual: @"ht%3Atp"]) TEST(@"-[setURLEncodedScheme:]", - (mu.URLEncodedScheme = @"ht%3Atp") && [mu.scheme isEqual: @"ht:tp"]) + (mutableURL.URLEncodedScheme = @"ht%3Atp") && + [mutableURL.scheme isEqual: @"ht:tp"]) EXPECT_EXCEPTION( @"-[setURLEncodedScheme:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedScheme = @"~") - - TEST(@"-[setHost:]", - (mu.host = @"ho:st") && [mu.URLEncodedHost isEqual: @"ho%3Ast"] && - (mu.host = @"12:34:ab") && - [mu.URLEncodedHost isEqual: @"[12:34:ab]"] && - (mu.host = @"12:34:aB") && - [mu.URLEncodedHost isEqual: @"[12:34:aB]"] && - (mu.host = @"12:34:g") && - [mu.URLEncodedHost isEqual: @"12%3A34%3Ag"]) - - TEST(@"-[setURLEncodedHost:]", - (mu.URLEncodedHost = @"ho%3Ast") && [mu.host isEqual: @"ho:st"] && - (mu.URLEncodedHost = @"[12:34]") && [mu.host isEqual: @"12:34"] && - (mu.URLEncodedHost = @"[12::ab]") && [mu.host isEqual: @"12::ab"]) - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #1", OFInvalidFormatException, mu.URLEncodedHost = @"/") - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #2", OFInvalidFormatException, mu.URLEncodedHost = @"[12:34") - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #3", OFInvalidFormatException, mu.URLEncodedHost = @"[a::g]") - - TEST(@"-[setUser:]", - (mu.user = @"us:er") && [mu.URLEncodedUser isEqual: @"us%3Aer"]) - - TEST(@"-[setURLEncodedUser:]", - (mu.URLEncodedUser = @"us%3Aer") && [mu.user isEqual: @"us:er"]) - - EXPECT_EXCEPTION(@"-[setURLEncodedUser:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedHost = @"/") - - TEST(@"-[setPassword:]", - (mu.password = @"pass:word") && - [mu.URLEncodedPassword isEqual: @"pass%3Aword"]) - - TEST(@"-[setURLEncodedPassword:]", - (mu.URLEncodedPassword = @"pass%3Aword") && - [mu.password isEqual: @"pass:word"]) + OFInvalidFormatException, mutableURL.URLEncodedScheme = @"~") + + TEST(@"-[setHost:]", + (mutableURL.host = @"ho:st") && + [mutableURL.URLEncodedHost isEqual: @"ho%3Ast"] && + (mutableURL.host = @"12:34:ab") && + [mutableURL.URLEncodedHost isEqual: @"[12:34:ab]"] && + (mutableURL.host = @"12:34:aB") && + [mutableURL.URLEncodedHost isEqual: @"[12:34:aB]"] && + (mutableURL.host = @"12:34:g") && + [mutableURL.URLEncodedHost isEqual: @"12%3A34%3Ag"]) + + TEST(@"-[setURLEncodedHost:]", + (mutableURL.URLEncodedHost = @"ho%3Ast") && + [mutableURL.host isEqual: @"ho:st"] && + (mutableURL.URLEncodedHost = @"[12:34]") && + [mutableURL.host isEqual: @"12:34"] && + (mutableURL.URLEncodedHost = @"[12::ab]") && + [mutableURL.host isEqual: @"12::ab"]) + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #1", OFInvalidFormatException, mutableURL.URLEncodedHost = @"/") + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #2", OFInvalidFormatException, + mutableURL.URLEncodedHost = @"[12:34") + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #3", OFInvalidFormatException, + mutableURL.URLEncodedHost = @"[a::g]") + + TEST(@"-[setUser:]", + (mutableURL.user = @"us:er") && + [mutableURL.URLEncodedUser isEqual: @"us%3Aer"]) + + TEST(@"-[setURLEncodedUser:]", + (mutableURL.URLEncodedUser = @"us%3Aer") && + [mutableURL.user isEqual: @"us:er"]) + + EXPECT_EXCEPTION(@"-[setURLEncodedUser:] with invalid characters fails", + OFInvalidFormatException, mutableURL.URLEncodedHost = @"/") + + TEST(@"-[setPassword:]", + (mutableURL.password = @"pass:word") && + [mutableURL.URLEncodedPassword isEqual: @"pass%3Aword"]) + + TEST(@"-[setURLEncodedPassword:]", + (mutableURL.URLEncodedPassword = @"pass%3Aword") && + [mutableURL.password isEqual: @"pass:word"]) EXPECT_EXCEPTION( @"-[setURLEncodedPassword:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedPassword = @"/") + OFInvalidFormatException, mutableURL.URLEncodedPassword = @"/") TEST(@"-[setPath:]", - (mu.path = @"pa/th@?") && [mu.URLEncodedPath isEqual: @"pa/th@%3F"]) + (mutableURL.path = @"pa/th@?") && + [mutableURL.URLEncodedPath isEqual: @"pa/th@%3F"]) TEST(@"-[setURLEncodedPath:]", - (mu.URLEncodedPath = @"pa/th@%3F") && [mu.path isEqual: @"pa/th@?"]) + (mutableURL.URLEncodedPath = @"pa/th@%3F") && + [mutableURL.path isEqual: @"pa/th@?"]) EXPECT_EXCEPTION(@"-[setURLEncodedPath:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedPath = @"?") + OFInvalidFormatException, mutableURL.URLEncodedPath = @"?") TEST(@"-[setQuery:]", - (mu.query = @"que/ry?#") && - [mu.URLEncodedQuery isEqual: @"que/ry?%23"]) + (mutableURL.query = @"que/ry?#") && + [mutableURL.URLEncodedQuery isEqual: @"que/ry?%23"]) TEST(@"-[setURLEncodedQuery:]", - (mu.URLEncodedQuery = @"que/ry?%23") && - [mu.query isEqual: @"que/ry?#"]) + (mutableURL.URLEncodedQuery = @"que/ry?%23") && + [mutableURL.query isEqual: @"que/ry?#"]) EXPECT_EXCEPTION( @"-[setURLEncodedQuery:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedQuery = @"`") + OFInvalidFormatException, mutableURL.URLEncodedQuery = @"`") TEST(@"-[setQueryDictionary:]", - (mu.queryDictionary = [OFDictionary dictionaryWithKeysAndObjects: + (mutableURL.queryDictionary = + [OFDictionary dictionaryWithKeysAndObjects: @"foo&bar", @"baz=qux", @"f=oobar", @"b&azqux", nil]) && - [mu.URLEncodedQuery isEqual: + [mutableURL.URLEncodedQuery isEqual: @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"]) TEST(@"-[setFragment:]", - (mu.fragment = @"frag/ment?#") && - [mu.URLEncodedFragment isEqual: @"frag/ment?%23"]) + (mutableURL.fragment = @"frag/ment?#") && + [mutableURL.URLEncodedFragment isEqual: @"frag/ment?%23"]) TEST(@"-[setURLEncodedFragment:]", - (mu.URLEncodedFragment = @"frag/ment?%23") && - [mu.fragment isEqual: @"frag/ment?#"]) + (mutableURL.URLEncodedFragment = @"frag/ment?%23") && + [mutableURL.fragment isEqual: @"frag/ment?#"]) EXPECT_EXCEPTION( @"-[setURLEncodedFragment:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedFragment = @"`") + OFInvalidFormatException, mutableURL.URLEncodedFragment = @"`") TEST(@"-[URLByAppendingPathComponent:isDirectory:]", [[[OFURL URLWithString: @"file:///foo/bar"] URLByAppendingPathComponent: @"qux" isDirectory: false] isEqual: [OFURL URLWithString: @"file:///foo/bar/qux"]] && Index: tests/OFValueTests.m ================================================================== --- tests/OFValueTests.m +++ tests/OFValueTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -17,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFValue"; +static OFString *const module = @"OFValue"; @implementation TestsAppDelegate (OFValueTests) - (void)valueTests { void *pool = objc_autoreleasePoolPush(); Index: tests/OFWindowsRegistryKeyTests.m ================================================================== --- tests/OFWindowsRegistryKeyTests.m +++ tests/OFWindowsRegistryKeyTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,18 +15,18 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFWindowsRegistryKey"; +static OFString *const module = @"OFWindowsRegistryKey"; @implementation TestsAppDelegate (OFWindowsRegistryKeyTests) - (void)windowsRegistryKeyTests { void *pool = objc_autoreleasePoolPush(); OFData *data = [OFData dataWithItems: "abcdef" count: 6]; - OFWindowsRegistryKey *softwareKey, *ObjFWKey; + OFWindowsRegistryKey *softwareKey, *objFWKey; DWORD type; TEST(@"+[OFWindowsRegistryKey classesRootKey]", [OFWindowsRegistryKey classesRootKey]) @@ -40,44 +40,47 @@ [OFWindowsRegistryKey localMachineKey]) TEST(@"+[OFWindowsRegistryKey usersKey]", [OFWindowsRegistryKey usersKey]) - TEST(@"-[openSubkeyAtPath:securityAndAccessRights:]", + TEST(@"-[openSubkeyAtPath:securityAndAccessRights:] #1", (softwareKey = [[OFWindowsRegistryKey currentUserKey] openSubkeyAtPath: @"Software" - securityAndAccessRights: KEY_ALL_ACCESS]) && + securityAndAccessRights: KEY_ALL_ACCESS])) + + EXPECT_EXCEPTION(@"-[openSubkeyAtPath:securityAndAccessRights:] #2", + OFOpenWindowsRegistryKeyFailedException, [[OFWindowsRegistryKey currentUserKey] openSubkeyAtPath: @"nonexistent" - securityAndAccessRights: KEY_ALL_ACCESS] == nil) + securityAndAccessRights: KEY_ALL_ACCESS]) TEST(@"-[createSubkeyAtPath:securityAndAccessRights:]", - (ObjFWKey = [softwareKey createSubkeyAtPath: @"ObjFW" + (objFWKey = [softwareKey createSubkeyAtPath: @"ObjFW" securityAndAccessRights: KEY_ALL_ACCESS])) TEST(@"-[setData:forValueNamed:type:]", - R([ObjFWKey setData: data forValueNamed: @"data" type: REG_BINARY])) + R([objFWKey setData: data forValueNamed: @"data" type: REG_BINARY])) TEST(@"-[dataForValueNamed:subkeyPath:flags:type:]", - [[ObjFWKey dataForValueNamed: @"data" type: &type] isEqual: data] && + [[objFWKey dataForValueNamed: @"data" type: &type] isEqual: data] && type == REG_BINARY) TEST(@"-[setString:forValueNamed:type:]", - R([ObjFWKey setString: @"foobar" forValueNamed: @"string"]) && - R([ObjFWKey setString: @"%PATH%;foo" + R([objFWKey setString: @"foobar" forValueNamed: @"string"]) && + R([objFWKey setString: @"%PATH%;foo" forValueNamed: @"expand" type: REG_EXPAND_SZ])) TEST(@"-[stringForValue:subkeyPath:]", - [[ObjFWKey stringForValueNamed: @"string"] isEqual: @"foobar"] && - [[ObjFWKey stringForValueNamed: @"expand" type: &type] + [[objFWKey stringForValueNamed: @"string"] isEqual: @"foobar"] && + [[objFWKey stringForValueNamed: @"expand" type: &type] isEqual: @"%PATH%;foo"] && type == REG_EXPAND_SZ) - TEST(@"-[deleteValueNamed:]", R([ObjFWKey deleteValueNamed: @"data"])) + TEST(@"-[deleteValueNamed:]", R([objFWKey deleteValueNamed: @"data"])) TEST(@"-[deleteSubkeyAtPath:]", R([softwareKey deleteSubkeyAtPath: @"ObjFW"])) objc_autoreleasePoolPop(pool); } @end Index: tests/OFXMLElementBuilderTests.m ================================================================== --- tests/OFXMLElementBuilderTests.m +++ tests/OFXMLElementBuilderTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLElementBuilder"; +static OFString *const module = @"OFXMLElementBuilder"; static OFXMLNode *nodes[2]; static size_t i = 0; @implementation TestsAppDelegate (OFXMLElementBuilderTests) - (void)elementBuilder: (OFXMLElementBuilder *)builder @@ -37,26 +37,26 @@ } - (void)XMLElementBuilderTests { void *pool = objc_autoreleasePoolPush(); - OFXMLParser *p = [OFXMLParser parser]; + OFXMLParser *parser = [OFXMLParser parser]; OFXMLElementBuilder *builder = [OFXMLElementBuilder builder]; - OFString *str = @"barbaz" + OFString *string = @"barbaz" " " ""; - p.delegate = builder; + parser.delegate = builder; builder.delegate = self; TEST(@"Building elements from parsed XML", - R([p parseString: str]) && - nodes[0] != nil && [nodes[0].XMLString isEqual: str] && - R([p parseString: @""]) && + R([parser parseString: string]) && + nodes[0] != nil && [nodes[0].XMLString isEqual: string] && + R([parser parseString: @""]) && nodes[1] != nil && [nodes[1].XMLString isEqual: @""] && i == 2) [nodes[0] release]; [nodes[1] release]; objc_autoreleasePoolPop(pool); } @end Index: tests/OFXMLNodeTests.m ================================================================== --- tests/OFXMLNodeTests.m +++ tests/OFXMLNodeTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,112 +15,112 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLNode"; +static OFString *module; @implementation TestsAppDelegate (OFXMLNodeTests) - (void)XMLNodeTests { void *pool = objc_autoreleasePoolPush(); - id nodes[4]; - OFArray *a; + id node1, node2, node3, node4; + OFArray *array; + + module = @"OFXMLNode"; TEST(@"+[elementWithName:]", - (nodes[0] = [OFXMLElement elementWithName: @"foo"]) && - [[nodes[0] XMLString] isEqual: @""]) + (node1 = [OFXMLElement elementWithName: @"foo"]) && + [[node1 XMLString] isEqual: @""]) TEST(@"+[elementWithName:stringValue:]", - (nodes[1] = [OFXMLElement elementWithName: @"foo" - stringValue: @"b&ar"]) && - [[nodes[1] XMLString] isEqual: @"b&ar"]) + (node2 = [OFXMLElement elementWithName: @"foo" + stringValue: @"b&ar"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"+[elementWithName:namespace:]", - (nodes[2] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test"]) && - R([nodes[2] addAttributeWithName: @"test" stringValue: @"test"]) && - R([nodes[2] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"]) && - [[nodes[2] XMLString] isEqual: @""] && - (nodes[3] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test"]) && - R([nodes[3] addAttributeWithName: @"test" stringValue: @"test"]) && - [[nodes[3] XMLString] isEqual: + (node3 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test"]) && + R([node3 addAttributeWithName: @"test" stringValue: @"test"]) && + R([node3 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"]) && + [[node3 XMLString] isEqual: @""] && + (node4 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test"]) && + R([node4 addAttributeWithName: @"test" stringValue: @"test"]) && + [[node4 XMLString] isEqual: @""]) TEST(@"+[elementWithName:namespace:stringValue:]", - (nodes[3] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"x"]) && - R([nodes[3] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"]) && - [[nodes[3] XMLString] isEqual: - @"x"]) + (node4 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"x"]) && + R([node4 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"]) && + [[node4 XMLString] isEqual: @"x"]) TEST(@"+[charactersWithString:]", - (nodes[3] = [OFXMLCharacters charactersWithString: @""]) && - [[nodes[3] XMLString] isEqual: @"<foo>"]) + (node4 = [OFXMLCharacters charactersWithString: @""]) && + [[node4 XMLString] isEqual: @"<foo>"]) TEST(@"+[CDATAWithString:]", - (nodes[3] = [OFXMLCDATA CDATAWithString: @""]) && - [[nodes[3] XMLString] isEqual: @"]]>"]); + (node4 = [OFXMLCDATA CDATAWithString: @""]) && + [[node4 XMLString] isEqual: @"]]>"]); TEST(@"+[commentWithText:]", - (nodes[3] = [OFXMLComment commentWithText: @" comment "]) && - [[nodes[3] XMLString] isEqual: @""]) + (node4 = [OFXMLComment commentWithText: @" comment "]) && + [[node4 XMLString] isEqual: @""]) module = @"OFXMLElement"; TEST(@"-[addAttributeWithName:stringValue:]", - R([nodes[0] addAttributeWithName: @"foo" stringValue: @"b&ar"]) && - [[nodes[0] XMLString] isEqual: @""] && - R([nodes[1] addAttributeWithName: @"foo" stringValue: @"b&ar"]) && - [[nodes[1] XMLString] isEqual: - @"b&ar"]) + R([node1 addAttributeWithName: @"foo" stringValue: @"b&ar"]) && + [[node1 XMLString] isEqual: @""] && + R([node2 addAttributeWithName: @"foo" stringValue: @"b&ar"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[setPrefix:forNamespace:]", - R([nodes[1] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"])) + R([node2 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"])) TEST(@"-[addAttributeWithName:namespace:stringValue:]", - R([nodes[1] addAttributeWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"bar"]) && - R([nodes[1] addAttributeWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"ignored"]) && - [[nodes[1] XMLString] isEqual: + R([node2 addAttributeWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"bar"]) && + R([node2 addAttributeWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"ignored"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[removeAttributeForName:namespace:]", - R([nodes[1] removeAttributeForName: @"foo"]) && - [[nodes[1] XMLString] isEqual: + R([node2 removeAttributeForName: @"foo"]) && + [[node2 XMLString] isEqual: @"b&ar"] && - R([nodes[1] removeAttributeForName: @"foo" - namespace: @"urn:objfw:test"]) && - [[nodes[1] XMLString] isEqual: @"b&ar"]) + R([node2 removeAttributeForName: @"foo" + namespace: @"urn:objfw:test"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[addChild:]", - R([nodes[0] addChild: [OFXMLElement elementWithName: @"bar"]]) && - [[nodes[0] XMLString] isEqual: + R([node1 addChild: [OFXMLElement elementWithName: @"bar"]]) && + [[node1 XMLString] isEqual: @""] && - R([nodes[2] addChild: [OFXMLElement elementWithName: @"bar" - namespace: @"urn:objfw:test"]]) && - [[nodes[2] XMLString] isEqual: + R([node3 addChild: [OFXMLElement elementWithName: @"bar" + namespace: @"urn:objfw:test"]]) && + [[node3 XMLString] isEqual: @""]) TEST(@"+[elementWithXMLString:] and -[stringValue]", [[[OFXMLElement elementWithXMLString: @"\r\nfoo" @"bazqux"] stringValue] isEqual: @"foobarbazqux"]) TEST(@"-[elementsForName:namespace:]", - (a = [nodes[2] elementsForName: @"bar" - namespace: @"urn:objfw:test"]) && - a.count == 1 && [[[a firstObject] XMLString] isEqual: + (array = [node3 elementsForName: @"bar" + namespace: @"urn:objfw:test"]) && + array.count == 1 && [[array.firstObject XMLString] isEqual: @""]) TEST(@"-[isEqual:]", [[OFXMLElement elementWithXMLString: @""] isEqual: [OFXMLElement elementWithXMLString: @""]] && Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -18,99 +18,114 @@ #include #include #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLParser"; +static OFString *const module = @"OFXMLParser"; static int i = 0; -enum event_type { - PROCESSING_INSTRUCTION, - TAG_OPEN, - TAG_CLOSE, - STRING, - CDATA, - COMMENT +enum EventType { + eventTypeProcessingInstruction, + eventTypeTagOpen, + eventTypeTagClose, + eventTypeString, + eventTypeCDATA, + eventTypeComment }; @implementation TestsAppDelegate (OFXMLParser) - (void)parser: (OFXMLParser *)parser - didCreateEvent: (enum event_type)type + didCreateEvent: (enum EventType)type name: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace attributes: (OFArray *)attrs string: (OFString *)string { - OFString *msg; + OFString *message; i++; - msg = [OFString stringWithFormat: @"Parsing part #%d", i]; + message = [OFString stringWithFormat: @"Parsing part #%d", i]; switch (i) { case 1: - TEST(msg, type == PROCESSING_INSTRUCTION && + TEST(message, + type == eventTypeProcessingInstruction && [name isEqual: @"xml"] && [string isEqual: @"version='1.0'"]) break; case 2: - TEST(msg, type == PROCESSING_INSTRUCTION && + TEST(message, + type == eventTypeProcessingInstruction && [name isEqual: @"p?i"] && string == nil) break; case 3: - TEST(msg, type == TAG_OPEN && [name isEqual: @"root"] && - prefix == nil && ns == nil && attrs.count == 0) + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"root"] && + prefix == nil && namespace == nil && attrs.count == 0) break; case 4: - TEST(msg, type == STRING && [string isEqual: @"\n\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n\n "]) break; case 5: - TEST(msg, type == CDATA && [string isEqual: @"f<]]]oo]"] && + TEST(message, + type == eventTypeCDATA && [string isEqual: @"f<]]]oo]"] && parser.lineNumber == 3) break; case 6: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bar"] && - prefix == nil && ns == nil && attrs == nil) + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bar"] && + prefix == nil && namespace == nil && attrs == nil) break; case 7: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bar"] && - prefix == nil && ns == nil && attrs == nil) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bar"] && + prefix == nil && namespace == nil && attrs == nil) break; case 8: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 9: - TEST(msg, type == TAG_OPEN && [name isEqual: @"foobar"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"foobar"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 1 && /* xmlns attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] && [[attrs objectAtIndex: 0] namespace] == nil && [[[attrs objectAtIndex: 0] stringValue] isEqual: @"urn:objfw:test:foobar"]) break; case 10: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 11: - TEST(msg, type == TAG_OPEN && [name isEqual: @"qux"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"qux"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 1 && /* xmlns:foo attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"foo"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"http://www.w3.org/2000/xmlns/"] && [[[attrs objectAtIndex: 0] stringValue] isEqual: @"urn:objfw:test:foo"]) break; case 12: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 13: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bla"] && [prefix isEqual: @"foo"] && - [ns isEqual: @"urn:objfw:test:foo"] && + [namespace isEqual: @"urn:objfw:test:foo"] && attrs.count == 2 && /* foo:bla attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"urn:objfw:test:foo"] && @@ -119,15 +134,18 @@ [[[attrs objectAtIndex: 1] name] isEqual: @"blafoo"] && [[attrs objectAtIndex: 1] namespace] == nil && [[[attrs objectAtIndex: 1] stringValue] isEqual: @"foo"]) break; case 14: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 15: - TEST(msg, type == TAG_OPEN && [name isEqual: @"blup"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"blup"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 2 && /* foo:qux attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"qux"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"urn:objfw:test:foo"] && @@ -136,20 +154,25 @@ [[[attrs objectAtIndex: 1] name] isEqual: @"quxqux"] && [[attrs objectAtIndex: 1] namespace] == nil && [[[attrs objectAtIndex: 1] stringValue] isEqual: @"test"]) break; case 16: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"blup"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"blup"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) break; case 17: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 18: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bla"] && [prefix isEqual: @"bla"] && - [ns isEqual: @"urn:objfw:test:bla"] && attrs.count == 3 && + [namespace isEqual: @"urn:objfw:test:bla"] && + attrs.count == 3 && /* xmlns:bla attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"http://www.w3.org/2000/xmlns/"] && [[[attrs objectAtIndex: 0] stringValue] isEqual: @@ -163,20 +186,24 @@ [[[attrs objectAtIndex: 2] namespace] isEqual: @"urn:objfw:test:bla"] && [[[attrs objectAtIndex: 2] stringValue] isEqual: @"blafoo"]) break; case 19: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bla"] && [prefix isEqual: @"bla"] && - [ns isEqual: @"urn:objfw:test:bla"]) + [namespace isEqual: @"urn:objfw:test:bla"]) break; case 20: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 21: - TEST(msg, type == TAG_OPEN && [name isEqual: @"abc"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:abc"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"abc"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:abc"] && attrs.count == 3 && /* xmlns attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] && [[attrs objectAtIndex: 0] namespace] == nil && [[[attrs objectAtIndex: 0] stringValue] isEqual: @@ -190,57 +217,70 @@ [[[attrs objectAtIndex: 2] namespace] isEqual: @"urn:objfw:test:foo"] && [[[attrs objectAtIndex: 2] stringValue] isEqual: @"abc"]) break; case 22: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"abc"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:abc"]) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"abc"] && + prefix == nil && [namespace isEqual: @"urn:objfw:test:abc"]) break; case 23: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 24: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bla"] && [prefix isEqual: @"foo"] && - [ns isEqual: @"urn:objfw:test:foo"]) + [namespace isEqual: @"urn:objfw:test:foo"]) break; case 25: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 26: - TEST(msg, type == COMMENT && [string isEqual: @" commänt "]) + TEST(message, + type == eventTypeComment && [string isEqual: @" commänt "]) break; case 27: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 28: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"qux"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"qux"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) break; case 29: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 30: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"foobar"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"foobar"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) break; case 31: - TEST(msg, type == STRING && [string isEqual: @"\n"]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n"]) break; case 32: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"root"] && - prefix == nil && ns == nil); + TEST(message, + type == eventTypeTagClose && [name isEqual: @"root"] && + prefix == nil && namespace == nil); break; } } - (void)parser: (OFXMLParser *)parser foundProcessingInstructionWithTarget: (OFString *)target data: (OFString *)data { [self parser: parser - didCreateEvent: PROCESSING_INSTRUCTION + didCreateEvent: eventTypeProcessingInstruction name: target prefix: nil namespace: nil attributes: nil string: data]; @@ -247,62 +287,62 @@ } - (void)parser: (OFXMLParser *)parser didStartElement: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace attributes: (OFArray *)attrs { [self parser: parser - didCreateEvent: TAG_OPEN + didCreateEvent: eventTypeTagOpen name: name prefix: prefix - namespace: ns + namespace: namespace attributes: attrs string: nil]; } - (void)parser: (OFXMLParser *)parser didEndElement: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace { [self parser: parser - didCreateEvent: TAG_CLOSE + didCreateEvent: eventTypeTagClose name: name prefix: prefix - namespace: ns + namespace: namespace attributes: nil string: nil]; } - (void)parser: (OFXMLParser *)parser foundCharacters: (OFString *)string { [self parser: parser - didCreateEvent: STRING + didCreateEvent: eventTypeString name: nil prefix: nil namespace: nil attributes: nil string: string]; } -- (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)cdata +- (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)CDATA { [self parser: parser - didCreateEvent: CDATA + didCreateEvent: eventTypeCDATA name: nil prefix: nil namespace: nil attributes: nil - string: cdata]; + string: CDATA]; } - (void)parser: (OFXMLParser *)parser foundComment: (OFString *)comment { [self parser: parser - didCreateEvent: COMMENT + didCreateEvent: eventTypeComment name: nil prefix: nil namespace: nil attributes: nil string: comment]; @@ -318,11 +358,11 @@ } - (void)XMLParserTests { void *pool = objc_autoreleasePoolPush(); - const char *str = "\xEF\xBB\xBF" + const char *string = "\xEF\xBB\xBF" "\r\r" " \n" " \r\n" " \n" " \n" @@ -334,27 +374,27 @@ " \n" " \n" " \n" ""; OFXMLParser *parser; - size_t j, len; + size_t j, length; TEST(@"+[parser]", (parser = [OFXMLParser parser])) TEST(@"-[setDelegate:]", (parser.delegate = self)) /* Simulate a stream where we only get chunks */ - len = strlen(str); + length = strlen(string); - for (j = 0; j < len; j+= 2) { + for (j = 0; j < length; j+= 2) { if (parser.hasFinishedParsing) abort(); - if (j + 2 > len) - [parser parseBuffer: str + j length: 1]; + if (j + 2 > length) + [parser parseBuffer: string + j length: 1]; else - [parser parseBuffer: str + j length: 2]; + [parser parseBuffer: string + j length: 2]; } TEST(@"Checking if everything was parsed", i == 32 && parser.lineNumber == 18) DELETED tests/PBKDF2Tests.m Index: tests/PBKDF2Tests.m ================================================================== --- tests/PBKDF2Tests.m +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "TestsAppDelegate.h" - -static OFString *module = @"PBKDF2"; - -@implementation TestsAppDelegate (PBKDF2Tests) -- (void)PBKDF2Tests -{ - void *pool = objc_autoreleasePoolPush(); - OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true]; - unsigned char key[25]; - - /* Test vectors from RFC 6070 */ - - TEST(@"PBKDF2-SHA1, 1 iteration", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" - "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) - - TEST(@"PBKDF2-SHA1, 2 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 2, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" - "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" - "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) - - /* This test takes too long, even on a fast machine. */ -#if 0 - TEST(@"PBKDF2-SHA1, 16777216 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 16777216, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" - "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) -#endif - - TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"saltSALTsaltSALTsalt" - "SALTsaltSALTsalt", - .saltLength = 36, - .password = "passwordPASSWORDpassword", - .passwordLength = 24, - .key = key, - .keyLength = 25, - .allowsSwappableMemory = true - })) && - memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" - "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"sa\0lt", - .saltLength = 5, - .password = "pass\0word", - .passwordLength = 9, - .key = key, - .keyLength = 16, - .allowsSwappableMemory = true - })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" - "\xF0\x34\x25\xE0\xC3", 16) == 0) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/RuntimeARCTests.m ================================================================== --- tests/RuntimeARCTests.m +++ tests/RuntimeARCTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,21 +15,30 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"Runtime (ARC)"; +static OFString *const module = @"Runtime (ARC)"; @interface RuntimeARCTest: OFObject @end @implementation RuntimeARCTest - (instancetype)init { self = [super init]; +#ifdef OF_WINDOWS + /* + * Clang has a bug on Windows where it creates an invalid call into + * objc_retainAutoreleasedReturnValue(). Work around it by not using an + * autoreleased exception. + */ + @throw [[OFException alloc] init]; +#else @throw [OFException exception]; +#endif return self; } @end Index: tests/RuntimeTests.m ================================================================== --- tests/RuntimeTests.m +++ tests/RuntimeTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -15,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"Runtime"; +static OFString *const module = @"Runtime"; @interface OFObject (SuperTest) - (id)superTest; @end @@ -61,33 +61,34 @@ @implementation TestsAppDelegate (RuntimeTests) - (void)runtimeTests { void *pool = objc_autoreleasePoolPush(); - RuntimeTest *rt = [[[RuntimeTest alloc] init] autorelease]; - OFString *t, *foo; + RuntimeTest *test = [[[RuntimeTest alloc] init] autorelease]; + OFString *string, *foo; #ifdef OF_OBJFW_RUNTIME - int cid1, cid2; + int classID; uintmax_t value; id object; #endif EXPECT_EXCEPTION(@"Calling a non-existent method via super", - OFNotImplementedException, [rt superTest]) + OFNotImplementedException, [test superTest]) TEST(@"Calling a method via a super with self == nil", - [rt nilSuperTest] == nil) + [test nilSuperTest] == nil) - t = [OFMutableString stringWithString: @"foo"]; + string = [OFMutableString stringWithString: @"foo"]; foo = @"foo"; - [rt setFoo: t]; - TEST(@"copy, nonatomic properties", [rt.foo isEqual: foo] && - rt.foo != foo && rt.foo.retainCount == 1) + test.foo = string; + TEST(@"copy, nonatomic properties", [test.foo isEqual: foo] && + test.foo != foo && test.foo.retainCount == 1) - rt.bar = t; - TEST(@"retain, atomic properties", rt.bar == t && t.retainCount == 3) + test.bar = string; + TEST(@"retain, atomic properties", + test.bar == string && string.retainCount == 3) #ifdef OF_OBJFW_RUNTIME if (sizeof(uintptr_t) == 8) value = 0xDEADBEEFDEADBEF; else if (sizeof(uintptr_t) == 4) @@ -94,18 +95,19 @@ value = 0xDEADBEF; else abort(); TEST(@"Tagged pointers", - (cid1 = objc_registerTaggedPointerClass([OFString class])) != -1 && - (cid2 = objc_registerTaggedPointerClass([OFNumber class])) != -1 && - (object = objc_createTaggedPointer(cid2, (uintptr_t)value)) && + objc_registerTaggedPointerClass([OFString class]) != -1 && + (classID = objc_registerTaggedPointerClass([OFNumber class])) != + -1 && + (object = objc_createTaggedPointer(classID, (uintptr_t)value)) && object_getClass(object) == [OFNumber class] && [object class] == [OFNumber class] && object_getTaggedPointerValue(object) == value && - objc_createTaggedPointer(cid2, UINTPTR_MAX >> 4) != nil && - objc_createTaggedPointer(cid2, (UINTPTR_MAX >> 4) + 1) == nil) + objc_createTaggedPointer(classID, UINTPTR_MAX >> 4) != nil && + objc_createTaggedPointer(classID, (UINTPTR_MAX >> 4) + 1) == nil) #endif objc_autoreleasePoolPop(pool); } @end DELETED tests/ScryptTests.m Index: tests/ScryptTests.m ================================================================== --- tests/ScryptTests.m +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2008-2021 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" - -#include - -#import "TestsAppDelegate.h" - -static OFString *module = @"scrypt"; -/* Test vectors form RFC 7914 */ -static const unsigned char salsa20Input[64] = { - 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, - 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, - 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, - 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, - 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, - 0xB8, 0xB8, 0xC2, 0x5E -}; -static const unsigned char salsa20Output[64] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81 -}; -static const union { - unsigned char uc[128]; - uint32_t u32[32]; -} blockMixInput = { .uc = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, - 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, - 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, - 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, - 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, - 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, - 0xEA, 0xAF, 0x7E, 0x89 -}}; -static const unsigned char blockMixOutput[128] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81, - 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, - 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, - 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, - 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, - 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, - 0x4E, 0xEF, 0xE4, 0x25 -}; -static const unsigned char ROMixInput[128] = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, - 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, - 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, - 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, - 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, - 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 -}; -static const unsigned char ROMixOutput[128] = { - 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, - 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, - 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, - 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, - 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, - 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, - 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, - 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, - 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, - 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, - 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E -}; -static const unsigned char testVector1[64] = { - 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, - 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, - 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, - 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, - 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, - 0x38, 0xD1, 0x89, 0x06 -}; -static const unsigned char testVector2[64] = { - 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, - 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, - 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, - 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, - 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, - 0xA2, 0xCC, 0x06, 0x40 -}; -static const unsigned char testVector3[64] = { - 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, - 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, - 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, - 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, - 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, - 0x45, 0x57, 0x58, 0x87 -}; -/* The forth test vector is too expensive to include it in the tests. */ -#if 0 -static const unsigned char testVector4[64] = { - 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, - 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, - 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, - 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, - 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, - 0xA7, 0x7A, 0x41, 0xA4 -}; -#endif - -@implementation TestsAppDelegate (ScryptTests) -- (void)scryptTests -{ - void *pool = objc_autoreleasePoolPush(); - uint32_t salsa20Buffer[16]; - uint32_t blockMixBuffer[32]; - uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; - unsigned char output[64]; - - TEST(@"Salsa20/8 Core", - R(memcpy(salsa20Buffer, salsa20Input, 64)) && - R(OFSalsa20_8Core(salsa20Buffer)) && - memcmp(salsa20Buffer, salsa20Output, 64) == 0) - - TEST(@"Block mix", - R(OFScryptBlockMix(blockMixBuffer, blockMixInput.u32, 1)) && - memcmp(blockMixBuffer, blockMixOutput, 128) == 0) - - TEST(@"ROMix", - R(memcpy(ROMixBuffer, ROMixInput, 128)) && - R(OFScryptROMix(ROMixBuffer, 1, 16, ROMixTmp)) && - memcmp(ROMixBuffer, ROMixOutput, 128) == 0) - - TEST(@"scrypt test vector #1", - R(OFScrypt((OFScryptParameters){ - .blockSize = 1, - .costFactor = 16, - .parallelization = 1, - .salt = (unsigned char *)"", - .saltLength = 0, - .password = "", - .passwordLength = 0, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector1, 64) == 0) - - TEST(@"scrypt test vector #2", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 1024, - .parallelization = 16, - .salt = (unsigned char *)"NaCl", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector2, 64) == 0) - - TEST(@"scrypt test vector #3", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 16384, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector3, 64) == 0) - - /* The forth test vector is too expensive to include it in the tests. */ -#if 0 - TEST(@"scrypt test vector #4", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 1048576, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector4, 64) == 0) -#endif - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/SocketTests.m Index: tests/SocketTests.m ================================================================== --- tests/SocketTests.m +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2008-2021 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 "TestsAppDelegate.h" - -#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) -#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; - -static OFString *module = @"Socket"; - -@implementation TestsAppDelegate (SocketTests) -- (void)socketTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSocketAddress addr; - - TEST(@"Parsing an IPv4", - R(addr = OFSocketAddressParseIP(@"127.0.0.1", 1234)) && - OFFromBigEndian32(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 && - OFFromBigEndian16(addr.sockaddr.in.sin_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0.256", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0. 1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", OFInvalidFormatException, - OFSocketAddressParseIP(@" 127.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.a.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0..1", 1234)) - - TEST(@"Port of an IPv4 address", OFSocketAddressPort(&addr) == 1234) - - TEST(@"Converting an IPv4 to a string", - [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"]) - - TEST(@"Parsing an IPv6 #1", - R(addr = OFSocketAddressParseIP( - @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && - COMPARE_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #2", - R(addr = OFSocketAddressParseIP(@"::", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #3", - R(addr = OFSocketAddressParseIP(@"aaAa::bBbb", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #4", - R(addr = OFSocketAddressParseIP(@"aaAa::", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #5", - R(addr = OFSocketAddressParseIP(@"::aaAa", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, - OFSocketAddressParseIP(@"1: ::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:: :2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", OFInvalidFormatException, - OFSocketAddressParseIP(@"1::2::3", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", OFInvalidFormatException, - OFSocketAddressParseIP(@"10000::1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", OFInvalidFormatException, - OFSocketAddressParseIP(@"::10000", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", OFInvalidFormatException, - OFSocketAddressParseIP(@"::1::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2", 1234)) - - TEST(@"Port of an IPv6 address", OFSocketAddressPort(&addr) == 1234) - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #1", - [OFSocketAddressString(&addr) isEqual: @"::"]) - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) - TEST(@"Converting an IPv6 to a string #2", - [OFSocketAddressString(&addr) isEqual: @"::1"]) - - SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #3", - [OFSocketAddressString(&addr) isEqual: @"1::"]) - - SET_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #4", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) - TEST(@"Converting an IPv6 to a string #5", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:0"]) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #6", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc::"]) - - SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #7", - [OFSocketAddressString(&addr) - isEqual: @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #8", - [OFSocketAddressString(&addr) - isEqual: @"::5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #9", - [OFSocketAddressString(&addr) isEqual: @"0:0:5566::ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #10", - [OFSocketAddressString(&addr) - isEqual: @"::5566:7788:99aa:bbcc:0:0"]) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -116,10 +116,14 @@ @end @interface TestsAppDelegate (OFJSONTests) - (void)JSONTests; @end + +@interface TestsAppDelegate (OFHMACTests) +- (void)HMACTests; +@end @interface TestsAppDelegate (OFKernelEventObserverTests) - (void)kernelEventObserverTests; @end @@ -132,22 +136,34 @@ @end @interface TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests; @end + +@interface TestsAppDelegate (OFMemoryStreamTests) +- (void)memoryStreamTests; +@end @interface TestsAppDelegate (OFMethodSignatureTests) - (void)methodSignatureTests; @end + +@interface TestsAppDelegate (OFNotificationCenterTests) +- (void)notificationCenterTests; +@end @interface TestsAppDelegate (OFNumberTests) - (void)numberTests; @end @interface TestsAppDelegate (OFObjectTests) - (void)objectTests; @end + +@interface TestsAppDelegate (OFPBKDF2Tests) +- (void)PBKDF2Tests; +@end @interface TestsAppDelegate (OFPropertyListTests) - (void)propertyListTests; @end @@ -165,11 +181,11 @@ @interface TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests; @end -@interface TestsAppDelegate (ScryptTests) +@interface TestsAppDelegate (OFScryptTests) - (void)scryptTests; @end @interface TestsAppDelegate (OFSHA1HashTests) - (void)SHA1HashTests; @@ -209,12 +225,12 @@ @interface TestsAppDelegate (OFSystemInfoTests) - (void)systemInfoTests; @end -@interface TestsAppDelegate (OFHMACTests) -- (void)HMACTests; +@interface TestsAppDelegate (OFSocketTests) +- (void)socketTests; @end @interface TestsAppDelegate (OFStreamTests) - (void)streamTests; @end @@ -232,10 +248,18 @@ @end @interface TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests; @end + +@interface TestsAppDelegate (OFUNIXDatagramSocketTests) +- (void)UNIXDatagramSocketTests; +@end + +@interface TestsAppDelegate (OFUNIXStreamSocketTests) +- (void)UNIXStreamSocketTests; +@end @interface TestsAppDelegate (OFURLTests) - (void)URLTests; @end @@ -257,13 +281,5 @@ @interface TestsAppDelegate (OFXMLParserTests) - (void)XMLParserTests; @end - -@interface TestsAppDelegate (PBKDF2Tests) -- (void)PBKDF2Tests; -@end - -@interface TestsAppDelegate (SocketTests) -- (void)socketTests; -@end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -48,27 +48,45 @@ /* Newer versions of libctru started using id as a parameter name. */ # define id id_3ds # include <3ds.h> # undef id #endif + +#ifdef OF_NINTENDO_SWITCH +# define id nx_id +# include +# undef id + +static OFDate *lastConsoleUpdate; + +static void +updateConsole(bool force) +{ + if (force || lastConsoleUpdate.timeIntervalSinceNow <= -1.0 / 60) { + consoleUpdate(NULL); + [lastConsoleUpdate release]; + lastConsoleUpdate = [[OFDate alloc] init]; + } +} +#endif extern unsigned long OFHashSeed; #ifdef OF_PSP static int -exit_cb(int arg1, int arg2, void *arg) +exitCallback(int arg1, int arg2, void *arg) { sceKernelExitGame(); return 0; } static int -callback_thread(SceSize args, void *argp) +threadCallback(SceSize args, void *argp) { sceKernelRegisterExitCallback( - sceKernelCreateCallback("Exit Callback", exit_cb, NULL)); + sceKernelCreateCallback("Exit Callback", exitCallback, NULL)); sceKernelSleepThreadCB(); return 0; } #endif @@ -83,14 +101,14 @@ #if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) /* * This does not work on Win32 if ObjFW is built as a DLL. * * On AmigaOS, some destructors need to be able to send messages. - * Calling objc_exit() via atexit() would result in the runtime being + * Calling objc_deinit() via atexit() would result in the runtime being * destructed before for the destructors ran. */ - atexit(objc_exit); + atexit(objc_deinit); #endif /* We need deterministic hashes for tests */ OFHashSeed = 0; @@ -120,11 +138,11 @@ pspDebugScreenInit(); sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL); - if ((tid = sceKernelCreateThread("update_thread", callback_thread, + if ((tid = sceKernelCreateThread("update_thread", threadCallback, 0x11, 0xFA0, 0, 0)) >= 0) sceKernelStartThread(tid, 0, 0); #endif #ifdef OF_NINTENDO_DS @@ -136,12 +154,23 @@ atexit(gfxExit); consoleInit(GFX_TOP, NULL); #endif -#if defined(OF_WII) || defined(OF_PSP) || defined(OF_NINTENDO_DS) || \ - defined(OF_NINTENDO_3DS) +#ifdef OF_NINTENDO_SWITCH + consoleInit(NULL); + padConfigureInput(1, HidNpadStyleSet_NpadStandard); + updateConsole(true); + +# ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] changeCurrentDirectoryPath: @"romfs:/"]; +# endif +#endif + +#if defined(OF_WII) || defined(OF_WII_U) || defined(OF_PSP) || \ + defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \ + defined(OF_NINTENDO_SWITCH) @try { return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); } @catch (id e) { OFString *string = [OFString stringWithFormat: @@ -188,10 +217,16 @@ if (hidKeysDown() & KEY_START) [OFApplication terminateWithStatus: 1]; gspWaitForVBlank(); } +# elif defined(OF_NINTENDO_SWITCH) + while (appletMainLoop()) + updateConsole(true); + + consoleExit(NULL); + abort(); # else abort(); # endif } #else @@ -198,99 +233,120 @@ return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); #endif } @implementation TestsAppDelegate -- (void)outputTesting: (OFString *)test - inModule: (OFString *)module +- (void)outputTesting: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { [OFStdOut setForegroundColor: [OFColor yellow]]; [OFStdOut writeFormat: @"[%@] %@: testing...", module, test]; } else [OFStdOut writeFormat: @"[%@] %@: ", module, test]; + +#ifdef OF_NINTENDO_SWITCH + updateConsole(false); +#endif } -- (void)outputSuccess: (OFString *)test - inModule: (OFString *)module +- (void)outputSuccess: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut eraseLine]; [OFStdOut writeFormat: @"\r[%@] %@: ok\n", module, test]; } else [OFStdOut writeLine: @"ok"]; + +#ifdef OF_NINTENDO_SWITCH + updateConsole(false); +#endif } -- (void)outputFailure: (OFString *)test - inModule: (OFString *)module +- (void)outputFailure: (OFString *)test inModule: (OFString *)module { if (OFStdOut.hasTerminal) { [OFStdOut setForegroundColor: [OFColor red]]; [OFStdOut eraseLine]; [OFStdOut writeFormat: @"\r[%@] %@: failed\n", module, test]; - -#ifdef OF_WII - [OFStdOut reset]; - [OFStdOut writeLine: @"Press A to continue!"]; - - for (;;) { - WPAD_ScanPads(); - - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - return; - - VIDEO_WaitVSync(); - } -#endif -#ifdef OF_PSP - [OFStdOut reset]; - [OFStdOut writeLine: @"Press X to continue!"]; - - for (;;) { - SceCtrlData pad; - - sceCtrlReadBufferPositive(&pad, 1); - if (pad.Buttons & PSP_CTRL_CROSS) { - for (;;) { - sceCtrlReadBufferPositive(&pad, 1); - if (!(pad.Buttons & PSP_CTRL_CROSS)) - return; - } - } - } -#endif -#ifdef OF_NINTENDO_DS - [OFStdOut reset]; - [OFStdOut writeString: @"Press A to continue!"]; - - for (;;) { - swiWaitForVBlank(); - scanKeys(); - if (keysDown() & KEY_A) - break; - } -#endif -#ifdef OF_NINTENDO_3DS - [OFStdOut reset]; - [OFStdOut writeString: @"Press A to continue!"]; - - for (;;) { - hidScanInput(); - - if (hidKeysDown() & KEY_A) - break; - - gspWaitForVBlank(); - } -#endif - + } else + [OFStdOut writeLine: @"failed"]; + +#ifdef OF_WII + [OFStdOut reset]; + [OFStdOut writeLine: @"Press A to continue!"]; + + for (;;) { + WPAD_ScanPads(); + + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + return; + + VIDEO_WaitVSync(); + } +#endif +#ifdef OF_PSP + [OFStdOut reset]; + [OFStdOut writeLine: @"Press X to continue!"]; + + for (;;) { + SceCtrlData pad; + + sceCtrlReadBufferPositive(&pad, 1); + if (pad.Buttons & PSP_CTRL_CROSS) { + for (;;) { + sceCtrlReadBufferPositive(&pad, 1); + if (!(pad.Buttons & PSP_CTRL_CROSS)) + return; + } + } + } +#endif +#ifdef OF_NINTENDO_DS + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + for (;;) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_A) + break; + } +#endif +#ifdef OF_NINTENDO_3DS + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + for (;;) { + hidScanInput(); + + if (hidKeysDown() & KEY_A) + break; + + gspWaitForVBlank(); + } +#endif +#ifdef OF_NINTENDO_SWITCH + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; + + while (appletMainLoop()) { + PadState pad; + + padUpdate(&pad); + updateConsole(true); + + if (padGetButtonsDown(&pad) & HidNpadButton_A) + break; + } +#endif + + if (OFStdOut.hasTerminal) { [OFStdOut writeString: @"\r"]; [OFStdOut reset]; [OFStdOut eraseLine]; - } else - [OFStdOut writeLine: @"failed"]; + } } - (void)applicationDidFinishLaunching { #if defined(OF_IOS) && defined(OF_HAVE_FILES) @@ -332,23 +388,23 @@ [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; [self streamTests]; -#ifdef OF_HAVE_FILES + [self memoryStreamTests]; + [self notificationCenterTests]; [self MD5HashTests]; [self RIPEMD160HashTests]; [self SHA1HashTests]; [self SHA224HashTests]; [self SHA256HashTests]; [self SHA384HashTests]; [self SHA512HashTests]; [self HMACTests]; -#endif [self PBKDF2Tests]; [self scryptTests]; -#if defined(OF_HAVE_FILES) && defined(HAVE_CODEPAGE_437) +#ifdef HAVE_CODEPAGE_437 [self INIFileTests]; #endif #ifdef OF_HAVE_SOCKETS [self socketTests]; [self TCPSocketTests]; @@ -356,10 +412,14 @@ # ifdef OF_HAVE_IPX [self IPXSocketTests]; [self SPXSocketTests]; [self SPXStreamSocketTests]; # endif +# ifdef OF_HAVE_UNIX_SOCKETS + [self UNIXDatagramSocketTests]; + [self UNIXStreamSocketTests]; +# endif [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS [self threadTests]; #endif @@ -372,13 +432,11 @@ [self HTTPCookieManagerTests]; #endif [self XMLParserTests]; [self XMLNodeTests]; [self XMLElementBuilderTests]; -#ifdef OF_HAVE_FILES [self serializationTests]; -#endif [self JSONTests]; [self propertyListTests]; #if defined(OF_HAVE_PLUGINS) [self pluginTests]; #endif @@ -430,10 +488,17 @@ if (hidKeysDown() & KEY_START) [OFApplication terminateWithStatus: _fails]; gspWaitForVBlank(); } +#elif defined(OF_NINTENDO_SWITCH) + while (appletMainLoop()) + updateConsole(true); + + consoleExit(NULL); + + [OFApplication terminateWithStatus: _fails]; #else [OFApplication terminateWithStatus: _fails]; #endif } @end Index: tests/iOS.xcodeproj/project.pbxproj ================================================================== --- tests/iOS.xcodeproj/project.pbxproj +++ tests/iOS.xcodeproj/project.pbxproj @@ -133,11 +133,11 @@ /* Begin PBXProject section */ 4BEBFB532013934E002E8710 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0920; + LastUpgradeCheck = 1330; ORGANIZATIONNAME = "Jonathan Schleifer"; TargetAttributes = { 4BEBFB5A2013934E002E8710 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; @@ -200,17 +200,19 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -255,17 +257,19 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; Index: tests/objc_sync/Makefile ================================================================== --- tests/objc_sync/Makefile +++ tests/objc_sync/Makefile @@ -3,31 +3,31 @@ PROG_NOINST = objc_sync${PROG_SUFFIX} SRCS = test.m include ../../buildsys.mk -post-all: ${RUN_TESTS} - .PHONY: run run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/objfw.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../../src/libobjfw.dylib; then \ ${LN_S} ../../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -37,12 +37,13 @@ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/runtime/objfwrt.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi @@ -53,15 +54,19 @@ LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT CPPFLAGS += -I../../src -I../../src/runtime -I../.. -LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} +LIBS := -L../../src -lobjfw \ + -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ + ${LIBS} LD = ${OBJC} Index: tests/objc_sync/test.m ================================================================== --- tests/objc_sync/test.m +++ tests/objc_sync/test.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: tests/plugin/TestPlugin.h ================================================================== --- tests/plugin/TestPlugin.h +++ tests/plugin/TestPlugin.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -11,10 +11,10 @@ * 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 "OFPlugin.h" +#import "OFObject.h" -@interface TestPlugin: OFPlugin +@interface TestPlugin: OFObject - (int)test: (int)num; @end Index: tests/plugin/TestPlugin.m ================================================================== --- tests/plugin/TestPlugin.m +++ tests/plugin/TestPlugin.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -26,16 +26,16 @@ if (class == Nil) /* * musl has broken dlclose(): Instead of calling the destructor * on dlclose(), they call it on exit(). This of course means - * that our tests might have already called objc_exit() and the - * class is already gone. + * that our tests might have already called objc_deinit() and + * the class is already gone. */ return; - objc_unregister_class(class); + objc_unregisterClass(class); } #endif @implementation TestPlugin - (int)test: (int)num @@ -42,10 +42,10 @@ { return num * 2; } @end -id -OFPluginInit(void) +Class +class(void) { - return [[[TestPlugin alloc] init] autorelease]; + return [TestPlugin class]; } Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -1,8 +1,14 @@ + + 01234567-89ab-cdef-fedc-ba9876543210 + + + uuid + Blub B"la Index: tests/terminal/Makefile ================================================================== --- tests/terminal/Makefile +++ tests/terminal/Makefile @@ -3,31 +3,31 @@ PROG_NOINST = terminal_tests${PROG_SUFFIX} SRCS = TerminalTests.m include ../../buildsys.mk -post-all: ${RUN_TESTS} - .PHONY: run run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/objfw.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../../src/libobjfw.dylib; then \ ${LN_S} ../../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -37,12 +37,13 @@ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi - if test -f ../../src/runtime/objfwrt.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi @@ -53,15 +54,19 @@ LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. -LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} +LIBS := -L../../src -lobjfw \ + -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ + ${LIBS} LD = ${OBJC} Index: tests/terminal/TerminalTests.m ================================================================== --- tests/terminal/TerminalTests.m +++ tests/terminal/TerminalTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/Makefile ================================================================== --- utils/Makefile +++ utils/Makefile @@ -8,22 +8,22 @@ include ../buildsys.mk DISTCLEAN = objfw-config -install-extra: objfw-config objfw-compile objfw-new - for i in objfw-config objfw-compile objfw-new; do \ +install-extra: objfw-config objfw-compile objfw-embed + for i in objfw-config objfw-compile objfw-embed; do \ ${INSTALL_STATUS}; \ if ${MKDIR_P} ${DESTDIR}${bindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/${BIN_PREFIX}$$i; then \ ${INSTALL_OK}; \ else \ ${INSTALL_FAILED}; \ fi \ done uninstall-extra: - for i in objfw-config objfw-compile objfw-new; do \ + for i in objfw-config objfw-compile objfw-embed; do \ if test -f ${DESTDIR}${bindir}/${BIN_PREFIX}$$i; then \ if rm -f ${DESTDIR}${bindir}/${BIN_PREFIX}$$i; then \ ${DELETE_OK}; \ else \ ${DELETE_FAILED}; \ Index: utils/objfw-compile ================================================================== --- utils/objfw-compile +++ utils/objfw-compile @@ -1,8 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008-2021 Jonathan Schleifer +# Copyright (c) 2008-2022 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 @@ -293,19 +293,19 @@ fi ;; esac objs="$objs $obj" build="no" - deps=$($OBJC -E -M $CPPFLAGS $OBJCFLAGS $i | - sed 's/.*: //' | sed 's/\\//g') - if test -f "$obj"; then + if test ! -f "$obj" -o "$i" -nt "$obj"; then + build="yes" + else + deps=$($OBJC -E -M $CPPFLAGS $OBJCFLAGS $i | + sed 's/.*: //' | sed 's/\\//g') for dep in $deps; do test "$dep" -nt $obj && build="yes" done - else - build="yes" fi if test x"$build" = x"yes"; then link="yes" status_compiling $i Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -1,8 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008-2021 Jonathan Schleifer +# Copyright (c) 2008-2022 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 ADDED utils/objfw-embed Index: utils/objfw-embed ================================================================== --- /dev/null +++ utils/objfw-embed @@ -0,0 +1,26 @@ +#!/bin/sh +if test $# != 3; then + echo "Usage: $0 source_file filename output.m" 1>&2 + exit 1 +fi + +exec 1>$3 + +cat < +#include + +extern void OFRegisterEmbeddedFile(const char *, const uint8_t *, size_t); + +static const uint8_t bytes[] = { +EOF +od -vtx1 $1 | sed '/^[^ ][^ ]*$/d;s/ */ /g;s/ $//g;s/^[^ ][^ ]* //;s/ /, 0x/g;s/^/ 0x/;s/$/,/' +cat <"$name.m" <<__EOF__ -#import - -@interface $name: OFObject -@end - -OF_APPLICATION_DELEGATE($name) - -@implementation $name -- (void)applicationDidFinishLaunching -{ - [OFApplication terminate]; -} -@end -__EOF__ - ;; -class) - test -f "$name.h" && already_exists "$name.h" - test -f "$name.m" && already_exists "$name.m" - - cat >"$name.h" <<__EOF__ -#import - -@interface $name: OFObject -@end -__EOF__ - cat >"$name.m" <<__EOF__ -#import "$name.h" - -@implementation $name -@end -__EOF__ - ;; -*) - show_help - ;; -esac Index: utils/ofarc/Archive.h ================================================================== --- utils/ofarc/Archive.h +++ utils/ofarc/Archive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/GZIPArchive.h ================================================================== --- utils/ofarc/GZIPArchive.h +++ utils/ofarc/GZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/GZIPArchive.m ================================================================== --- utils/ofarc/GZIPArchive.m +++ utils/ofarc/GZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/LHAArchive.h ================================================================== --- utils/ofarc/LHAArchive.h +++ utils/ofarc/LHAArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -480,12 +480,17 @@ attributes.fileGroupOwnerAccountID]; entry.owner = attributes.fileOwnerAccountName; entry.group = attributes.fileGroupOwnerAccountName; #endif - if ([type isEqual: OFFileTypeDirectory]) + if ([type isEqual: OFFileTypeDirectory]) { entry.compressionMethod = @"-lhd-"; + + if (![entry.fileName hasSuffix: @"/"]) + entry.fileName = [entry.fileName + stringByAppendingString: @"/"]; + } output = [_archive streamForWritingEntry: entry]; if ([type isEqual: OFFileTypeRegular]) { unsigned long long written = 0; Index: utils/ofarc/OFArc.h ================================================================== --- utils/ofarc/OFArc.h +++ utils/ofarc/OFArc.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -142,10 +142,31 @@ [OFStdErr writeLine: OF_LOCALIZED( @"writing_not_supported", @"Writing archives of type %[type] is not (yet) supported!", @"type", type)]; } + +static void +addFiles(id archive, OFArray OF_GENERIC(OFString *) *files) +{ + OFMutableArray *expandedFiles = + [OFMutableArray arrayWithCapacity: files.count]; + OFFileManager *fileManager = [OFFileManager defaultManager]; + + for (OFString *file in files) { + OFFileAttributes attributes = + [fileManager attributesOfItemAtPath: file]; + + if ([attributes.fileType isEqual: OFFileTypeDirectory]) + [expandedFiles addObjectsFromArray: + [fileManager subpathsOfDirectoryAtPath: file]]; + else + [expandedFiles addObject: file]; + } + + [archive addFiles: expandedFiles]; +} @implementation OFArc - (void)applicationDidFinishLaunching { OFString *outputDir, *encodingString, *type; @@ -334,11 +355,11 @@ openArchiveWithPath: remainingArguments.firstObject type: type mode: mode encoding: encoding]; - [archive addFiles: files]; + addFiles(archive, files); break; case 'l': if (remainingArguments.count != 1) help(OFStdErr, false, 1); Index: utils/ofarc/TarArchive.h ================================================================== --- utils/ofarc/TarArchive.h +++ utils/ofarc/TarArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/ZIPArchive.h ================================================================== --- utils/ofarc/ZIPArchive.h +++ utils/ofarc/ZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofarc/ZIPArchive.m ================================================================== --- utils/ofarc/ZIPArchive.m +++ utils/ofarc/ZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofhash/OFHash.m ================================================================== --- utils/ofhash/OFHash.m +++ utils/ofhash/OFHash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -41,22 +41,25 @@ static void help(void) { [OFStdErr writeLine: OF_LOCALIZED(@"usage", - @"Usage: %[prog] [--md5|--ripemd160|--sha1|--sha224|--sha256|" - @"--sha384|--sha512] file1 [file2 ...]", + @"Usage: %[prog] [--md5] [--ripemd160] [--sha1] [--sha224] " + @"[--sha256] [--sha384] [--sha512] file1 [file2 ...]", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } static void printHash(OFString *algo, OFString *path, id hash) { - const unsigned char *digest = hash.digest; size_t digestSize = hash.digestSize; + const unsigned char *digest; + + [hash calculate]; + digest = hash.digest; [OFStdOut writeFormat: @"%@ ", algo]; for (size_t i = 0; i < digestSize; i++) [OFStdOut writeFormat: @"%02x", digest[i]]; Index: utils/ofhash/lang/de.json ================================================================== --- utils/ofhash/lang/de.json +++ utils/ofhash/lang/de.json @@ -1,9 +1,9 @@ { "usage": [ - "Benutzung: %[prog] [--md5|--ripemd160|--sha1|--sha224|--sha256|", - "--sha384|--sha512] datei1 [datei2 ...]" + "Benutzung: %[prog] [--md5] [--ripemd160] [--sha1] [--sha224] ", + "[--sha256] [--sha384] [--sha512] datei1 [datei2 ...]" ], "unknown_long_option": "%[prog]: Unbekannte Option: --%[opt]", "unknown_option": "%[prog]: Unbekannte Option: -%[opt]", "failed_to_open_file": "Fehler beim Öffnen der Datei %[file]: %[error]", "failed_to_read_file": "Fehler beim Lesen der Datei %[file]: %[error]" Index: utils/ofhttp/Makefile ================================================================== --- utils/ofhttp/Makefile +++ utils/ofhttp/Makefile @@ -13,14 +13,15 @@ ${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2} CPPFLAGS += -I../../src \ -I../../src/runtime \ -I../../src/exceptions \ + -I../../src/tls \ -I../.. \ -DLANGUAGE_DIR='"${datadir}/ofhttp/lang"' \ -DLIB_PREFIX='"${LIB_PREFIX}"' \ -DLIB_SUFFIX='"${LIB_SUFFIX}"' -LIBS := -L../../src -lobjfw \ +LIBS := -L../../src -L../../src/tls ${OFHTTP_LIBS} -lobjfw \ -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ ${LIBS} LD = ${OBJC} LDFLAGS += ${LDFLAGS_RPATH} Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -31,12 +31,16 @@ #endif #import "OFSandbox.h" #import "OFStdIOStream.h" #import "OFSystemInfo.h" #import "OFTCPSocket.h" -#import "OFTLSSocket.h" +#import "OFTLSStream.h" #import "OFURL.h" + +#ifdef HAVE_TLS_SUPPORT +# import "ObjFWTLS.h" +#endif #import "OFConnectionFailedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -75,10 +79,18 @@ ProgressBar *_progressBar; } - (void)downloadNextURL; @end + +#ifdef HAVE_TLS_SUPPORT +void +_reference_to_ObjFWTLS(void) +{ + _ObjFWTLS_reference = 1; +} +#endif OF_APPLICATION_DELEGATE(OFHTTP) static void help(OFStream *stream, bool full, int status) @@ -276,21 +288,10 @@ objc_autoreleasePoolPop(pool); return [fileName autorelease]; } @implementation OFHTTP -#ifdef OF_HAVE_PLUGINS -+ (void)initialize -{ - if (self != [OFHTTP class]) - return; - - /* Opportunistically try loading ObjOpenSSL and ignore any errors. */ - OFDLOpen(@LIB_PREFIX @"objopenssl" @LIB_SUFFIX, OFDLOpenFlagLazy); -} -#endif - - (instancetype)init { self = [super init]; @try { @@ -530,15 +531,15 @@ #ifdef OF_HAVE_SANDBOX if (outputPath != nil) [sandbox unveilPath: outputPath permissions: (_continue ? @"rwc" : @"wc")]; else - [sandbox unveilPath: [[OFFileManger defaultManager] + [sandbox unveilPath: [[OFFileManager defaultManager] currentDirectoryPath] permissions: (_continue ? @"rwc" : @"wc")]; - /* In case we use ObjOpenSSL for https later */ + /* In case we use OpenSSL for HTTPS later */ [sandbox unveilPath: @"/etc/ssl" permissions: @"r"]; sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif @@ -576,22 +577,25 @@ } if (_insecure) _HTTPClient.allowsInsecureRedirects = true; +#ifdef OF_WINDOWS + _useUnicode = [OFSystemInfo isWindowsNT]; +#else _useUnicode = ([OFLocale encoding] == OFStringEncodingUTF8); +#endif [self performSelector: @selector(downloadNextURL) afterDelay: 0]; } -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)sock - request: (OFHTTPRequest *)request +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)stream + request: (OFHTTPRequest *)request { - if (_insecure && [sock respondsToSelector: - @selector(setVerifiesCertificates:)]) - ((id )sock).verifiesCertificates = false; + /* Use setter instead of property access to work around GCC bug. */ + [stream setVerifiesCertificates: !_insecure]; } - (void)client: (OFHTTPClient *)client wantsRequestBody: (OFStream *)body request: (OFHTTPRequest *)request @@ -843,15 +847,16 @@ } else if ([exception isKindOfClass: [OFUnsupportedProtocolException class]]) { if (!_quiet) [OFStdOut writeString: @"\n"]; - [OFStdErr writeLine: OF_LOCALIZED(@"no_ssl_library", - @"%[prog]: No TLS library loaded!\n" - @" In order to download via https, you need to " - @"preload an TLS library for ObjFW\n" - @" such as ObjOpenSSL!", + [OFStdErr writeLine: OF_LOCALIZED(@"no_tls_support", + @"%[prog]: No TLS support in ObjFW!\n" + @" In order to download via HTTPS, you need to " + @"either build ObjFW with TLS\n" + @" support or preload a library adding TLS " + @"support to ObjFW!", @"prog", [OFApplication programName])]; } else if ([exception isKindOfClass: [OFReadOrWriteFailedException class]]) { OFString *error = OF_LOCALIZED( @"download_failed_read_or_write_failed_any", Index: utils/ofhttp/ProgressBar.h ================================================================== --- utils/ofhttp/ProgressBar.h +++ utils/ofhttp/ProgressBar.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 Index: utils/ofhttp/ProgressBar.m ================================================================== --- utils/ofhttp/ProgressBar.m +++ utils/ofhttp/ProgressBar.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 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 @@ -27,10 +27,15 @@ static const float oneKibibyte = 1024; static const float oneMebibyte = 1024 * 1024; static const float oneGibibyte = 1024 * 1024 * 1024; static const OFTimeInterval updateInterval = 0.1; + +#ifdef OF_MINT +/* freemint-gcc does not have trunc() */ +# define trunc(x) ((int64_t)(x)) +#endif #ifndef HAVE_TRUNCF # define truncf(x) trunc(x) #endif Index: utils/ofhttp/lang/de.json ================================================================== --- utils/ofhttp/lang/de.json +++ utils/ofhttp/lang/de.json @@ -50,15 +50,17 @@ ], "download_failed_invalid_server_reply": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " Ungültige Antwort vom Server!" ], - "no_ssl_library": [ - "%[prog]: Keine TLS-Bibliothek geladen!\n", - " Um Dateien über https zu laden, müssen Sie eine TLS-Bibliothek für ", - "ObjFW,\n", - " wie z.B. ObjOpenSSL, mittels LD_PRELOAD laden." + "no_tls_support": [ + "%[prog]: Keine TLS-Unterstützung in ObjFW!\n", + " Um via HTTPS runterzuladen, müssen Sie entweder ObjFW mit TLS-", + "Unterstützung\n", + " kompilieren oder eine Bibliothek mittels „preoad” laden, welche ", + "TLS-Support\n", + " zu ObjFW hinzufügt!" ], "download_failed_read_or_write_failed_any": "Lesen oder Schreiben", "download_failed_read_or_write_failed_read": "Lesen", "download_failed_read_or_write_failed_write": "Schreiben", "download_failed_read_or_write_failed": [